Implement 32bit divmod based on Bisqwit's algorithm, implement 16 and 32-bit decimal print
This commit is contained in:
parent
c7af8e833b
commit
b613ab8965
4 changed files with 268 additions and 44 deletions
50
c64/main.asm
50
c64/main.asm
|
@ -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"
|
||||||
|
|
89
c64/math.asm
89
c64/math.asm
|
@ -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:
|
||||||
|
|
||||||
|
|
45
c64/math.inc
45
c64/math.inc
|
@ -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
|
||||||
|
|
128
c64/screen.asm
128
c64/screen.asm
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue