cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

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