git.y1.nz

gbdk-2020

GameBoy Development Kit
download: https://git.y1.nz/archives/gbdk.tar.gz
README | Files | Log | Refs | LICENSE

gbdk-lib/libc/asm/sm83/div.s

      1 ;--------------------------------------------------------------------------
      2 ;  div.s
      3 ;
      4 ;  Copyright (c) 2026, Phidias618
      5 ;
      6 ;--------------------------------------------------------------------------
      7 
      8         .module divmod
      9         .area   _CODE
     10 
     11 .globl  __divuchar
     12 .globl  __moduchar
     13 .globl  __divuint
     14 .globl  __moduint
     15 
     16 .globl  __divsuchar
     17 .globl  __modsuchar
     18 .globl  __divuschar
     19 .globl  __moduschar
     20 .globl  __divschar
     21 .globl  __modschar
     22 
     23 .globl  __divsint
     24 .globl  __modsint
     25 
     26 
     27 ; unsigned division
     28 
     29 __moduchar:
     30         ld	c, e
     31         ld      e, a
     32         xor a
     33         ld b, a
     34         ld d, a
     35 __moduint:
     36         call    .divmod_uint_bcde
     37 
     38         ld      c, e
     39         ld      b, d
     40 
     41         ret
     42 
     43 .divmod_uchar_bcde:
     44 __divuchar:
     45         ld	c, e
     46         ld  e, a
     47         xor a
     48         ld b, a
     49         ld d, a
     50         ; Fall through .divmod_uint_bcde
     51 .divmod_uint_bcde:
     52 __divuint::
     53         ; computes the quotient and the remainder of X / Y
     54         ; X is stored in de
     55         ; Y is stored in bc
     56         ; outputs the quotient in bc
     57         ; outputs the remainder in de
     58         ; if Y = 0 then the carry is set and quotient = 0 and remainder = 0
     59         ; otherwise the carry is cleared
     60 		
     61         
     62         ; stores -Y in hl and check that -Y is not zero
     63         xor a
     64 		sub c
     65 		ld l, a
     66 		sbc a
     67 		sub b
     68 		ld h, a
     69 		
     70 		or l
     71         jr z, .division_by_zero
     72         
     73         ; if X < Y then
     74         ;	return quotient = 0 and remainder = X
     75         ; else
     76         ;	computes the largest (Y << K) such that (Y << K) <= X
     77         ; 	put the 17 bit value -(Y << (K + 1)) into hl with the MSB stored using the carry
     78         ; 	put K, using a base 1 representation, using the most significant bits of bc
     79         ld bc, #0
     80         
     81         ld a, e
     82         add l
     83         ld a, d
     84         adc h
     85         jr c, 10$
     86         ; X < Y
     87         ; bc already stores 0
     88         ret
     89 0$:
     90         rr b
     91         rr c
     92 10$:	
     93         add hl, hl
     94         jr nc, 1$
     95         
     96         ld a, e
     97         add l
     98         ld a, d
     99         adc h
    100         jr c, 0$
    101         scf
    102 1$:
    103 
    104         ; swaps the content of hl and de
    105         ld a, h
    106         ld h, d
    107         ld d, a
    108         
    109         ld a, l
    110         ld l, e
    111         ld e, a
    112         
    113         ; computes X / Y one bit at a time using the following algorithm
    114         ; r = X
    115         ; q  = 0
    116         ; while K >= 0
    117         ;	b = 0
    118         ;	if (Y << K) <= r then
    119         ;		r += -(Y << K)
    120         ;		b = 1
    121         ;	q = (q << 1) | b
    122         ;	K -= 1
    123         ;
    124         ; 
    125         ; r is stored in hl
    126         ; q is stored in bc
    127         ; storing both q and K in bc will not create issue as they will not use the same bits at the same time
    128         ; -(Y << K) is stored in de
    129 2$:
    130         ; on the first iteration :
    131         ;	this shifts DE such that DE now stores -(Y << K)
    132         ; on every iteration but the first:
    133         ;	transforms -(Y << K) into -(Y << (K-1))
    134         ;	sra d is not used as the MSB should always be filled with a 1 when shifting de
    135         ;	this works because the carry will always be set if this is not the first iteration
    136         rr  d
    137         rr  e
    138         
    139         ; compare remainder with (Y << K)
    140         ld a, e 
    141         add l
    142         ld a, d
    143         adc h
    144         
    145         jr nc, 3$
    146         add hl, de
    147 3$:
    148         ; fill bc with one bit of the result and decrements K at the same time
    149         rl c
    150         rl b
    151         
    152         jr c, 2$
    153 ret_hl_in_de:
    154         ld d, h
    155         ld e, l
    156         ; status of the registers
    157         ; bc = quotient
    158         ; de = remainder
    159         ; carry = 0 if Y != 0, 1 if Y == 0
    160         
    161         ret
    162 .division_by_zero:
    163         ; returns both a quotient of 0 and a remainder of 0
    164         ; if this is reached, then bc = 0
    165         scf
    166 		jr ret_hl_in_de
    167 
    168 
    169 ; mixed sign division
    170 
    171 __modsuchar:
    172         call .divmod_suchar_bcde
    173         ld b, d
    174         ld c, e
    175         ret
    176 .divmod_suchar_bcde:
    177 __divsuchar:
    178         ld d, #0
    179         ld c, e
    180         ld e, a
    181         
    182         jr signext_c
    183 
    184 __moduschar:
    185         call .divmod_uschar_bcde
    186         ld b, d
    187         ld c, e
    188         ret
    189 .divmod_uschar_bcde:
    190 __divuschar:
    191         ld b, #0
    192         ld c, e
    193         ld e, a
    194 		add a
    195         sbc a
    196         ld d, a
    197         
    198         jr .divmod_sint_bcde
    199 		
    200 ; signed division
    201 
    202 __modschar:
    203         call .divmod_schar_bcde
    204         ld b, d
    205         ld c, e
    206         ret
    207 __modsint::
    208         call .divmod_sint_bcde
    209         ld b, d
    210         ld c, e
    211         ret
    212 
    213 ; these 2 functions exists for compatibility reasons
    214 .div8::
    215 .mod8::
    216         ld a, c
    217         ; Fall through .divmod_schar_bcde
    218 .divmod_schar_bcde:
    219 __divschar:
    220         ld		c, e
    221         ld      e, a
    222 		add a
    223         sbc a
    224         ld d, a
    225 signext_c:
    226         ld a, c
    227         rlca
    228         sbc a
    229         ld b, a
    230         ; Fall through .divmod_sint_bcde
    231 .divmod_sint_bcde:
    232 __divsint::
    233         ; saves the sign of the quotient as the carry and the sign of the remainder as the 7th bit of A
    234         ld a, d		; high byte of dividend
    235         xor b		; high byte of divisor
    236         rla			; save the 7th bit of A as the carry
    237         ld a, d
    238         push af
    239         
    240         ; take the absolute value of de
    241         add a
    242         jr nc, 0$
    243         
    244         xor a
    245         sub e
    246         ld e, a
    247         sbc a
    248         sub d
    249         ld d, a
    250 0$:
    251         ; take the absolute value of bc
    252         bit 7, b
    253         jr z, 1$
    254         
    255         xor a
    256         sub c
    257         ld c, a
    258         sbc a
    259         sub b
    260         ld b, a
    261 1$:
    262         call .divmod_uint_bcde
    263         jr c, .error
    264         pop af		; retrieve the signs the the quotient and the sign of the remainder
    265         
    266         jr nc, 2$
    267         ld l, a		; saves the sign of the remainder
    268         ; negates the quotient
    269         xor a
    270         sub c
    271         ld c, a
    272         sbc a
    273         sub b
    274         ld b, a
    275         
    276         ld a, l
    277 2$:
    278         rlca
    279         ret nc
    280         ; negates the remainder
    281         xor a
    282         sub e
    283         ld e, a
    284         sbc a
    285         sub d
    286         ld d, a
    287         
    288         or a			; clears the carry
    289         ret
    290 .error:
    291         pop hl			; do not pop af in order to preserve the carry as set
    292         ret
    293 
    294 
    295 ;	the following functions are here in order to not break compatibility
    296 
    297         ;; 16-bit division
    298         ;;
    299         ;; Entry conditions
    300         ;;   BC = dividend
    301         ;;   DE = divisor
    302         ;;
    303         ;; Exit conditions
    304         ;;   BC = quotient
    305         ;;   DE = remainder
    306         ;;   If divisor is non-zero, carry=0
    307         ;;   If divisor is 0, carry=1 and both quotient and remainder are 0
    308         ;;
    309         ;; Register used: AF,BC,DE,HL
    310 .div16::
    311 .mod16::
    312 	ld hl, #.divmod_sint_bcde
    313 swap_bc_de_jp_hl:
    314         ld a, b
    315         ld b, d
    316         ld d, a
    317         
    318         ld a, c
    319         ld c, e
    320         ld e, a
    321         
    322         jp (hl)
    323 .divu8::
    324 .modu8::
    325         ld      b,#0x00
    326         ld      d,b
    327         ; Fall through to .divu16
    328 .divu16::
    329 .modu16::
    330         ld hl, #.divmod_uint_bcde
    331         jr swap_bc_de_jp_hl

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.