--- /dev/null
+div: div.c
+ gcc -o $@ $^
--- /dev/null
+#include <stdio.h>
+
+int main(void) {
+ printf("%08x %08x\n", 0x1234 / 0x56, 0x1234 % 0x56);
+ printf("%08x %08x\n", 0x6543 / 0x21, 0x6543 % 0x21);
+ printf("%08x %08x\n", 0xb975 / 0x31, 0xb975 % 0x31);
+ printf("%08x %08x\n", 0xdb97 / 0x531, 0xdb97 % 0x531);
+
+ printf("%08x %08x\n", 0x1234 / 0x56, 0x1234 % 0x56);
+ printf("%08x %08x\n", 0x6543 / 0x21, 0x6543 % 0x21);
+ printf("%08x %08x\n", (int)0xffffb975 / 0x31, (int)0xffffb975 % 0x31);
+ printf("%08x %08x\n", (int)0xffffdb97 / 0x531, (int)0xffffdb97 % 0x531);
+
+ printf("%08x %08x\n", -0x1234 / 0x56, -0x1234 % 0x56);
+ printf("%08x %08x\n", -0x6543 / 0x21, -0x6543 % 0x21);
+ printf("%08x %08x\n", -(int)0xffffb975 / 0x31, -(int)0xffffb975 % 0x31);
+ printf("%08x %08x\n", -(int)0xffffdb97 / 0x531, -(int)0xffffdb97 % 0x531);
+
+ printf("%08x %08x\n", 0x1234 / -0x56, 0x1234 % -0x56);
+ printf("%08x %08x\n", 0x6543 / -0x21, 0x6543 % -0x21);
+ printf("%08x %08x\n", (int)0xffffb975 / -0x31, (int)0xffffb975 % -0x31);
+ printf("%08x %08x\n", (int)0xffffdb97 / -0x531, (int)0xffffdb97 % -0x531);
+
+ printf("%08x %08x\n", -0x1234 / -0x56, -0x1234 % -0x56);
+ printf("%08x %08x\n", -0x6543 / -0x21, -0x6543 % -0x21);
+ printf("%08x %08x\n", -(int)0xffffb975 / -0x31, -(int)0xffffb975 % -0x31);
+ printf("%08x %08x\n", -(int)0xffffdb97 / -0x531, -(int)0xffffdb97 % -0x531);
+
+ return 0;
+}
+++ /dev/null
-#!/usr/bin/env python3
-
-print(
- f'''{0x1234 // 0x56:04x} {0x1234 % 0x56:04x}
-{0x6543 // 0x21:04x} {0x6543 % 0x21:04x}
-{0xb975 // 0x31:04x} {0xb975 % 0x31:04x}
-{0xdb97 // 0x531:04x} {0xdb97 % 0x531:04x}'''
-)
ld hl,0x1234
ld de,0x56
call div_hl_de
- ex de,hl
- call print_word
- ex de,hl
- call print_space
- call print_word
- call print_crlf
+ call print_div
ld hl,0x6543
ld de,0x21
call div_hl_de
- ex de,hl
- call print_word
- ex de,hl
- call print_space
- call print_word
- call print_crlf
+ call print_div
ld hl,0xb975
ld de,0x31
call div_hl_de
- ex de,hl
- call print_word
- ex de,hl
- call print_space
- call print_word
- call print_crlf
+ 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
+
+ rst 0
+
+print_div:
ex de,hl
call print_word
ex de,hl
call print_space
call print_word
- call print_crlf
-
- pop de
- call sm
-
- ; push argument
- .db <imm_w
- .dw 5
+ jp print_crlf
- ; push result pointer
- .db <add_isp
- .dw 0
-
- ; call sm_factorial(argument)
- .db <call_i
- .dw sm_factorial
- .db <adj_isp
- .dw 2
-
-; ; print it the easy way
+; pop de
+; call sm
+;
+; ; push argument
+; .db <imm_w
+; .dw 5
+;
+; ; push result pointer
+; .db <add_isp
+; .dw 0
+;
+; ; call sm_factorial(argument)
+; .db <call_i
+; .dw sm_factorial
+; .db <adj_isp
+; .dw 2
+;
+;; ; print it the easy way
+;; .db <esc
+;; ex de,hl
+;; call print_word
+;; call print_crlf
+;; ex de,hl
+;; call sm
+;
+; ; print 10000s
+; .db <div_iuw
+; .dw 10000
+; .db <add_iw
+; .dw '0
+; .db <call_i
+; .dw sm_print_char
+; .db <adj_isp
+; .dw 2
+;
+; ; print 1000s
+; .db <div_iuw
+; .dw 1000
+; .db <add_iw
+; .dw '0
+; .db <call_i
+; .dw sm_print_char
+; .db <adj_isp
+; .dw 2
+;
+; ; print 100s
+; .db <div_iuw
+; .dw 100
+; .db <add_iw
+; .dw '0
+; .db <call_i
+; .dw sm_print_char
+; .db <adj_isp
+; .dw 2
+;
+; ; print 10s
+; .db <div_iuw
+; .dw 10
+; .db <add_iw
+; .dw '0
+; .db <call_i
+; .dw sm_print_char
+; .db <adj_isp
+; .dw 2
+;
+; ; print 1s
+; .db <add_iw
+; .dw '0
+; .db <call_i
+; .dw sm_print_char
+; .db <adj_isp
+; .dw 2
+;
+; .db <imm_w
+; .dw 0xd
+; .db <call_i
+; .dw sm_print_char
+; .db <adj_isp
+; .dw 2
+;
+; .db <imm_w
+; .dw 0xa
+; .db <call_i
+; .dw sm_print_char
+; .db <adj_isp
+; .dw 2
+;
; .db <esc
-; ex de,hl
-; call print_word
-; call print_crlf
-; ex de,hl
+; rst 0 ; can't return into ccp as clobbered by stack growth
+;
+;sm_factorial:
+; ; get argument
+; .db <add_isp
+; .dw 4
+; .db <ld_w
+;
+; ; is argument < 2?
+; .db <lt_isw
+; .dw 2
+; .db <jnz_i
+; .dw 1$
+;
+; ; no, set up for *result =
+; .db <add_isp
+; .dw 2
+; .db <ld_w
+;
+; ; get argument
+; .db <add_isp
+; .dw 6
+; .db <ld_w
+;
+; ; subtract 1
+; .db <add_iw
+; .dw -1
+;
+; ; push result pointer
+; .db <add_isp
+; .dw 0
+;
+; ; call sm_factorial(argument - 1)
+; .db <call_i
+; .dw sm_factorial
+; .db <adj_isp
+; .dw 2
+;
+; ; get argument
+; .db <add_isp
+; .dw 8
+; .db <ld_w
+;
+; ; multiply
+; .db <mul_w
+;
+; ; set *result = sm_factorial(argument - 1) * argument
+; .db <st_w
+;
+; ; return
+; .db <jmp
+;
+;1$: ; yes, set up for *result =
+; .db <add_isp
+; .dw 2
+; .db <ld_w
+;
+; ; set *result = 1
+; .db <st_iw
+; .dw 1
+;
+; ; return
+; .db <jmp
+;
+;sm_print_char:
+; .db <esc
+; ld hl,0
+; add hl,sp
+; ld a,(hl)
+; call print_char
; call sm
-
- ; print 10000s
- .db <div_iuw
- .dw 10000
- .db <add_iw
- .dw '0
- .db <call_i
- .dw sm_print_char
- .db <adj_isp
- .dw 2
-
- ; print 1000s
- .db <div_iuw
- .dw 1000
- .db <add_iw
- .dw '0
- .db <call_i
- .dw sm_print_char
- .db <adj_isp
- .dw 2
-
- ; print 100s
- .db <div_iuw
- .dw 100
- .db <add_iw
- .dw '0
- .db <call_i
- .dw sm_print_char
- .db <adj_isp
- .dw 2
-
- ; print 10s
- .db <div_iuw
- .dw 10
- .db <add_iw
- .dw '0
- .db <call_i
- .dw sm_print_char
- .db <adj_isp
- .dw 2
-
- ; print 1s
- .db <add_iw
- .dw '0
- .db <call_i
- .dw sm_print_char
- .db <adj_isp
- .dw 2
-
- .db <imm_w
- .dw 0xd
- .db <call_i
- .dw sm_print_char
- .db <adj_isp
- .dw 2
-
- .db <imm_w
- .dw 0xa
- .db <call_i
- .dw sm_print_char
- .db <adj_isp
- .dw 2
-
- .db <esc
- rst 0 ; can't return into ccp as clobbered by stack growth
-
-sm_factorial:
- ; get argument
- .db <add_isp
- .dw 4
- .db <ld_w
-
- ; is argument < 2?
- .db <lt_isw
- .dw 2
- .db <jnz_i
- .dw 1$
-
- ; no, set up for *result =
- .db <add_isp
- .dw 2
- .db <ld_w
-
- ; get argument
- .db <add_isp
- .dw 6
- .db <ld_w
-
- ; subtract 1
- .db <add_iw
- .dw -1
-
- ; push result pointer
- .db <add_isp
- .dw 0
-
- ; call sm_factorial(argument - 1)
- .db <call_i
- .dw sm_factorial
- .db <adj_isp
- .dw 2
-
- ; get argument
- .db <add_isp
- .dw 8
- .db <ld_w
-
- ; multiply
- .db <mul_w
-
- ; set *result = sm_factorial(argument - 1) * argument
- .db <st_w
-
- ; return
- .db <jmp
-
-1$: ; yes, set up for *result =
- .db <add_isp
- .dw 2
- .db <ld_w
-
- ; set *result = 1
- .db <st_iw
- .dw 1
-
- ; return
- .db <jmp
-
-sm_print_char:
- .db <esc
- ld hl,0
- add hl,sp
- ld a,(hl)
- call print_char
- call sm
- .db <jmp
+; .db <jmp
digits:
.ascii '0123456789abcdef'
div_hl_de:
push bc
- ld a,h
ld c,l
+divu: ld a,h
ld hl,0
- scf
call div0
ld b,a
ld a,c
ld c,b
call div
- jr c,1$
+ jr nc,1$
add hl,de
1$: ld d,c
ld e,a
pop bc
ret
+div_hl_de_signed:
+ push bc
+ ld c,l
+ ld a,h
+ or a
+ ld a,d
+ rla
+ jr c,4$ ; negative divisor
+
+ ; positive divisor
+ jp p,divu ; positive dividend, positive divisor
+
+ ; negative dividend, positive divisor
+ dec hl ; reduces remainder by 1 (we inc later)
+ ld a,h
+ ld hl,-1
+ call div1
+ ld b,a
+ ld a,c
+ ld c,b
+ call div
+ inc a
+ jr c,1$
+ sbc hl,de
+1$: inc hl ; get into range -divisor+1..0
+ ld d,c
+ ld e,a
+ pop bc
+ ret
+
+2$: ; positive dividend, negative divisor
+ ld hl,0
+ call div3
+ ld b,a
+ ld a,c
+ ld c,b
+ call divn
+; inc a
+; jr c,3$
+; sbc hl,de
+3$: ld d,c
+ ld e,a
+ pop bc
+ ret
+
+4$: ; negative divisor
+ jp p,2$
+
+ ; negative dividend, negative divisor
+ dec hl ; reduces remainder by 1 (we inc later)
+ ld a,h
+ ld hl,-1
+ call div2
+ ld b,a
+ ld a,c
+ ld c,b
+ call divn
+; jr nc,5$
+; add hl,de
+5$: inc hl ; get into range divisor+1..0
+ ld d,c
+ ld e,a
+ pop bc
+ ret
+
; non-restoring division routine
; de = divisor, hl:a = dividend with hl = previous remainder, a = next byte
; 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
-; and inverted cf return sense so that it eliminates a scf instruction in div0
-
-div: jr nc,div1
-div0: ; enter with cf=1
- push af
- ld a,'A
- call print_char
- pop af
- call print_word
- push af
- ld a,':
- call print_char
- pop af
- call print_byte
- push af
- ld a,'/
- call print_char
- pop af
- ex de,hl
- call print_word
- ex de,hl
+
+div: jr c,div1
+div0:
+ ;push af
+ ;ld a,'A
+ ;call print_char
+ ;pop af
+ ;call print_word
+ ;push af
+ ;ld a,':
+ ;call print_char
+ ;pop af
+ ;call print_byte
+ ;push af
+ ;ld a,'/
+ ;call print_char
+ ;pop af
+ ;ex de,hl
+ ;call print_word
+ ;ex de,hl
ld b,8
+ scf
rla
div00: adc hl,hl
sbc hl,de
div01: add a,a
djnz div00
dec a
- scf
- push af
- ld a,'B
- call print_char
- pop af
- push af
- ld a,'0
- adc a,0
- call print_char
- ld a,':
- call print_char
- pop af
- call print_byte
- push af
- ld a,',
- call print_char
- pop af
- call print_word
- call print_crlf
+ or a
+ ;push af
+ ;ld a,'B
+ ;call print_char
+ ;pop af
+ ;push af
+ ;ld a,'0
+ ;adc a,0
+ ;call print_char
+ ;ld a,':
+ ;call print_char
+ ;pop af
+ ;call print_byte
+ ;push af
+ ;ld a,',
+ ;call print_char
+ ;pop af
+ ;call print_word
+ ;call print_crlf
ret
-div1:
- push af
- ld a,'C
- call print_char
- pop af
- call print_word
- push af
- ld a,':
- call print_char
- pop af
- call print_byte
- push af
- ld a,'/
- call print_char
- pop af
- ex de,hl
- call print_word
- ex de,hl
+div1: ; enter with cf=0
+ ;push af
+ ;ld a,'C
+ ;call print_char
+ ;pop af
+ ;call print_word
+ ;push af
+ ;ld a,':
+ ;call print_char
+ ;pop af
+ ;call print_byte
+ ;push af
+ ;ld a,'/
+ ;call print_char
+ ;pop af
+ ;ex de,hl
+ ;call print_word
+ ;ex de,hl
ld b,8
add a,a
div10: adc hl,hl
djnz div10
;inc a
;dec a ; compensation
- jr c,.
- push af
- ld a,'D
- call print_char
- pop af
- push af
- ld a,'0
- adc a,0
- call print_char
- ld a,':
- call print_char
- pop af
- call print_byte
- push af
- ld a,',
- call print_char
- pop af
- call print_word
- call print_crlf
+ scf
+ ;push af
+ ;ld a,'D
+ ;call print_char
+ ;pop af
+ ;push af
+ ;ld a,'0
+ ;adc a,0
+ ;call print_char
+ ;ld a,':
+ ;call print_char
+ ;pop af
+ ;call print_byte
+ ;push af
+ ;ld a,',
+ ;call print_char
+ ;pop af
+ ;call print_word
+ ;call print_crlf
+ ret
+
+; div2/3 are the same as div0/1 but carry reversed after add/subtract divisor
+
+divn: jr c,div3
+div2:
+ ;push af
+ ;ld a,'A
+ ;call print_char
+ ;pop af
+ ;call print_word
+ ;push af
+ ;ld a,':
+ ;call print_char
+ ;pop af
+ ;call print_byte
+ ;push af
+ ;ld a,'/
+ ;call print_char
+ ;pop af
+ ;ex de,hl
+ ;call print_word
+ ;ex de,hl
+ ld b,8
+ scf
+ rla
+div20: adc hl,hl
+ sbc hl,de
+ jr c,div21
+ dec a
+ jr div31
+div21: add a,a
+ djnz div20
+ dec a
+ or a
+ ;push af
+ ;ld a,'B
+ ;call print_char
+ ;pop af
+ ;push af
+ ;ld a,'0
+ ;adc a,0
+ ;call print_char
+ ;ld a,':
+ ;call print_char
+ ;pop af
+ ;call print_byte
+ ;push af
+ ;ld a,',
+ ;call print_char
+ ;pop af
+ ;call print_word
+ ;call print_crlf
+ ret
+
+div3:
+ ;push af
+ ;ld a,'C
+ ;call print_char
+ ;pop af
+ ;call print_word
+ ;push af
+ ;ld a,':
+ ;call print_char
+ ;pop af
+ ;call print_byte
+ ;push af
+ ;ld a,'/
+ ;call print_char
+ ;pop af
+ ;ex de,hl
+ ;call print_word
+ ;ex de,hl
+ ld b,8
+ add a,a
+div30: adc hl,hl
+ add hl,de
+ jr c,div31
+ inc a
+ jr div21
+div31: add a,a
+ djnz div30
+ ;inc a
+ ;dec a ; compensation
+ scf
+ ;push af
+ ;ld a,'D
+ ;call print_char
+ ;pop af
+ ;push af
+ ;ld a,'0
+ ;adc a,0
+ ;call print_char
+ ;ld a,':
+ ;call print_char
+ ;pop af
+ ;call print_byte
+ ;push af
+ ;ld a,',
+ ;call print_char
+ ;pop af
+ ;call print_word
+ ;call print_crlf
ret