.area SM (abs,ovr) .org 0x100 ld hl,0x308 ld de,8 ld bc,0x30 ;0x38 ;0x10 ldir ld hl,0x1234 ld de,0x56 call div_hl_de call print_div ld hl,0x6543 ld de,0x21 call div_hl_de call print_div ld hl,0xb975 ld de,0x31 call div_hl_de call print_div ld hl,0xdb97 ld de,0x531 call div_hl_de call print_div ld hl,0x1234 ld de,0x56 call div_hl_de_signed call print_div ld hl,0x6543 ld de,0x21 call div_hl_de_signed call print_div ld hl,0xb975 ld de,0x31 call div_hl_de_signed call print_div ld hl,0xdb97 ld de,0x531 call div_hl_de_signed call print_div ld hl,-0x1234 ld de,0x56 call div_hl_de_signed call print_div ld hl,-0x6543 ld de,0x21 call div_hl_de_signed call print_div ld hl,-0xb975 ld de,0x31 call div_hl_de_signed call print_div ld hl,-0xdb97 ld de,0x531 call div_hl_de_signed call print_div ld hl,0x1234 ld de,-0x56 call div_hl_de_signed call print_div ld hl,0x6543 ld de,-0x21 call div_hl_de_signed call print_div ld hl,0xb975 ld de,-0x31 call div_hl_de_signed call print_div ld hl,0xdb97 ld de,-0x531 call div_hl_de_signed call print_div ld hl,-0x1234 ld de,-0x56 call div_hl_de_signed call print_div ld hl,-0x6543 ld de,-0x21 call div_hl_de_signed call print_div ld hl,-0xb975 ld de,-0x31 call div_hl_de_signed call print_div ld hl,-0xdb97 ld de,-0x531 call div_hl_de_signed call print_div pop de call sm ; push argument .db esc rst 0x30 ; print stack inc bc jp (hl) sm: pop bc .db 0x21 ; ld hl, dispatch_l1: ; tos in de and hl, pc in bc push de dispatch_l2: ; tos in hl, pc in bc ex de,hl dispatch_l3: ; tos in de, pc in bc, h clobbered ld h,>esc dispatch_l4: ; tos in de, pc in bc, h = >esc ld a,(bc) ld l,a inc bc rst 0x30 ; print stack jp (hl) ; 0x100 esc: rst 0x10 ; ex bc,hl jp (hl) call_i: ; same as imm_w, call rst 8 ; ld hl,(bc)+ push de ld e,c ld d,b jr dispatch_l6 _call: rst 0x10 ; ex bc,hl ex de,hl jr dispatch_l6 jmp_i: ; same as imm_w, jmp rst 8 ; ld hl,(bc)+ jr dispatch_l6 jz_i: ; same as imm_w, jz rst 8 ; ld hl,(bc)+ ex de,hl .db 0x3e ; ld a, jz: pop hl ld a,l or h jr nz,dispatch_mm1 jr dispatch_l5 jnz_i: ; same as imm_w, jnz rst 8 ; ld hl,(bc)+ ex de,hl .db 0x3e ; ld a, jnz: pop hl ld a,l or h jr z,dispatch_mm1 jr dispatch_l5 xchg_w: pop hl jr dispatch_l1 dup_w: push de jr dispatch_l4 imm_w: rst 8 ; ld hl,(bc)+ jr dispatch_l1 add_isp: ; same as imm_w, add_sp rst 8 ; ld hl,(bc)+ push de .db 0x3e ; ld a, add_sp: ex de,hl add hl,sp jr dispatch_l2 ld_iw: ; same as imm_w, ld_w rst 8 ; ld hl,(bc)+ push de .db 0x3e ; ld a, ld_w: ex de,hl ld e,(hl) inc hl ld d,(hl) jr dispatch_l3 ld_isb: ; same as imm_w, ld_sb rst 8 ; ld hl,(bc)+ push de .db 0x3e ; ld a, ld_sb: ex de,hl ld e,(hl) ld a,e rla sbc a,a ld d,a jr dispatch_l3 ld_iub: ; same as imm_w, ld_ub rst 8 ; ld hl,(bc)+ push de .db 0x3e ; ld a, ld_ub: ex de,hl ld e,(hl) ld d,0 jr dispatch_l3 neg_w: dec de not_w: ld a,e cpl ld e,a ld a,d cpl ld d,a jr dispatch_l4 add_iw: ; same as imm_w, add_w rst 8 ; ld hl,(bc)+ .db 0x3e ; ld a, add_w: pop hl add hl,de jr dispatch_l2 ;sub_iw: ; same as imm_w, sub_w ; rst 8 ; ld hl,(bc)+ ; .db 0x3e ; ld a, sub_xw: ; same as xchg_w, sub_w pop hl rst 0x10 ; ex bc,hl .db 0x3e ; ld a, sub_w: ; same as neg_w, add_w pop hl or a sbc hl,de jr dispatch_l2 eq_iw: ; same as imm_w, eq_w rst 8 ; ld hl,(bc)+ .db 0x3e ; ld a, eq_w: pop hl sub a sbc hl,de ld e,a ld d,a jr nz,dispatch_l3 inc e jr dispatch_l3 ; middle dispatch routines jmp: ; also means ret ld c,e ld b,d jr dispatch_m0 adj_isp: ; same as imm_w, adj_sp rst 8 ; ld hl,(bc)+ push de .db 0x3e ; ld a, adj_sp: ; same as add_sp, st_sp ex de,hl add hl,sp .db 0x3e ; ld a, st_sp: ex de,hl ld sp,hl jr dispatch_mm1 ;st_ixw: ; same as imm_w, xchg_w, st_w ; rst 8 ; ld hl,(bc)+ ; ld (hl),e ; inc hl ; ld (hl),d ; jr dispatch_mm1 st_iw: ; same as imm_w, st_w rst 8 ; ld hl,(bc)+ ex de,hl .db 0x3e ; ld a, st_w: pop hl ld (hl),e inc hl ld (hl),d jr dispatch_mm1 st_ixb: ; same as imm_w, xchg_w, st_d rst 8 ; ld hl,(bc)+ .db 0x3e ; ld a, st_d: pop hl ld (hl),e jr dispatch_mm1 ; middle dispatcher, near 0x180, smaller in size ; used for store-type routines that empty stack and need it to be popped dispatch_mm1: ; pc in bc ld h,>esc dispatch_m0: ; pc in bc, h = >esc pop de dispatch_m4: ld a,(bc) ld l,a rst 0x30 ; print stack inc bc jp (hl) lt_iuw: ; same as imm_w, lt_iuw rst 8 ; ld hl,(bc)+ .db 0x3e ; ld a, gt_uw: ; same as xchg_w, lt_uw pop hl ex de,hl .db 0x3e ; ld a, lt_uw: pop hl sub a sbc hl,de ld d,a adc a,a ld e,a jr dispatch_u3 lt_isw: ; same as imm_w, lt_isw rst 8 ; ld hl,(bc)+ .db 0x3e ; ld a, gt_sw: ; same as xchg_w, lt_sw pop hl ex de,hl .db 0x3e ; ld a, lt_sw: pop hl sub a sbc hl,de ld d,a jp pe,lt_sw_overflow add hl,hl adc a,a ld e,a jr dispatch_u3 lt_sw_overflow: add hl,hl ccf adc a,a ld e,a jr dispatch_u3 and_iw: ; same as imm_w, and_w rst 8 ; ld hl,(bc)+ .db 0x3e ; ld a, and_w: pop hl ld a,l or e ld e,a ld a,h or d ld d,a jr dispatch_u3 or_iw: ; same as imm_w, and_w rst 8 ; ld hl,(bc)+ .db 0x3e ; ld a, or_w: pop hl ld a,l or e ld e,a ld a,h or d ld d,a jr dispatch_u3 xor_iw: ; same as imm_w, and_w rst 8 ; ld hl,(bc)+ .db 0x3e ; ld a, xor_w: pop hl ld a,l xor e ld e,a ld a,h xor d ld d,a jr dispatch_u3 ;sl_xw: ; pop hl ; ex de,hl ; .db 0x3e ; ld a, sl_w: pop hl call sl_hl_e jr dispatch_u2 ;sr_xuw: ; pop hl ; ex de,hl ; .db 0x3e ; ld a, sr_uw: pop hl call srl_hl_e jr dispatch_u2 ;sr_xsw: ; pop hl ; ex de,hl ; .db 0x3e ; ld a, sr_sw: pop hl call sra_hl_e jr dispatch_u2 mul_iw: rst 8 ; ld hl,(bc)+ .db 0x3e ; ld a, mul_w: pop hl call mul_hl_de jr dispatch_u2 div_iuw: rst 8 ; ld hl,(bc)+ .db 0x3e ; ld a, div_xuw: pop hl ex de,hl .db 0x3e ; ld a, div_uw: pop hl call div_hl_de ; jr dispatch_um1 ; upper dispatcher, after 0x200 dispatch_um1: ; tos in hl and de, pc in bc push hl .db 0x3e ; ld a, ;dispatch_u1: ; tos in de and hl, pc in bc ; push de dispatch_u2: ; tos in hl, pc in bc ex de,hl dispatch_u3: ; tos in de, pc in bc, h clobbered ld h,>esc dispatch_u4: ; tos in de, pc in bc, h = >esc ld a,(bc) ld l,a rst 0x30 ; print stack inc bc jp (hl) ; math package sl_hl_e: ld a,e and 0xf ret z 1$: add hl,hl dec a jr nz,1$ ret srl_hl_e: ld a,e and 0xf ret z push bc ld b,a ld a,l srl_hl_loop: srl h rra djnz srl_hl_loop ld l,a pop bc ret sra_hl_e: ld a,e and 0xf ret z push bc ld b,a ld a,l sra_hl_loop: sra h rra djnz sra_hl_loop ld l,a pop bc ret mul_hl_de: push bc ld a,h ld c,l ld hl,0 call mul ;ld b,a ; for 32-bit result ld a,c call mul ;ld c,a ; for 32-bit result pop bc ret mul: ; bit 0 add hl,hl rla jr nc,1$ add hl,de 1$: ; bit 1 add hl,hl rla jr nc,2$ add hl,de 2$: ; bit 2 add hl,hl rla jr nc,3$ add hl,de 3$: ; bit 3 add hl,hl rla jr nc,4$ add hl,de 4$: ; bit 4 add hl,hl rla jr nc,5$ add hl,de 5$: ; bit 5 add hl,hl rla jr nc,6$ add hl,de 6$: ; bit 6 add hl,hl rla jr nc,7$ add hl,de 7$: ; bit 7 add hl,hl rla ret nc add hl,de ret div_hl_de_signed: push bc ld a,h or a ld a,d rla jp p,4$ ; positive dividend ; negative dividend dec hl ; reduces remainder by 1 (we inc later) ld a,h ld c,l ld hl,-1 jr c,2$ ; negative dividend, negative divisor ; negative dividend, positive divisor call div1 ld b,a ld a,c call div inc a jr c,1$ sbc hl,de 1$: inc hl ; get into range -divisor+1..0 ld d,b ld e,a pop bc ret 2$: ; negative dividend, negative divisor call divn0 ld b,a ld a,c call divn jr nc,3$ add hl,de 3$: inc hl ; get into range divisor+1..0 ld d,b ld e,a pop bc ret 4$: ; positive dividend ld a,h ld c,l ld hl,0 jr nc,divu ; positive dividend, positive divisor ; positive dividend, negative divisor call divn1 ld b,a ld a,c call divn inc a jr c,5$ sbc hl,de 5$: ld d,b ld e,a pop bc ret div_hl_de: push bc ld a,h ld c,l ld hl,0 divu: ; positive dividend, positive divisor call div0 ld b,a ld a,c call div jr nc,1$ add hl,de 1$: ld d,b ld e,a pop bc ret ; non-restoring division routine ; de = divisor, hl:a = dividend with hl = previous remainder, a = next byte ; enter at div0 with positive remainder in hl, such that hl < de ; enter at div1 with negative remainder in hl, such that hl >= -de ; div0/1 return a = 8-bit quotient as an odd number interpreted as -ff..ff, ; by summing positive/negative place values, e.g. -80 +40 +20 -10 +8 -4 -2 +1 ; if entered at div0, there is a -80 and so quotient is in range -ff..-1 ; if entered at div1, there is a +80 and so quotient is in range 1..ff ; falls out of loop after div01 with positive remainder, div11 with negative, ; depending on this we should re-enter at div0 or div1, signalled by cf return ; the successive quotient bytes can be concatenated into a full quotient, ; but negative bytes require the next higher quotient byte to be decremented, ; we know in advance if this will happen because the implied sign of the ; quotient byte depends only on whether we entered at div0 or div1, hence, ; before the div11 return we'll decrement to compensate for next negative byte ; the decrement can also be seen as compensating for the extra add hl,de that ; may be needed to make negative remainder positive before return to caller, ; thus leaving quotient in a consistent state regardless of which exit taken, ; remainder needs the add hl,de if cf=1 returned (equiv. return byte is even) ; in the following code each sbc hl,de gets an inc a and each add hl,de gets ; a dec a, guaranteeing the integrity of the division, the initial scf/rla is ; needed to make the result 100 + -ff..ff or 1..1ff, so that the decrements ; cannot borrow into the upcoming dividend bits also held in a, and there must ; be another shift between the scf/rla and increment/decrement so that the scf ; is implicitly in the 100s place, making the code awkward though it's correct ; now optimized to only inc/dec a when doing zero-crossing, fix above analysis div: jr c,div1 div0: ; bit 0, above scf rla adc hl,hl sbc hl,de jr nc,div01 dec a div11: ; bit 1, below add a,a adc hl,hl add hl,de jr nc,div12 inc a div02: ; bit 2, above add a,a adc hl,hl sbc hl,de jr nc,div03 dec a div13: ; bit 3, below add a,a adc hl,hl add hl,de jr nc,div14 inc a div04: ; bit 4, above add a,a adc hl,hl sbc hl,de jr nc,div05 dec a div15: ; bit 5, below add a,a adc hl,hl add hl,de jr nc,div16 inc a div06: ; bit 6, above add a,a adc hl,hl sbc hl,de jr nc,div07 dec a div17: ; bit 7, below add a,a adc hl,hl add hl,de jr nc,div18 inc a div08: ; done, above add a,a dec a or a ret div1: ; bit 0, below add a,a adc hl,hl add hl,de jr nc,div11 inc a div01: ; bit 1, above add a,a adc hl,hl sbc hl,de jr nc,div02 dec a div12: ; bit 2, below add a,a adc hl,hl add hl,de jr nc,div13 inc a div03: ; bit 3, above add a,a adc hl,hl sbc hl,de jr nc,div04 dec a div14: ; bit 4, below add a,a adc hl,hl add hl,de jr nc,div15 inc a div05: ; bit 5, above add a,a adc hl,hl sbc hl,de jr nc,div06 dec a div16: ; bit 6, below add a,a adc hl,hl add hl,de jr nc,div17 inc a div07: ; bit 7, above add a,a adc hl,hl sbc hl,de jr nc,div08 dec a div18: ; done, below add a,a ;inc a ;dec a ; compensation scf ret ; divn0/1 are the same as div0/1 but carry reversed after add/subtract divisor ; this is for negative divisors where we expect carry (means no zero crossing) ; when divisor negated, remainder also negated, so we expect to do subtraction ; when remainder negative and vice versa, need to clear carry after add hl,hl divn: jr c,divn1 divn0: ; bit 0, above scf rla adc hl,hl or a sbc hl,de jr c,divn01 dec a divn11: ; bit 1, below add a,a adc hl,hl add hl,de jr c,divn12 inc a divn02: ; bit 2, above add a,a adc hl,hl or a sbc hl,de jr c,divn03 dec a divn13: ; bit 3, below add a,a adc hl,hl add hl,de jr c,divn14 inc a divn04: ; bit 4, above add a,a adc hl,hl or a sbc hl,de jr c,divn05 dec a divn15: ; bit 5, below add a,a adc hl,hl add hl,de jr c,divn16 inc a divn06: ; bit 6, above add a,a adc hl,hl or a sbc hl,de jr c,divn07 dec a divn17: ; bit 7, below add a,a adc hl,hl add hl,de jr c,divn18 inc a divn08: ; done, above add a,a dec a or a ret divn1: ; bit 0, below add a,a adc hl,hl add hl,de jr c,divn11 inc a divn01: ; bit 1, above add a,a adc hl,hl or a sbc hl,de jr c,divn02 dec a divn12: ; bit 2, below add a,a adc hl,hl add hl,de jr c,divn13 inc a divn03: ; bit 3, above add a,a adc hl,hl or a sbc hl,de jr c,divn04 dec a divn14: ; bit 4, below add a,a adc hl,hl add hl,de jr c,divn15 inc a divn05: ; bit 5, above add a,a adc hl,hl or a sbc hl,de jr c,divn06 dec a divn16: ; bit 6, below add a,a adc hl,hl add hl,de jr c,divn17 inc a divn07: ; bit 7, above add a,a adc hl,hl or a sbc hl,de jr c,divn08 dec a divn18: ; done, below add a,a ;inc a ;dec a ; compensation scf ret ; debugging digits: .ascii '0123456789abcdef' print_word: push af ld a,h call print_byte ld a,l call print_byte pop af ret print_byte: push af push af rrca rrca rrca rrca call print_digit pop af call print_digit pop af ret print_digit: push de push hl and 0xf ld e,a ld d,0 ld hl,digits add hl,de ld a,(hl) pop hl pop de jp print_char print_space: push af ld a,0x20 call print_char pop af ret print_trace: push af push bc push de push hl ld a,'p call print_char ld a,'c call print_char ld a,'= call print_char rst 0x10 ; ex bc,hl call print_word rst 0x10 ; ex bc,hl call print_space ld a,'o call print_char ld a,'p call print_char ld a,'= call print_char call print_word call print_space ld a,'s call print_char ld a,'p call print_char ld a,'= call print_char ld hl,10 add hl,sp call print_word call print_space ld a,'t call print_char ld a,'o call print_char ld a,'s call print_char ld a,'= call print_char ex de,hl call print_word ex de,hl call print_space ld a,'s call print_char ld a,'t call print_char ld a,'k call print_char ld b,4 ld a,'= 1$: call print_char ld e,(hl) inc hl ld d,(hl) inc hl ex de,hl call print_word ex de,hl ld a,' djnz 1$ pop hl pop de pop bc pop af print_crlf: push af ld a,0xd call print_char ld a,0xa call print_char pop af ret print_char: push bc push de push hl ld e,a ld c,2 call 5 pop hl pop de pop bc ret print_div: ex de,hl call print_word ex de,hl call print_space call print_word jp print_crlf