From b613ab89658528e645248ab70cf562835f62b2a3 Mon Sep 17 00:00:00 2001 From: Sijmen Schoon Date: Wed, 9 Dec 2020 00:48:29 +0100 Subject: [PATCH] Implement 32bit divmod based on Bisqwit's algorithm, implement 16 and 32-bit decimal print --- c64/main.asm | 50 +++++++++++++++---- c64/math.asm | 89 +++++++++++++++++++++------------- c64/math.inc | 45 +++++++++++++++++ c64/screen.asm | 128 ++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 268 insertions(+), 44 deletions(-) diff --git a/c64/main.asm b/c64/main.asm index ba9a370..6873104 100644 --- a/c64/main.asm +++ b/c64/main.asm @@ -2,12 +2,29 @@ #import "math.inc" -* = $0801 // BASIC start address (#2049) -.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 + BasicUpstart2(main) + + .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 - .const SCREEN_RAM = $0400 .const COLOR_RAM = $d800 @@ -32,20 +49,33 @@ main: jsr clear_screen - // lda #0 - // sta $d020 - // sta $d021 + // Swap out BASIC and kernal + sei + 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: - // inc $d020 jmp !loop- buffer: - .fill $0100, 0 + .fill $0400, 0 #import "day01.asm" #import "screen.asm" +#import "math.asm" diff --git a/c64/math.asm b/c64/math.asm index 5eb93e1..e4b6be8 100644 --- a/c64/math.asm +++ b/c64/math.asm @@ -1,3 +1,5 @@ +// vim: filetype=kickass + .const T1=$03 .const T2=$fd .const PRODUCT=$22 @@ -282,18 +284,32 @@ generate_multiplication_tables: // // udivmod32 // -// TODO consistent name -// TODO document input, output, destroyed +// 32-bit unsigned integer div/mod routine. +// 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 multiple = $28 // ..2b -.const temp = $2b // ..2f +.const multiple = $24 // ..27 +.const temp = $28 // ..2b udivmod32: + lda #0 + sta udivmod32_result + 0 + sta udivmod32_result + 1 + sta udivmod32_result + 2 + sta udivmod32_result + 3 + // if (divisor == 0) { lda udivmod32_divisor + 0 bne !if_end+ @@ -322,12 +338,12 @@ udivmod32: // remainder = dividend; lda udivmod32_dividend + 0 sta udivmod32_remainder + 0 - lda udivmod32_dividend + 0 - sta udivmod32_remainder + 0 - lda udivmod32_dividend + 0 - sta udivmod32_remainder + 0 - lda udivmod32_dividend + 0 - sta udivmod32_remainder + 0 + lda udivmod32_dividend + 1 + sta udivmod32_remainder + 1 + lda udivmod32_dividend + 2 + sta udivmod32_remainder + 2 + lda udivmod32_dividend + 3 + sta udivmod32_remainder + 3 // uint32_t multiple = 1; @@ -338,25 +354,12 @@ udivmod32: sta multiple + 2 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 < dividend) { + // while (!(scaled_divisor & 0x80000000)) { !while_start: - sec - lda scaled_divisor + 0 - sbc udivmod32_dividend + 0 - 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+ + lda #$80 + and scaled_divisor + 3 + bne !while_end+ // scaled_divisor <<= 1 asl scaled_divisor + 0 @@ -382,15 +385,19 @@ udivmod32: lda udivmod32_remainder + 0 sbc scaled_divisor + 0 sta temp + 0 + lda udivmod32_remainder + 1 sbc scaled_divisor + 1 sta temp + 1 + lda udivmod32_remainder + 2 sbc scaled_divisor + 2 sta temp + 2 + lda udivmod32_remainder + 3 sbc scaled_divisor + 3 sta temp + 3 + bcc !if_end+ // remain -= scaled_divisor; @@ -403,6 +410,24 @@ udivmod32: lda temp + 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: diff --git a/c64/math.inc b/c64/math.inc index a613bb0..7f61353 100644 --- a/c64/math.inc +++ b/c64/math.inc @@ -1,4 +1,8 @@ // 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() { sta zp_temp @@ -95,6 +99,47 @@ 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 .macro i16_i8_add_a(dst_lo, dst_hi) { clc diff --git a/c64/screen.asm b/c64/screen.asm index 458ba4e..d668586 100644 --- a/c64/screen.asm +++ b/c64/screen.asm @@ -52,9 +52,7 @@ print_newline: sta cursor_pointer_lo bcc !done+ inc cursor_pointer_hi - !done: - rts // @@ -136,6 +134,13 @@ write_string: rts +.macro i16_print_hex_0x(lo, hi) { + lda hi + jsr print_hex_0x + lda lo + jsr print_hex +} + print_hex_0x: sta zp_temp @@ -180,3 +185,122 @@ print_hex: !hex_chars: .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