%define COM_UARTF 0x03 %define COM_UARTW 0x05 %define COM_UARTR 0x04 %define COM_LED 0x06 %define COM_DIP 0x08 %define COM_UARTIN 0x09 %define LF 0x0a %define CR 0x0d %define LFCR 0x0a0d %define COM_UART_TRANS 0b0000_0001 %define COM_UART_RECV 0b0000_0010 %define COM_UART_ECHO 0b0000_0100 %define COM_UART_RR 0b0000_1000 ; Read Ready %macro MEMP 1 MEM1 %1@1 MEM0 %1@0 %endmacro %macro BRP 1 BR1 %1@1 BR0 %1@0 %endmacro %macro RET 0 BR0 STACK BR1 STACK BRZ NULL %endmacro %macro CALL 1 BRP %1 STACK %%return@1 STACK %%return@0 BRZ NULL %%return: %endmacro %macro JUMP 1 BRP %1 BRZ NULL %endmacro %macro BRPZ 2 BRP %1 BRZ %2 %endmacro %macro PRINTMEM 0 STACK REG0 REG0 LWHI CALL print_hex REG0 LWLO CALL print_hex REG0 0x20 CALL print_char REG0 STACK %endmacro %macro PRINTREG 0 STACK REG0 STACK REG0 REG0 REG1 CALL print_hex REG0 STACK CALL print_hex REG0 0x20 CALL print_char REG0 STACK %endmacro %macro PRINTREGLN 0 STACK REG0 STACK REG0 REG0 REG1 CALL print_hex REG0 STACK CALL print_hex ;REG0 0x20 ;CALL print_char ;REG0 LWHI ;CALL print_hex ;REG0 LWLO ;CALL print_hex CALL println REG0 STACK %endmacro ; ================== ; Jump on conditions ; ================== %macro BGT 1 BRPZ %1,LE %endmacro %macro BLT 1 BRPZ %1,GE %endmacro %macro BGE 1 BRPZ %1,LT %endmacro %macro BLE 1 BRPZ %1,GT %endmacro %macro BEQ 1 BRPZ %1,NE %endmacro %macro BNE 1 BRPZ %1,EQ %endmacro %macro CALC_SIEVE_POINTER 4 ; args: [value of n] [shifted value to store to] [jump label] [debug letter] ;; start debug ;STACK REG0 ;REG0 %4 ;CALL print_char ;REG0 STACK ;STACK REG0 ;REG0 %1 ;CALL print_u8 ;REG0 0x20 ;CALL print_char ;REG0 STACK ;; stop debug ALU0 %1 STACK ALU0 ALU1 16 ALU0 DIV ;ALU1 sieve2@0 MEM0 ADD ;ALU0 sieve2@1 ALU1 0x00 MEM1 ADC ; Memory pointer ready ALU0 STACK ALU1 16 ALU1 MOD ALU0 1 %2 SLL ALU0 8 ; if n%16 >= 8 BGE %3 ; is high byte memhi %endmacro %macro COPY 1 ; copy current pointer to memory %1 STACK MEMLO STACK MEMHI MEMP %1 ALU0 STACK ; can't use 2 memory operations at once. MEMHI ALU0 ALU0 STACK MEMLO ALU0 %endmacro section .data depth=4096,width=2 DBE 1 intro_text: DB "\x1Bc\x1B[2J\x1B[HBooting \x1B[1m\x1B[36mOISC\x1B[0m system\r\n",0 generalbuf: DBE 1 generalbuf2: DBE 1 generalbuf3: DBE 1 sieve_x: DBE 1 sieve_x2: DBE 1 sieve_y: DBE 1 sieve_y2: DBE 1 sieve1: DBE 1 sieve_arr: DBE 16 memend: DBE 1 section .text depth=3072,width=2,bin_width=13,parity=2,fill_bits=27648 ;MEMP generalbuf2 ;MEMP generalbuf ;MEMLO 0x00 ;MEMHI 0x00 REG0 0xFF REG1 0xFF CALL print_u16 REG0 intro_text@0 REG1 intro_text@1 CALL print_string ;; test mul_u16 ;MEMP generalbuf ;MEMLO 60059@0 ; num1 lo ;MEMHI 60059@1 ; num1 hi ;MEMP generalbuf2 ;MEMLO 60 ; num1 lo ;MEMHI 0 ; num1 hi ;CALL div_u16 ;STACK REG0 ;STACK REG1 ;MEMP generalbuf3 ;REG0 MEMLO ;REG1 MEMHI ;CALL print_u16 ;REG0 '.' ;CALL print_char ;REG1 STACK ;REG0 STACK ;CALL print_u16 ;JUMP forever ;REG0 MEMLO ;CALL print_hex ;REG0 MEMHI ;CALL print_hex ;ALU0 0x44 ;ALU1 0x44 ;REG0 NE ;CALL print_hex ;ALU0 0x33 ;ALU1 0x00 ;REG0 NE ;CALL print_hex ;CALL println ;MEMP memend ;MEMLO 0x04 REG0 '@' CALL print_char CALL clean_ram REG0 '@' CALL print_char CALL calc_sieve REG0 '@' CALL print_char ;JUMP forever CALL println REG0 0 REG1 0 .print_sieve: ; Set memory pointer ALU0 memend@0 ALU1 REG0 MEM0 ADD ALU0 memend@1 ALU1 REG1 MEM1 ADC ; check for overflow ALU0 MEM1 ALU1 0x0e BGT .done STACK REG0 STACK REG1 BR0 MEMHI STACK BR0 BR0 MEMLO STACK BR0 ; now is loop for every bit in memory MEMP generalbuf3 MEMLO 16 MEMHI 0 CALL mul_u16 BR0 STACK MEMLO BR0 MEMHI 1 .print_loop0: ALU0 MEMHI ALU1 MEMLO BRPZ .z0,AND ;; This number is prime CALL print_u16 CALL println MEMP generalbuf3 ;PRINTREG ;JUMP .d0 .z0: ;CALL print_u16 ;PRINTREG ;; This number is not prime .d0: ALU1 1 ALU0 MEMHI MEMHI SLL ALU0 REG0 REG0 ADD ALU0 REG1 ALU1 0 REG1 ADC BRPZ .print_loop0e,MEMHI JUMP .print_loop0 .print_loop0e: BR0 STACK MEMLO BR0 MEMHI 1 ;PRINTREG .print_loop1: ALU0 MEMHI ALU1 MEMLO BRPZ .z1,AND ;; This number is prime CALL print_u16 CALL println MEMP generalbuf3 JUMP .d1 .z1: ;PRINTREG ;CALL print_u16 ;; This number is not prime .d1: ALU1 1 ALU0 MEMHI MEMHI SLL BRPZ .print_loop1e,MEMHI ALU0 REG0 REG0 ADD ALU0 REG1 ALU1 0 REG1 ADC JUMP .print_loop1 .print_loop1e: REG1 STACK REG0 STACK ALU0 REG0 ALU1 1 REG0 ADD ALU0 REG1 ALU1 0 REG1 ADC JUMP .print_sieve .done: REG0 '@' CALL print_char JUMP forever .hi: ALU0 MEMHI .next: ALU1 REG1 BRPZ .noprint,AND STACK REG0 CALL print_u8 REG0 0x20 CALL print_char REG0 STACK .noprint: ALU1 1 ALU0 REG0 REG0 ADD BRPZ forever,REG0 JUMP .print_sieve ; REG0 0 ;hex_test: ; ALU0 REG0 ; ALU1 1 ; REG0 ADD ; CALL print_hex ; REG1 REG0 ; REG0 0x20 ; CALL print_char ; REG0 REG1 ; BRPZ .end,REG0 ; JUMP hex_test ;.end: forever: JUMP forever clean_ram: MEMP memend .loop: MEMLO 0x00 MEMHI 0x00 ALU0 1 ALU1 MEM0 MEM0 ADD ALU0 0 ALU1 MEM1 MEM1 ADC ALU0 MEM1 ALU1 0x0e BGT .done JUMP .loop .done: RET log2n_u8: ;; Only for 2^n numbers REG1 0 ALU1 1 .loop: BRPZ .done,REG0 ALU0 REG0 REG0 SRL ALU0 REG1 REG1 ADD JUMP .loop .done: RET mod_u16: ;; Russian Peasant Multiplication ;; https://stackoverflow.com/questions/2566010 ;; {reg1,reg0} = {reg1,reg0} % *generalbuf{memhi,memlo} %def $a0,REG0 %def $a1,REG1 %def $b0,MEMLO %def $b1,MEMHI %def $x0,MEMLO %def $x1,MEMHI COPY generalbuf2 ; X = B STACK $a0 STACK $a1 ALU0 $a1 ; \ ALU1 1 ; | $a1 SRL ; | ALU0 $a0 ; | A >> 1 (divide by 2) STACK ROR ; | ALU0 SRL ; | ALU1 STACK; | $a0 OR ; / ; Do while (X <= A/2) .while_a_start: ALU0 $x1 ALU1 $a1 BGT .while_a_end BLT .while_a_0 ALU0 $x0 ALU1 $a0 BGE .while_a_end .while_a_0: ALU0 $x0 ; \ ALU1 1 ; | $x0 SLL ; | STACK ROL ; | x <<= 1 ALU0 $x1 ; | ALU0 SLL ; | ALU1 STACK ; | $x1 OR ; / JUMP .while_a_start .while_a_end: $a1 STACK $a0 STACK ; restore a .while_b_start: MEMP generalbuf ;PRINTREG ; Do while (A >= B) ALU0 $a1 ALU1 $b1 BLT .while_b_end BGT .while_b_0 ALU0 $a0 ALU1 $b0 BLT .while_b_end .while_b_0: MEMP generalbuf2 ; Check if A >= X ALU0 $a1 ALU1 $x1 BLT .next BGT .a_ge_x ALU0 $a0 ALU1 $x0 BLT .next .a_ge_x: ;PRINTREG ALU0 $a0 ALU1 $x0 $a0 SUB ; \ ALU0 $a1 ; | A -= X ALU1 $x1 ; | $a1 SBC ; / .next: ; X >>= 1 ALU0 $x1 ALU1 1 $x1 SRL STACK ROR ALU0 $x0 ALU0 SRL ALU1 STACK $x0 OR BRPZ .check_null,$x1 ; Back to while loop JUMP .while_b_start .check_null: BRPZ .while_b_end,$x0 JUMP .while_b_start .while_b_end: RET %macro SLL16 3 ALU0 %2 ALU1 %1 ; multiply by 2 %2 SLL STACK ROL ALU0 %3 ; multiply by 2 with carry ALU0 SLL ALU1 STACK %3 OR %endmacro div_u16: ;; Divide 16bit by 16bit (can be expanded) ;; source: https://en.wikipedia.org/wiki/Division_algorithm#Integer_division_(unsigned)_with_remainder ;; generalbuf3 = generalbuf / generalbuf2; reg1,reg0 => reminder %def $Nl,MEMLO ; \ %def $Nh,MEMHI ; / generalbuf %def $Dl,MEMLO ; \ %def $Dh,MEMHI ; / generalbuf2 %def $Ql,MEMLO ; \ %def $Qh,MEMHI ; / generalbuf3 %def $Rl,REG0 %def $Rh,REG1 $Rl 0 $Rh 0 MEMP generalbuf3 MEMLO 0 MEMHI 0 STACK 0b1000_0000 ; put 0 .for_start0: SLL16 1,$Rl,$Rh ;; Finding N(i) ALU0 STACK STACK ALU0 MEMP generalbuf ALU1 $Nh BRPZ .z0,AND ; Nl & i == 0 ALU0 0b0000_0001 ALU1 $Rl $Rl OR ; R(0) = N(i) = 1 JUMP .check0 .z0: ALU0 0b1111_1110 ALU1 $Rl $Rl AND ; R(0) = N(i) = 0 .check0: ; if R >= D MEMP generalbuf2 ALU0 $Rh ALU1 $Dh BLT .for_end0 BGT .sub0 ALU0 $Rl ALU1 $Dl BLT .for_end0 .sub0: ALU0 $Rl ALU1 $Dl $Rl SUB ALU0 $Rh ALU1 $Dh $Rh SBC MEMP generalbuf3 ALU0 $Qh ; Q(i) = 1 ALU1 STACK STACK ALU1 $Qh OR .for_end0: ALU0 STACK ALU1 1 ALU0 SRL BRPZ .done0,ALU0 STACK ALU0 JUMP .for_start0 .done0: STACK 0b1000_0000 ; put 0 .for_start1: SLL16 1,$Rl,$Rh ;; Finding N(i) ALU0 STACK STACK ALU0 MEMP generalbuf ALU1 $Nl BRPZ .z1,AND ALU0 0b0000_0001 ALU1 $Rl $Rl OR ; R(0) = N(i) = 1 JUMP .check1 .z1: ALU0 0b1111_1110 ALU1 $Rl $Rl AND ; R(0) = N(i) = 0 .check1: ; if R >= D MEMP generalbuf2 ALU0 $Rh ALU1 $Dh BLT .for_end1 BGT .sub1 ALU0 $Rl ALU1 $Dl BLT .for_end1 .sub1: ALU0 $Rl ALU1 $Dl $Rl SUB ALU0 $Rh ALU1 $Dh $Rh SBC MEMP generalbuf3 ALU0 $Ql ; Q(i) = 1 ALU1 STACK STACK ALU1 $Ql OR .for_end1: ALU0 STACK ALU1 1 ALU0 SRL BRPZ .done1,ALU0 STACK ALU0 JUMP .for_start1 .done1: RET ;div_u16: ;; Divide 16bit number by 8bit ;; Insparation taken from: ;; http://www.avr-asm-tutorial.net/avr_en/calc/DIV8E.html ; ; %def $rd1l,MEMLO ; %def $rd1h,MEMHI ; %def $rd2,REG0 ; %def $rd1u,REG1 ; %def $rel,MEMLO ; %def $reh,MEMHI ; ; $rd1u 0 ; MEMP generalbuf2 ; $rel 1 ; $reh 0 ;.div8a: ; MEMP generalbuf ; ALU0 1 ; ALU1 $rd1l ; multiply by 2 ; $rd1l SLL ; STACK ROL ; ; ALU1 $rd1h ; multiply by 2 with carry ; ALU1 SLL ; ALU0 STACK ; $rd1h OR ; STACK ROL ; ; ALU0 1 ; ALU1 $rd1u ; ALU1 SLL ; ALU0 STACK ; $rd1u OR ; ALU0 0 ; ALU1 ROL ; BNE .div8b ; ALU0 $rd1u ; ALU1 $rd2 ; $rd1u SUB ; ALU1 SUBC ; ALU0 0 ; BNE .div8c ;.div8b: ; ALU0 $rd1u ; ALU1 $rd2 ; $rd1u SUB ; STACK 1 ; JUMP .div8d ;.div8c: ; STACK 0 ;.div8d: ; MEMP generalbuf2 ; ALU0 1 ; ALU1 $rel ; ALU0 SLL ; ALU1 STACK ; $rel OR ; STACK ROL ; ; ALU0 1 ; ALU1 $reh ; ALU0 SLL ; ALU1 STACK ; $reh OR ; BRP .div8a ; BRZ ROL ;.done: ; RET calc_sieve: ; Sieve of Atkin %def $xl,MEMLO %def $xh,MEMHI %def $x2l,REG0 %def $x2h,REG1 %def $yl,MEMLO %def $yh,MEMHI %def $y2l,REG0 %def $y2h,REG1 ; loop x setup MEMP sieve_x $xl 1 ; $xh 0 ; x=1 .loopx: COPY sieve_x2 ; temp copy x to x2 REG0 $xl REG1 $xh CALL mul_u16 ALU1 0 ALU0 MEMHI BRP .endp1 BRZ EQ ; if x^2 >= 2^16 ALU0 MEMLO BRZ EQ ; if x^2 >= 2^16 MEMHI REG1 MEMLO REG0 ; loop y setup MEMP sieve_y $yl 1 ; $yh 0 ; y=1 .loopy: COPY sieve_y2 ; temp copy y to y2 REG0 $yl REG1 $yh CALL mul_u16 ALU1 0 ALU0 MEMHI BRP .loopxe BRZ EQ ; if y^2 >= 2^16 ALU0 MEMLO BRZ EQ ; if y^2 >= 2^16 MEMHI REG1 MEMLO REG0 ; ================== ; Start of Main loop ; ================== ;MEMP sieve1 %def $nh,REG1 %def $nl,REG0 ;MEMP sieve_y2 ;PRINTMEM ;CALL println .c1: MEMP sieve_x2 COPY sieve1 ; copy x^2 to n REG0 4 REG1 0 CALL mul_u16 ; x^2 * 0x0004 ALU0 MEMHI; \ ALU1 0 ; | BRP .c2 ; | checking if 4*x^2 overflow BRZ EQ ; | ALU0 MEMLO; | BRZ EQ ; / ; n += y^2 ;$nl MEMLO ;$nh MEMHI MEMP sieve_y2 ALU0 $nl ; $nl ALU1 MEMLO ; $y2l $nl ADD ALU0 $nh ALU1 MEMHI ; $y2h $nh ADC ALU0 ADDC ; \ ALU1 0 ; | check for 4*x^2+y^2 oveflow BNE .c2 ; / ;CALL print_u16 ;STACK REG0 ;REG0 0x20 ;CALL print_char ;REG0 STACK MEMP sieve1 ; \ MEMLO $nl ; | save n to sieve1 MEMHI $nh ; / ; checkinf for n%12 == 1 || n%12 == 5 MEMP generalbuf MEMHI 0 MEMLO 12 ; storing 12 CALL mod_u16 ; n = n%12 ALU0 0 ALU1 $nh ; if n%12 high byte != 0 BNE .c2 ALU0 1 ; if n%12 == 1 ALU1 $nl BEQ .c1x ALU0 5 ; if n%12 == 5 BNE .c2 .c1x: ; call sieve CALL xorSieveArray .c2: MEMP sieve_x2 COPY sieve1 ; copy x^2 to n REG0 3 REG1 0 CALL mul_u16 ; x^2 * 0x0003 ALU0 MEMHI; \ ALU1 0 ; | BRP .c3 ; | checking if 3*x^2 overflow BRZ EQ ; | ALU0 MEMLO; | BRZ EQ ; / ; n += y^2 MEMP sieve_y2 ALU0 $nl ; $nl ALU1 MEMLO ; $y2l $nl ADD ALU0 $nh ALU1 MEMHI $nh ADC ALU0 ADDC ; \ ALU1 0 ; | chcek for 3*x^2+y^2 overflow BNE .c3 ; / MEMP sieve1 MEMHI $nh MEMLO $nl ; checkinf for n%12 == 7 MEMP generalbuf MEMHI 0 MEMLO 12 ; storing 12 CALL mod_u16 ; n = n%12 ALU0 0 ALU1 REG1 ; if n%12 high byte != 0 BRP .c3 BRZ EQ ALU0 7 ; if n%12 == 7 ALU1 REG0 BRZ EQ CALL xorSieveArray .c3: ; checking if x > y MEMP sieve_y REG0 MEMLO REG1 MEMHI MEMP sieve_x ALU0 REG1 ; xh ALU1 MEMHI ; yh BGT .c3c BLT .loopye ; jump if x < y ALU0 REG0 ; xl ALU1 MEMLO ; yl BGE .loopye ; jump to .loopy if x < y .c3c: MEMP sieve_x2 COPY sieve1 ; copy x^2 to n REG0 3 REG1 0 CALL mul_u16 ; x^2 * 0x0003 ; now n is 32bit in {MEMHI, MEMLO, REG1, REG0} ; where do we store y^2? Should be in stack but for test lets use BRP BR0 MEMLO BR1 MEMHI MEMP sieve_y2 COPY sieve1 ALU0 REG0 ALU1 MEMLO REG0 SUB ALU0 REG1 ALU1 MEMHI REG1 SBC ALU0 BR0 ALU1 0 MEMLO SBC ALU0 BR1 ALU1 0 MEMHI SBC ; now 32bit in {MEMHI, MEMLO, REG1, REG0} ; has been subtraced with y^2 ALU0 MEMHI ; \ ALU1 0 ; | BRP .loopye; | checking if 3*x^2-y^2 overflow BRZ EQ ; | ALU0 MEMLO ; | BRZ EQ ; / MEMLO $nl MEMHI $nh ; checkinf for n%12 == 11 MEMP generalbuf MEMHI 0 MEMLO 12 ; storing 12 CALL mod_u16 ; n = n%12 ALU0 0 ALU1 $nh ; if n%12 high byte != 0 BRP .loopye BRZ NE ALU0 7 ; if n%12 == 7 ALU1 $nl BRZ NE ; n should be in *sieve1 CALL xorSieveArray ; ================ ; End of main loop ; ================ .loopye: MEMP sieve_y ALU0 $yl ; \ ALU1 1 ; | $yl ADD ; | y++ ALU1 ADDC ; | ALU0 $yh ; | $yh ADD ; / JUMP .loopy .loopxe: MEMP sieve_x ALU0 $xl ; \ ALU1 1 ; | $xl ADD ; | x++ ALU1 ADDC ; | ALU0 $xh ; | $xh ADD ; / JUMP .loopx ; ============= ; End of part 1 ; ============= .endp1: ; ; now lets reject squares ; %def $r,REG0 ; %def $r2,REG1 ; $r 5 ; r:=5 ;.loopr: ; ALU0 $r ; ALU1 $r ; $r2 MULLO ; reg1 := r^2 ; ALU0 MULHI ; ALU1 0x00 ; BNE .endp2 ; end if r^2 > 255 ; ; accessing mem cell ; STACK REG0 ; CALC_SIEVE_POINTER REG0,REG0,.hi,'R' ; ALU1 MEMLO ; JUMP .x1 ;.hi: ; ALU1 MEMHI ;.x1: ; ALU0 REG0 ; REG0 STACK ; BRPZ .loopre,AND ; if sieve[r] = 0 ; ; loopi ; STACK $r; reg0 := r ; REG0 $r2 ; i := r^2 ;.loopi: ; STACK REG0 ; CALC_SIEVE_POINTER REG0,REG0,.x2hi,'D' ; ALU0 REG0 ; ALU1 0xFF ; ALU0 XOR ; invert REG0 ; ALU1 MEMLO ; MEMLO AND ; set sieve[i] = 0 ; JUMP .x2 ;.x2hi: ; ALU0 REG0 ; ALU1 0xFF ; ALU0 XOR ; invert REG0 ; ALU1 MEMHI ; MEMHI AND ; set sieve[i] = 0 ;.x2: ; REG0 STACK ;.loopie: ; ALU0 REG0 ; ALU1 REG1 ; REG0 ADD ; BRPZ .loopi,ADDC ; if not overflow ; $r STACK ; restoring stack for r ; ;.loopre: ; ALU0 $r ; ALU1 1 ; $r ADD ; r ++ ; JUMP .loopr ;.endp2: RET xorSieveArray: ; short n = *sieve1 ; sieve[n//16] ^= 1<