Jump to content
  • entries
    17
  • comments
    28
  • views
    32,072

(16 bit division), Fast divide by 10


Omegamatrix

3,138 views

I took a stab at making a 16 bit division routine tonight. I took the approach of dividing the high and low bytes separately, since I have already written a bunch of 8 bit division routines. I then corrected the result with a couple of small look up tables.

 

 

This is the 16 bit routine I came up with. At 111 cycles max, and 96 bytes total it's not too bad. :)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;    UNSIGNED DIVIDE BY 10 (16 BIT)
;    111 cycles (max), 96 bytes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TensRemaining:
    .byte 0,25,51,76,102,128,153,179,204,230
ModRemaing:
    .byte 0,6,2,8,4,0,6,2,8,4
.overflowFound:
    cmp    #4                    ;2  @74  We have overflowed, but we can apply a shortcut.
    lda    #25                   ;2  @76  Divide by 10 will be at least 25, and the
    bne    .finishLowTen         ;3  @79  carry is set when higher for the next addition.                                 ; always branch
.startBigDivide:
    lda    counterHigh           ;3  @3
    sta    temp                  ;3  @6
    lsr                          ;2  @8
    adc    #13                   ;2  @10
    adc    temp                  ;3  @13
    ror                          ;2  @15
    lsr                          ;2  @17
    lsr                          ;2  @19
    adc    temp                  ;3  @22
    ror                          ;2  @24
    adc    temp                  ;3  @27
    ror                          ;2  @29
    lsr                          ;2  @31
    and    #$7C                  ;2  @33   AND'ing here...
    sta    temp                  ;3  @36   and saving result as highTen (times 4)
    lsr                          ;2  @38
    lsr                          ;2  @40
    sta    highTen               ;3  @43
    adc    temp                  ;3  @46   highTen (times 5)
    asl                          ;2  @48   highTen (times 10)
    sbc    counterHigh           ;3  @51
    eor    #$FF                  ;2  @53
    tay                          ;2  @55   mod 10 result!
    lda    TensRemaining,Y       ;4  @59   Fill the low byte with the tens it should
    sta    lowTen                ;3  @62   have at this point from the high byte divide.
    lda    counterLow            ;3  @65
    adc    ModRemaing,Y          ;4  @69
    bcs    .overflowFound        ;2³ @71/72
    sta    temp                  ;3  @74
    lsr                          ;2  @76
    adc    #13                   ;2  @78
    adc    temp                  ;3  @81
    ror                          ;2  @83
    lsr                          ;2  @85
    lsr                          ;2  @87
    adc    temp                  ;3  @90
    ror                          ;2  @92
    adc    temp                  ;3  @95
    ror                          ;2  @97
    lsr                          ;2  @99
    lsr                          ;2  @101
    lsr                          ;2  @103
    clc                          ;2  @105
.finishLowTen:
    adc    lowTen                ;3  @108
    sta    lowTen                ;3  @111
 

There is a verification program and source code below. It rom has a black screen for a few seconds before displaying PASS.

 

blogentry-7074-0-31338800-1401168797_thumb.png

 

div10_16bit(rev2).zip

 

Here is a second version of the divide by ten. It takes 126 cycles, but uses only 79 bytes. So you can choose whatever routine is best. Code for it is below. :)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;    UNSIGNED DIVIDE BY 10 (16 BIT)
;    126 cycles (max), 79 bytes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TensRemaining:
    .byte 0,25,51,76,102,128,153,179,204,230
ModRemaing:
    .byte 0,6,2,8,4,0,6,2,8,4
.startBigDivide:
    ldy    #-2                   ;2  @2   skips a branch the first time through
    lda    counterHigh           ;3  @5
.do8bitDiv:
    sta    temp                  ;3  @8
    lsr                          ;2  @10
    adc    #13                   ;2  @12
    adc    temp                  ;3  @15
    ror                          ;2  @17
    lsr                          ;2  @19
    lsr                          ;2  @21
    adc    temp                  ;3  @24
    ror                          ;2  @26
    adc    temp                  ;3  @29
    ror                          ;2  @31
    lsr                          ;2  @33
    and    #$7C                  ;2  @35   AND'ing here...
    sta    temp                  ;3  @38   and saving result as highTen (times 4)
    lsr                          ;2  @40
    lsr                          ;2  @42
    iny                          ;2  @44
    bpl    .finishLowTen         ;2³ @46/47...120
    sta    highTen               ;3  @49
    adc    temp                  ;3  @52   highTen (times 5)
    asl                          ;2  @54   highTen (times 10)
    sbc    counterHigh           ;3  @57
    eor    #$FF                  ;2  @59
    tay                          ;2  @61   mod 10 result!
    lda    TensRemaining,Y       ;4  @65   Fill the low byte with the tens it should
    sta    lowTen                ;3  @68   have at this point from the high byte divide.
    lda    counterLow            ;3  @71
    adc    ModRemaing,Y          ;4  @75
    bcc    .do8bitDiv            ;2³ @77/78
.overflowFound:
    cmp    #4                    ;2  @79   We have overflowed, but we can apply a shortcut.
    lda    #25                   ;2  @81   Divide by 10 will be at least 25, and the
                                 ;         carry is set when higher for the next addition..
finishLowTen:
    adc    lowTen                ;3  @123
    sta    lowTen                ;3  @126  routine ends at either 87 or 126 cycles
 

1 Comment


Recommended Comments

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...