diff --git a/README.md b/README.md index 68d647c..e09aafc 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/arith.a b/arith.a index 8f57053..bf17013 100644 --- a/arith.a +++ b/arith.a @@ -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 @@ -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. diff --git a/tests/div81.a b/tests/div81.a new file mode 100644 index 0000000..05d55a7 --- /dev/null +++ b/tests/div81.a @@ -0,0 +1,10 @@ +* = $0800 + +jmp main + +!source "zeropage.a" +!source "arith.a" + +main + jsr divMod8Bit + brk \ No newline at end of file diff --git a/tests/div81.json b/tests/div81.json new file mode 100644 index 0000000..b850552 --- /dev/null +++ b/tests/div81.json @@ -0,0 +1,5 @@ +{ + "Name": "8 by 8 bit division 1", + "TestDriverSource": "div81.a", + "TestScript": "div81.lua" +} \ No newline at end of file diff --git a/tests/div81.lua b/tests/div81.lua new file mode 100644 index 0000000..03506cb --- /dev/null +++ b/tests/div81.lua @@ -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 \ No newline at end of file diff --git a/zeropage.a b/zeropage.a index c7ce21e..4e55f6d 100644 --- a/zeropage.a +++ b/zeropage.a @@ -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 \ No newline at end of file