First cut at the full signed division with separate code for each quadrant, some...
authorNick Downing <nick@ndcode.org>
Thu, 13 Jun 2019 14:22:25 +0000 (00:22 +1000)
committerNick Downing <nick@ndcode.org>
Thu, 13 Jun 2019 14:23:19 +0000 (00:23 +1000)
Makefile [new file with mode: 0644]
div.c [new file with mode: 0644]
div.py [deleted file]
sm.asm

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..77d2f91
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2 @@
+div: div.c
+       gcc -o $@ $^
diff --git a/div.c b/div.c
new file mode 100644 (file)
index 0000000..d5d74a4
--- /dev/null
+++ b/div.c
@@ -0,0 +1,30 @@
+#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;
+}
diff --git a/div.py b/div.py
deleted file mode 100755 (executable)
index 63f01a6..0000000
--- a/div.py
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/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}'''
-)
diff --git a/sm.asm b/sm.asm
index c4095fb..856d028 100644 (file)
--- a/sm.asm
+++ b/sm.asm
        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'
@@ -843,22 +913,86 @@ mul_hl_de:
 
 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
@@ -892,28 +1026,28 @@ div_hl_de:
 ; 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
@@ -923,45 +1057,45 @@ div00:   adc     hl,hl
 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
@@ -973,23 +1107,126 @@ div11:  add     a,a
        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