Implement 32bit divmod based on Bisqwit's algorithm, implement 16 and 32-bit decimal print

This commit is contained in:
Sijmen 2020-12-09 00:48:29 +01:00
parent c7af8e833b
commit b613ab8965
Signed by: vijfhoek
GPG Key ID: DAF7821E067D9C48
4 changed files with 268 additions and 44 deletions

View File

@ -2,12 +2,29 @@
#import "math.inc" #import "math.inc"
* = $0801 // BASIC start address (#2049) BasicUpstart2(main)
.byte $0d,$08,$dc,$07,$9e,$20,$34,$39 // BASIC loader to start at $c000...
.byte $31,$35,$32,$00,$00,$00 // puts BASIC line 2012 SYS 49152 .align $100
* = * "Square table"
square1_lo:
.fill 512, 0
square1_hi:
.fill 512, 0
square2_lo:
.fill 512, 0
square2_hi:
.fill 512, 0
* = * "Day 1 input"
day01_input:
.import text "../rust/inputs/day01"
.byte 0
//* = $8000 "Cartridge ROM"
//* = $a000 "Basic ROM"
* = $c000 * = $c000
.const SCREEN_RAM = $0400 .const SCREEN_RAM = $0400
.const COLOR_RAM = $d800 .const COLOR_RAM = $d800
@ -32,20 +49,33 @@
main: main:
jsr clear_screen jsr clear_screen
// lda #0 // Swap out BASIC and kernal
// sta $d020 sei
// sta $d021 lda %00110000
sta $01
jsr day01 jsr generate_multiplication_tables
// Test division by 10
lda #$cc
sta udivmod32_dividend + 0
lda #$28
sta udivmod32_dividend + 1
lda #$f9
sta udivmod32_dividend + 2
lda #$07
sta udivmod32_dividend + 3
jsr print_decimal_u32
!loop: !loop:
// inc $d020
jmp !loop- jmp !loop-
buffer: buffer:
.fill $0100, 0 .fill $0400, 0
#import "day01.asm" #import "day01.asm"
#import "screen.asm" #import "screen.asm"
#import "math.asm"

View File

@ -1,3 +1,5 @@
// vim: filetype=kickass
.const T1=$03 .const T1=$03
.const T2=$fd .const T2=$fd
.const PRODUCT=$22 .const PRODUCT=$22
@ -282,18 +284,32 @@ generate_multiplication_tables:
// //
// udivmod32 // udivmod32
// //
// TODO consistent name // 32-bit unsigned integer div/mod routine.
// TODO document input, output, destroyed // Based on https://bisqwit.iki.fi/story/howto/bitmath/
//
// TODO consistent name
// TODO could probably be optimized further
//
// Input:
// - udivmod32_dividend: LSB of the dividend.
// - udivmod32_divisor: LSB of the divisor.
//
// Output:
// - udivmod32_result: LSB of the division result.
// - udivmod32_remainder: LSB of the modulo result.
//
// Destroys: a, $20..$2b
// //
.const udivmod32_dividend = $10 // 11,12,13
.const udivmod32_divisor = $14 // 15,16,17
.const udivmod32_result = $18 // 19,1a,1b
.const udivmod32_remainder = $1c // 1d,1e,1f
.const scaled_divisor = $20 // ..23 .const scaled_divisor = $20 // ..23
.const multiple = $28 // ..2b .const multiple = $24 // ..27
.const temp = $2b // ..2f .const temp = $28 // ..2b
udivmod32: udivmod32:
lda #0
sta udivmod32_result + 0
sta udivmod32_result + 1
sta udivmod32_result + 2
sta udivmod32_result + 3
// if (divisor == 0) { // if (divisor == 0) {
lda udivmod32_divisor + 0 lda udivmod32_divisor + 0
bne !if_end+ bne !if_end+
@ -322,12 +338,12 @@ udivmod32:
// remainder = dividend; // remainder = dividend;
lda udivmod32_dividend + 0 lda udivmod32_dividend + 0
sta udivmod32_remainder + 0 sta udivmod32_remainder + 0
lda udivmod32_dividend + 0 lda udivmod32_dividend + 1
sta udivmod32_remainder + 0 sta udivmod32_remainder + 1
lda udivmod32_dividend + 0 lda udivmod32_dividend + 2
sta udivmod32_remainder + 0 sta udivmod32_remainder + 2
lda udivmod32_dividend + 0 lda udivmod32_dividend + 3
sta udivmod32_remainder + 0 sta udivmod32_remainder + 3
// uint32_t multiple = 1; // uint32_t multiple = 1;
@ -338,25 +354,12 @@ udivmod32:
sta multiple + 2 sta multiple + 2
sta multiple + 3 sta multiple + 3
// uint32_t result = 0;
sta udivmod32_result + 0
sta udivmod32_result + 1
sta udivmod32_result + 2
sta udivmod32_result + 3
// while (!(scaled_divisor & 0x80000000)) {
// while (scaled_divisor < dividend) {
!while_start: !while_start:
sec lda #$80
lda scaled_divisor + 0 and scaled_divisor + 3
sbc udivmod32_dividend + 0 bne !while_end+
lda scaled_divisor + 1
sbc udivmod32_dividend + 1
lda scaled_divisor + 2
sbc udivmod32_dividend + 2
lda scaled_divisor + 3
sbc udivmod32_dividend + 3
bcs !while_end+
// scaled_divisor <<= 1 // scaled_divisor <<= 1
asl scaled_divisor + 0 asl scaled_divisor + 0
@ -382,15 +385,19 @@ udivmod32:
lda udivmod32_remainder + 0 lda udivmod32_remainder + 0
sbc scaled_divisor + 0 sbc scaled_divisor + 0
sta temp + 0 sta temp + 0
lda udivmod32_remainder + 1 lda udivmod32_remainder + 1
sbc scaled_divisor + 1 sbc scaled_divisor + 1
sta temp + 1 sta temp + 1
lda udivmod32_remainder + 2 lda udivmod32_remainder + 2
sbc scaled_divisor + 2 sbc scaled_divisor + 2
sta temp + 2 sta temp + 2
lda udivmod32_remainder + 3 lda udivmod32_remainder + 3
sbc scaled_divisor + 3 sbc scaled_divisor + 3
sta temp + 3 sta temp + 3
bcc !if_end+ bcc !if_end+
// remain -= scaled_divisor; // remain -= scaled_divisor;
@ -403,6 +410,24 @@ udivmod32:
lda temp + 3 lda temp + 3
sta udivmod32_remainder + 3 sta udivmod32_remainder + 3
// result += multiple;
clc
lda udivmod32_result + 0
adc multiple + 0
sta udivmod32_result + 0
lda udivmod32_result + 1
adc multiple + 1
sta udivmod32_result + 1
lda udivmod32_result + 2
adc multiple + 2
sta udivmod32_result + 2
lda udivmod32_result + 3
adc multiple + 3
sta udivmod32_result + 3
// } // }
!if_end: !if_end:

View File

@ -1,4 +1,8 @@
// vim: filetype=kickass // vim: filetype=kickass
.const udivmod32_dividend = $10 // 11,12,13
.const udivmod32_divisor = $14 // 15,16,17
.const udivmod32_result = $18 // 19,1a,1b
.const udivmod32_remainder = $1c // 1d,1e,1f
.macro i8_div5_a() { .macro i8_div5_a() {
sta zp_temp sta zp_temp
@ -95,6 +99,47 @@
i16_i16_add(lo, hi, $fd, $fe) i16_i16_add(lo, hi, $fd, $fe)
} }
.macro u32_mul2(lsb) {
asl lsb + 0
rol lsb + 1
rol lsb + 2
rol lsb + 3
}
.macro u32_mul10(lsb) {
u32_mul2(lsb)
lda lsb + 0
sta $2c + 0
lda lsb + 1
sta $2c + 1
lda lsb + 2
sta $2c + 2
lda lsb + 3
sta $2c + 3
u32_mul2(lsb)
u32_mul2(lsb)
i32_i32_add(lsb, $2c)
}
.macro i32_i32_add(dst, src) {
clc
lda dst + 0
adc src + 0
sta dst + 0
lda dst + 1
adc src + 1
sta dst + 1
lda dst + 2
adc src + 2
sta dst + 2
lda dst + 3
adc src + 3
sta dst + 3
}
// Destroys: a, dst_lo, dst_hi // Destroys: a, dst_lo, dst_hi
.macro i16_i8_add_a(dst_lo, dst_hi) { .macro i16_i8_add_a(dst_lo, dst_hi) {
clc clc

View File

@ -52,9 +52,7 @@ print_newline:
sta cursor_pointer_lo sta cursor_pointer_lo
bcc !done+ bcc !done+
inc cursor_pointer_hi inc cursor_pointer_hi
!done: !done:
rts
// //
@ -136,6 +134,13 @@ write_string:
rts rts
.macro i16_print_hex_0x(lo, hi) {
lda hi
jsr print_hex_0x
lda lo
jsr print_hex
}
print_hex_0x: print_hex_0x:
sta zp_temp sta zp_temp
@ -180,3 +185,122 @@ print_hex:
!hex_chars: !hex_chars:
.text "0123456789ABCDEF" .text "0123456789ABCDEF"
print_decimal_u16:
ldy #6
// Null-terminate the buffer
lda #0
sta !buffer+, y
!loop:
u16_div10()
lda $24
sta $22
lda $25
sta $23
i16_mul10($22, $23)
i16_i16_sub($22, $23, $03, $04, $22, $23)
lda $24
sta $03
lda $25
sta $04
lda $22
clc
adc #'0'
sta !buffer+ - 1, y
dey
bne !loop-
// Find the first digit
ldy #0
!:
lda !buffer+, y
iny
cmp #'0'
beq !-
dey
tya
clc
adc #<(!buffer+)
sta $03
lda #0
adc #>(!buffer+)
sta $04
jsr write_string
rts
//
// Input:
// - udivmod32_dividend - Number to print
print_decimal_u32:
ldy #11
// Null-terminate the buffer
lda #0
sta !buffer+, y
lda #0
sta udivmod32_divisor + 3
sta udivmod32_divisor + 2
sta udivmod32_divisor + 1
lda #10
sta udivmod32_divisor + 0
!loop:
jsr udivmod32
lda udivmod32_remainder
clc
adc #'0'
sta !buffer+ - 1, y
lda udivmod32_result + 0
sta udivmod32_dividend + 0
lda udivmod32_result + 1
sta udivmod32_dividend + 1
lda udivmod32_result + 2
sta udivmod32_dividend + 2
lda udivmod32_result + 3
sta udivmod32_dividend + 3
dey
bne !loop-
// Find the first digit
ldy #0
!:
lda !buffer+, y
iny
cmp #'0'
beq !-
dey
tya
clc
adc #<(!buffer+)
sta $03
lda #0
adc #>(!buffer+)
sta $04
jsr write_string
rts
!buffer:
.fill 12, 0