Skip to content

Commit 0325b2c

Browse files
authored
Add solutions in Centurion assembly and JCL (PlummersSoftwareLLC#900)
1 parent 09c0aef commit 0325b2c

File tree

6 files changed

+906
-0
lines changed

6 files changed

+906
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Centurion assembly solution by ren14500
2+
3+
![Algorithm](https://img.shields.io/badge/Algorithm-base-green)
4+
![Faithfulness](https://img.shields.io/badge/Faithful-no-yellowgreen)
5+
![Parallelism](https://img.shields.io/badge/Parallel-no-green)
6+
![Bit count](https://img.shields.io/badge/Bits-1-green)
7+
![Deviation](https://img.shields.io/badge/Deviation-sievesize-blue)
8+
9+
## Description
10+
11+
This solution provides two implementations in Centurion assembly, that being the assembly language for the Centurion minicomputer. The Centurion minicomputer is the topic of a [series of videos](https://youtube.com/playlist?list=PLnw98JPyObn0wJFdbcRDP7LMz8Aw2T97V) on the YouTube channel [UsagiElectric](https://www.youtube.com/@UsagiElectric).
12+
13+
The Centurion minicomputer was built around the [CPU6 board](https://github.com/Nakazoto/CenturionComputer/wiki/CPU6-Board), which was a further development of the original CPU4 architecture. In turn, that architecture was at least heavily inspired by the [Eldorado Electrodata Corporation EE200](https://github.com/Nakazoto/CenturionComputer/tree/main/Computer/EE200).
14+
15+
As it stands, there does not seem to be a comprehensive programmer's manual available for Centurion CPU6 assembly. The instruction set and the assembly syntax used in this solution have been deduced by combining the following sources:
16+
17+
- [The EE200 documentation](https://github.com/Nakazoto/CenturionComputer/tree/main/Computer/EE200) referred to earlier.
18+
- [A wiki page](https://github.com/sjsoftware/centurion-cpu6/wiki/Centurion-CPU6-Instruction-Reference) written by [sjsoftware/gecho](https://github.com/sjsoftware). The page covers their efforts towards disassembling the CPU6 microcode to fully document the CPU's opcode behavior.
19+
- The output of the CPL compiler. CPL is a language for which [a Primes solution is also available](../../PrimeCenturionPL/solution_1/).
20+
- Reverse engineering of XASSM, the Centurion assembler executable.
21+
22+
In fact, for those interested in the Centurion CPU6 instruction set and the assembler syntax, this solution may itself act as a source of information. For one, the source code included in this solution has been extensively documented.
23+
24+
## Implementations
25+
26+
This solution includes two implementations:
27+
28+
- An implementation to be run on top of the Centurion OS. It uses service calls for time keeping and I/O, and is kept in the file [sieveo.asm](sieveo.asm).
29+
- An implementation to be run on bare metal, that is directly on the Centurion hardware. It uses memory-mapped I/O (MMIO) to communicate with the console (CRT0), and is kept in the file [sieveb.asm](sieveb.asm).
30+
31+
## Sieve sizes
32+
33+
The sieve size for the implementations can be configured by uncommenting a triple of lines at the top of the assembly source files; details are included in the files themselves.
34+
The maxmimum sieve size supported by the implementations is 65,535.
35+
36+
## Run instructions
37+
38+
This solution's implementations can be assembled and executed on an actual Centurion minicomputer, or a sufficiently complete emulator. A list of known emulators can be found on [the respective page](https://github.com/Nakazoto/CenturionComputer/wiki/Emulators-and-Simulations) on Nakazoto's [CenturionComputer wiki](https://github.com/Nakazoto/CenturionComputer/wiki) on GitHub.
39+
40+
Use the following commands to edit, assemble and run the solution:
41+
42+
```text
43+
S.CED ZSIEVE 0 CRT0
44+
P.ASM SIEVE 0 DUMMY X
45+
.RUN XSIEVE
46+
```
47+
48+
For the bare metal version, use the same commands to edit and compile, but don't use `.RUN` to run the program. Instead, one needs to reboot the (emulated) Centurion and run it from the bootloader - those instructions are in the top of the sieveb.asm file.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
* Sieve of Eratosthenes by ren14500. Public domain.
2+
*
3+
* This version runs bare-metal and uses MMIO to CRT0 for I/O.
4+
*
5+
* Assemble with P.ASM, hit SELECT to get to LOS and enter the executable name.
6+
*
7+
* Search for *** to find optional parts to comment or uncomment.
8+
*
9+
* Maximum prime and square root of it. The number of bytes needed to hold the
10+
* flags. Uncomment one set. If 65,535 is not used, you must uncomment some
11+
* code later as well!
12+
MXPRIME EQU 65535 ; 65,535
13+
RTPRIME EQU 255 ; 65,535
14+
FLAGBYTES EQU 65535/8+1 ; 65,535
15+
***MXPRIME EQU 40000 ; 40,000
16+
***RTPRIME EQU 200 ; 40,000
17+
***FLAGBYTES EQU 40000/8 ; 40,000
18+
***MXPRIME EQU 32768 ; 32,768
19+
***RTPRIME EQU 181 ; 32,768
20+
***FLAGBYTES EQU 32768/8 ; 32,768
21+
***MXPRIME EQU 10000 ; 10,000
22+
***RTPRIME EQU 100 ; 10,000
23+
***FLAGBYTES EQU 10000/8 ; 10,000
24+
***MXPRIME EQU 1000 ; 1,000
25+
***RTPRIME EQU 31 ; 1,000
26+
***FLAGBYTES EQU 1000/8 ; 1,000
27+
***MXPRIME EQU 100 ; 100
28+
***RTPRIME EQU 10 ; 100
29+
***FLAGBYTES EQU 100/8+1 ; 100
30+
*
31+
* Set the program title and begin.
32+
TITLE 'SIEVEO'
33+
ZSIEVEO BEGIN X'0200'
34+
*
35+
* Reserve space for the stack.
36+
DS 100
37+
STKTOP EQU *
38+
*
39+
* Bitmasks to get each bit from a flags byte.
40+
GMASKS DB X'01'
41+
DB X'02'
42+
DB X'04'
43+
DB X'08'
44+
DB X'10'
45+
DB X'20'
46+
DB X'40'
47+
DB X'80'
48+
*
49+
* Bitmasks to clear each bit from a flags byte.
50+
CMASKS DB X'FE'
51+
DB X'FD'
52+
DB X'FB'
53+
DB X'F7'
54+
DB X'EF'
55+
DB X'DF'
56+
DB X'BF'
57+
DB X'7F'
58+
*
59+
* Constants.
60+
WELCOME DB X'8D' ; CR
61+
DW X'8A8A' ; LF LF
62+
DC 'START'
63+
CRLF DW X'8D8A' ; CR LF
64+
DB 0
65+
TWO DC ' 2'
66+
DB 0
67+
COMMA DC ','
68+
DB 0
69+
COUNT DC 'COUNT:'
70+
DB 0
71+
PROOT DW RTPRIME ; Square root of prime.
72+
*
73+
* Variables.
74+
PRIMES DS FLAGBYTES ; Flags. Bits set to 0 are not prime.
75+
FACTORC DS 2 ; Factor current.
76+
FACTOR2 DS 2 ; Factor doubled.
77+
PNUM DS 2 ; Prime number.
78+
PCOUNT DW 1 ; Count of primes.
79+
PFMT DC '@@@@@@@' ; Format for printing primes.
80+
PLEN EQU *-PFMT ; Length of format.
81+
PBUFF DB 0,PLEN+1 ; Buffer for printing.
82+
*
83+
* Entrypoint. Set the stack pointer.
84+
ENTRY XFR= STKTOP,S ; Literal STKTOP -> S.
85+
JSR/ PRINTSTR ; Jump to subroutine direct.
86+
DW WELCOME ; Address of string to print.
87+
*
88+
* Set all odd bits to 1 to assume prime. Non-primes will get zeroed later.
89+
* Register assignments:
90+
* A = Working register.
91+
* B = Working register.
92+
* X =
93+
* Y = Working register.
94+
* Z =
95+
LDAB= X'AA' ; Literal 0xAA -> AL.
96+
STAB/ PRIMES ; Direct AL -> (PRIMES). Set first flags.
97+
LDA= FLAGBYTES-2 ; Literal length remaining-1 -> A.
98+
LDB= PRIMES ; Literal source address -> B.
99+
XFR= PRIMES+1,Y ; Literal destination address -> Y.
100+
MVL ; Move long.
101+
*
102+
* Main loop. Register assignments:
103+
* A = Working register.
104+
* B = Working register.
105+
* X = Working register.
106+
* Y = Address of primes flags.
107+
* Z = Current factor.
108+
*
109+
* Start at factor 3.
110+
XFR= 3,Z ; Literal 3 -> Z.
111+
XFR= PRIMES,Y ; Literal address of primes flags -> Y.
112+
*
113+
* Outer loop to search for the next prime and clear multiples thereof.
114+
OUTER EQU *
115+
*
116+
* Find the next prime.
117+
XFR Z,X ; Z -> X.
118+
SRR X,3 ; X / 8 -> X. X = index of byte containing flags.
119+
ADD Y,X ; Y + X -> X. X = address of ^^^.
120+
XFR Z,B ; Z -> B.
121+
AND= 7,B ; Literal B % 8 -> B. B = index of bit in byte.
122+
ADD= GMASKS,B ; Literal GMASKS + B -> B. B = address of bitmask.
123+
LDBB+ B ; Indexed bitmask (B) -> BL.
124+
LDAB+ X ; Indexed flags byte (X) -> AL.
125+
ANDB BL,AL ; BL & AL -> AL.
126+
BNZ CLRMULT ; If the bit was set, branch to clear multiples.
127+
JMP NXTPRIME ; Relative jump to try the next prime.
128+
*
129+
* Clear multiples of this prime.
130+
CLRMULT XFR Z,A ; Z -> A.
131+
MUL A,A ; A * A -> A,B. Start at the factor squared.
132+
STB/ FACTORC ; Direct B -> (FACTORC). Ignore A - no overflow.
133+
XFR B,X ; B -> X.
134+
XFR Z,A ; Z -> A.
135+
SLA ; A * 2 -> A. Double the factor.
136+
STA/ FACTOR2 ; Direct A -> (FACTOR2).
137+
*
138+
* Loop to clear each multiple.
139+
CLRLOOP XFR X,B ; X -> B.
140+
LDAB= X'1F' ; 0x1F -> AL. Mask for clearing after dividing.
141+
SRR X,3 ; X / 8 -> X. Arithmetic, so need to clear bits.
142+
ANDB AL,XU ; AL & XU -> XU. X = ind of byte containing flags.
143+
ADD Y,X ; Y + X -> X. X = address of ^^^.
144+
AND= 7,B ; Literal B % 8 -> B. B = index of bit in byte.
145+
ADD= CMASKS,B ; Literal CMASKS + B -> B. B = address of bitmask.
146+
LDBB+ B ; Indexed bitmask (B) -> BL.
147+
LDAB+ X ; Indexed flags byte (X) -> AL.
148+
ANDB BL,AL ; BL & AL -> AL.
149+
STAB+ X ; Indexed A -> (X).
150+
LDX/ FACTORC ; Direct (FACTORC) -> X.
151+
LDA/ FACTOR2 ; Direct (FACTOR2) -> A.
152+
ADD A,X ; A + X -> X. X = next multiple.
153+
BL NXTPRIME ; On overflow, must be past max prime.
154+
STX/ FACTORC ; Direct X -> (FACTORC).
155+
*** For max prime = 65535 (0xFFFF), comment out the next 4 lines as these
156+
*** checks are unnecessary (though will work). For any other max prime, the
157+
*** next 4 lines must be uncommented.
158+
LDA= MXPRIME ; Literal MXPRIME -> A.
159+
XFR X,B ; X -> B.
160+
SUB A,B ; A - B -> B.
161+
BNL NXTPRIME ; Max prime less than next multiple, break out.
162+
JMP CLRLOOP ; Clear the next multiple.
163+
*
164+
* Skip to the next possible factor.
165+
NXTPRIME INR Z,2 ; Z + 2 -> Z.
166+
LDA/ PROOT ; Direct (PROOT) -> A.
167+
SUB Z,A ; Z - A -> A.
168+
BLE OUTER ; Loop if factor is less than/equal sqrt of prime.
169+
*
170+
* Skip past the first prime (2).
171+
JSR/ PRINTSTR ; Jump to subroutine direct.
172+
DW TWO ; Address of string to print.
173+
*
174+
* Print primes and get the count. Register assignments:
175+
* A = Current bitmask (upper), current flags (lower).
176+
* B = Current prime.
177+
* X = Max prime.
178+
* Y = Address of primes flags, updated.
179+
* Z = Primes count.
180+
LDA= X'0800' ; Literal 0x08 (bit 3) -> AU, 0 -> AL.
181+
LDAB+ Y+ ; Indexed (Y) -> AL, then increment Y. 1st flags.
182+
LDB= 3 ; Literal 3 -> B.
183+
STB/ PNUM ; Direct B -> (PNUM).
184+
XFR= 1,Z ; Literal 1 -> Z.
185+
PRLOOP XAB ; A -> B.
186+
ANDB BU,BL ; BU & BL -> BL.
187+
BZ NOTPRIME ; If bit not set, skip past output.
188+
INR Z ; Z + 1 -> Z.
189+
*** Comment out the next 10 lines to omit printing results.
190+
JSR/ PRINTSTR ; Jump to subroutine direct.
191+
DW COMMA ; Address of string to print.
192+
MVF (PLEN)/PFMT,/PBUFF ; Direct move PLEN bytes (PFMT)->(PBUFF).
193+
STK A,4 ; Push A,B to the stack.
194+
LDAB= PLEN ; PLEN -> AL. Length of string to convert to.
195+
LDBB= X'A0' ; 0xA0 (' ') -> BL. Padding character.
196+
CFB /PBUFF(10),/PNUM(2) ; Direct convert to base-10.
197+
POP A,4 ; Pop B,A from the stack.
198+
JSR/ PRINTSTR ; Jump to subroutine direct.
199+
DW PBUFF ; Address of string to print.
200+
NOTPRIME LDB/ PNUM ; Direct load (PNUM) -> B.
201+
INR B ; B + 1 -> B.
202+
BZ PDONE ; On overflow, we're past the max prime.
203+
STB/ PNUM ; Direct B -> (PNUM).
204+
XFR= MXPRIME,X ; Literal MXPRIME -> X.
205+
SUB X,B ; X - B -> B.
206+
BNL PDONE ; Max prime less than prime candidate, break out.
207+
SLRB AU ; AU << 1 -> AU
208+
BNL PRLOOP ; If no overflow, loop for next bit in flags.
209+
INRB AU ; AU = 1. New mask for next flags.
210+
LDAB+ Y+ ; Indexed (Y) -> AL, then increment Y. Next flags.
211+
JMP PRLOOP ; Relative jump to continue printing.
212+
PDONE EQU *
213+
*
214+
* Print the count.
215+
JSR/ PRINTSTR ; Jump to subroutine direct.
216+
DW CRLF ; Address of string to print.
217+
JSR/ PRINTSTR ; Jump to subroutine direct.
218+
DW COUNT ; Address of string to print.
219+
XFR Z,A ; Z -> A.
220+
STA/ PNUM ; Direct A -> (PNUM).
221+
MVF (PLEN)/PFMT,/PBUFF ; Direct move PLEN bytes (PFMT)->(PBUFF).
222+
LDAB= PLEN ; PLEN -> AL. Length of string to convert to.
223+
LDBB= X'A0' ; 0xA0 (' ') -> BL. Padding character.
224+
CFB /PBUFF(10),/PNUM(2) ; Direct convert to base-10.
225+
JSR/ PRINTSTR ; Jump to subroutine direct.
226+
DW PBUFF ; Address of string to print.
227+
JSR/ PRINTSTR ; Jump to subroutine direct.
228+
DW CRLF ; Address of string to print.
229+
*
230+
* Enter infinite loop.
231+
INFINITE JMP INFINITE ; Relative jump to self.
232+
*
233+
* Print the null-terminated string pointed to by (X). Register assignments:
234+
* A = MUX status.
235+
* B = Next character.
236+
* X = RSR target.
237+
* Y = MUX status mask.
238+
* Z = Address of next character.
239+
* See https://github.com/Nakazoto/CenturionComputer/wiki/MUX-Board#mux-mmio
240+
PRINTSTR STK A,4 ; Push A,B to the stack.
241+
STK Y,4 ; Push Y,Z to the stack.
242+
LDA+ X+ ; (X) -> A, then increment X.
243+
XAZ ; A -> Z.
244+
XFR= X'0002',Y ; Literal bit 1 set -> Y.
245+
PSLOOP LDBB+ Z+ ; (Z) -> BL, then increment Z.
246+
BZ PSEND ; Branch if zero.
247+
PSWAIT LDAB/ X'F200' ; Load direct 0xF200 -> A.
248+
ANDB YL,AL ; YL & AL -> AL
249+
BZ PSWAIT ; Branch if bit was not set.
250+
STBB/ X'F201' ; Store direct B -> 0xF201.
251+
JMP PSLOOP ; Jump relative for next character.
252+
PSEND POP Y,4 ; Pop Z,Y from the stack.
253+
POP A,4 ; Pop B,A from the stack.
254+
RSR ; Return from subroutine.
255+
*
256+
* End of source.
257+
END ENTRY ; Specify the entrypoint.
258+

0 commit comments

Comments
 (0)