Skip to content

Commit

Permalink
Add 8 bit by 8 bit unsigned division as preparation for 32 bit by 32 …
Browse files Browse the repository at this point in the history
…bit division
  • Loading branch information
rmsk2 committed Jun 17, 2023
1 parent ed49316 commit f7bac2b
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 2 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ available

It does not use any ROM routines and is therefore independent of any operating environment. In other words:
It should run on any machine with a compatible microprocessor. This includes: All Commodore 8 bit machines,
the Atari 8 bit machines, the Apple II, the BBC micro, the Acorn Electron, the Oric, the Commander X16, heck
it should even run on the KIM-1. The following routines are provided:
the Atari 8 bit machines, the Apple II, the BBC micro, the Acorn Electron, the Oric, the Commander X16, the
Foenix F256 Jr./K (even though it does not make use of the hardware accelerated 16x16 bit multiplication
feature of the F256) heck it should even run on the KIM-1. The following routines are provided:

- Addition
- Subtraction
Expand Down
63 changes: 63 additions & 0 deletions arith.a
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,52 @@ mul16Bit
rts
}


; --------------------------------------------------
; This subroutine takes its two 8 bit operands in the accu and the x register and divides
; them. The division result of A / X is returned in A and the remainder is returned in
; X. This is taken from
;
; https://www.retro-programming.de/programming/assembler/fuer-fortgeschrittene/mul-div-ganzzahl/
;
; and modified by me including a bug fix for all cases where the dividend is smaller than the divisor.
; In the original code the remainder was zero and not ZP_DIVIDEND in these cases.
; --------------------------------------------------
divMod8Bit
sta ZP_DIVIDEND
stx ZP_DIVISOR
lda #$00 ; erstmal eine 0
sta ZP_RESULT ; ins Ergebnis
sta ZP_HELP ; und in die Hilfsvariable
lda ZP_DIVIDEND
cmp ZP_DIVISOR ; DIVIDEND < DIVISOR?
bcc .dividendLtDivisor ; yes => do nothing, as the result data (ZP_RESULT = 0, ZP_DIVIDEND is remainder) is correct
lda ZP_DIVISOR ; prüfen ob durch 0 geteilt werden soll
beq .stopPrg ; In case divisor is zero stop program
ldx #$08 ; acht Schleifendurchläufe
.loop
asl ZP_DIVIDEND ; höchstes BIT ins Carry-Flag shiften
rol ZP_HELP ; C-Flag ins niedrigste BIT rotieren
lda ZP_HELP ; ZP_HELP in den Akku
cmp ZP_DIVISOR ; prüfen ob ZP_HELP größer/gleich Divisor
bcc .skip ; falls nein -> weiter bei .skip
sbc ZP_DIVISOR ; sonst Divisor vom Akku abziehen
sta ZP_HELP ; Akku bei ZP_HELP speichern
.skip
rol ZP_RESULT ; C-Flag ins Ergebnis rotieren
dex ; Schleifenzähler verringern
bne .loop ; solange größer 0, nochmal -> .loop
.exit
lda ZP_RESULT ; Here the result is always nonzero as DIVIDEND >= DIVISOR
ldx ZP_HELP
rts
.dividendLtDivisor
lda #0
ldx ZP_DIVIDEND
rts
.stopPrg
brk

; --------------------------------------------------
; The 32 bit integer routines represent a number as 5 bytes. The first byte
; is the sign where 1 indicates a negative sign and 0 a positive sign. The sign byte
Expand Down Expand Up @@ -417,6 +463,23 @@ square32BitUnsigned
rts


RES_DIV
!byte 0,0,0,0

RES_REM
!byte 0,0,0,0

; --------------------------------------------------
; This subroutine expects operand one in ARITH_SCRATCH1/2 and operand two in ARITH_SCRATCH3/4
; and determines the division result and remainder when dividing operand one by operand two. This
; routine ignores the sign byte and treats its operands as positive integers. It also assumes that
; operand one is greater or equal to operand two. And it assumes that operand two is not zero.
;
; The result is returned in the buffers RES_DIV and RES_REM.
; --------------------------------------------------
divMod32BitUnsigned
rts

; --------------------------------------------------
; This subroutine expects its operands in ARITH_SCRATCH1/2 and ARITH_SCRATCH3/4
; and compares them. This routine ignores the sign byte it only compares the absolute values.
Expand Down
10 changes: 10 additions & 0 deletions tests/div81.a
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
* = $0800

jmp main

!source "zeropage.a"
!source "arith.a"

main
jsr divMod8Bit
brk
5 changes: 5 additions & 0 deletions tests/div81.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"Name": "8 by 8 bit division 1",
"TestDriverSource": "div81.a",
"TestScript": "div81.lua"
}
44 changes: 44 additions & 0 deletions tests/div81.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
test_data = {
[1] = {val1 = 35, val2 = 2},
[2] = {val1 = 255, val2 = 255},
[3] = {val1 = 0, val2 = 255},
[4] = {val1 = 173, val2 = 12},
[5] = {val1 = 12, val2 = 173},
[6] = {val1 = 173, val2 = 255},
[7] = {val1 = 1, val2 = 183},
[8] = {val1 = 64, val2 = 32},
[9] = {val1 = 122, val2 = 10},
[10] = {val1 = 122, val2 = 122}
}

function num_iterations()
return #test_data
end

iter_count = 0

function arrange()
iter_count = iter_count + 1
set_pc(load_address)
set_accu(test_data[iter_count].val1)
set_xreg(test_data[iter_count].val2)
end

function assert()
in1 = test_data[iter_count].val1
in2 = test_data[iter_count].val2

correct_mod = in1 % in2
res_mod = (get_xreg() == correct_mod)
if not res_mod then
return false, string.format("Unexpected value: %d mod %d is not %d (should be %d)", in1, in2, get_xreg(), correct_mod)
end

correct_div = math.floor(in1 / in2)
res_div = (get_accu() == correct_div)
if not res_div then
return false, string.format("Unexpected value: %d div %d is not %d (should be %d)", in1, in2, get_accu(), correct_div)
end

return true, "All OK"
end
5 changes: 5 additions & 0 deletions zeropage.a
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ LOOKUP_SCRATCH3 = $F9
COUNT_L = $9E
COUNT_R = $9F
HELP_MUL = $FA

ZP_RESULT = LOOKUP_SCRATCH1
ZP_HELP = LOOKUP_SCRATCH2
ZP_DIVISOR = LOOKUP_SCRATCH3
ZP_DIVIDEND = HELP_MUL

0 comments on commit f7bac2b

Please sign in to comment.