Applied patch #2762516
[fw/sdcc] / device / lib / z80 / div.s
1         ;; Originally from GBDK by Pascal Felber.
2
3         .area   _CODE
4
5 __divuint_rrx_s::
6         pop     af
7         pop     hl
8         pop     de
9         push    de
10         push    hl
11         push    af
12
13         jr      __divu16
14
15 __divsuchar_rrx_s::
16         ld      hl,#2+1
17         add     hl,sp
18
19         ld      e,(hl)
20         dec     hl
21         ld      l,(hl)
22         xor     a
23
24         jr      signexte
25
26 __modsuchar_rrx_s::
27         ld      hl,#2+1
28         add     hl,sp
29
30         ld      e,(hl)
31         dec     hl
32         ld      l,(hl)
33         xor     a
34
35         call    signexte
36
37         ex      de,hl
38         ret
39
40 __divuschar_rrx_s::
41         ld      hl,#2+1
42         ld      d, h
43         add     hl,sp
44
45         ld      e,(hl)
46         dec     hl
47         ld      l,(hl)
48
49         ld      a,l             ; Sign extend
50         rlca
51         sbc     a
52         ld      h,a
53
54         jr      __div16
55
56 __divschar_rrx_s::
57         ld      hl,#2+1
58         add     hl,sp
59
60         ld      e,(hl)
61         dec     hl
62         ld      l,(hl)
63
64         ;; Fall through
65 __divschar_rrx_hds::
66 __div8::
67         ld      a,l             ; Sign extend
68         rlca
69         sbc     a
70 signexte:
71         ld      h,a
72         ld      a,e             ; Sign extend
73         rlca
74         sbc     a
75         ld      d,a
76         ; Fall through to __div16
77
78         ;; signed 16-bit division
79         ;;
80         ;; Entry conditions
81         ;;   HL = dividend
82         ;;   DE = divisor
83         ;;
84         ;; Exit conditions
85         ;;   HL = quotient
86         ;;   DE = remainder
87         ;;   If divisor is non-zero, carry=0
88         ;;   If divisor is 0, carry=1 and both quotient and remainder are 0
89         ;;
90         ;; Register used: AF,BC,DE,HL
91 __divsint_rrx_hds::
92 __div16::
93         ;; Determine sign of quotient by xor-ing high bytes of dividend
94         ;;  and divisor. Quotient is positive if signs are the same, negative
95         ;;  if signs are different
96         ;; Remainder has same sign as dividend
97         ld      a,h             ; Get high byte of dividend
98         xor     d               ; Xor with high byte of divisor
99         rla                     ; Sign of quotient goes into the carry
100         ld      a,h             ; Get high byte of dividend
101         push    af              ; Save sign of both quotient and reminder
102
103         ;; Take absolute value of dividend
104         rla
105         jr      NC,.chkde       ; Jump if dividend is positive
106         sub     a               ; Substract dividend from 0
107         sub     l
108         ld      l,a
109         sbc     a               ; Propagate borrow (A=0xFF if borrow)
110         sub     h
111         ld      h,a
112         ;; Take absolute value of divisor
113 .chkde:
114         bit     7,d
115         jr      Z,.dodiv        ; Jump if divisor is positive
116         sub     a               ; Substract divisor from 0
117         sub     e
118         ld      e,a
119         sbc     a               ; Propagate borrow (A=0xFF if borrow)
120         sub     d
121         ld      d,a
122         ;; Divide absolute values
123 .dodiv:
124         call    __divu16
125         jr      C,.exit         ; Exit if divide by zero
126         ;; Negate quotient if it is negative
127         pop     af              ; recover sign of quotient
128         jr      NC,.dorem       ; Jump if quotient is positive
129         ld      b,a
130         sub     a               ; Substract quotient from 0
131         sub     l
132         ld      l,a
133         sbc     a               ; Propagate borrow (A=0xFF if borrow)
134         sub     h
135         ld      h,a
136         ld      a,b
137 .dorem:
138         ;; Negate remainder if it is negative
139         rla
140         ret     NC              ; Return if remainder is positive
141         sub     a               ; Substract remainder from 0
142         sub     e
143         ld      e,a
144         sbc     a               ; Propagate remainder (A=0xFF if borrow)
145         sub     d
146         ld      d,a
147         ret
148 .exit:
149         pop     af
150
151 .dividebyzero:
152         ld      h,d             ; Divide by zero error: D=E=0
153         ld      l,e
154         scf                     ; Set carry, invalid result
155         ret
156
157         ;; Unsigned
158 __divuchar_rrx_s::
159         ld      hl,#2+1
160         add     hl,sp
161
162         ld      e,(hl)
163         dec     hl
164         ld      l,(hl)
165
166         ;; Fall through
167 __divuchar_rrx_hds::
168 __divu8::
169         ld      h,#0x00
170         ld      d,h
171         ; Fall through to divu16
172
173         ;; unsigned 16-bit division
174         ;; Restructured on April 2009 by Marco Bodrato(http://bodrato.it/ )
175         ;;
176         ;; Entry conditions
177         ;;   HL = dividend
178         ;;   DE = divisor
179         ;;
180         ;; Exit conditions
181         ;;   HL = quotient
182         ;;   DE = remainder
183         ;;   If divisor is non-zero, carry=0
184         ;;   If divisor is 0, carry=1 and both quotient and remainder are 0
185         ;;
186         ;; Register used: AF,B,DE,HL
187 __divuint_rrx_hds::
188 __divu16::
189         ;; Check for division by zero
190         ld      a,e
191         or      d
192         jr      Z,.dividebyzero ; Branch if divisor is non-zero
193         ld      a,h
194         ld      c,l
195         ld      hl,#0
196         ;; Carry was cleared by OR, this "0" bit will pass trough AC.[*]
197         ld      b,#16           ; 16 bits in dividend
198 .dvloop:
199         ;; Cleaned up on April 2009 by Marco Bodrato(http://bodrato.it/ )
200         ;; Shift next bit of quotient into bit 0 of dividend
201         ;; Shift next MSB of dividend into LSB of remainder
202         ;; AC holds both dividend and quotient. While we shift a bit from
203         ;;  MSB of dividend, we shift next bit of quotient in from carry
204         ;; HL holds remainder
205         ;; Do a 32-bit left shift, shifting carry to C, C to A,
206         ;;  A to HL
207         rl      c               ; Carry (next bit of quotient) to bit 0
208         rla
209         adc     hl,hl           ; HL < 32768 before, no carry, ever.
210
211         ;; If remainder is >= divisor, next bit of quotient is 1. We try
212         ;;  to compute the difference.
213         sbc     hl,de
214         jr      NC,.nodrop      ; Jump if remainder is >= dividend
215         add     hl,de           ; Otherwise, restore remainder
216         ;; The add above sets the carry, because sbc hl,de did set it.
217 .nodrop:
218         ccf                     ; Complement borrow so 1 indicates a
219                                 ;  successful substraction (this is the
220                                 ;  next bit of quotient)
221         djnz    .dvloop
222         ;; Shift last carry bit into quotient
223         rl      c               ; Carry to C
224         rla
225         ;; Carry now contains the same value it contained before
226         ;; entering .dvloop[*]: "0" = valid result.
227         ld      d,a
228         ld      e,c             ; DE = quotient, HL = remainder
229         ex      de,hl           ; HL = quotient, DE = remainder
230         ret