div.s (9261B)
1;-------------------------------------------------------------------------- 2; div.s 3; 4; Copyright (C) 2000, Michael Hope 5; Copyright (C) 2021, Sebastian 'basxto' Riedel (sdcc@basxto.de) 6; Copyright (c) 2021, Philipp Klaus Krause 7; 8; This library is free software; you can redistribute it and/or modify it 9; under the terms of the GNU General Public License as published by the 10; Free Software Foundation; either version 2, or (at your option) any 11; later version. 12; 13; This library is distributed in the hope that it will be useful, 14; but WITHOUT ANY WARRANTY; without even the implied warranty of 15; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16; GNU General Public License for more details. 17; 18; You should have received a copy of the GNU General Public License 19; along with this library; see the file COPYING. If not, write to the 20; Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, 21; MA 02110-1301, USA. 22; 23; As a special exception, if you link this library with other files, 24; some of which are compiled with SDCC, to produce an executable, 25; this library does not by itself cause the resulting executable to 26; be covered by the GNU General Public License. This exception does 27; not however invalidate any other reasons why the executable file 28; might be covered by the GNU General Public License. 29;-------------------------------------------------------------------------- 30 31 ;; Originally from GBDK by Pascal Felber. 32 .module divmod 33 .area _CODE 34.globl __divsuchar 35.globl __modsuchar 36.globl __divuschar 37.globl __moduschar 38.globl __divschar 39.globl __modschar 40.globl __divsint 41.globl __modsint 42.globl __divuchar 43.globl __moduchar 44.globl __divuint 45.globl __moduint 46 47__divsuchar: 48 ld c, a 49 ld b, #0 50 51 jp signexte 52 53__modsuchar: 54 ld c, a 55 ld b, #0 56 57 call signexte 58 59 ld c, e 60 ld b, d 61 62 ret 63 64__divuschar: 65 ld d, #0 66 67 ld c, a ; Sign extend 68 rlca 69 sbc a 70 ld b,a 71 72 jp .div16 73 74__moduschar: 75 ld e, a 76 ld d, #0 77 78 ld a,c ; Sign extend 79 rlca 80 sbc a 81 ld b,a 82 83 call .div16 84 85 ld c, e 86 ld b, d 87 88 ret 89 90__divschar: 91 ld c, a 92 93 call .div8 94 95 ret 96 97__modschar: 98 ld c, a 99 100 call .div8 101 102 ld c, e 103 ld b, d 104 105 ret 106 107__divsint: 108 ld a, e 109 ld e, c 110 ld c, a 111 112 ld a, d 113 ld d, b 114 ld b, a 115 116 jp .div16 117 118__modsint: 119 ld a, e 120 ld e, c 121 ld c, a 122 123 ld a, d 124 ld d, b 125 ld b, a 126 127 call .div16 128 129 ld c, e 130 ld b, d 131 132 ret 133 134 ;; Unsigned 135__divuchar: 136 ld c, a 137 138 call .divu8 139 140 ret 141 142__moduchar: 143 ld c, a 144 145 call .divu8 146 147 ld c, e 148 ld b, d 149 150 ret 151 152__divuint: 153 ld a, e 154 ld e, c 155 ld c, a 156 157 ld a, d 158 ld d, b 159 ld b, a 160 161 jp .divu16 162 163__moduint: 164 ld a, e 165 ld e, c 166 ld c, a 167 168 ld a, d 169 ld d, b 170 ld b, a 171 172 call .divu16 173 174 ld c, e 175 ld b, d 176 177 ret 178 179.div8:: 180.mod8:: 181 ld a,c ; Sign extend 182 rlca 183 sbc a 184 ld b,a 185signexte: 186 ld a, e ; Sign extend 187 rlca 188 sbc a 189 ld d, a 190 191 ; Fall through to .div16 192 193 ;; 16-bit division 194 ;; 195 ;; Entry conditions 196 ;; BC = dividend 197 ;; DE = divisor 198 ;; 199 ;; Exit conditions 200 ;; BC = quotient 201 ;; DE = remainder 202 ;; If divisor is non-zero, carry=0 203 ;; If divisor is 0, carry=1 and both quotient and remainder are 0 204 ;; 205 ;; Register used: AF,BC,DE,HL 206.div16:: 207.mod16:: 208 ;; Determine sign of quotient by xor-ing high bytes of dividend 209 ;; and divisor. Quotient is positive if signs are the same, negative 210 ;; if signs are different 211 ;; Remainder has same sign as dividend 212 ld a,b ; Get high byte of dividend 213 push af ; Save as sign of remainder 214 xor d ; Xor with high byte of divisor 215 push af ; Save sign of quotient 216 217 ;; Take absolute value of divisor 218 bit 7,d 219 jr Z,.chkde ; Jump if divisor is positive 220 sub a ; Substract divisor from 0 221 sub e 222 ld e,a 223 sbc a ; Propagate borrow (A=0xFF if borrow) 224 sub d 225 ld d,a 226 ;; Take absolute value of dividend 227.chkde: 228 bit 7,b 229 jr Z,.dodiv ; Jump if dividend is positive 230 sub a ; Substract dividend from 0 231 sub c 232 ld c,a 233 sbc a ; Propagate borrow (A=0xFF if borrow) 234 sub b 235 ld b,a 236 ;; Divide absolute values 237.dodiv: 238 call .divu16 239 jr C,.exit ; Exit if divide by zero 240 ;; Negate quotient if it is negative 241 pop af ; recover sign of quotient 242 and #0x80 243 jr Z,.dorem ; Jump if quotient is positive 244 sub a ; Substract quotient from 0 245 sub c 246 ld c,a 247 sbc a ; Propagate borrow (A=0xFF if borrow) 248 sub b 249 ld b,a 250.dorem: 251 ;; Negate remainder if it is negative 252 pop af ; recover sign of remainder 253 and #0x80 254 ret Z ; Return if remainder is positive 255 sub a ; Substract remainder from 0 256 sub e 257 ld e,a 258 sbc a ; Propagate remainder (A=0xFF if borrow) 259 sub d 260 ld d,a 261 ret 262.exit: 263 pop af 264 pop af 265 ret 266 267.divu8:: 268.modu8:: 269 ld b,#0x00 270 ld d,b 271 ; Fall through to divu16 272 273.divu16:: 274.modu16:: 275 ;; Check for division by zero 276 ld a,e 277 or d 278 jr NZ,.divide ; Branch if divisor is non-zero 279 ld bc,#0x00 ; Divide by zero error 280 ld d,b 281 ld e,c 282 scf ; Set carry, invalid result 283 ret 284.divide: 285 ld l,c ; L = low byte of dividend/quotient 286 ld h,b ; H = high byte of dividend/quotient 287 ld bc,#0x00 ; BC = remainder 288 or a ; Clear carry to start 289 ld a,#16 ; 16 bits in dividend 290.dvloop: 291 ;; Shift next bit of quotient into bit 0 of dividend 292 ;; Shift next MSB of dividend into LSB of remainder 293 ;; BC holds both dividend and quotient. While we shift a bit from 294 ;; MSB of dividend, we shift next bit of quotient in from carry 295 ;; HL holds remainder 296 ;; Do a 32-bit left shift, shifting carry to L, L to H, 297 ;; H to C, C to B 298 push af ; save number of bits remaining 299 rl l ; Carry (next bit of quotient) to bit 0 300 rl h ; Shift remaining bytes 301 rl c 302 rl b ; Clears carry since BC was 0 303 ;; If remainder is >= divisor, next bit of quotient is 1. This 304 ;; bit goes to carry 305 push bc ; Save current remainder 306 ld a,c ; Substract divisor from remainder 307 sbc e 308 ld c,a 309 ld a,b 310 sbc d 311 ld b,a 312 ccf ; Complement borrow so 1 indicates a 313 ; successful substraction (this is the 314 ; next bit of quotient) 315 jr C,.drop ; Jump if remainder is >= dividend 316 pop bc ; Otherwise, restore remainder 317 pop af ; recover # bits remaining, carry flag destroyed 318 dec a 319 or a ; restore (clear) the carry flag 320 jr NZ,.dvloop 321 jr .nodrop 322.drop: 323 pop af ; faster and smaller than 2x inc sp 324 pop af ; recover # bits remaining, carry flag destroyed 325 dec a 326 scf ; restore (set) the carry flag 327 jr NZ,.dvloop 328 jr .nodrop 329.nodrop: 330 ;; Shift last carry bit into quotient 331 ld d,b ; DE = remainder 332 ld e,c 333 rl l ; Carry to L 334 ld c,l ; C = low byte of quotient 335 rl h 336 ld b,h ; B = high byte of quotient 337 or a ; Clear carry, valid result 338 ret 339