|
| 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