From 7d50acc9ab8dba76e5b4464e3df40a513e0dd680 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 24 Feb 2020 19:24:28 +0100 Subject: [PATCH 01/57] removed two stubs for probably useless routines --- STATUS.md | 2 -- c64/basic/,stubs_math/b983.MULSHF.s | 18 ------------------ c64/basic/,stubs_math/b983.interop | 3 --- c64/basic/,stubs_math/ba59.MLTPLY.s | 18 ------------------ c64/basic/,stubs_math/ba59.interop | 3 --- 5 files changed, 44 deletions(-) delete mode 100644 c64/basic/,stubs_math/b983.MULSHF.s delete mode 100644 c64/basic/,stubs_math/b983.interop delete mode 100644 c64/basic/,stubs_math/ba59.MLTPLY.s delete mode 100644 c64/basic/,stubs_math/ba59.interop diff --git a/STATUS.md b/STATUS.md index 10c217d9..6e2776f6 100644 --- a/STATUS.md +++ b/STATUS.md @@ -197,11 +197,9 @@ Floating point mathematical routines - not official, but well known and broadly | `$B86A` | `add_FAC2_FAC1` | DONE | | | `$B8FE` | `normal_FAC1` | DONE | | | `$B947` | `inv_FAC1_mantissa` | NOT DONE | | -| `$B983` | `MULSHF` | NOT DONE | | | `$B9EA` | `log_FAC1` | NOT DONE | | | `$BA28` | `mul_MEM_FAC1` | PARTIAL | needs `mul_FAC2_FAC1` | | `$BA2B` | `mul_FAC2_FAC1` | NOT DONE | some work started | -| `$BA59` | `MLTPLY` | NOT DONE | | | `$BA8C` | `mov_MEM_FAC2` | DONE | | | `$BA90` | `get_FAC2_via_INDEX` | NOT DONE | | | `$BAE2` | `mul10_FAC1` | NOT DONE | | diff --git a/c64/basic/,stubs_math/b983.MULSHF.s b/c64/basic/,stubs_math/b983.MULSHF.s deleted file mode 100644 index b4389b13..00000000 --- a/c64/basic/,stubs_math/b983.MULSHF.s +++ /dev/null @@ -1,18 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# X16 BASIC_0 #TAKE-OFFSET 2000 -// #LAYOUT# * BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - -// -// Math package - SHIFT routine -// -// See also: -// - [CM64] Computes Mapping the Commodore 64 - page 113 -// - -// XXX implement, test - - -MULSHF: - - STUB_IMPLEMENTATION() diff --git a/c64/basic/,stubs_math/b983.interop b/c64/basic/,stubs_math/b983.interop deleted file mode 100644 index 0d18777c..00000000 --- a/c64/basic/,stubs_math/b983.interop +++ /dev/null @@ -1,3 +0,0 @@ -This is an important floating point math routine, documented in many places. - -XXX - try to find real-life example diff --git a/c64/basic/,stubs_math/ba59.MLTPLY.s b/c64/basic/,stubs_math/ba59.MLTPLY.s deleted file mode 100644 index 294cd246..00000000 --- a/c64/basic/,stubs_math/ba59.MLTPLY.s +++ /dev/null @@ -1,18 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# X16 BASIC_0 #TAKE-OFFSET 2000 -// #LAYOUT# * BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - -// -// Math package - add a mantissa byte of FAC2 to FAC1, do it .A times -// -// See also: -// - [CM64] Computes Mapping the Commodore 64 - page 113 -// - -// XXX implement, test - - -MULTPLY: - - STUB_IMPLEMENTATION() diff --git a/c64/basic/,stubs_math/ba59.interop b/c64/basic/,stubs_math/ba59.interop deleted file mode 100644 index 0d18777c..00000000 --- a/c64/basic/,stubs_math/ba59.interop +++ /dev/null @@ -1,3 +0,0 @@ -This is an important floating point math routine, documented in many places. - -XXX - try to find real-life example From 500a62e9ec78c58d49e66b0462a495e7cf0638f8 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 24 Feb 2020 19:59:56 +0100 Subject: [PATCH 02/57] imported 8x8 multiplication routine by djmips --- CREDITS.md | 1 + c64/basic/math/mul_FAC2_FAC1.s | 60 ++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/CREDITS.md b/CREDITS.md index 72143f5f..a1ebe654 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -6,6 +6,7 @@ * TWW/CTR - for his keyboard handling code * Graham - for his PAL/NTSC detection routine * enthusi/Onslaught - for his example Turbo Tape 64 compatible loader +* djmips - for fast 8x8 multiplication routine ## for documentation diff --git a/c64/basic/math/mul_FAC2_FAC1.s b/c64/basic/math/mul_FAC2_FAC1.s index 35b71b39..44c21c17 100644 --- a/c64/basic/math/mul_FAC2_FAC1.s +++ b/c64/basic/math/mul_FAC2_FAC1.s @@ -88,3 +88,63 @@ mul_FAC2_FAC1_sub_exp_bias: mul_FAC2_FAC1_done: rts + + +mul_8x8: // XXX we should probably move this subroutine to separate file + + // Routine based on code by djmips, taken from: + // - https://codebase64.org/doku.php?id=base:8bit_multiplication_16bit_product_fast_no_tables + // + // input: mul1, mul2 + // optput: .A (high byte), mul1 (low byte) + +.label mul1 = INDEX+2 +.label mul2 = INDEX+3 + + lda #$00 + + dec mul2 // decrement because we will be adding with carry set for speed (an extra one) + ror mul1 + bcc !+ + adc mul2 +!: + ror + ror mul1 + bcc !+ + adc mul2 +!: + ror + ror mul1 + bcc !+ + adc mul2 +!: + ror + ror mul1 + bcc !+ + adc mul2 +!: + ror + ror mul1 + bcc !+ + adc mul2 +!: + ror + ror mul1 + bcc !+ + adc mul2 +!: + ror + ror mul1 + bcc !+ + adc mul2 +!: + ror + ror mul1 + bcc !+ + adc mul2 +!: + ror + ror mul1 + inc mul2 + + rts From 89dc41633d83819ada6e2e4bf7c9dfb71a813f1a Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 24 Feb 2020 20:54:05 +0100 Subject: [PATCH 03/57] floating point multiplication mostly complete, but needs testing --- STATUS.md | 2 +- c64/basic/math/mul_FAC2_FAC1.s | 200 ++++++++++++++++++++++++++++----- 2 files changed, 171 insertions(+), 31 deletions(-) diff --git a/STATUS.md b/STATUS.md index 6e2776f6..5a4fe399 100644 --- a/STATUS.md +++ b/STATUS.md @@ -199,7 +199,7 @@ Floating point mathematical routines - not official, but well known and broadly | `$B947` | `inv_FAC1_mantissa` | NOT DONE | | | `$B9EA` | `log_FAC1` | NOT DONE | | | `$BA28` | `mul_MEM_FAC1` | PARTIAL | needs `mul_FAC2_FAC1` | -| `$BA2B` | `mul_FAC2_FAC1` | NOT DONE | some work started | +| `$BA2B` | `mul_FAC2_FAC1` | PARTIAL | not testeed yet | | `$BA8C` | `mov_MEM_FAC2` | DONE | | | `$BA90` | `get_FAC2_via_INDEX` | NOT DONE | | | `$BAE2` | `mul10_FAC1` | NOT DONE | | diff --git a/c64/basic/math/mul_FAC2_FAC1.s b/c64/basic/math/mul_FAC2_FAC1.s index 44c21c17..70219515 100644 --- a/c64/basic/math/mul_FAC2_FAC1.s +++ b/c64/basic/math/mul_FAC2_FAC1.s @@ -17,7 +17,11 @@ // - https://codebase64.org/doku.php?id=base:kernal_floating_point_mathematics // -// XXX provide implementation +// XXX test this code + +mul_FAC2_FAC1_done: + + rts mul_FAC2_FAC1: @@ -79,72 +83,208 @@ mul_FAC2_FAC1_sub_exp_bias: sbc #$80 // bias sta FAC1_exponent + // Multiply the mantissas - first clear the RESHO temporary area + + lda #$00 + sta RESHO+0 + sta RESHO+1 + sta RESHO+2 + sta RESHO+3 + sta RESHO+4 + // Multiply the mantissas - - // XXX - STUB_IMPLEMENTATION() + // XXX maybe we should preserve .X on stack? this will not cost us too much -mul_FAC2_FAC1_done: + lda FACOV + jsr mul_by_A + jsr mul_shift_RESHO + bcc !+ + inc RESHO+0 +!: + lda FAC1_mantissa+3 + jsr mul_by_A + jsr mul_shift_RESHO + bcc !+ + inc RESHO+0 +!: + lda FAC1_mantissa+2 + jsr mul_by_A + jsr mul_shift_RESHO + bcc !+ + inc RESHO+0 +!: + lda FAC1_mantissa+1 + jsr mul_by_A + jsr mul_shift_RESHO + bcc !+ + inc RESHO+0 +!: + lda FAC1_mantissa+0 + jsr mul_by_A + jsr mul_shift_RESHO + bcc !+ + inc RESHO+0 +!: + // Copy RESHO to FAC1 mantissa + + lda RESHO+4 + sta FACOV + lda RESHO+3 + sta FAC1_mantissa+3 + lda RESHO+2 + sta FAC1_mantissa+2 + lda RESHO+1 + sta FAC1_mantissa+1 + lda RESHO+0 + sta FAC1_mantissa+0 + + // XXX correction is probably needed + + jmp normal_FAC1 + + + + +mul_by_A: // XXX we should probably move this subroutine to a separate file + + sta INDEX+3 + + // Multiply FAC2_mantissa+3 + + lda FAC2_mantissa+3 + jsr mul_8x8 + + adc RESHO+4 + sta RESHO+4 + txa + adc RESHO+3 + sta RESHO+3 + bcc !+ + inc RESHO+2 + bcc !+ + inc RESHO+1 + bcc !+ + inc RESHO+0 +!: + // Multiply FAC2_mantissa+2 + + lda FAC2_mantissa+2 + jsr mul_8x8 + + adc RESHO+3 + sta RESHO+3 + txa + adc RESHO+2 + sta RESHO+2 + bcc !+ + inc RESHO+1 + bcc !+ + inc RESHO+0 +!: + // Multiply FAC2_mantissa+1 + + lda FAC2_mantissa+1 + jsr mul_8x8 + + adc RESHO+2 + sta RESHO+2 + txa + adc RESHO+1 + sta RESHO+1 + bcc !+ + inc RESHO+0 +!: + // Multiply FAC2_mantissa+0 + + lda FAC2_mantissa+0 + jsr mul_8x8 + adc RESHO+1 + sta RESHO+1 + txa + adc RESHO+0 + sta RESHO+0 rts -mul_8x8: // XXX we should probably move this subroutine to separate file + +mul_shift_RESHO: // XXX we should probably move this subroutine to a separate file + + // Shift RESHO by one byte + + lda RESHO+3 + sta RESHO+4 + lda RESHO+2 + sta RESHO+3 + lda RESHO+1 + sta RESHO+2 + lda RESHO+0 + sta RESHO+1 + lda #$00 + sta RESHO+0 + + rts + + +mul_8x8: // XXX we should probably move this subroutine to a separate file + + sta INDEX+2 // Routine based on code by djmips, taken from: // - https://codebase64.org/doku.php?id=base:8bit_multiplication_16bit_product_fast_no_tables // - // input: mul1, mul2 - // optput: .A (high byte), mul1 (low byte) - -.label mul1 = INDEX+2 -.label mul2 = INDEX+3 + // input: INDEX+2, INDEX+3 + // output: .X (high byte), .A and INDEX+2 (low byte), carry always clear lda #$00 - dec mul2 // decrement because we will be adding with carry set for speed (an extra one) - ror mul1 + dec INDEX+3 // decrement because we will be adding with carry set for speed (an extra one) + ror INDEX+2 bcc !+ - adc mul2 + adc INDEX+3 !: ror - ror mul1 + ror INDEX+2 bcc !+ - adc mul2 + adc INDEX+3 !: ror - ror mul1 + ror INDEX+2 bcc !+ - adc mul2 + adc INDEX+3 !: ror - ror mul1 + ror INDEX+2 bcc !+ - adc mul2 + adc INDEX+3 !: ror - ror mul1 + ror INDEX+2 bcc !+ - adc mul2 + adc INDEX+3 !: ror - ror mul1 + ror INDEX+2 bcc !+ - adc mul2 + adc INDEX+3 !: ror - ror mul1 + ror INDEX+2 bcc !+ - adc mul2 + adc INDEX+3 !: ror - ror mul1 + ror INDEX+2 bcc !+ - adc mul2 + adc INDEX+3 !: ror - ror mul1 - inc mul2 + ror INDEX+2 + inc INDEX+3 + + tax + lda INDEX+2 + clc rts From 22fa667cc4bb05c693904166e46a744571cc04e7 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 24 Feb 2020 22:37:41 +0100 Subject: [PATCH 04/57] smalll size optimization --- c64/basic/math/normal_FAC1.s | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/c64/basic/math/normal_FAC1.s b/c64/basic/math/normal_FAC1.s index 5dc96fa5..5c0cc405 100644 --- a/c64/basic/math/normal_FAC1.s +++ b/c64/basic/math/normal_FAC1.s @@ -44,8 +44,7 @@ normal_FAC1_by_bit: // Multiply the mantissa by 2 - clc - rol FACOV + asl FACOV rol FAC1_mantissa+3 rol FAC1_mantissa+2 rol FAC1_mantissa+1 From 1183aab005cf4ffb29856318c3f214e746bbf899 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 26 Feb 2020 18:26:36 +0100 Subject: [PATCH 05/57] some work towards floating point division --- CREDITS.md | 1 + STATUS.md | 2 +- c64/basic/,stubs_math/bb12.div_FAC2_FAC1.s | 24 ----- c64/basic/math/bb12.div_FAC2_FAC1.s | 108 +++++++++++++++++++ c64/basic/{,stubs_math => math}/bb12.interop | 0 5 files changed, 110 insertions(+), 25 deletions(-) delete mode 100644 c64/basic/,stubs_math/bb12.div_FAC2_FAC1.s create mode 100644 c64/basic/math/bb12.div_FAC2_FAC1.s rename c64/basic/{,stubs_math => math}/bb12.interop (100%) diff --git a/CREDITS.md b/CREDITS.md index a1ebe654..c20920a0 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -7,6 +7,7 @@ * Graham - for his PAL/NTSC detection routine * enthusi/Onslaught - for his example Turbo Tape 64 compatible loader * djmips - for fast 8x8 multiplication routine +* Verz - for integer division routine ## for documentation diff --git a/STATUS.md b/STATUS.md index 5a4fe399..1ef99cd7 100644 --- a/STATUS.md +++ b/STATUS.md @@ -205,7 +205,7 @@ Floating point mathematical routines - not official, but well known and broadly | `$BAE2` | `mul10_FAC1` | NOT DONE | | | `$BAFE` | `div10_FAC1_p` | NOT DONE | | | `$BB0F` | `div_MEM_FAC1` | PARTIAL | needs `div_FAC2_FAC1` | -| `$BB12` | `div_FAC2_FAC1` | NOT DONE | | +| `$BB12` | `div_FAC2_FAC1` | NOT DONE | some work already started | | `$BBA2` | `mov_MEM_FAC1` | DONE | | | `$BBA6` | `get_FAC2_via_INDEX` | NOT DONE | | | `$BBC7` | `mov_r_FAC1_TMP2` | PARTIAL | not fully tested yet | diff --git a/c64/basic/,stubs_math/bb12.div_FAC2_FAC1.s b/c64/basic/,stubs_math/bb12.div_FAC2_FAC1.s deleted file mode 100644 index 03f5b8db..00000000 --- a/c64/basic/,stubs_math/bb12.div_FAC2_FAC1.s +++ /dev/null @@ -1,24 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# X16 BASIC_0 #TAKE-OFFSET 2000 -// #LAYOUT# * BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - -// -// Math package - divide FAC2 by FAC1, ignores sign -// -// Input: -// - .A - must load FAC1 exponent ($61) beforehand to set the zero flag -// -// Output: -// - leaves the quotient FAC1 and the remainder in FAC2 -// -// See also: -// - [CM64] Computes Mapping the Commodore 64 - page 114 -// - https://www.c64-wiki.com/wiki/Floating_point_arithmetic -// - https://codebase64.org/doku.php?id=base:kernal_floating_point_mathematics -// - -// XXX provide implementation - -div_FAC2_FAC1: - STUB_IMPLEMENTATION() diff --git a/c64/basic/math/bb12.div_FAC2_FAC1.s b/c64/basic/math/bb12.div_FAC2_FAC1.s new file mode 100644 index 00000000..51ad5f31 --- /dev/null +++ b/c64/basic/math/bb12.div_FAC2_FAC1.s @@ -0,0 +1,108 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE-OFFSET 2000 +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Math package - divide FAC2 (dividend) by FAC1 (divisor), ignores sign +// +// Input: +// - .A - must load FAC1 exponent ($61) beforehand to set the zero flag +// +// Output: +// - leaves the quotient FAC1 and the remainder in FAC2 +// +// See also: +// - [CM64] Computes Mapping the Commodore 64 - page 114 +// - https://www.c64-wiki.com/wiki/Floating_point_arithmetic +// - https://codebase64.org/doku.php?id=base:kernal_floating_point_mathematics +// + +// XXX provide implementation + +div_FAC2_FAC1: + STUB_IMPLEMENTATION() + + + + + + +// XXX move this to a separate file + +// Unsigned integer 32-bit mantissa division, based on code by Verz +// divident: FAC2_mantissa, divisor: FAC1_mantissa, result: FAC2_mantissa, remainder: RESHO +// temporary storage: INDEX+1, INDEX+2, INDEX+3 +// +// https://codebase64.org/doku.php?id=base:24bit_division_24-bit_result + +// XXX test this, optimize (for temporary storage use .Y, .Z and RESHO+4) + +div_mantissas: + + // Preset remainder to 0 + // XXX should be common with multiplication + + lda #$00 + sta RESHO+0 + sta RESHO+1 + sta RESHO+2 + sta RESHO+3 + + ldx #$32 // repeat for each bit + + // FALLTROUGH + +div_mantissas_loop: + + // Multiply divident by 2, msb -> Carry + + asl FAC2_mantissa+3 + rol FAC2_mantissa+2 + rol FAC2_mantissa+1 + rol FAC2_mantissa+0 + + // Multiply remainder by 2, lsb <- Carry + + rol RESHO+3 + rol RESHO+2 + rol RESHO+1 + rol RESHO+0 + + // Subtract divisor to see if it fits in + + lda RESHO+3 + sec + sbc FAC1_mantissa+2 + sta INDEX+3 + + lda RESHO+2 + sbc FAC1_mantissa+2 + sta INDEX+2 + + lda RESHO+1 + sbc FAC1_mantissa+1 + sta INDEX+1 + + lda RESHO+0 + sbc FAC1_mantissa+0 + bcc div_mantissas_skip // if Carry is not set then divisor did not fit in yet + + sta RESHO+0 // else save substraction result as new remainder, + lda INDEX+1 + sta RESHO+1 + lda INDEX+2 + sta RESHO+2 + lda INDEX+3 + sta RESHO+3 + + inc FAC2_mantissa+3 // and INCrement result cause divisor fit in 1 times + + // FALLTROUGH + +div_mantissas_skip: + + dex + bne div_mantissas_loop + + rts diff --git a/c64/basic/,stubs_math/bb12.interop b/c64/basic/math/bb12.interop similarity index 100% rename from c64/basic/,stubs_math/bb12.interop rename to c64/basic/math/bb12.interop From 11bf202c813bd35496cdbf2252d1542c3a162b1d Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 26 Feb 2020 20:12:05 +0100 Subject: [PATCH 06/57] more work on external BASIC ROM support --- c64/basic/,imports.s | 5 +++ .../board_m65/4000.mega65_vectable_basic_1.s | 35 +++++++++++++++++++ c64/basic/board_m65/mega65_map_helpers.s | 28 +++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 c64/basic/board_m65/4000.mega65_vectable_basic_1.s create mode 100644 c64/basic/board_m65/mega65_map_helpers.s diff --git a/c64/basic/,imports.s b/c64/basic/,imports.s index ebcf56c9..b45fc2ab 100644 --- a/c64/basic/,imports.s +++ b/c64/basic/,imports.s @@ -18,6 +18,11 @@ } +#if ROM_LAYOUT_M65 +.label map_end = KERNAL().map_end +.label map_NORMAL = KERNAL().map_NORMAL +#endif + #if CONFIG_PANIC_SCREEN .label panic = KERNAL().panic #endif diff --git a/c64/basic/board_m65/4000.mega65_vectable_basic_1.s b/c64/basic/board_m65/4000.mega65_vectable_basic_1.s new file mode 100644 index 00000000..18b1e0cc --- /dev/null +++ b/c64/basic/board_m65/4000.mega65_vectable_basic_1.s @@ -0,0 +1,35 @@ +// #LAYOUT# M65 BASIC_0 #TAKE-FLOAT +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Definitions for communication with Mega65 segment BASIC_1 from BASIC_0 +// + + +#if SEGMENT_BASIC_0 + + // Label definitions + + .label VB1__TEST = $4000 + 2 * 0 + +TEST: + + jsr map_BASIC_1 + jmp (VB1__TEST) + +#else + + // Vector table (OpenROMs private!) + + .word TEST + + +TEST: + + inc 53280 + inc 53281 + + jmp map_NORMAL + +#endif diff --git a/c64/basic/board_m65/mega65_map_helpers.s b/c64/basic/board_m65/mega65_map_helpers.s new file mode 100644 index 00000000..73e22cdb --- /dev/null +++ b/c64/basic/board_m65/mega65_map_helpers.s @@ -0,0 +1,28 @@ +// #LAYOUT# M65 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// ROM mapping routines for Mega65 +// + +// Available memory maps: +// - NORMAL - nothing mapped in (taken from Kernal) +// - BASIC_1 - for calling KERNAL_1 segment code + + +map_BASIC_1: + + php + pha + phx + phy + phz + + lda #$00 + tay + taz + + lda #$20 + ldx #$42 // 0x4000 <- map 8KB from 0x22000 + + jmp map_end From 540c1a6d7d47909e0f6c9ea87d65704165fa2f43 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 26 Feb 2020 20:55:01 +0100 Subject: [PATCH 07/57] moved Mega65 startup banner to extra ROM segment --- c64/aliases/,aliases_rom_kernal.s | 3 ++ c64/basic/,imports.s | 5 ++ c64/basic/ab1e.strout.s | 1 + .../board_m65/4000.mega65_vectable_basic_1.s | 17 +----- c64/basic/board_m65/mega65_dummy.s | 7 --- c64/basic/board_m65/mega65_imports.s | 23 ++++++++ c64/basic/board_m65/mega65_proxies.s | 54 +++++++++++++++++++ c64/basic/init/e422.initmsg.jmp.s | 11 ++++ c64/basic/init/initmsg_bytes_free.s | 3 +- c64/basic/init/initmsg_real.s | 11 +++- c64/basic/init/startup_banner.s | 3 +- .../board_m65/mega65_tape_normal_byte_store.s | 2 +- 12 files changed, 114 insertions(+), 26 deletions(-) delete mode 100644 c64/basic/board_m65/mega65_dummy.s create mode 100644 c64/basic/board_m65/mega65_imports.s create mode 100644 c64/basic/board_m65/mega65_proxies.s diff --git a/c64/aliases/,aliases_rom_kernal.s b/c64/aliases/,aliases_rom_kernal.s index 35e89d07..2f568ce2 100644 --- a/c64/aliases/,aliases_rom_kernal.s +++ b/c64/aliases/,aliases_rom_kernal.s @@ -1,5 +1,8 @@ +// #LAYOUT# * BASIC_1 #IGNORE +// #LAYOUT# * * #TAKE // Kernal jump table + .label JCINT = $FF81 .label JIOINIT = $FF84 .label JRAMTAS = $FF87 diff --git a/c64/basic/,imports.s b/c64/basic/,imports.s index b45fc2ab..8c7b7643 100644 --- a/c64/basic/,imports.s +++ b/c64/basic/,imports.s @@ -1,3 +1,8 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 BASIC_0 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE-OFFSET 2000 +// #LAYOUT# * * #IGNORE + // Routines imported from Kernal - our private API diff --git a/c64/basic/ab1e.strout.s b/c64/basic/ab1e.strout.s index d067e9e1..0c2e99b7 100644 --- a/c64/basic/ab1e.strout.s +++ b/c64/basic/ab1e.strout.s @@ -1,6 +1,7 @@ // #LAYOUT# STD * #TAKE // #LAYOUT# X16 BASIC_0 #TAKE-OFFSET 2000 // #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE-FLOAT // #LAYOUT# * * #IGNORE // Print string at $YYAA diff --git a/c64/basic/board_m65/4000.mega65_vectable_basic_1.s b/c64/basic/board_m65/4000.mega65_vectable_basic_1.s index 18b1e0cc..6914ef45 100644 --- a/c64/basic/board_m65/4000.mega65_vectable_basic_1.s +++ b/c64/basic/board_m65/4000.mega65_vectable_basic_1.s @@ -11,25 +11,12 @@ // Label definitions - .label VB1__TEST = $4000 + 2 * 0 - -TEST: - - jsr map_BASIC_1 - jmp (VB1__TEST) + .label VB1__INITMSG = $4000 + 2 * 0 #else // Vector table (OpenROMs private!) - .word TEST - - -TEST: - - inc 53280 - inc 53281 - - jmp map_NORMAL + .word INITMSG #endif diff --git a/c64/basic/board_m65/mega65_dummy.s b/c64/basic/board_m65/mega65_dummy.s deleted file mode 100644 index 338a1c16..00000000 --- a/c64/basic/board_m65/mega65_dummy.s +++ /dev/null @@ -1,7 +0,0 @@ -// #LAYOUT# M65 BASIC_1 #TAKE -// #LAYOUT# * * #IGNORE - - -// Dummy, just to have anything in segment 1 - - brk diff --git a/c64/basic/board_m65/mega65_imports.s b/c64/basic/board_m65/mega65_imports.s new file mode 100644 index 00000000..4a82834f --- /dev/null +++ b/c64/basic/board_m65/mega65_imports.s @@ -0,0 +1,23 @@ +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Definitions for calling Mega65 segments BASIC_0 and KERNAL_0 routines from BASIC_1 +// + +#import "BASIC_0_combined.sym" + + +.label JCHROUT = BASIC_0.proxy_B1_JCHROUT +.label plot_set = KERNAL_0.plot_set + +.label basic_do_new = BASIC_0.proxy_B1_basic_do_new +.label rom_revision_basic_string = BASIC_0.rom_revision_basic_string +.label print_integer = BASIC_0.proxy_B1_print_integer +.label print_packed_message = BASIC_0.proxy_B1_print_packed_message +#if CONFIG_SHOW_PAL_NTSC +.label print_pal_ntsc = BASIC_0.proxy_B1_print_pal_ntsc +#endif +#if CONFIG_SHOW_FEATURES +.label print_features = BASIC_0.proxy_B1_print_features +#endif diff --git a/c64/basic/board_m65/mega65_proxies.s b/c64/basic/board_m65/mega65_proxies.s new file mode 100644 index 00000000..f78b47b9 --- /dev/null +++ b/c64/basic/board_m65/mega65_proxies.s @@ -0,0 +1,54 @@ +// #LAYOUT# M65 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Proxies for calling Mega65 segment BASIC_0 and KERNAL_0 routines from BASIC_1 +// + + +proxy_B1_JCHROUT: + + jsr map_NORMAL + jsr JCHROUT + jmp map_BASIC_1 + + +proxy_B1_basic_do_new: + + jsr map_NORMAL + jsr basic_do_new + jmp map_BASIC_1 + + +proxy_B1_print_integer: + + jsr map_NORMAL + jsr print_integer + jmp map_BASIC_1 + + +proxy_B1_print_packed_message: + + jsr map_NORMAL + jsr print_packed_message + jmp map_BASIC_1 + +#if CONFIG_SHOW_PAL_NTSC + +proxy_B1_print_pal_ntsc: + + jsr map_NORMAL + jsr print_pal_ntsc + jmp map_BASIC_1 + +#endif + +#if CONFIG_SHOW_FEATURES + +proxy_B1_print_features: + + jsr map_NORMAL + jsr print_features + jmp map_BASIC_1 + +#endif diff --git a/c64/basic/init/e422.initmsg.jmp.s b/c64/basic/init/e422.initmsg.jmp.s index 9d69690f..591ed9ac 100644 --- a/c64/basic/init/e422.initmsg.jmp.s +++ b/c64/basic/init/e422.initmsg.jmp.s @@ -11,4 +11,15 @@ // INITMSG: + +#if ROM_LAYOUT_M65 + + jsr map_BASIC_1 + jsr_ind VB1__INITMSG + jmp map_NORMAL + +#else + jmp initmsg_real + +#endif diff --git a/c64/basic/init/initmsg_bytes_free.s b/c64/basic/init/initmsg_bytes_free.s index ee2c4fa5..0093c12a 100644 --- a/c64/basic/init/initmsg_bytes_free.s +++ b/c64/basic/init/initmsg_bytes_free.s @@ -1,5 +1,6 @@ // #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE // #LAYOUT# * * #IGNORE // diff --git a/c64/basic/init/initmsg_real.s b/c64/basic/init/initmsg_real.s index 15ca951c..10aedb76 100644 --- a/c64/basic/init/initmsg_real.s +++ b/c64/basic/init/initmsg_real.s @@ -1,13 +1,22 @@ // #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE // #LAYOUT# * * #IGNORE // Routine is too long to fit in the original location +#if ROM_LAYOUT_M65 + +INITMSG: + +#else + initmsg_real: +#endif + // Clear the screen first, some cartridges (like IEEE-488) leeave a mess on the screen lda #147 jsr JCHROUT diff --git a/c64/basic/init/startup_banner.s b/c64/basic/init/startup_banner.s index faedc2c3..bf828819 100644 --- a/c64/basic/init/startup_banner.s +++ b/c64/basic/init/startup_banner.s @@ -1,5 +1,6 @@ // #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE // #LAYOUT# * * #IGNORE // diff --git a/c64/kernal/board_m65/mega65_tape_normal_byte_store.s b/c64/kernal/board_m65/mega65_tape_normal_byte_store.s index 4c8cc13f..ae641f34 100644 --- a/c64/kernal/board_m65/mega65_tape_normal_byte_store.s +++ b/c64/kernal/board_m65/mega65_tape_normal_byte_store.s @@ -2,7 +2,7 @@ // #LAYOUT# * * #IGNORE // -// Tape (normal) helper routine - byte storage when ban changing is needed +// Tape (normal) helper routine - byte storage when banking change is needed // From 1665098ac945be92bd7a74eab1dcd5244c956af9 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 26 Feb 2020 21:29:50 +0100 Subject: [PATCH 08/57] prevent packed strings from appearing in all BASIC segments --- Makefile | 1 + c64/basic/packed_strings/packed_chars.s | 7 +++++++ c64/basic/packed_strings/packed_keywords.s | 7 +++++++ c64/basic/packed_strings/packed_tokens.s | 7 +++++++ c64/basic/packed_strings/packed_words.s | 7 +++++++ c64/basic/ready_message.s | 3 +-- tools/compress_text.c | 17 +++++++++++------ 7 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 c64/basic/packed_strings/packed_chars.s create mode 100644 c64/basic/packed_strings/packed_keywords.s create mode 100644 c64/basic/packed_strings/packed_tokens.s create mode 100644 c64/basic/packed_strings/packed_words.s diff --git a/Makefile b/Makefile index eecfb259..75b7270a 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,7 @@ SRCDIR_BASIC = $(SRCDIR_COMMON) \ c64/basic/init \ c64/basic/math \ c64/basic/math_consts \ + c64/basic/packed_strings \ c64/basic/rom_revision SRCDIR_KERNAL = $(SRCDIR_COMMON) \ diff --git a/c64/basic/packed_strings/packed_chars.s b/c64/basic/packed_strings/packed_chars.s new file mode 100644 index 00000000..16ed8b6e --- /dev/null +++ b/c64/basic/packed_strings/packed_chars.s @@ -0,0 +1,7 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +packed_message_chars: + + put_packed_chars() diff --git a/c64/basic/packed_strings/packed_keywords.s b/c64/basic/packed_strings/packed_keywords.s new file mode 100644 index 00000000..f62bd5a5 --- /dev/null +++ b/c64/basic/packed_strings/packed_keywords.s @@ -0,0 +1,7 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +packed_keywords: + + put_packed_keywords() diff --git a/c64/basic/packed_strings/packed_tokens.s b/c64/basic/packed_strings/packed_tokens.s new file mode 100644 index 00000000..574907ca --- /dev/null +++ b/c64/basic/packed_strings/packed_tokens.s @@ -0,0 +1,7 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +packed_message_tokens: + + put_packed_tokens() diff --git a/c64/basic/packed_strings/packed_words.s b/c64/basic/packed_strings/packed_words.s new file mode 100644 index 00000000..49fcf0b9 --- /dev/null +++ b/c64/basic/packed_strings/packed_words.s @@ -0,0 +1,7 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +packed_message_words: + + put_packed_words() diff --git a/c64/basic/ready_message.s b/c64/basic/ready_message.s index 791cb7eb..9d528c38 100644 --- a/c64/basic/ready_message.s +++ b/c64/basic/ready_message.s @@ -4,7 +4,6 @@ ready_message: - // See src/make_error_tables.c for packed message handling - // information. + ldx #29 jmp print_packed_message diff --git a/tools/compress_text.c b/tools/compress_text.c index fcfc7dca..6f7b0daf 100644 --- a/tools/compress_text.c +++ b/tools/compress_text.c @@ -436,15 +436,16 @@ int main(void) exit(-1); } - printf("packed_message_chars:\n"); + printf(".macro put_packed_chars()\n{\n"); for(int i=0;i=8) { @@ -455,8 +456,9 @@ int main(void) } else printf("\t.byte $%02x\n",message_tokens[i]); } - - printf("packed_message_words:\n"); + printf("}\n"); + + printf(".macro put_packed_words()\n{\n"); for(int i=0;i=8) { @@ -467,8 +469,9 @@ int main(void) } else printf("\t.byte $%02x\n",packed_words[i]); } + printf("}\n"); - printf("packed_keywords:\n"); + printf(".macro put_packed_keywords()\n{\n"); for(int i=0;i=8) { @@ -479,7 +482,9 @@ int main(void) } else printf("\t.byte $%02x\n",packed_keywords[i]); } - printf("\t.label packed_keyword_table_len = $%X\n",packedkey_len); + printf("}\n"); + + printf(".label packed_keyword_table_len = $%X\n",packedkey_len); fprintf(stderr,"Error list takes %d bytes raw.\n",raw_size); fprintf(stderr,"%d token bytes used to encode all messages.\n",token_count); From ebf8bf4eb773c6cc8e800ca6aa81e705a6de92b5 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 26 Feb 2020 21:59:03 +0100 Subject: [PATCH 09/57] moved most of the LIST command to Mega65 extra ROM --- Makefile | 3 +- .../{packed_strings => assets}/packed_chars.s | 0 .../packed_keywords.s | 0 .../packed_tokens.s | 0 .../{packed_strings => assets}/packed_words.s | 0 .../board_m65/4000.mega65_vectable_basic_1.s | 2 + c64/basic/board_m65/mega65_imports.s | 6 +- c64/basic/board_m65/mega65_proxies.s | 26 ++++ c64/basic/commands/cmd_list.s | 114 +--------------- c64/basic/print/list_single_line.s | 127 ++++++++++++++++++ c64/basic/{ => print}/print_integer.s | 0 c64/basic/{ => print}/print_packed_message.s | 0 12 files changed, 165 insertions(+), 113 deletions(-) rename c64/basic/{packed_strings => assets}/packed_chars.s (100%) rename c64/basic/{packed_strings => assets}/packed_keywords.s (100%) rename c64/basic/{packed_strings => assets}/packed_tokens.s (100%) rename c64/basic/{packed_strings => assets}/packed_words.s (100%) create mode 100644 c64/basic/print/list_single_line.s rename c64/basic/{ => print}/print_integer.s (100%) rename c64/basic/{ => print}/print_packed_message.s (100%) diff --git a/Makefile b/Makefile index 75b7270a..548e3a58 100644 --- a/Makefile +++ b/Makefile @@ -12,13 +12,14 @@ SRCDIR_BASIC = $(SRCDIR_COMMON) \ c64/basic \ c64/basic/,stubs \ c64/basic/,stubs_math \ + c64/basic/assets \ c64/basic/board_m65 \ c64/basic/board_x16 \ c64/basic/commands \ c64/basic/init \ c64/basic/math \ c64/basic/math_consts \ - c64/basic/packed_strings \ + c64/basic/print \ c64/basic/rom_revision SRCDIR_KERNAL = $(SRCDIR_COMMON) \ diff --git a/c64/basic/packed_strings/packed_chars.s b/c64/basic/assets/packed_chars.s similarity index 100% rename from c64/basic/packed_strings/packed_chars.s rename to c64/basic/assets/packed_chars.s diff --git a/c64/basic/packed_strings/packed_keywords.s b/c64/basic/assets/packed_keywords.s similarity index 100% rename from c64/basic/packed_strings/packed_keywords.s rename to c64/basic/assets/packed_keywords.s diff --git a/c64/basic/packed_strings/packed_tokens.s b/c64/basic/assets/packed_tokens.s similarity index 100% rename from c64/basic/packed_strings/packed_tokens.s rename to c64/basic/assets/packed_tokens.s diff --git a/c64/basic/packed_strings/packed_words.s b/c64/basic/assets/packed_words.s similarity index 100% rename from c64/basic/packed_strings/packed_words.s rename to c64/basic/assets/packed_words.s diff --git a/c64/basic/board_m65/4000.mega65_vectable_basic_1.s b/c64/basic/board_m65/4000.mega65_vectable_basic_1.s index 6914ef45..52769961 100644 --- a/c64/basic/board_m65/4000.mega65_vectable_basic_1.s +++ b/c64/basic/board_m65/4000.mega65_vectable_basic_1.s @@ -12,11 +12,13 @@ // Label definitions .label VB1__INITMSG = $4000 + 2 * 0 + .label VB1__list_single_line = $4000 + 2 * 1 #else // Vector table (OpenROMs private!) .word INITMSG + .word list_single_line #endif diff --git a/c64/basic/board_m65/mega65_imports.s b/c64/basic/board_m65/mega65_imports.s index 4a82834f..c89a7161 100644 --- a/c64/basic/board_m65/mega65_imports.s +++ b/c64/basic/board_m65/mega65_imports.s @@ -8,13 +8,17 @@ #import "BASIC_0_combined.sym" +.label peek_under_roms = BASIC_0.proxy_B1_peek_under_roms .label JCHROUT = BASIC_0.proxy_B1_JCHROUT .label plot_set = KERNAL_0.plot_set - .label basic_do_new = BASIC_0.proxy_B1_basic_do_new +.label packed_keywords = BASIC_0.packed_keywords +.label packed_word_search = BASIC_0.packed_word_search .label rom_revision_basic_string = BASIC_0.rom_revision_basic_string .label print_integer = BASIC_0.proxy_B1_print_integer .label print_packed_message = BASIC_0.proxy_B1_print_packed_message +.label print_return = BASIC_0.proxy_B1_print_return +.label print_space = BASIC_0.proxy_B1_print_space #if CONFIG_SHOW_PAL_NTSC .label print_pal_ntsc = BASIC_0.proxy_B1_print_pal_ntsc #endif diff --git a/c64/basic/board_m65/mega65_proxies.s b/c64/basic/board_m65/mega65_proxies.s index f78b47b9..14d898cd 100644 --- a/c64/basic/board_m65/mega65_proxies.s +++ b/c64/basic/board_m65/mega65_proxies.s @@ -6,6 +6,17 @@ // +proxy_B1_peek_under_roms: + + jsr map_NORMAL +#if CONFIG_MEMORY_MODEL_60K + jsr peek_under_roms +#else // CONFIG_MEMORY_MODEL_38K + lda (OLDTXT),y +#endif + jmp map_BASIC_1 + + proxy_B1_JCHROUT: jsr map_NORMAL @@ -33,6 +44,21 @@ proxy_B1_print_packed_message: jsr print_packed_message jmp map_BASIC_1 + +proxy_B1_print_return: + + jsr map_NORMAL + jsr print_return + jmp map_BASIC_1 + + +proxy_B1_print_space: + + jsr map_NORMAL + jsr print_space + jmp map_BASIC_1 + + #if CONFIG_SHOW_PAL_NTSC proxy_B1_print_pal_ntsc: diff --git a/c64/basic/commands/cmd_list.s b/c64/basic/commands/cmd_list.s index 973ebc89..a1fcdb1d 100644 --- a/c64/basic/commands/cmd_list.s +++ b/c64/basic/commands/cmd_list.s @@ -11,6 +11,9 @@ cmd_list: // Set current line pointer to start of memory jsr init_oldtxt + // Always start with empty line, for readability + jsr print_return + list_loop: ldy #1 @@ -39,114 +42,3 @@ list_more_lines: // Now link to the next line jsr basic_find_next_line jmp list_loop - -list_single_line: // entry point needed by DOS wedge - // Print line number - ldy #3 - -#if CONFIG_MEMORY_MODEL_60K - jsr peek_under_roms -#else // CONFIG_MEMORY_MODEL_38K - lda (OLDTXT),y -#endif - - pha - dey - -#if CONFIG_MEMORY_MODEL_60K - jsr peek_under_roms -#else // CONFIG_MEMORY_MODEL_38K - lda (OLDTXT),y -#endif - - tax - pla - jsr print_integer - jsr print_space - - // Iterate through printing out the line - // contents - lda #0 - sta QTSW - - ldy #4 -list_print_loop: - -#if CONFIG_MEMORY_MODEL_60K - ldx #packed_keywords - sta FRESPC+1 - - // Subtract $80 from token to get offset in word - // list - txa - and #$7f - tax - - // Now ask for it to be printed - ldy #$ff - jsr packed_word_search - - ply_trash_a - pla - - cmp #$8f - bne list_not_rem - // REM command locks quote flag on until the end of the line, allowing - // funny characters in REM statements without problem. - sta QTSW // Any value other than $00 or $FF will lock quote mode on, so the token value of REM is fine here - // FALL THROUGH -list_not_rem: - - iny - bne list_print_loop // branch always - -list_is_pi: - lda #$7E - - // FALLTROUGH - -list_is_literal: - jsr JCHROUT - iny - bne list_print_loop - -list_end_of_line: - // Print end of line - jmp print_return diff --git a/c64/basic/print/list_single_line.s b/c64/basic/print/list_single_line.s new file mode 100644 index 00000000..e3936d88 --- /dev/null +++ b/c64/basic/print/list_single_line.s @@ -0,0 +1,127 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 * #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +list_single_line: + +#if (ROM_LAYOUT_M65 && SEGMENT_BASIC_0) + + jsr map_BASIC_1 + jsr_ind VB1__list_single_line + jmp map_NORMAL + +#else + + // Print line number + ldy #3 + +#if ROM_LAYOUT_M65 || CONFIG_MEMORY_MODEL_60K + jsr peek_under_roms +#else + lda (OLDTXT),y +#endif + + pha + dey + +#if ROM_LAYOUT_M65 || CONFIG_MEMORY_MODEL_60K + jsr peek_under_roms +#else + lda (OLDTXT),y +#endif + + tax + pla + jsr print_integer + jsr print_space + + // Iterate through printing out the line + // contents + lda #0 + sta QTSW + + ldy #4 +list_print_loop: + +#if ROM_LAYOUT_M65 || CONFIG_MEMORY_MODEL_60K + ldx #packed_keywords + sta FRESPC+1 + + // Subtract $80 from token to get offset in word + // list + txa + and #$7f + tax + + // Now ask for it to be printed + ldy #$ff + jsr packed_word_search + + ply_trash_a + pla + + cmp #$8f + bne list_not_rem + // REM command locks quote flag on until the end of the line, allowing + // funny characters in REM statements without problem. + sta QTSW // Any value other than $00 or $FF will lock quote mode on, so the token value of REM is fine here + // FALL THROUGH +list_not_rem: + + iny + bne list_print_loop // branch always + +list_is_pi: + lda #$7E + + // FALLTROUGH + +list_is_literal: + jsr JCHROUT + iny + bne list_print_loop + +list_end_of_line: + // Print end of line + jmp print_return + + +#endif // ROM layout diff --git a/c64/basic/print_integer.s b/c64/basic/print/print_integer.s similarity index 100% rename from c64/basic/print_integer.s rename to c64/basic/print/print_integer.s diff --git a/c64/basic/print_packed_message.s b/c64/basic/print/print_packed_message.s similarity index 100% rename from c64/basic/print_packed_message.s rename to c64/basic/print/print_packed_message.s From d1bc38694dc2a5a0d23ae777bb79b2462b541a98 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 26 Feb 2020 22:20:53 +0100 Subject: [PATCH 10/57] packed string support moved to Mega65 extra ROM segment --- c64/basic/assets/packed_chars.s | 3 ++- c64/basic/assets/packed_keywords.s | 3 ++- c64/basic/assets/packed_tokens.s | 3 ++- c64/basic/assets/packed_words.s | 3 ++- c64/basic/basic_do_error.s | 6 ++++++ c64/basic/board_m65/4000.mega65_vectable_basic_1.s | 6 +++++- c64/basic/board_m65/mega65_imports.s | 4 +--- c64/basic/board_m65/mega65_proxies.s | 7 ------- c64/basic/pack_word.s | 3 ++- c64/basic/print/print_packed_message.s | 14 +++++++++++++- c64/basic/tokenise_line.s | 13 ++++++++++++- 11 files changed, 47 insertions(+), 18 deletions(-) diff --git a/c64/basic/assets/packed_chars.s b/c64/basic/assets/packed_chars.s index 16ed8b6e..985ca369 100644 --- a/c64/basic/assets/packed_chars.s +++ b/c64/basic/assets/packed_chars.s @@ -1,5 +1,6 @@ // #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE // #LAYOUT# * * #IGNORE packed_message_chars: diff --git a/c64/basic/assets/packed_keywords.s b/c64/basic/assets/packed_keywords.s index f62bd5a5..82229cde 100644 --- a/c64/basic/assets/packed_keywords.s +++ b/c64/basic/assets/packed_keywords.s @@ -1,5 +1,6 @@ // #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE // #LAYOUT# * * #IGNORE packed_keywords: diff --git a/c64/basic/assets/packed_tokens.s b/c64/basic/assets/packed_tokens.s index 574907ca..0a2709a2 100644 --- a/c64/basic/assets/packed_tokens.s +++ b/c64/basic/assets/packed_tokens.s @@ -1,5 +1,6 @@ // #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE // #LAYOUT# * * #IGNORE packed_message_tokens: diff --git a/c64/basic/assets/packed_words.s b/c64/basic/assets/packed_words.s index 49fcf0b9..515892e6 100644 --- a/c64/basic/assets/packed_words.s +++ b/c64/basic/assets/packed_words.s @@ -1,5 +1,6 @@ // #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE // #LAYOUT# * * #IGNORE packed_message_words: diff --git a/c64/basic/basic_do_error.s b/c64/basic/basic_do_error.s index 084a8bea..f4f21fd4 100644 --- a/c64/basic/basic_do_error.s +++ b/c64/basic/basic_do_error.s @@ -5,9 +5,15 @@ // Computes Mapping the 64 p93 basic_do_error: + // Save error number phx_trash_a +#if ROM_LAYOUT_M65 + // Restore normal memory map + jsr map_NORMAL +#endif + // Print ? at start jsr print_return lda #$3F diff --git a/c64/basic/board_m65/4000.mega65_vectable_basic_1.s b/c64/basic/board_m65/4000.mega65_vectable_basic_1.s index 52769961..46c49a83 100644 --- a/c64/basic/board_m65/4000.mega65_vectable_basic_1.s +++ b/c64/basic/board_m65/4000.mega65_vectable_basic_1.s @@ -12,13 +12,17 @@ // Label definitions .label VB1__INITMSG = $4000 + 2 * 0 - .label VB1__list_single_line = $4000 + 2 * 1 + .label VB1__tokenise_line = $4000 + 2 * 1 + .label VB1__list_single_line = $4000 + 2 * 2 + .label VB1__print_packed_message = $4000 + 2 * 3 #else // Vector table (OpenROMs private!) .word INITMSG + .word tokenise_line .word list_single_line + .word print_packed_message #endif diff --git a/c64/basic/board_m65/mega65_imports.s b/c64/basic/board_m65/mega65_imports.s index c89a7161..e611cab3 100644 --- a/c64/basic/board_m65/mega65_imports.s +++ b/c64/basic/board_m65/mega65_imports.s @@ -12,11 +12,8 @@ .label JCHROUT = BASIC_0.proxy_B1_JCHROUT .label plot_set = KERNAL_0.plot_set .label basic_do_new = BASIC_0.proxy_B1_basic_do_new -.label packed_keywords = BASIC_0.packed_keywords -.label packed_word_search = BASIC_0.packed_word_search .label rom_revision_basic_string = BASIC_0.rom_revision_basic_string .label print_integer = BASIC_0.proxy_B1_print_integer -.label print_packed_message = BASIC_0.proxy_B1_print_packed_message .label print_return = BASIC_0.proxy_B1_print_return .label print_space = BASIC_0.proxy_B1_print_space #if CONFIG_SHOW_PAL_NTSC @@ -25,3 +22,4 @@ #if CONFIG_SHOW_FEATURES .label print_features = BASIC_0.proxy_B1_print_features #endif +.label do_STRING_TOO_LONG_error = BASIC_0.do_STRING_TOO_LONG_error diff --git a/c64/basic/board_m65/mega65_proxies.s b/c64/basic/board_m65/mega65_proxies.s index 14d898cd..f6f2fbf7 100644 --- a/c64/basic/board_m65/mega65_proxies.s +++ b/c64/basic/board_m65/mega65_proxies.s @@ -38,13 +38,6 @@ proxy_B1_print_integer: jmp map_BASIC_1 -proxy_B1_print_packed_message: - - jsr map_NORMAL - jsr print_packed_message - jmp map_BASIC_1 - - proxy_B1_print_return: jsr map_NORMAL diff --git a/c64/basic/pack_word.s b/c64/basic/pack_word.s index 5b8e502e..d975ca38 100644 --- a/c64/basic/pack_word.s +++ b/c64/basic/pack_word.s @@ -1,5 +1,6 @@ // #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE // #LAYOUT# * * #IGNORE // Pack a word using the simple compression scheme. diff --git a/c64/basic/print/print_packed_message.s b/c64/basic/print/print_packed_message.s index 8aba8b25..7a062e6a 100644 --- a/c64/basic/print/print_packed_message.s +++ b/c64/basic/print/print_packed_message.s @@ -1,5 +1,6 @@ // #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# M65 * #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE // #LAYOUT# * * #IGNORE // This routine prints messages that have been packed @@ -17,6 +18,14 @@ print_packed_message: // .X = message number +#if (ROM_LAYOUT_M65 && SEGMENT_BASIC_0) + + jsr map_BASIC_1 + jsr_ind VB1__print_packed_message + jmp map_NORMAL + +#else + lda #$ff ldy #$ff packed_message_search: @@ -230,3 +239,6 @@ is_uncommon_char: phy_trash_a jmp has_nybl + + +#endif // ROM layout diff --git a/c64/basic/tokenise_line.s b/c64/basic/tokenise_line.s index 0c54eed7..0678658b 100644 --- a/c64/basic/tokenise_line.s +++ b/c64/basic/tokenise_line.s @@ -1,5 +1,6 @@ // #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# M65 * #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE // #LAYOUT# * * #IGNORE // Tokenise a line of BASIC @@ -8,6 +9,14 @@ tokenise_line: +#if (ROM_LAYOUT_M65 && SEGMENT_BASIC_0) + + jsr map_BASIC_1 + jsr_ind VB1__tokenise_line + jmp map_NORMAL + +#else + // We need to consider each offset in the string to see if it matches // a token. No BASIC keyword is > 7 bytes, so we need to start with that // length (or remaining length of string) and count our way back down. @@ -270,3 +279,5 @@ done_searching_for_token: sec lda #$00 rts + +#endif // ROM layout From 4a510d78fdd484b24af9927492a86367c187ad0c Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 26 Feb 2020 22:36:08 +0100 Subject: [PATCH 11/57] moved most of the CLR and NEW commands to Mega65 extra ROM segment --- c64/basic/basic_do_new.s | 90 +++++++++++++++++++ .../board_m65/4000.mega65_vectable_basic_1.s | 4 + c64/basic/board_m65/mega65_imports.s | 2 +- c64/basic/board_m65/mega65_proxies.s | 7 -- c64/basic/commands/cmd_clr.s | 12 +++ c64/basic/commands/cmd_new.s | 74 +-------------- 6 files changed, 108 insertions(+), 81 deletions(-) create mode 100644 c64/basic/basic_do_new.s create mode 100644 c64/basic/commands/cmd_clr.s diff --git a/c64/basic/basic_do_new.s b/c64/basic/basic_do_new.s new file mode 100644 index 00000000..c50d10b1 --- /dev/null +++ b/c64/basic/basic_do_new.s @@ -0,0 +1,90 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 * #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +basic_do_new: + +#if (ROM_LAYOUT_M65 && SEGMENT_BASIC_0) + + jsr map_BASIC_1 + jsr_ind VB1__basic_do_new + jmp map_NORMAL + +basic_do_clr: + + jsr map_BASIC_1 + jsr_ind VB1__basic_do_clr + jmp map_NORMAL + +#else + + // Setup pointers to memory storage XXX should depend on text start vector + lda #<$0801 + sta TXTTAB+0 + lda #>$0801 + sta TXTTAB+1 + sta VARTAB+1 + lda #<$0803 + sta VARTAB+0 + + // Zero line pointer + // XXX - We should also zero $0800, i.e., TXTTAB - 1 + ldy #$00 + tya + sta (TXTTAB),y + iny + sta (TXTTAB),y + + + // Get top of memory. + // If a cart is present, then it is $7FFF, + // if not, then it is $F7FF, since we support having + // programs and variables under ROM. + // i.e., we support 56KB RAM for BASIC, keeping some space + // free for some optimisation structures, e.g., FOR/NEXT loop + // records (without them going on the stack), GOSUB stack + // (same story), expression value cache? + + sec // Read, not write value + jsr JMEMTOP + cpx #$80 + beq !+ +#if CONFIG_MEMORY_MODEL_60K + lda #>$F7FF +#else // CONFIG_MEMORY_MODEL_38K + lda #>$A000 +#endif + .byte $2C +!: +#if CONFIG_MEMORY_MODEL_60K + lda #>$F7FF +#else // CONFIG_MEMORY_MODEL_38K + lda #>$A000 +#endif + sta MEMSIZ+1 + sta FRETOP+1 +#if CONFIG_MEMORY_MODEL_60K + lda #<$F7FF +#else // CONFIG_MEMORY_MODEL_38K + lda #<$A000 +#endif + sta MEMSIZ+0 + sta FRETOP+0 + + // FALL THROUGH + +basic_do_clr: + + // Clear variables, arrays and strings + lda VARTAB+0 + sta ARYTAB+0 + sta STREND+0 + lda VARTAB+1 + sta ARYTAB+1 + sta STREND+1 + + rts + +#endif // ROM layout diff --git a/c64/basic/board_m65/4000.mega65_vectable_basic_1.s b/c64/basic/board_m65/4000.mega65_vectable_basic_1.s index 46c49a83..992f8e7c 100644 --- a/c64/basic/board_m65/4000.mega65_vectable_basic_1.s +++ b/c64/basic/board_m65/4000.mega65_vectable_basic_1.s @@ -15,6 +15,8 @@ .label VB1__tokenise_line = $4000 + 2 * 1 .label VB1__list_single_line = $4000 + 2 * 2 .label VB1__print_packed_message = $4000 + 2 * 3 + .label VB1__basic_do_clr = $4000 + 2 * 4 + .label VB1__basic_do_new = $4000 + 2 * 5 #else @@ -24,5 +26,7 @@ .word tokenise_line .word list_single_line .word print_packed_message + .word basic_do_clr + .word basic_do_new #endif diff --git a/c64/basic/board_m65/mega65_imports.s b/c64/basic/board_m65/mega65_imports.s index e611cab3..fb4e5161 100644 --- a/c64/basic/board_m65/mega65_imports.s +++ b/c64/basic/board_m65/mega65_imports.s @@ -10,8 +10,8 @@ .label peek_under_roms = BASIC_0.proxy_B1_peek_under_roms .label JCHROUT = BASIC_0.proxy_B1_JCHROUT +.label JMEMTOP = KERNAL_0.JMEMTOP .label plot_set = KERNAL_0.plot_set -.label basic_do_new = BASIC_0.proxy_B1_basic_do_new .label rom_revision_basic_string = BASIC_0.rom_revision_basic_string .label print_integer = BASIC_0.proxy_B1_print_integer .label print_return = BASIC_0.proxy_B1_print_return diff --git a/c64/basic/board_m65/mega65_proxies.s b/c64/basic/board_m65/mega65_proxies.s index f6f2fbf7..6da2f738 100644 --- a/c64/basic/board_m65/mega65_proxies.s +++ b/c64/basic/board_m65/mega65_proxies.s @@ -24,13 +24,6 @@ proxy_B1_JCHROUT: jmp map_BASIC_1 -proxy_B1_basic_do_new: - - jsr map_NORMAL - jsr basic_do_new - jmp map_BASIC_1 - - proxy_B1_print_integer: jsr map_NORMAL diff --git a/c64/basic/commands/cmd_clr.s b/c64/basic/commands/cmd_clr.s new file mode 100644 index 00000000..8f7b7af5 --- /dev/null +++ b/c64/basic/commands/cmd_clr.s @@ -0,0 +1,12 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +cmd_clr: + + jsr basic_do_clr + + // CLR command does not stop execution + // (Cconfirmed on a c64) + jmp basic_execute_statement diff --git a/c64/basic/commands/cmd_new.s b/c64/basic/commands/cmd_new.s index fc455a77..31c6681b 100644 --- a/c64/basic/commands/cmd_new.s +++ b/c64/basic/commands/cmd_new.s @@ -4,81 +4,9 @@ cmd_new: + jsr basic_do_new // NEW command terminates execution // (Confirmed on a C64) jmp basic_main_loop - -cmd_clr: - jsr basic_do_clr - // CLR command does not stop execution - // (Cconfirmed on a c64) - jmp basic_execute_statement - -basic_do_new: - // Setup pointers to memory storage XXX should depend on text start vector - lda #<$0801 - sta TXTTAB+0 - lda #>$0801 - sta TXTTAB+1 - sta VARTAB+1 - lda #<$0803 - sta VARTAB+0 - - // Zero line pointer - // XXX - We should also zero $0800, i.e., TXTTAB - 1 - ldy #$00 - tya - sta (TXTTAB),y - iny - sta (TXTTAB),y - - - // Get top of memory. - // If a cart is present, then it is $7FFF, - // if not, then it is $F7FF, since we support having - // programs and variables under ROM. - // i.e., we support 56KB RAM for BASIC, keeping some space - // free for some optimisation structures, e.g., FOR/NEXT loop - // records (without them going on the stack), GOSUB stack - // (same story), expression value cache? - - sec // Read, not write value - jsr JMEMTOP - cpx #$80 - beq !+ -#if CONFIG_MEMORY_MODEL_60K - lda #>$F7FF -#else // CONFIG_MEMORY_MODEL_38K - lda #>$A000 -#endif - .byte $2C -!: -#if CONFIG_MEMORY_MODEL_60K - lda #>$F7FF -#else // CONFIG_MEMORY_MODEL_38K - lda #>$A000 -#endif - sta MEMSIZ+1 - sta FRETOP+1 -#if CONFIG_MEMORY_MODEL_60K - lda #<$F7FF -#else // CONFIG_MEMORY_MODEL_38K - lda #<$A000 -#endif - sta MEMSIZ+0 - sta FRETOP+0 - - // FALL THROUGH - -basic_do_clr: - // Clear variables, arrays and strings - lda VARTAB+0 - sta ARYTAB+0 - sta STREND+0 - lda VARTAB+1 - sta ARYTAB+1 - sta STREND+1 - - rts From 6f7e099004889ae27dd591f508dd3861e532657c Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 27 Feb 2020 17:03:55 +0100 Subject: [PATCH 12/57] implemented another batch of small floating point routiines --- STATUS.md | 14 +++++++------- .../{bf7b.FPWRT.s => bf7b.pwr_FAC2_FAC1.s} | 2 +- .../{,stubs_math => math}/b849.add_HALF_FAC1.s | 7 ++++--- c64/basic/{,stubs_math => math}/b849.interop | 0 .../{,stubs_math => math}/bafe.div10_FAC1_p.s | 11 +++++++++-- c64/basic/{,stubs_math => math}/bafe.interop | 0 c64/basic/{,stubs_math => math}/bc2b.interop | 0 c64/basic/{,stubs_math => math}/bc2b.sgn_FAC1_A.s | 11 ++++++++--- c64/basic/{,stubs_math => math}/bf71.interop | 0 c64/basic/{,stubs_math => math}/bf71.sqr_FAC1.s | 7 ++++--- c64/basic/{,stubs_math => math}/bf78.interop | 0 .../bf78.FPWR.s => math/bf78.pwr_FAC2_MEM.s} | 10 ++++++---- 12 files changed, 39 insertions(+), 23 deletions(-) rename c64/basic/,stubs_math/{bf7b.FPWRT.s => bf7b.pwr_FAC2_FAC1.s} (97%) rename c64/basic/{,stubs_math => math}/b849.add_HALF_FAC1.s (82%) rename c64/basic/{,stubs_math => math}/b849.interop (100%) rename c64/basic/{,stubs_math => math}/bafe.div10_FAC1_p.s (84%) rename c64/basic/{,stubs_math => math}/bafe.interop (100%) rename c64/basic/{,stubs_math => math}/bc2b.interop (100%) rename c64/basic/{,stubs_math => math}/bc2b.sgn_FAC1_A.s (87%) rename c64/basic/{,stubs_math => math}/bf71.interop (100%) rename c64/basic/{,stubs_math => math}/bf71.sqr_FAC1.s (89%) rename c64/basic/{,stubs_math => math}/bf78.interop (100%) rename c64/basic/{,stubs_math/bf78.FPWR.s => math/bf78.pwr_FAC2_MEM.s} (71%) diff --git a/STATUS.md b/STATUS.md index 1ef99cd7..4e5acc7a 100644 --- a/STATUS.md +++ b/STATUS.md @@ -189,7 +189,7 @@ Floating point mathematical routines - not official, but well known and broadly | `$B794` | `convert_A_to_FAC1` | NOT DONE | | | `$B7B5` | `STRVAL` | NOT DONE | imports string to FAC1 | | `$B7F7` | `convert_FAC1_to_ADDR` | NOT DONE | | -| `$B849` | `add_HALF_FAC1` | NOT DONE | | +| `$B849` | `add_HALF_FAC1` | DONE | | | `$B850` | `sub_MEM_FAC1` | DONE | | | `$B853` | `sub_FAC2_FAC1` | DONE | | | `$B862` | `add_align_exponents` | DONE | | @@ -203,7 +203,7 @@ Floating point mathematical routines - not official, but well known and broadly | `$BA8C` | `mov_MEM_FAC2` | DONE | | | `$BA90` | `get_FAC2_via_INDEX` | NOT DONE | | | `$BAE2` | `mul10_FAC1` | NOT DONE | | -| `$BAFE` | `div10_FAC1_p` | NOT DONE | | +| `$BAFE` | `div10_FAC1_p` | PARTIAL | needs `div_FAC2_FAC1` | | `$BB0F` | `div_MEM_FAC1` | PARTIAL | needs `div_FAC2_FAC1` | | `$BB12` | `div_FAC2_FAC1` | NOT DONE | some work already started | | `$BBA2` | `mov_MEM_FAC1` | DONE | | @@ -216,7 +216,7 @@ Floating point mathematical routines - not official, but well known and broadly | `$BC0C` | `mov_r_FAC1_FAC2` | PARTIAL | not fully tested yet | | `$BC0F` | `mov_FAC1_FAC2` | DONE | | | `$BC1B` | `round_FAC1` | PARTIAL | not fully tested yet | -| `$BC2B` | `sgn_FAC1_A` | NOT DONE | | +| `$BC2B` | `sgn_FAC1_A` | DONE | | | `$BC39` | `sgn_FAC1` | NOT DONE | | | `$BC3C` | `convert_A_to_FAC1` | NOT DONE | | | `$BC44` | `convert_i16_to_FAC1` | NOT DONE | | @@ -227,15 +227,15 @@ Floating point mathematical routines - not official, but well known and broadly | `$BCF3` | `FIN` | NOT DONE | imports string to FAC1, ignores spaces | | `$BD7E` | `FINLOG` | NOT DONE | | | `$BDDD` | `FOUT` | NOT DONE | outputs FAC1 to string at $0100 | -| `$BF71` | `sqr_FAC1` | NOT DONE | | +| `$BF71` | `sqr_FAC1` | PARTIAL | needs `sqr_FAC2` | | `$BF74` | `sqr_FAC2` | NOT DONE | | -| `$BF78` | `FPWR` | NOT DONE | set FAC1 as RAM raised to the power of FAC1 | -| `$BF7B` | `FPWRT` | NOT DONE | set FAC1 as FAC2 raised to the power of FAC1 | +| `$BF78` | `pwr_FAC2_MEM` | PARTIAL | needs `pwr_FAC2_FAC1` | +| `$BF7B` | `pwr_FAC2_FAC1` | NOT DONE | | | `$BFB4` | `toggle_sign_FAC1` | DONE | | | `$BFED` | `exp_FAC1` | NOT DONE | | | `$E043` | `poly1_FAC1` | NOT DONE | | | `$E059` | `poly2_FAC1` | NOT DONE | | -| `$E097` | `rnd_FAC1` | PARTIAL | requires `sgn_FAC1_A` | +| `$E097` | `rnd_FAC1` | DONE | | | `$E09A` | `rnd_A` | DONE | | | `$E0BE` | `rnd_generate` | DONE | | | `$E264` | `cos_FAC1` | NOT DONE | | diff --git a/c64/basic/,stubs_math/bf7b.FPWRT.s b/c64/basic/,stubs_math/bf7b.pwr_FAC2_FAC1.s similarity index 97% rename from c64/basic/,stubs_math/bf7b.FPWRT.s rename to c64/basic/,stubs_math/bf7b.pwr_FAC2_FAC1.s index 1bc6264a..6bb1a7f6 100644 --- a/c64/basic/,stubs_math/bf7b.FPWRT.s +++ b/c64/basic/,stubs_math/bf7b.pwr_FAC2_FAC1.s @@ -21,5 +21,5 @@ // XXX provide implementation -FPWRT: +pwr_FAC2_FAC1: STUB_IMPLEMENTATION() diff --git a/c64/basic/,stubs_math/b849.add_HALF_FAC1.s b/c64/basic/math/b849.add_HALF_FAC1.s similarity index 82% rename from c64/basic/,stubs_math/b849.add_HALF_FAC1.s rename to c64/basic/math/b849.add_HALF_FAC1.s index deac2795..76f21ff0 100644 --- a/c64/basic/,stubs_math/b849.add_HALF_FAC1.s +++ b/c64/basic/math/b849.add_HALF_FAC1.s @@ -9,8 +9,9 @@ // See also: // - [CM64] Computes Mapping the Commodore 64 - page 112 -// XXX implement - add_HALF_FAC1: - STUB_IMPLEMENTATION() + ldy #>const_HALF + lda #const_TEN + lda # Date: Thu, 27 Feb 2020 17:35:22 +0100 Subject: [PATCH 13/57] added multiplication by 10 routine, not yet tested --- STATUS.md | 2 +- c64/basic/,stubs_math/bae2.mul10_FAC1.s | 18 -------- c64/basic/{,stubs_math => math}/bae2.interop | 0 c64/basic/math/bae2.mul10_FAC1.s | 43 ++++++++++++++++++++ c64/basic/math/mul10_FAC1_mul2.s | 25 ++++++++++++ 5 files changed, 69 insertions(+), 19 deletions(-) delete mode 100644 c64/basic/,stubs_math/bae2.mul10_FAC1.s rename c64/basic/{,stubs_math => math}/bae2.interop (100%) create mode 100644 c64/basic/math/bae2.mul10_FAC1.s create mode 100644 c64/basic/math/mul10_FAC1_mul2.s diff --git a/STATUS.md b/STATUS.md index 4e5acc7a..28ea4e50 100644 --- a/STATUS.md +++ b/STATUS.md @@ -202,7 +202,7 @@ Floating point mathematical routines - not official, but well known and broadly | `$BA2B` | `mul_FAC2_FAC1` | PARTIAL | not testeed yet | | `$BA8C` | `mov_MEM_FAC2` | DONE | | | `$BA90` | `get_FAC2_via_INDEX` | NOT DONE | | -| `$BAE2` | `mul10_FAC1` | NOT DONE | | +| `$BAE2` | `mul10_FAC1` | PARTIAL | not tested yet | | `$BAFE` | `div10_FAC1_p` | PARTIAL | needs `div_FAC2_FAC1` | | `$BB0F` | `div_MEM_FAC1` | PARTIAL | needs `div_FAC2_FAC1` | | `$BB12` | `div_FAC2_FAC1` | NOT DONE | some work already started | diff --git a/c64/basic/,stubs_math/bae2.mul10_FAC1.s b/c64/basic/,stubs_math/bae2.mul10_FAC1.s deleted file mode 100644 index 4d6e570d..00000000 --- a/c64/basic/,stubs_math/bae2.mul10_FAC1.s +++ /dev/null @@ -1,18 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# X16 BASIC_0 #TAKE-OFFSET 2000 -// #LAYOUT# * BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - -// -// Math package - multiply FAC1 by 10 -// -// See also: -// - [CM64] Computes Mapping the Commodore 64 - page 114 -// - https://www.c64-wiki.com/wiki/Floating_point_arithmetic -// - https://codebase64.org/doku.php?id=base:kernal_floating_point_mathematics -// - -// XXX provide implementation - -mul10_FAC1: - STUB_IMPLEMENTATION() diff --git a/c64/basic/,stubs_math/bae2.interop b/c64/basic/math/bae2.interop similarity index 100% rename from c64/basic/,stubs_math/bae2.interop rename to c64/basic/math/bae2.interop diff --git a/c64/basic/math/bae2.mul10_FAC1.s b/c64/basic/math/bae2.mul10_FAC1.s new file mode 100644 index 00000000..96f21fe7 --- /dev/null +++ b/c64/basic/math/bae2.mul10_FAC1.s @@ -0,0 +1,43 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE-OFFSET 2000 +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Math package - multiply FAC1 by 10 +// +// See also: +// - [CM64] Computes Mapping the Commodore 64 - page 114 +// - https://www.c64-wiki.com/wiki/Floating_point_arithmetic +// - https://codebase64.org/doku.php?id=base:kernal_floating_point_mathematics +// + +// XXX test this + +mul10_FAC1: + + // Handle special case of FAC1 equal 0 + + lda FAC1_exponent + beq mul10_FAC1_done + + // Start by multiplying FAC1 by 2 + + jsr mul10_FAC1_mul2 + + // Move FAC1 to FAC2, so that FAC1 = FAC2 = 2 * initial + + jsr mov_FAC1_FAC2 + + // Multiply FAC1 by 4 + + jsr mul10_FAC1_mul2 + jsr mul10_FAC1_mul2 + + // Now we have FAC1 = 8 * initial and FAC2 = 2 * initial; so just add these 2 values + + jmp add_FAC2_FAC1 + +mul10_FAC1_done: + + rts diff --git a/c64/basic/math/mul10_FAC1_mul2.s b/c64/basic/math/mul10_FAC1_mul2.s new file mode 100644 index 00000000..c70514c8 --- /dev/null +++ b/c64/basic/math/mul10_FAC1_mul2.s @@ -0,0 +1,25 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Multiply FAC1 by 2, do not normalize +// + +mul10_FAC1_mul2: + + // First handle the mantissa + + asl FACOV + rol FAC1_mantissa+3 + rol FAC1_mantissa+2 + rol FAC1_mantissa+1 + rol FAC1_mantissa+0 + bcc !+ + + // We need to increment the exponent + + inc FAC1_exponent + bcs_16 set_FAC1_max + + rts From 55f1a1ae8a4c9010f9431d214684506f8cb36a77 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 27 Feb 2020 17:40:58 +0100 Subject: [PATCH 14/57] fix for multiplication by 10 --- c64/basic/math/mul10_FAC1_mul2.s | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/c64/basic/math/mul10_FAC1_mul2.s b/c64/basic/math/mul10_FAC1_mul2.s index c70514c8..61bf73aa 100644 --- a/c64/basic/math/mul10_FAC1_mul2.s +++ b/c64/basic/math/mul10_FAC1_mul2.s @@ -8,16 +8,7 @@ mul10_FAC1_mul2: - // First handle the mantissa - - asl FACOV - rol FAC1_mantissa+3 - rol FAC1_mantissa+2 - rol FAC1_mantissa+1 - rol FAC1_mantissa+0 - bcc !+ - - // We need to increment the exponent + // Increment the exponent inc FAC1_exponent bcs_16 set_FAC1_max From a40b419b1fc05092b6a9b309d496b473005e7e05 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 27 Feb 2020 18:28:57 +0100 Subject: [PATCH 15/57] various multiplication fixes --- STATUS.md | 6 +-- c64/basic/math/bae2.mul10_FAC1.s | 2 - c64/basic/math/mul10_FAC1_mul2.s | 2 +- c64/basic/math/mul_FAC2_FAC1.s | 81 +++++------------------------- c64/basic/math/mul_FAC2_FAC1_8x8.s | 67 ++++++++++++++++++++++++ 5 files changed, 83 insertions(+), 75 deletions(-) create mode 100644 c64/basic/math/mul_FAC2_FAC1_8x8.s diff --git a/STATUS.md b/STATUS.md index 28ea4e50..d5ed350b 100644 --- a/STATUS.md +++ b/STATUS.md @@ -198,11 +198,11 @@ Floating point mathematical routines - not official, but well known and broadly | `$B8FE` | `normal_FAC1` | DONE | | | `$B947` | `inv_FAC1_mantissa` | NOT DONE | | | `$B9EA` | `log_FAC1` | NOT DONE | | -| `$BA28` | `mul_MEM_FAC1` | PARTIAL | needs `mul_FAC2_FAC1` | -| `$BA2B` | `mul_FAC2_FAC1` | PARTIAL | not testeed yet | +| `$BA28` | `mul_MEM_FAC1` | DONE | | +| `$BA2B` | `mul_FAC2_FAC1` | PARTIAL | very imprecise; not yet clear, why | | `$BA8C` | `mov_MEM_FAC2` | DONE | | | `$BA90` | `get_FAC2_via_INDEX` | NOT DONE | | -| `$BAE2` | `mul10_FAC1` | PARTIAL | not tested yet | +| `$BAE2` | `mul10_FAC1` | DONE | | | `$BAFE` | `div10_FAC1_p` | PARTIAL | needs `div_FAC2_FAC1` | | `$BB0F` | `div_MEM_FAC1` | PARTIAL | needs `div_FAC2_FAC1` | | `$BB12` | `div_FAC2_FAC1` | NOT DONE | some work already started | diff --git a/c64/basic/math/bae2.mul10_FAC1.s b/c64/basic/math/bae2.mul10_FAC1.s index 96f21fe7..5b20e8a7 100644 --- a/c64/basic/math/bae2.mul10_FAC1.s +++ b/c64/basic/math/bae2.mul10_FAC1.s @@ -12,8 +12,6 @@ // - https://codebase64.org/doku.php?id=base:kernal_floating_point_mathematics // -// XXX test this - mul10_FAC1: // Handle special case of FAC1 equal 0 diff --git a/c64/basic/math/mul10_FAC1_mul2.s b/c64/basic/math/mul10_FAC1_mul2.s index 61bf73aa..55b8f160 100644 --- a/c64/basic/math/mul10_FAC1_mul2.s +++ b/c64/basic/math/mul10_FAC1_mul2.s @@ -11,6 +11,6 @@ mul10_FAC1_mul2: // Increment the exponent inc FAC1_exponent - bcs_16 set_FAC1_max + beq_16 set_FAC1_max rts diff --git a/c64/basic/math/mul_FAC2_FAC1.s b/c64/basic/math/mul_FAC2_FAC1.s index 70219515..0b11c614 100644 --- a/c64/basic/math/mul_FAC2_FAC1.s +++ b/c64/basic/math/mul_FAC2_FAC1.s @@ -17,7 +17,7 @@ // - https://codebase64.org/doku.php?id=base:kernal_floating_point_mathematics // -// XXX test this code +// XXX the code here is very imprecise, find out why mul_FAC2_FAC1_done: @@ -139,7 +139,13 @@ mul_FAC2_FAC1_sub_exp_bias: lda RESHO+0 sta FAC1_mantissa+0 - // XXX correction is probably needed + // Correct the exponent + + lda FAC1_exponent + clc + adc #$08 + bcs_16 set_FAC1_max // branch if overflow + sta FAC1_exponent jmp normal_FAC1 @@ -153,7 +159,7 @@ mul_by_A: // XXX we should probably move this subroutine to a separate file // Multiply FAC2_mantissa+3 lda FAC2_mantissa+3 - jsr mul_8x8 + jsr mul_FAC2_FAC1_8x8 adc RESHO+4 sta RESHO+4 @@ -170,7 +176,7 @@ mul_by_A: // XXX we should probably move this subroutine to a separate file // Multiply FAC2_mantissa+2 lda FAC2_mantissa+2 - jsr mul_8x8 + jsr mul_FAC2_FAC1_8x8 adc RESHO+3 sta RESHO+3 @@ -185,7 +191,7 @@ mul_by_A: // XXX we should probably move this subroutine to a separate file // Multiply FAC2_mantissa+1 lda FAC2_mantissa+1 - jsr mul_8x8 + jsr mul_FAC2_FAC1_8x8 adc RESHO+2 sta RESHO+2 @@ -198,7 +204,7 @@ mul_by_A: // XXX we should probably move this subroutine to a separate file // Multiply FAC2_mantissa+0 lda FAC2_mantissa+0 - jsr mul_8x8 + jsr mul_FAC2_FAC1_8x8 adc RESHO+1 sta RESHO+1 txa @@ -225,66 +231,3 @@ mul_shift_RESHO: // XXX we should probably move this subroutine to a separate fi sta RESHO+0 rts - - -mul_8x8: // XXX we should probably move this subroutine to a separate file - - sta INDEX+2 - - // Routine based on code by djmips, taken from: - // - https://codebase64.org/doku.php?id=base:8bit_multiplication_16bit_product_fast_no_tables - // - // input: INDEX+2, INDEX+3 - // output: .X (high byte), .A and INDEX+2 (low byte), carry always clear - - lda #$00 - - dec INDEX+3 // decrement because we will be adding with carry set for speed (an extra one) - ror INDEX+2 - bcc !+ - adc INDEX+3 -!: - ror - ror INDEX+2 - bcc !+ - adc INDEX+3 -!: - ror - ror INDEX+2 - bcc !+ - adc INDEX+3 -!: - ror - ror INDEX+2 - bcc !+ - adc INDEX+3 -!: - ror - ror INDEX+2 - bcc !+ - adc INDEX+3 -!: - ror - ror INDEX+2 - bcc !+ - adc INDEX+3 -!: - ror - ror INDEX+2 - bcc !+ - adc INDEX+3 -!: - ror - ror INDEX+2 - bcc !+ - adc INDEX+3 -!: - ror - ror INDEX+2 - inc INDEX+3 - - tax - lda INDEX+2 - clc - - rts diff --git a/c64/basic/math/mul_FAC2_FAC1_8x8.s b/c64/basic/math/mul_FAC2_FAC1_8x8.s new file mode 100644 index 00000000..d247b0bd --- /dev/null +++ b/c64/basic/math/mul_FAC2_FAC1_8x8.s @@ -0,0 +1,67 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Helper routine, based on code by djmips from: +// - https://codebase64.org/doku.php?id=base:8bit_multiplication_16bit_product_fast_no_tables +// +// input: .A, INDEX+3 +// output: .X (high byte), .A and INDEX+2 (low byte), carry always clear +// + +mul_FAC2_FAC1_8x8: + + sta INDEX+2 + + lda #$00 + + dec INDEX+3 // decrement because we will be adding with carry set for speed (an extra one) + ror INDEX+2 + bcc !+ + adc INDEX+3 +!: + ror + ror INDEX+2 + bcc !+ + adc INDEX+3 +!: + ror + ror INDEX+2 + bcc !+ + adc INDEX+3 +!: + ror + ror INDEX+2 + bcc !+ + adc INDEX+3 +!: + ror + ror INDEX+2 + bcc !+ + adc INDEX+3 +!: + ror + ror INDEX+2 + bcc !+ + adc INDEX+3 +!: + ror + ror INDEX+2 + bcc !+ + adc INDEX+3 +!: + ror + ror INDEX+2 + bcc !+ + adc INDEX+3 +!: + ror + ror INDEX+2 + inc INDEX+3 + + tax + lda INDEX+2 + clc + + rts From 6afae69a318d70d14279b9f85164765479158e24 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 27 Feb 2020 18:48:34 +0100 Subject: [PATCH 16/57] speed optimization of multiplication routine --- STATUS.md | 2 +- c64/basic/math/mul_FAC2_FAC1_8x8.s | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/STATUS.md b/STATUS.md index d5ed350b..aeaabc42 100644 --- a/STATUS.md +++ b/STATUS.md @@ -199,7 +199,7 @@ Floating point mathematical routines - not official, but well known and broadly | `$B947` | `inv_FAC1_mantissa` | NOT DONE | | | `$B9EA` | `log_FAC1` | NOT DONE | | | `$BA28` | `mul_MEM_FAC1` | DONE | | -| `$BA2B` | `mul_FAC2_FAC1` | PARTIAL | very imprecise; not yet clear, why | +| `$BA2B` | `mul_FAC2_FAC1` | PARTIAL | sometime imprecise - like PI*PI | | `$BA8C` | `mov_MEM_FAC2` | DONE | | | `$BA90` | `get_FAC2_via_INDEX` | NOT DONE | | | `$BAE2` | `mul10_FAC1` | DONE | | diff --git a/c64/basic/math/mul_FAC2_FAC1_8x8.s b/c64/basic/math/mul_FAC2_FAC1_8x8.s index d247b0bd..fa0ebfec 100644 --- a/c64/basic/math/mul_FAC2_FAC1_8x8.s +++ b/c64/basic/math/mul_FAC2_FAC1_8x8.s @@ -7,13 +7,20 @@ // - https://codebase64.org/doku.php?id=base:8bit_multiplication_16bit_product_fast_no_tables // // input: .A, INDEX+3 -// output: .X (high byte), .A and INDEX+2 (low byte), carry always clear +// output: .X (high byte), .A (low byte), carry always clear // mul_FAC2_FAC1_8x8: sta INDEX+2 + // Special case (optimization) - handle 0 + + lda INDEX+2 + beq mul_FAC2_FAC1_8x8_zero + lda INDEX+3 + beq mul_FAC2_FAC1_8x8_zero + lda #$00 dec INDEX+3 // decrement because we will be adding with carry set for speed (an extra one) @@ -62,6 +69,14 @@ mul_FAC2_FAC1_8x8: tax lda INDEX+2 - clc + clc + rts + +mul_FAC2_FAC1_8x8_zero: + + lda #$00 + tax + + clc rts From 9f29d058dd04299d36809505c4eba53569dbf4f9 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 27 Feb 2020 19:22:24 +0100 Subject: [PATCH 17/57] further multiplication fixes --- c64/basic/math/mul_FAC2_FAC1.s | 39 ++++++++++++++++-------------- c64/basic/math/mul_FAC2_FAC1_8x8.s | 13 +++------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/c64/basic/math/mul_FAC2_FAC1.s b/c64/basic/math/mul_FAC2_FAC1.s index 0b11c614..e97235bd 100644 --- a/c64/basic/math/mul_FAC2_FAC1.s +++ b/c64/basic/math/mul_FAC2_FAC1.s @@ -97,32 +97,32 @@ mul_FAC2_FAC1_sub_exp_bias: // XXX maybe we should preserve .X on stack? this will not cost us too much lda FACOV - jsr mul_by_A - jsr mul_shift_RESHO + jsr mul_FAC2_FAC1_by_A + jsr mul_FAC2_FAC1_shift_RESHO bcc !+ inc RESHO+0 !: lda FAC1_mantissa+3 - jsr mul_by_A - jsr mul_shift_RESHO + jsr mul_FAC2_FAC1_by_A + jsr mul_FAC2_FAC1_shift_RESHO bcc !+ inc RESHO+0 !: lda FAC1_mantissa+2 - jsr mul_by_A - jsr mul_shift_RESHO + jsr mul_FAC2_FAC1_by_A + jsr mul_FAC2_FAC1_shift_RESHO bcc !+ inc RESHO+0 !: lda FAC1_mantissa+1 - jsr mul_by_A - jsr mul_shift_RESHO + jsr mul_FAC2_FAC1_by_A + jsr mul_FAC2_FAC1_shift_RESHO bcc !+ inc RESHO+0 !: lda FAC1_mantissa+0 - jsr mul_by_A - jsr mul_shift_RESHO + jsr mul_FAC2_FAC1_by_A + jsr mul_FAC2_FAC1_shift_RESHO bcc !+ inc RESHO+0 !: @@ -149,11 +149,9 @@ mul_FAC2_FAC1_sub_exp_bias: jmp normal_FAC1 +mul_FAC2_FAC1_by_A: - - -mul_by_A: // XXX we should probably move this subroutine to a separate file - + beq mul_FAC2_FAC1_by_A_done sta INDEX+3 // Multiply FAC2_mantissa+3 @@ -168,9 +166,9 @@ mul_by_A: // XXX we should probably move this subroutine to a separate file sta RESHO+3 bcc !+ inc RESHO+2 - bcc !+ + bne !+ inc RESHO+1 - bcc !+ + bne !+ inc RESHO+0 !: // Multiply FAC2_mantissa+2 @@ -185,7 +183,7 @@ mul_by_A: // XXX we should probably move this subroutine to a separate file sta RESHO+2 bcc !+ inc RESHO+1 - bcc !+ + bne !+ inc RESHO+0 !: // Multiply FAC2_mantissa+1 @@ -211,11 +209,16 @@ mul_by_A: // XXX we should probably move this subroutine to a separate file adc RESHO+0 sta RESHO+0 + // FALLTROUGH + +mul_FAC2_FAC1_by_A_done: + rts -mul_shift_RESHO: // XXX we should probably move this subroutine to a separate file + +mul_FAC2_FAC1_shift_RESHO: // XXX we should probably move this subroutine to a separate file // Shift RESHO by one byte diff --git a/c64/basic/math/mul_FAC2_FAC1_8x8.s b/c64/basic/math/mul_FAC2_FAC1_8x8.s index fa0ebfec..aa903e0d 100644 --- a/c64/basic/math/mul_FAC2_FAC1_8x8.s +++ b/c64/basic/math/mul_FAC2_FAC1_8x8.s @@ -6,21 +6,16 @@ // Helper routine, based on code by djmips from: // - https://codebase64.org/doku.php?id=base:8bit_multiplication_16bit_product_fast_no_tables // -// input: .A, INDEX+3 +// input: .A (and Zero flag set according to .A), INDEX+3 // output: .X (high byte), .A (low byte), carry always clear // mul_FAC2_FAC1_8x8: + // Special case (optimization) - handle 0 in INDEX+2 + beq mul_FAC2_FAC1_8x8_zero + sta INDEX+2 - - // Special case (optimization) - handle 0 - - lda INDEX+2 - beq mul_FAC2_FAC1_8x8_zero - lda INDEX+3 - beq mul_FAC2_FAC1_8x8_zero - lda #$00 dec INDEX+3 // decrement because we will be adding with carry set for speed (an extra one) From e11bfe5a87d6c111ac9801610742fd7457c1fba5 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 27 Feb 2020 19:46:49 +0100 Subject: [PATCH 18/57] multiplication cleanup --- STATUS.md | 2 +- c64/basic/math/mul_FAC2_FAC1.s | 32 +++++----------------------- c64/basic/math/mul_FAC2_FAC1_shift.s | 22 +++++++++++++++++++ 3 files changed, 28 insertions(+), 28 deletions(-) create mode 100644 c64/basic/math/mul_FAC2_FAC1_shift.s diff --git a/STATUS.md b/STATUS.md index aeaabc42..b568ba51 100644 --- a/STATUS.md +++ b/STATUS.md @@ -199,7 +199,7 @@ Floating point mathematical routines - not official, but well known and broadly | `$B947` | `inv_FAC1_mantissa` | NOT DONE | | | `$B9EA` | `log_FAC1` | NOT DONE | | | `$BA28` | `mul_MEM_FAC1` | DONE | | -| `$BA2B` | `mul_FAC2_FAC1` | PARTIAL | sometime imprecise - like PI*PI | +| `$BA2B` | `mul_FAC2_FAC1` | DONE | | | `$BA8C` | `mov_MEM_FAC2` | DONE | | | `$BA90` | `get_FAC2_via_INDEX` | NOT DONE | | | `$BAE2` | `mul10_FAC1` | DONE | | diff --git a/c64/basic/math/mul_FAC2_FAC1.s b/c64/basic/math/mul_FAC2_FAC1.s index e97235bd..c42a213c 100644 --- a/c64/basic/math/mul_FAC2_FAC1.s +++ b/c64/basic/math/mul_FAC2_FAC1.s @@ -17,8 +17,6 @@ // - https://codebase64.org/doku.php?id=base:kernal_floating_point_mathematics // -// XXX the code here is very imprecise, find out why - mul_FAC2_FAC1_done: rts @@ -98,31 +96,31 @@ mul_FAC2_FAC1_sub_exp_bias: lda FACOV jsr mul_FAC2_FAC1_by_A - jsr mul_FAC2_FAC1_shift_RESHO + jsr mul_FAC2_FAC1_shift bcc !+ inc RESHO+0 !: lda FAC1_mantissa+3 jsr mul_FAC2_FAC1_by_A - jsr mul_FAC2_FAC1_shift_RESHO + jsr mul_FAC2_FAC1_shift bcc !+ inc RESHO+0 !: lda FAC1_mantissa+2 jsr mul_FAC2_FAC1_by_A - jsr mul_FAC2_FAC1_shift_RESHO + jsr mul_FAC2_FAC1_shift bcc !+ inc RESHO+0 !: lda FAC1_mantissa+1 jsr mul_FAC2_FAC1_by_A - jsr mul_FAC2_FAC1_shift_RESHO + jsr mul_FAC2_FAC1_shift bcc !+ inc RESHO+0 !: lda FAC1_mantissa+0 jsr mul_FAC2_FAC1_by_A - jsr mul_FAC2_FAC1_shift_RESHO + jsr mul_FAC2_FAC1_shift bcc !+ inc RESHO+0 !: @@ -214,23 +212,3 @@ mul_FAC2_FAC1_by_A: mul_FAC2_FAC1_by_A_done: rts - - - - -mul_FAC2_FAC1_shift_RESHO: // XXX we should probably move this subroutine to a separate file - - // Shift RESHO by one byte - - lda RESHO+3 - sta RESHO+4 - lda RESHO+2 - sta RESHO+3 - lda RESHO+1 - sta RESHO+2 - lda RESHO+0 - sta RESHO+1 - lda #$00 - sta RESHO+0 - - rts diff --git a/c64/basic/math/mul_FAC2_FAC1_shift.s b/c64/basic/math/mul_FAC2_FAC1_shift.s new file mode 100644 index 00000000..2f3c8acf --- /dev/null +++ b/c64/basic/math/mul_FAC2_FAC1_shift.s @@ -0,0 +1,22 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Shift RESHO by one byte - for multiplication +// + +mul_FAC2_FAC1_shift: + + lda RESHO+3 + sta RESHO+4 + lda RESHO+2 + sta RESHO+3 + lda RESHO+1 + sta RESHO+2 + lda RESHO+0 + sta RESHO+1 + lda #$00 + sta RESHO+0 + + rts From 56a1431db813bf97833c493ed97f08783e916ab7 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 27 Feb 2020 21:00:35 +0100 Subject: [PATCH 19/57] increased floating point multiplication precision --- c64/basic/math/mul_FAC2_FAC1_shift.s | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/c64/basic/math/mul_FAC2_FAC1_shift.s b/c64/basic/math/mul_FAC2_FAC1_shift.s index 2f3c8acf..6aed5169 100644 --- a/c64/basic/math/mul_FAC2_FAC1_shift.s +++ b/c64/basic/math/mul_FAC2_FAC1_shift.s @@ -8,6 +8,16 @@ mul_FAC2_FAC1_shift: + // Check if rounding is needed + + php + clc + lda RESHO+4 + bpl !+ + sec +!: + // Copy bytes + lda RESHO+3 sta RESHO+4 lda RESHO+2 @@ -18,5 +28,19 @@ mul_FAC2_FAC1_shift: sta RESHO+1 lda #$00 sta RESHO+0 + bcc !+ + // Perform rounding + + inc RESHO+4 + bne !+ + inc RESHO+3 + bne !+ + inc RESHO+2 + bne !+ + inc RESHO+1 + bne !+ + inc RESHO+0 +!: + plp rts From 4b381db9f764195da50276e98e5bb109f4ec577d Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 27 Feb 2020 21:53:36 +0100 Subject: [PATCH 20/57] LINKPRG moved to Mega65 extra ROM --- c64/basic/a533.linkprg.s | 38 ++++++++++++++----- .../board_m65/4000.mega65_vectable_basic_1.s | 12 +++--- c64/basic/board_m65/mega65_imports.s | 4 +- c64/basic/board_m65/mega65_proxies.s | 14 ++++++- c64/basic/print/list_single_line.s | 13 +++++-- 5 files changed, 61 insertions(+), 20 deletions(-) diff --git a/c64/basic/a533.linkprg.s b/c64/basic/a533.linkprg.s index f272bd30..57d6bdda 100644 --- a/c64/basic/a533.linkprg.s +++ b/c64/basic/a533.linkprg.s @@ -1,6 +1,7 @@ // #LAYOUT# STD * #TAKE +// #LAYOUT# M65 BASIC_0 #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE-FLOAT // #LAYOUT# X16 BASIC_0 #TAKE-OFFSET 2000 -// #LAYOUT# * BASIC_0 #TAKE // #LAYOUT# * * #IGNORE // @@ -12,6 +13,14 @@ LINKPRG: +#if (ROM_LAYOUT_M65 && SEGMENT_BASIC_0) + + jsr map_BASIC_1 + jsr_ind VB1__LINKPRG + jmp map_NORMAL + +#else + // Start by getting pointer to the first line jsr init_oldtxt @@ -19,11 +28,13 @@ linkprg_loop: // Is the pointer to the end of the program ldy #1 -#if CONFIG_MEMORY_MODEL_60K +#if ROM_LAYOUT_M65 + jsr peek_via_OLDTXT +#elif CONFIG_MEMORY_MODEL_60K ldx # Date: Fri, 28 Feb 2020 20:04:02 +0100 Subject: [PATCH 21/57] added polynomial for sine approximation --- STATUS.md | 2 +- c64/basic/,stubs_math/e26b.sin_FAC1.s | 11 +++++++++++ tools/generate_constants.cc | 10 ++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/STATUS.md b/STATUS.md index b568ba51..ad5d7e75 100644 --- a/STATUS.md +++ b/STATUS.md @@ -239,7 +239,7 @@ Floating point mathematical routines - not official, but well known and broadly | `$E09A` | `rnd_A` | DONE | | | `$E0BE` | `rnd_generate` | DONE | | | `$E264` | `cos_FAC1` | NOT DONE | | -| `$E26B` | `sin_FAC1` | NOT DONE | | +| `$E26B` | `sin_FAC1` | NOT DONE | some work already started | | `$E2B4` | `tan_FAC1` | NOT DONE | | | `$E30E` | `atn_FAC1` | NOT DONE | | diff --git a/c64/basic/,stubs_math/e26b.sin_FAC1.s b/c64/basic/,stubs_math/e26b.sin_FAC1.s index 99eb4569..82a86d2f 100644 --- a/c64/basic/,stubs_math/e26b.sin_FAC1.s +++ b/c64/basic/,stubs_math/e26b.sin_FAC1.s @@ -15,3 +15,14 @@ sin_FAC1: STUB_IMPLEMENTATION() + +poly_sin: + + .byte $05 // series length - 1 + + put_const_POLY_SIN_1() + put_const_POLY_SIN_2() + put_const_POLY_SIN_3() + put_const_POLY_SIN_4() + put_const_POLY_SIN_5() + put_const_POLY_SIN_6() diff --git a/tools/generate_constants.cc b/tools/generate_constants.cc index 6d27caed..5e40b233 100644 --- a/tools/generate_constants.cc +++ b/tools/generate_constants.cc @@ -57,6 +57,16 @@ std::vector GLOBAL_constants = ConstEntry( "INV_SQR_2", 1.0 / std::sqrt(2.0) ), ConstEntry( "LOG_2", std::log(2.0) ), ConstEntry( "INV_LOG_2", 1.0 / std::log(2.0) ), + + // Constants for sine approximation, minimized abs. error, degree 11, from: + // - https://publik-void.github.io/sin-cos-approximations/ + + ConstEntry( "POLY_SIN_1", -2.3794713545277060334805162803882547e-8 ), + ConstEntry( "POLY_SIN_2", 2.75188556386854406868696924998396177e-6 ), + ConstEntry( "POLY_SIN_3", -0.000198407028626057951892931706291369095 ), + ConstEntry( "POLY_SIN_4", 0.00833332926445715285723741015926085083 ), + ConstEntry( "POLY_SIN_5", -0.166666665414391662957238076832950332 ), + ConstEntry( "POLY_SIN_6", 0.99999999988985190065414932682350994 ), }; // From d762c4931209d62f11030719fb893138f9603c89 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Fri, 28 Feb 2020 22:44:19 +0100 Subject: [PATCH 22/57] some work towards division --- c64/basic/math/bb12.div_FAC2_FAC1.s | 70 +++++++++++++++++++++++++---- tools/generate_constants.cc | 2 +- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/c64/basic/math/bb12.div_FAC2_FAC1.s b/c64/basic/math/bb12.div_FAC2_FAC1.s index 51ad5f31..3d4878f0 100644 --- a/c64/basic/math/bb12.div_FAC2_FAC1.s +++ b/c64/basic/math/bb12.div_FAC2_FAC1.s @@ -4,13 +4,17 @@ // #LAYOUT# * * #IGNORE // -// Math package - divide FAC2 (dividend) by FAC1 (divisor), ignores sign +// Math package - divide FAC2 (dividend) by FAC1 (divisor) // // Input: -// - .A - must load FAC1 exponent ($61) beforehand to set the zero flag +// - .A - must load FAC1 exponent ($61) beforehand to set the zero flag (but our routine does not need this) // // Output: -// - leaves the quotient FAC1 and the remainder in FAC2 +// - FAC1 +// +// Note: +// - some documentation suggest this is a division leaving quotient and remainder (left in FAC2), +// but it seems (experimentation) that this is not true // // See also: // - [CM64] Computes Mapping the Commodore 64 - page 114 @@ -18,19 +22,61 @@ // - https://codebase64.org/doku.php?id=base:kernal_floating_point_mathematics // -// XXX provide implementation +// XXX finish the implementation div_FAC2_FAC1: + + // 'Pamiętaj, cholero - nie dziel przez zero!' - ancient polish proverb + + lda FAC1_exponent + beq_16 do_DIVISION_BY_ZERO_error + + // Handle special case - dividing 0 by non-zero value + + lda FAC2_exponent + beq div_FAC2_FAC1_setexp_quit + + // Multiply signs + + lda FAC1_sign + eor FAC2_sign + sta FAC1_sign + + // Subtract the exponents XXX what about bias? + + lda FAC2_exponent + sec + sbc FAC1_exponent + bcs !+ + + // Result too low, set 0 and quit + + lda #$00 + +div_FAC2_FAC1_setexp_quit: + + sta FAC1_exponent + rts + +!: + adc #$07 // add 8, as the carry is set here + bcs_16 set_FAC1_max // overflow + sta FAC1_exponent + + // Divide the mantissas + + // XXX + + + + STUB_IMPLEMENTATION() +// XXX adapt, move this to a separate file - - -// XXX move this to a separate file - -// Unsigned integer 32-bit mantissa division, based on code by Verz +// Unsigned integer 32-bit division, based on code by Verz // divident: FAC2_mantissa, divisor: FAC1_mantissa, result: FAC2_mantissa, remainder: RESHO // temporary storage: INDEX+1, INDEX+2, INDEX+3 // @@ -106,3 +152,9 @@ div_mantissas_skip: bne div_mantissas_loop rts + + + + + + diff --git a/tools/generate_constants.cc b/tools/generate_constants.cc index 5e40b233..9e45e591 100644 --- a/tools/generate_constants.cc +++ b/tools/generate_constants.cc @@ -58,7 +58,7 @@ std::vector GLOBAL_constants = ConstEntry( "LOG_2", std::log(2.0) ), ConstEntry( "INV_LOG_2", 1.0 / std::log(2.0) ), - // Constants for sine approximation, minimized abs. error, degree 11, from: + // Constants for sine approximation, minimized abs. error, degree 11, for [0, pi/2], from: // - https://publik-void.github.io/sin-cos-approximations/ ConstEntry( "POLY_SIN_1", -2.3794713545277060334805162803882547e-8 ), From b346cc85c5c7e2b19de619d3b2ead51929499b8e Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 29 Feb 2020 12:16:54 +0100 Subject: [PATCH 23/57] more multiplication/division work --- CREDITS.md | 1 - STATUS.md | 2 +- c64/basic/math/bb12.div_FAC2_FAC1.s | 115 ++++---------------------- c64/basic/math/mul_FAC2_FAC1.s | 73 ++++++---------- c64/basic/math/muldiv_RESHO_helpers.s | 29 +++++++ 5 files changed, 75 insertions(+), 145 deletions(-) create mode 100644 c64/basic/math/muldiv_RESHO_helpers.s diff --git a/CREDITS.md b/CREDITS.md index c20920a0..a1ebe654 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -7,7 +7,6 @@ * Graham - for his PAL/NTSC detection routine * enthusi/Onslaught - for his example Turbo Tape 64 compatible loader * djmips - for fast 8x8 multiplication routine -* Verz - for integer division routine ## for documentation diff --git a/STATUS.md b/STATUS.md index ad5d7e75..05eb218a 100644 --- a/STATUS.md +++ b/STATUS.md @@ -199,7 +199,7 @@ Floating point mathematical routines - not official, but well known and broadly | `$B947` | `inv_FAC1_mantissa` | NOT DONE | | | `$B9EA` | `log_FAC1` | NOT DONE | | | `$BA28` | `mul_MEM_FAC1` | DONE | | -| `$BA2B` | `mul_FAC2_FAC1` | DONE | | +| `$BA2B` | `mul_FAC2_FAC1` | PARTIAL | needs retest after rework | | `$BA8C` | `mov_MEM_FAC2` | DONE | | | `$BA90` | `get_FAC2_via_INDEX` | NOT DONE | | | `$BAE2` | `mul10_FAC1` | DONE | | diff --git a/c64/basic/math/bb12.div_FAC2_FAC1.s b/c64/basic/math/bb12.div_FAC2_FAC1.s index 3d4878f0..328a9005 100644 --- a/c64/basic/math/bb12.div_FAC2_FAC1.s +++ b/c64/basic/math/bb12.div_FAC2_FAC1.s @@ -34,7 +34,7 @@ div_FAC2_FAC1: // Handle special case - dividing 0 by non-zero value lda FAC2_exponent - beq div_FAC2_FAC1_setexp_quit + beq_16 set_FAC1_zero // Multiply signs @@ -42,29 +42,32 @@ div_FAC2_FAC1: eor FAC2_sign sta FAC1_sign - // Subtract the exponents XXX what about bias? + // Subtract the exponents + + lda #($80 + $08) // correction for bias and shifted mantissa + sta RESHO+0 + lda #$00 + sta RESHO+1 lda FAC2_exponent + jsr muldiv_RESHO_01_add_A + + lda RESHO+0 sec sbc FAC1_exponent bcs !+ - // Result too low, set 0 and quit - - lda #$00 - -div_FAC2_FAC1_setexp_quit: - - sta FAC1_exponent - rts - + lda RESHO+1 + sbc #$00 + bcc_16 set_FAC1_zero // result too low, set 0 and quit !: - adc #$07 // add 8, as the carry is set here - bcs_16 set_FAC1_max // overflow - sta FAC1_exponent + lda RESHO+1 + bcc_16 set_FAC1_max // overflow // Divide the mantissas + jsr muldiv_RESHO_set_0 + // XXX @@ -74,87 +77,5 @@ div_FAC2_FAC1_setexp_quit: -// XXX adapt, move this to a separate file - -// Unsigned integer 32-bit division, based on code by Verz -// divident: FAC2_mantissa, divisor: FAC1_mantissa, result: FAC2_mantissa, remainder: RESHO -// temporary storage: INDEX+1, INDEX+2, INDEX+3 -// -// https://codebase64.org/doku.php?id=base:24bit_division_24-bit_result - -// XXX test this, optimize (for temporary storage use .Y, .Z and RESHO+4) - -div_mantissas: - - // Preset remainder to 0 - // XXX should be common with multiplication - - lda #$00 - sta RESHO+0 - sta RESHO+1 - sta RESHO+2 - sta RESHO+3 - - ldx #$32 // repeat for each bit - - // FALLTROUGH - -div_mantissas_loop: - - // Multiply divident by 2, msb -> Carry - - asl FAC2_mantissa+3 - rol FAC2_mantissa+2 - rol FAC2_mantissa+1 - rol FAC2_mantissa+0 - - // Multiply remainder by 2, lsb <- Carry - - rol RESHO+3 - rol RESHO+2 - rol RESHO+1 - rol RESHO+0 - - // Subtract divisor to see if it fits in - - lda RESHO+3 - sec - sbc FAC1_mantissa+2 - sta INDEX+3 - - lda RESHO+2 - sbc FAC1_mantissa+2 - sta INDEX+2 - - lda RESHO+1 - sbc FAC1_mantissa+1 - sta INDEX+1 - - lda RESHO+0 - sbc FAC1_mantissa+0 - bcc div_mantissas_skip // if Carry is not set then divisor did not fit in yet - - sta RESHO+0 // else save substraction result as new remainder, - lda INDEX+1 - sta RESHO+1 - lda INDEX+2 - sta RESHO+2 - lda INDEX+3 - sta RESHO+3 - - inc FAC2_mantissa+3 // and INCrement result cause divisor fit in 1 times - - // FALLTROUGH - -div_mantissas_skip: - - dex - bne div_mantissas_loop - - rts - - - - - +// XXX use 8-bit divide from here: https://codebase64.org/doku.php?id=base:8bit_divide_8bit_product diff --git a/c64/basic/math/mul_FAC2_FAC1.s b/c64/basic/math/mul_FAC2_FAC1.s index c42a213c..39fb256e 100644 --- a/c64/basic/math/mul_FAC2_FAC1.s +++ b/c64/basic/math/mul_FAC2_FAC1.s @@ -17,6 +17,11 @@ // - https://codebase64.org/doku.php?id=base:kernal_floating_point_mathematics // +set_FAC1_zero: + + lda #$00 + sta FAC1_exponent + mul_FAC2_FAC1_done: rts @@ -39,59 +44,35 @@ mul_FAC2_FAC1: eor FAC2_sign sta FAC1_sign - // Check if exponents can be added without overflow/underflow - - lda FAC1_exponent - and #$80 - eor FAC2_exponent - - bmi mul_FAC2_FAC1_add_exponents // exponent signs are opposite, we can add them safely - - // Both exponents are either negative (below $80), or both are non-negative ($80 or above), - // try to add them - - lda FAC1_exponent - clc - adc FAC2_exponent - bpl mul_FAC2_FAC1_sub_exp_bias // branch if we can add values - - // We cannot add them, result would over/underflow; set result as - // either 0 or maximum possible float - - lda FAC1_exponent - bmi_16 set_FAC1_max + // Add the exponents (subtract the bias) XXX subroutines should be common with DIV - lda #$00 - sta FAC1_exponent - rts - -mul_FAC2_FAC1_add_exponents: - - // Add the exponents - - lda FAC1_exponent - clc - adc FAC2_exponent - - // FALLTROUGH - -mul_FAC2_FAC1_sub_exp_bias: - - sec - sbc #$80 // bias - sta FAC1_exponent - - // Multiply the mantissas - first clear the RESHO temporary area + jsr muldiv_RESHO_set_0 - lda #$00 + lda FAC1_exponent + jsr muldiv_RESHO_01_add_A + + lda FAC2_exponent + jsr muldiv_RESHO_01_add_A + + lda RESHO+0 + sbc #($80 - $08) // we need to correct double BIAS and shifted mantissa sta RESHO+0 + bcs !+ + lda RESHO+1 + sbc #$00 + bcs set_FAC1_zero sta RESHO+1 - sta RESHO+2 - sta RESHO+3 - sta RESHO+4 +!: + lda RESHO+1 + bne_16 set_FAC1_max // overflow + + lda RESHO+0 + sta FAC1_exponent // Multiply the mantissas + jsr muldiv_RESHO_set_0 + // XXX maybe we should preserve .X on stack? this will not cost us too much lda FACOV diff --git a/c64/basic/math/muldiv_RESHO_helpers.s b/c64/basic/math/muldiv_RESHO_helpers.s new file mode 100644 index 00000000..fef81a7b --- /dev/null +++ b/c64/basic/math/muldiv_RESHO_helpers.s @@ -0,0 +1,29 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Math package - helper routines for RESHO manipulation +// + + +muldiv_RESHO_set_0: + + lda #$00 + sta RESHO+0 + sta RESHO+1 + sta RESHO+2 + sta RESHO+3 + sta RESHO+4 + + rts + +muldiv_RESHO_01_add_A: + + clc + adc RESHO+0 + sta RESHO+0 + bcc !+ + inc RESHO+1 +!: + rts From 998807c078e04dd89d6e07aa662a8209651e23ba Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Tue, 3 Mar 2020 19:37:56 +0100 Subject: [PATCH 24/57] added FAC1 denormalization code, for division --- c64/basic/math/add_align_exponents.s | 2 - c64/basic/math/bb12.div_FAC2_FAC1.s | 6 +-- c64/basic/math/div_FAC1_denorm.s | 70 ++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 c64/basic/math/div_FAC1_denorm.s diff --git a/c64/basic/math/add_align_exponents.s b/c64/basic/math/add_align_exponents.s index 3956ed9c..882cb337 100644 --- a/c64/basic/math/add_align_exponents.s +++ b/c64/basic/math/add_align_exponents.s @@ -9,8 +9,6 @@ // - [CM64] Computes Mapping the Commodore 64 - page 115 // - https://www.c64-wiki.com/wiki/BASIC-ROM -// XXX finish and test this - add_align_exponents: // XXX assume here none of the exponents is 0, check if this is true for orignal ROMs diff --git a/c64/basic/math/bb12.div_FAC2_FAC1.s b/c64/basic/math/bb12.div_FAC2_FAC1.s index 328a9005..5f9cf4d5 100644 --- a/c64/basic/math/bb12.div_FAC2_FAC1.s +++ b/c64/basic/math/bb12.div_FAC2_FAC1.s @@ -66,6 +66,7 @@ div_FAC2_FAC1: // Divide the mantissas + jsr div_FAC1_denorm jsr muldiv_RESHO_set_0 // XXX @@ -74,8 +75,3 @@ div_FAC2_FAC1: STUB_IMPLEMENTATION() - - - - -// XXX use 8-bit divide from here: https://codebase64.org/doku.php?id=base:8bit_divide_8bit_product diff --git a/c64/basic/math/div_FAC1_denorm.s b/c64/basic/math/div_FAC1_denorm.s new file mode 100644 index 00000000..5c40c4a8 --- /dev/null +++ b/c64/basic/math/div_FAC1_denorm.s @@ -0,0 +1,70 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Math package - denormalize FAC1 mantissa and adapt its exponent accordingly, +// so that division is more precise +// + +// XXX test this + +div_FAC1_denorm: + + // Start by moving whole bytes, if possible + + lda FACOV + bne div_FAC1_denorm_by_bit // branch if last byte of mantissa is non-zero + + lda FAC1_exponent + cmp #$09 + bcc div_FAC1_denorm_by_bit // branch if not suitable to decrement exponent by 8 + + // Decrement exponent + + sbc #$08 // Carry already set here + sta FAC1_exponent + + // Move mantissa bytes + + lda FAC1_mantissa+3 + sta FACOV + lda FAC1_mantissa+2 + sta FAC1_mantissa+3 + lda FAC1_mantissa+1 + sta FAC1_mantissa+2 + lda FAC1_mantissa+0 + sta FAC1_mantissa+1 + lda #$00 + sta FAC1_mantissa+0 + + beq div_FAC1_denorm // branch always + +div_FAC1_denorm_by_bit: + + lda FACOV + and #$01 + bne div_FAC1_denorm_done // branch if lowest bit of mantissa is already 1 + + lda FAC1_exponent + cmp #$02 + bcc div_FAC1_denorm_done // branch if not suitable to decrement exponent + + // Decrement exponent + + dec FAC1_exponent + + // Move mantissa bits + + clc + ror FAC1_mantissa+0 + ror FAC1_mantissa+1 + ror FAC1_mantissa+2 + ror FAC1_mantissa+3 + ror FACOV + + bcc div_FAC1_denorm_done // branch always + +div_FAC1_denorm_done: + + rts From 659dccd393ba65d216df663f8ad0f135a3a1dd02 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Tue, 3 Mar 2020 20:56:40 +0100 Subject: [PATCH 25/57] floating point division written, not tested yet --- CREDITS.md | 1 + STATUS.md | 2 +- c64/basic/math/bb12.div_FAC2_FAC1.s | 20 ++++++-- c64/basic/math/div_mantissas.s | 79 +++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 c64/basic/math/div_mantissas.s diff --git a/CREDITS.md b/CREDITS.md index a1ebe654..fb5040c3 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -7,6 +7,7 @@ * Graham - for his PAL/NTSC detection routine * enthusi/Onslaught - for his example Turbo Tape 64 compatible loader * djmips - for fast 8x8 multiplication routine +* Verz - for the integer division routine ## for documentation diff --git a/STATUS.md b/STATUS.md index 05eb218a..2183672c 100644 --- a/STATUS.md +++ b/STATUS.md @@ -205,7 +205,7 @@ Floating point mathematical routines - not official, but well known and broadly | `$BAE2` | `mul10_FAC1` | DONE | | | `$BAFE` | `div10_FAC1_p` | PARTIAL | needs `div_FAC2_FAC1` | | `$BB0F` | `div_MEM_FAC1` | PARTIAL | needs `div_FAC2_FAC1` | -| `$BB12` | `div_FAC2_FAC1` | NOT DONE | some work already started | +| `$BB12` | `div_FAC2_FAC1` | PARTIAL | not tested yet | | `$BBA2` | `mov_MEM_FAC1` | DONE | | | `$BBA6` | `get_FAC2_via_INDEX` | NOT DONE | | | `$BBC7` | `mov_r_FAC1_TMP2` | PARTIAL | not fully tested yet | diff --git a/c64/basic/math/bb12.div_FAC2_FAC1.s b/c64/basic/math/bb12.div_FAC2_FAC1.s index 5f9cf4d5..5532ca46 100644 --- a/c64/basic/math/bb12.div_FAC2_FAC1.s +++ b/c64/basic/math/bb12.div_FAC2_FAC1.s @@ -22,7 +22,7 @@ // - https://codebase64.org/doku.php?id=base:kernal_floating_point_mathematics // -// XXX finish the implementation +// XXX test this code div_FAC2_FAC1: @@ -68,10 +68,22 @@ div_FAC2_FAC1: jsr div_FAC1_denorm jsr muldiv_RESHO_set_0 + jsr div_mantissas - // XXX + // Copy the result to FAC1 - XXX we probably already have similar code somewhere... + lda FAC2_mantissa+3 + sta FAC1_mantissa+3 + lda FAC2_mantissa+2 + sta FAC1_mantissa+2 + lda FAC2_mantissa+1 + sta FAC1_mantissa+1 + lda FAC2_mantissa+0 + sta FAC1_mantissa+0 + lda #$00 + sta FACOV - - STUB_IMPLEMENTATION() + // Normalize and quit + + jmp normal_FAC1 diff --git a/c64/basic/math/div_mantissas.s b/c64/basic/math/div_mantissas.s new file mode 100644 index 00000000..0e50d6c9 --- /dev/null +++ b/c64/basic/math/div_mantissas.s @@ -0,0 +1,79 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// Math package - mantissa division, based on code by Verz +// +// divident: FAC2_mantissa, divisor: FAC1_mantissa, result: FAC2_mantissa, remainder: RESHO +// temporary storage: INDEX+0, INDEX+1, INDEX+2, INDEX+3 +// +// RESHO (remainder) should be set to 0 before +// +// see https://codebase64.org/doku.php?id=base:24bit_division_24-bit_result + +// XXX test this + +div_mantissas: + + ldx #40 // repeat for each bit + + // FALLTROUGH + +div_mantissas_loop: + + // Multiply divident by 2, msb -> Carry + + asl FAC2_mantissa+3 + rol FAC2_mantissa+2 + rol FAC2_mantissa+1 + rol FAC2_mantissa+0 + + // Multiply remainder by 2, lsb <- Carry + + rol RESHO+4 + rol RESHO+3 + rol RESHO+2 + rol RESHO+1 + rol RESHO+0 + + // Subtract divisor to see if it fits in + + lda RESHO+4 + sec + sbc FAC1_mantissa+3 + sta INDEX+3 + + lda RESHO+3 + sbc FAC1_mantissa+2 + sta INDEX+2 + + lda RESHO+2 + sbc FAC1_mantissa+1 + sta INDEX+1 + + lda RESHO+1 + sbc FAC1_mantissa+0 + sta INDEX+0 + + lda RESHO+0 + sbc #$00 + bcc div_mantissas_skip // if Carry is not set then divisor did not fit in yet + + sta RESHO+0 // else save substraction result as new remainder, + lda INDEX+0 + sta RESHO+1 + lda INDEX+1 + sta RESHO+2 + lda INDEX+3 + sta RESHO+4 + + inc FAC2_mantissa+3 // and INCrement result cause divisor fit in 1 times + + // FALLTROUGH + +div_mantissas_skip: + + dex + bne div_mantissas_loop + + rts From f4d67bf2fb87a6bdae31b3bc8fe461e6465634fb Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 4 Mar 2020 21:36:39 +0100 Subject: [PATCH 26/57] Mega65 startup banner tweaks --- c64/basic/init/initmsg_real.s | 14 ++++++++ c64/basic/init/startup_banner.s | 63 +++++++++++++++++++++++++-------- 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/c64/basic/init/initmsg_real.s b/c64/basic/init/initmsg_real.s index 10aedb76..332ef462 100644 --- a/c64/basic/init/initmsg_real.s +++ b/c64/basic/init/initmsg_real.s @@ -135,6 +135,20 @@ initmsg_real: ldy #>startup_banner jsr STROUT +#if ROM_LAYOUT_M65 + + // XXX make it different for future Mega65 native mode + + ldx #$02 + ldy #$21 + jsr plot_set + + lda #text_mode_64 + jsr STROUT + +#endif + ldx #$05 ldy #$00 jsr plot_set diff --git a/c64/basic/init/startup_banner.s b/c64/basic/init/startup_banner.s index bf828819..68fb173a 100644 --- a/c64/basic/init/startup_banner.s +++ b/c64/basic/init/startup_banner.s @@ -79,24 +79,46 @@ pre_revision_string: #elif CONFIG_BANNER_BRAND && CONFIG_BRAND_MEGA_65 + // Fancy Mega65 banner - from Retrofan, slightly tweaked + + .byte $9A, $12, $20, $20, $7F, $A9, $20, $20, $1F, $20, $9A, $20, $20, $20, $20, $1F + .byte $20, $9A, $A9, $20, $20, $20, $92, $A1, $1F, $12, $20, $9A, $A9, $20, $20, $20 + .byte $7F, $1F, $20, $20, $9A, $A3, $A3, $A3, $A3, $A3, $A3, $A3, $1F + .byte $0D + .byte $9A, $12, $20, $20, $20, $20, $20 + .byte $20, $1F, $20, $9A, $20, $20, $92, $A2, $bb, $1F, $12, $20, $9A, $20, $20, $92 + .byte $Ac, $A2, $A2, $1F, $12, $20, $9A, $20, $20, $1F, $20, $9A, $20, $20, $1F, $20 + .byte $20, $1e, $A3, $A3, $A3, $A3, $A3, $A3, $1F + .byte $0D + .byte $9A, $12, $20, $20, $92, $7F, $A9, $12, $20, $20, $1F, $20, $9A, $20, $20, $A2 + .byte $92, $be, $1F, $12, $20, $9A, $20, $20, $92, $bc, $12, $20, $20, $1F, $20, $9A + .byte $20, $20, $20, $20, $20, $1F, $20, $20, $9e, $A3, $A3, $A3, $A3, $A3, $1F + .byte $0D + .byte $9A, $12, $20, $20, $1F, $20, $20, $9A, $20, $20, $1F, $20, $9A, $20, $20, $20 + .byte $20, $1F, $20, $9A, $20, $20, $20, $20, $20, $1F, $20, $9A, $20, $20, $1F, $20 + .byte $9A, $20, $20, $1F, $20, $20, $96, $A3, $A3, $A3, $A3, $1F, $92 + .byte $0D, $0D, $05, $00 + // Fancy Mega65 banner - from Retrofan - .byte $9a, $12, $20, $20, $7f, $a9, $20, $20, $1f, $20, $9a, $20, $20, $20 - .byte $20, $1f, $20, $9a, $a9, $20, $20, $20, $92, $a1, $1f, $12, $20, $9a, $a9, $20 - .byte $20, $20, $7f, $1f, $20, $20, $9a, $a3, $a3, $a3, $a3, $a3, $a3, $a3, $1f, $20 - .byte $20, $20, $20, $05, $92, $4d, $45, $47, $41, $9a, $12, $20, $20, $20, $20, $20 - .byte $20, $1f, $20, $9a, $20, $20, $92, $a2, $bb, $1f, $12, $20, $9a, $20, $20, $92 - .byte $ac, $a2, $a2, $1f, $12, $20, $9a, $20, $20, $1f, $20, $9a, $20, $20, $1f, $20 - .byte $20, $1e, $a3, $a3, $a3, $a3, $a3, $a3, $1f, $20, $20, $20, $20, $05, $92, $42 - .byte $41, $53, $49, $43, $9a, $12, $20, $20, $92, $7f, $a9, $12, $20, $20, $1f, $20 - .byte $9a, $20, $20, $a2, $92, $be, $1f, $12, $20, $9a, $20, $20, $92, $bc, $12, $20 - .byte $20, $1f, $20, $9a, $20, $20, $20, $20, $20, $1f, $20, $20, $9e, $a3, $a3, $a3 - .byte $a3, $a3, $1f, $20, $20, $20, $20, $05, $92, $2d, $2d, $2d, $2d, $2d, $2d, $9a - .byte $12, $20, $20, $1f, $20, $20, $9a, $20, $20, $1f, $20, $9a, $20, $20, $20, $20 - .byte $1f, $20, $9a, $20, $20, $20, $20, $20, $1f, $20, $9a, $20, $20, $1f, $20, $9a - .byte $20, $20, $1f, $20, $20, $96, $a3, $a3, $a3, $a3, $1f - .byte $92, $0D, $0D, $05, $00 + // + // .byte $9a, $12, $20, $20, $7f, $a9, $20, $20, $1f, $20, $9a, $20, $20, $20 + // .byte $20, $1f, $20, $9a, $a9, $20, $20, $20, $92, $a1, $1f, $12, $20, $9a, $a9, $20 + // .byte $20, $20, $7f, $1f, $20, $20, $9a, $a3, $a3, $a3, $a3, $a3, $a3, $a3, $1f, $20 + // .byte $20, $20, $20, $05, $92, $4d, $45, $47, $41, $9a, $12, $20, $20, $20, $20, $20 + // .byte $20, $1f, $20, $9a, $20, $20, $92, $a2, $bb, $1f, $12, $20, $9a, $20, $20, $92 + // .byte $ac, $a2, $a2, $1f, $12, $20, $9a, $20, $20, $1f, $20, $9a, $20, $20, $1f, $20 + // .byte $20, $1e, $a3, $a3, $a3, $a3, $a3, $a3, $1f, $20, $20, $20, $20, $05, $92, $42 + // .byte $41, $53, $49, $43, $9a, $12, $20, $20, $92, $7f, $a9, $12, $20, $20, $1f, $20 + // .byte $9a, $20, $20, $a2, $92, $be, $1f, $12, $20, $9a, $20, $20, $92, $bc, $12, $20 + // .byte $20, $1f, $20, $9a, $20, $20, $20, $20, $20, $1f, $20, $20, $9e, $a3, $a3, $a3 + // .byte $a3, $a3, $1f, $20, $20, $20, $20, $05, $92, $2d, $2d, $2d, $2d, $2d, $2d, $9a + // .byte $12, $20, $20, $1f, $20, $20, $9a, $20, $20, $1f, $20, $9a, $20, $20, $20, $20 + // .byte $1f, $20, $9a, $20, $20, $20, $20, $20, $1f, $20, $9a, $20, $20, $1f, $20, $9a + // .byte $20, $20, $1f, $20, $20, $96, $a3, $a3, $a3, $a3, $1f + // .byte $92, $0D, $0D, $05, $00 // Original Mega65 banner - supplied by Deft + // // .byte $9A,$12,$A3,$A3,$A3,$A3,$A3,$A3,$DF,$9B,$92,$20,$05,$12,$A0,$A0 // .byte $DF,$9B,$92,$20,$05,$12,$A0,$A0,$DF,$9B,$92,$20,$05,$12,$A0,$A0 // .byte $DF,$9B,$92,$20,$05,$12,$A0,$A0,$DF,$9A,$92,$20,$05,$20,$20,$20 @@ -113,4 +135,15 @@ pre_revision_string: // .byte $12,$DF,$92,$7F,$9B,$20,$9A,$20,$9B,"0.2.0.0",$0D // .byte $0D,$05,$92,$00 +#if ROM_LAYOUT_M65 + +text_mode_64: + + .text "LEGACY" + .byte $11, $9D, $9D, $9D, $9D, $9D + .text "MODE" + .byte $00 + +#endif + #endif From e7b4303e876c3dd1c56928bf5c589359b3059e48 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 5 Mar 2020 18:48:37 +0100 Subject: [PATCH 27/57] slightly altered chargen (VENDOR + G/M produces 1px bar) for Mega65 native mode --- .gitignore | 1 + Makefile | 10 ++- doc/Development.md | 6 ++ tools/patch_chargen.cc | 139 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 tools/patch_chargen.cc diff --git a/.gitignore b/.gitignore index e4515487..1f3eaccc 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ build/* dump.mem *project .*swp +*.log diff --git a/Makefile b/Makefile index 548e3a58..2e0fb537 100644 --- a/Makefile +++ b/Makefile @@ -80,6 +80,7 @@ DEP_KERNAL = $(SRC_KERNAL) $(SRCDIR_KERNAL) $(GEN_KERNAL) TOOL_COLLECT_DATA = build/tools/collect_data TOOL_COMPRESS_TEXT = build/tools/compress_text TOOL_GENERATE_CONSTANTS = build/tools/generate_constants +TOOL_PATCH_CHARGEN = build/tools/patch_chargen TOOL_PNGPREPARE = build/tools/pngprepare TOOL_BUILD_SEGMENT = build/tools/build_segment TOOL_RELEASE = build/tools/release @@ -172,7 +173,10 @@ build/tools/%: tools/%.cc tools/common.h # Rules - CHARGEN build/chargen.rom: $(TOOL_PNGPREPARE) assets/8x8font.png - $(TOOL_PNGPREPARE) charrom assets/8x8font.png build/chargen.rom + $(TOOL_PNGPREPARE) charrom assets/8x8font.png $@ + +build/chargen-patched.rom: $(TOOL_PATCH_CHARGEN) build/chargen.rom + $(TOOL_PATCH_CHARGEN) -i build/chargen.rom -o $@ -n 7px-OpenROMs # Dependencies - BASIC and KERNAL @@ -352,7 +356,7 @@ build/symbols_hybrid.vs: $(DIR_GEN)/KERNAL_combined.vs # Rules - platform 'Mega65' specific -$(TARGET_M65_x): $(SEG_LIST_M65) build/chargen.rom +$(TARGET_M65_x): $(SEG_LIST_M65) build/chargen.rom build/chargen-patched.rom dd if=/dev/zero bs=8192 count=1 of=build/m65_padding_08_KB dd if=/dev/zero bs=8192 count=8 of=build/m65_padding_64_KB cat build/m65_padding_08_KB > $(TARGET_M65_x) @@ -362,7 +366,7 @@ $(TARGET_M65_x): $(SEG_LIST_M65) build/chargen.rom cat build/m65_padding_08_KB >> $(TARGET_M65_x) cat $(DIR_M65)/basic.seg_0 >> $(TARGET_M65_x) cat build/chargen.rom >> $(TARGET_M65_x) - cat build/chargen.rom >> $(TARGET_M65_x) + cat build/chargen-patched.rom >> $(TARGET_M65_x) cat $(DIR_M65)/kernal.seg_0 >> $(TARGET_M65_x) cat build/m65_padding_64_KB >> $(TARGET_M65_x) rm -f build/m65_padding_* diff --git a/doc/Development.md b/doc/Development.md index 68cd49c6..27ab1690 100644 --- a/doc/Development.md +++ b/doc/Development.md @@ -59,6 +59,12 @@ There is no official PETSCII code for `TAB` - we can't utilize the ones from C12 Bits 3 and 4 are extension to the original variable, compatible with the C128 ROMs API. There is no official way to retrieve `NO_SCRL` status as of yet. The `40/80` key status cannot be retrieved in C64 mode at all (C128 hardware limitation). +#### Mega65 native mode + +Mega65 build starts in legacy mode, which is intended to be reasonably compatible with the C64 ROMs. However, a native Mega65 mode is planned too, to make it easier to utilise extra features of this machine. Soo far the following has been done: + +- Slightly different chargen. On C64 machines prewssing C= + G or C= + M key combinations produces the same visual result as C= + H or C= + N, respectively - despite keycap printing suggests they should produce tinner bars. This was intentional change in the C64 ROMs (compared to VIC-20), to prevent colour problems on 80s era TVs. Screen font used in the legacy mode duplicates this change, but the font intended for native mode has this change reverted back. + ## Tinkering with OpenROMs diff --git a/tools/patch_chargen.cc b/tools/patch_chargen.cc new file mode 100644 index 00000000..425b813a --- /dev/null +++ b/tools/patch_chargen.cc @@ -0,0 +1,139 @@ +// +// Utility to patch the character generator file to create +// font for Mega65 native mode and possibly other uses +// + +#include "common.h" + +#include + +#include +#include + +// +// Command line settings +// + +std::string CMD_inFile = "chargen.rom"; +std::string CMD_outFile = "chargen-native.rom"; +std::string CMD_name = "CHARGEN"; + +// +// Common helper functions +// + +void printUsage() +{ + std::cout << "\n" << + "usage: patch_chargen [-i ] [-o ] [-n name]" << "\n\n"; +} + +void printBanner() +{ + printBannerLineTop(); + std::cout << "// Generating patched font '" << CMD_name << "'" << "\n"; + printBannerLineBottom(); +} + +// +// Top-level functions +// + +void parseCommandLine(int argc, char **argv) +{ + int opt; + + // Retrieve command line options + + while ((opt = getopt(argc, argv, "i:o:n:")) != -1) + { + switch(opt) + { + case 'i': CMD_inFile = optarg; break; + case 'o': CMD_outFile = optarg; break; + case 'n': CMD_name = optarg; break; + default: printUsage(); ERROR(); + } + } +} + +// +// Font processing +// + +void processFont() +{ + std::vector fileContent; + + // Read the source file + + std::ifstream srcFile; + srcFile.open(CMD_inFile, std::ios::in | std::ios::binary | std::ios::ate); + + if (!srcFile.good()) ERROR(std::string("unable to open ROM file '") + CMD_inFile + "'"); + + auto srcSize = srcFile.tellg(); + if (srcSize != 4096) ERROR(std::string("incorrect size of ROM file '") + CMD_inFile + "'"); + + std::vector srcFileContent; + + fileContent.resize(srcSize); + srcFile.seekg (0, srcFile.beg); + srcFile.read((char *) fileContent.data(), fileContent.size()); + + if (!srcFile.good()) ERROR(std::string("unable to read ROM file '") + CMD_inFile + "'"); + srcFile.close(); + + // Patch the font + + for (uint8_t idx = 0; idx < 8; idx++) + { + // VENDOR + M - 2px width on C64 + + fileContent[0x67 * 8 + 0 + idx] = 0b00000001; // normal + fileContent[0x67 * 8 + 2048 + idx] = 0b00000001; // upper/lower case + fileContent[0xE7 * 8 + 0 + idx] = 0b11111110; // inversed + fileContent[0xE7 * 8 + 2048 + idx] = 0b11111110; // upper/lower case, inversed + + // VENDOR + G - 2px width on C64 + + fileContent[0x65 * 8 + 0 + idx] = 0b10000000; // normal + fileContent[0x65 * 8 + 2048 + idx] = 0b10000000; // upper/lower case + fileContent[0xE5 * 8 + 0 + idx] = 0b01111111; // inversed + fileContent[0xE5 * 8 + 2048 + idx] = 0b01111111; // upper/lower case, inversed + } + + // Remove old file + + unlink(CMD_outFile.c_str()); + + // Save the patched font + + std::ofstream outFile(CMD_outFile, std::fstream::out | std::ios::binary | std::fstream::trunc); + if (!outFile.good()) ERROR(std::string("can't open oputput file '") + CMD_outFile + "'"); + + outFile.write((const char*) fileContent.data(), fileContent.size()); + + if (!outFile.good()) + { + outFile.close(); + unlink(CMD_outFile.c_str()); + ERROR(std::string("can't write oputput file '") + CMD_outFile + "'"); + } + + outFile.close(); +} + +// +// Main function +// + +int main(int argc, char **argv) +{ + parseCommandLine(argc, argv); + + printBanner(); + processFont(); + + return 0; +} From 7dad715ffaff7575cf158aced01b4cebfdfce5e2 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 5 Mar 2020 19:26:13 +0100 Subject: [PATCH 28/57] spelling mistake fix --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 310d50d9..f4def5c1 100644 --- a/LICENSE +++ b/LICENSE @@ -3,7 +3,7 @@ The following copyright notices apply to the entirety of this package, including each source file, unless otherwise noted in each file or directory. Copyright Paul Gardner-Stephen, 2019. - Copyright Roman Standzikowski (FeralChil64), 2019-2020. + Copyright Roman Standzikowski (FeralChild64), 2019-2020. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by From b9661811579418f52d201d26fc4eca3e7f0e9c4f Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Fri, 6 Mar 2020 19:14:12 +0100 Subject: [PATCH 29/57] included PXL font v2.3, updated binaries --- CREDITS.md | 3 +- Makefile | 77 ++++++++++++++-------- bin/README.txt | 12 +++- bin/basic_generic.rom | Bin 8192 -> 8192 bytes bin/basic_testing.rom | Bin 8192 -> 8192 bytes bin/basic_ultimate64.rom | Bin 8192 -> 8192 bytes bin/{chargen.rom => chargen_openroms.rom} | Bin bin/chargen_pxlfont_2.3.rom | Bin 0 -> 4096 bytes bin/kernal_generic.rom | Bin 8192 -> 8192 bytes bin/kernal_testing.rom | Bin 8192 -> 8192 bytes bin/kernal_ultimate64.rom | Bin 8192 -> 8192 bytes bin/mega65.rom | Bin 131072 -> 131072 bytes bin/mega65_pxlfont.rom | Bin 0 -> 131072 bytes 13 files changed, 63 insertions(+), 29 deletions(-) rename bin/{chargen.rom => chargen_openroms.rom} (100%) create mode 100644 bin/chargen_pxlfont_2.3.rom create mode 100644 bin/mega65_pxlfont.rom diff --git a/CREDITS.md b/CREDITS.md index fb5040c3..bbf59ede 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -1,8 +1,9 @@ # CREDITS to people whose work was of great help to us -## for source code we reused +## for source code/assets we reused +* Retrofan - for his Mega65 banner artwork and PXLfont * TWW/CTR - for his keyboard handling code * Graham - for his PAL/NTSC detection routine * enthusi/Onslaught - for his example Turbo Tape 64 compatible loader diff --git a/Makefile b/Makefile index 2e0fb537..1768da54 100644 --- a/Makefile +++ b/Makefile @@ -91,29 +91,31 @@ TOOLS_LIST = $(pathsubst tools/%,build/tools/%,$(basename $(SRC_TOOLS))) # List of targets -TARGET_CUS_B = build/basic_custom.rom -TARGET_GEN_B = build/basic_generic.rom -TARGET_TST_B = build/basic_testing.rom -TARGET_U64_B = build/basic_ultimate64.rom +TARGET_CUS_B = build/basic_custom.rom +TARGET_GEN_B = build/basic_generic.rom +TARGET_TST_B = build/basic_testing.rom +TARGET_U64_B = build/basic_ultimate64.rom -TARGET_CUS_K = build/kernal_custom.rom -TARGET_GEN_K = build/kernal_generic.rom -TARGET_TST_K = build/kernal_testing.rom -TARGET_U64_K = build/kernal_ultimate64.rom +TARGET_CUS_K = build/kernal_custom.rom +TARGET_GEN_K = build/kernal_generic.rom +TARGET_TST_K = build/kernal_testing.rom +TARGET_U64_K = build/kernal_ultimate64.rom -TARGET_M65_x = build/mega65.rom -TARGET_X16_x = build/cx16-dummy.rom +TARGET_M65_x = build/mega65.rom +TARGET_M65_x_PXL = build/mega65_pxlfont.rom +TARGET_X16_x = build/cx16-dummy.rom -TARGET_LIST_CUS = $(TARGET_CUS_B) $(TARGET_CUS_K) -TARGET_LIST_GEN = $(TARGET_GEN_B) $(TARGET_GEN_K) -TARGET_LIST_TST = $(TARGET_TST_B) $(TARGET_TST_K) -TARGET_LIST_U64 = $(TARGET_U64_B) $(TARGET_U64_K) +TARGET_LIST_CUS = $(TARGET_CUS_B) $(TARGET_CUS_K) +TARGET_LIST_GEN = $(TARGET_GEN_B) $(TARGET_GEN_K) +TARGET_LIST_TST = $(TARGET_TST_B) $(TARGET_TST_K) +TARGET_LIST_U64 = $(TARGET_U64_B) $(TARGET_U64_K) -TARGET_LIST = build/chargen.rom \ +TARGET_LIST = build/chargen_openroms.rom \ $(TARGET_LIST_CUS) \ $(TARGET_LIST_GEN) \ $(TARGET_LIST_TST) \ $(TARGET_M65_x) \ + $(TARGET_M65_x_PXL) \ $(TARGET_LIST_U64) \ $(TARGET_X16_x) @@ -127,7 +129,7 @@ SEG_LIST_X16 = $(DIR_X16)/basic.seg_0 \ $(DIR_X16)/kernal.seg_0 \ $(DIR_X16)/kernal.seg_1 -REL_TARGET_LIST = $(TARGET_LIST_GEN) $(TARGET_LIST_TST) $(TARGET_M65_x) $(TARGET_LIST_U64) +REL_TARGET_LIST = $(TARGET_LIST_GEN) $(TARGET_LIST_TST) $(TARGET_M65_x) $(TARGET_M65_x_PXL) $(TARGET_LIST_U64) # Misc strings @@ -150,7 +152,7 @@ clean: updatebin: $(MAKE) -j64 --output-sync=target $(TARGET_LIST) $(TOOL_RELEASE) $(TOOL_RELEASE) -i ./build -o ./bin $(patsubst build/%,%,$(REL_TARGET_LIST)) - cp build/chargen.rom bin/chargen.rom + cp build/chargen_openroms.rom bin/chargen_openroms.rom # Rules - tools @@ -172,11 +174,17 @@ build/tools/%: tools/%.cc tools/common.h # Rules - CHARGEN -build/chargen.rom: $(TOOL_PNGPREPARE) assets/8x8font.png +build/chargen_openroms.rom: $(TOOL_PNGPREPARE) assets/8x8font.png $(TOOL_PNGPREPARE) charrom assets/8x8font.png $@ -build/chargen-patched.rom: $(TOOL_PATCH_CHARGEN) build/chargen.rom - $(TOOL_PATCH_CHARGEN) -i build/chargen.rom -o $@ -n 7px-OpenROMs +build/chargen_pxlfont.rom: bin/chargen_pxlfont_2.3.rom + cp $< $@ + +build/chargen_openroms.patched: $(TOOL_PATCH_CHARGEN) build/chargen_openroms.rom + $(TOOL_PATCH_CHARGEN) -i build/chargen_openroms.rom -o $@ -n 7px-OpenROMs + +build/chargen_pxlfont.patched: $(TOOL_PATCH_CHARGEN) build/chargen_pxlfont.rom + $(TOOL_PATCH_CHARGEN) -i build/chargen_pxlfont.rom -o $@ -n 6px-PXLfont # Dependencies - BASIC and KERNAL @@ -356,32 +364,49 @@ build/symbols_hybrid.vs: $(DIR_GEN)/KERNAL_combined.vs # Rules - platform 'Mega65' specific -$(TARGET_M65_x): $(SEG_LIST_M65) build/chargen.rom build/chargen-patched.rom +$(TARGET_M65_x) $(TARGET_M65_x_PXL): $(SEG_LIST_M65) build/chargen_openroms.rom build/chargen_openroms.patched build/chargen_pxlfont.rom build/chargen_pxlfont.patched dd if=/dev/zero bs=8192 count=1 of=build/m65_padding_08_KB dd if=/dev/zero bs=8192 count=8 of=build/m65_padding_64_KB + @echo cat build/m65_padding_08_KB > $(TARGET_M65_x) cat build/m65_padding_08_KB >> $(TARGET_M65_x) cat $(DIR_M65)/kernal.seg_1 >> $(TARGET_M65_x) cat $(DIR_M65)/basic.seg_1 >> $(TARGET_M65_x) cat build/m65_padding_08_KB >> $(TARGET_M65_x) cat $(DIR_M65)/basic.seg_0 >> $(TARGET_M65_x) - cat build/chargen.rom >> $(TARGET_M65_x) - cat build/chargen-patched.rom >> $(TARGET_M65_x) + cat build/chargen_openroms.rom >> $(TARGET_M65_x) + cat build/chargen_openroms.patched >> $(TARGET_M65_x) cat $(DIR_M65)/kernal.seg_0 >> $(TARGET_M65_x) cat build/m65_padding_64_KB >> $(TARGET_M65_x) + @echo + cat build/m65_padding_08_KB > $(TARGET_M65_x_PXL) + cat build/m65_padding_08_KB >> $(TARGET_M65_x_PXL) + cat $(DIR_M65)/kernal.seg_1 >> $(TARGET_M65_x_PXL) + cat $(DIR_M65)/basic.seg_1 >> $(TARGET_M65_x_PXL) + cat build/m65_padding_08_KB >> $(TARGET_M65_x_PXL) + cat $(DIR_M65)/basic.seg_0 >> $(TARGET_M65_x_PXL) + cat build/chargen_pxlfont.rom >> $(TARGET_M65_x_PXL) + cat build/chargen_pxlfont.patched >> $(TARGET_M65_x_PXL) + cat $(DIR_M65)/kernal.seg_0 >> $(TARGET_M65_x_PXL) + cat build/m65_padding_64_KB >> $(TARGET_M65_x_PXL) + @echo rm -f build/m65_padding_* + @echo # Rules - platform 'Commander X16' specific -$(TARGET_X16_x): $(SEG_LIST_X16) build/chargen.rom +$(TARGET_X16_x): $(SEG_LIST_X16) build/chargen_openroms.rom dd if=/dev/zero bs=8192 count=1 of=build/x16_padding_08_KB dd if=/dev/zero bs=8192 count=8 of=build/x16_padding_64_KB + @echo cat $(DIR_X16)/basic.seg_0 > $(TARGET_X16_x) cat $(DIR_X16)/kernal.seg_0 >> $(TARGET_X16_x) - cat build/chargen.rom >> $(TARGET_X16_x) + cat build/chargen_openroms.rom >> $(TARGET_X16_x) cat $(DIR_X16)/basic.seg_1 >> $(TARGET_X16_x) cat $(DIR_X16)/kernal.seg_1 >> $(TARGET_X16_x) + @echo rm -f build/x16_padding_* + @echo # Rules - tests @@ -407,7 +432,7 @@ test_testing: build/kernal_testing.rom build/basic_testing.rom build/symbols_tes test_ultimate64: build/kernal_ultimate64.rom build/basic_ultimate64.rom build/symbols_ultimate64.vs x64 -kernal build/kernal_ultimate64.rom -basic build/basic_ultimate64.rom -moncommands build/symbols_ultimate64.vs -1 $(TESTTAPE) -8 $(TESTDISK) -test_mega65: $(TARGET_M65_x) +test_mega65: $(TARGET_M65_x) $(TARGET_M65_PXL) ../xemu/build/bin/xmega65.native -dmarev 2 -forcerom -loadrom $(TARGET_M65_x) test_cx16: $(TARGET_X16_x) diff --git a/bin/README.txt b/bin/README.txt index de60839c..7358db92 100644 --- a/bin/README.txt +++ b/bin/README.txt @@ -2,14 +2,14 @@ Follow these rules, or bad things will happen! -- Don't mix ROMs for different platforms - use generic BASIC with generic KERNAL, Mega65 BASIC with Mega65 KERNAL, etc. +- Don't mix ROMs for different platforms - use generic BASIC with generic KERNAL, Ultimate64 BASIC with Ultimate64 KERNAL, etc. - Don't mix these ROMs with any other ROMs; exceptions: - kernal_hybrid.rom, which is meant to be used (and has to be used) with the original BASIC ROM; however, this hybrid ROM cannot be distributed due to legal/copyright reasons - - chargen.rom - this one is fully interchangeable + - chargen_*.rom - these ones are fully interchangeable - Don't mix ROMs from different builds/versions (again, CHARGEN is an exception). @@ -17,3 +17,11 @@ Follow these rules, or bad things will happen! Have fun! + + +------ + + +PXL font was created by Retrofan, we got a permission to include it with OpenROMs under GNU Lesser General Public License 3.0, see: + +- https://www.forum64.de/index.php?thread/84000-neuer-c64-systemfont-auch-plus4-c128-atari/&postID=1493383#post1493383 diff --git a/bin/basic_generic.rom b/bin/basic_generic.rom index 7828da6c6598c21531abe94742894e9f0a97f4ae..3818f62c7cfff7a7ec4d8684462b8e4b9504eabe 100644 GIT binary patch delta 3043 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 Af&c&j diff --git a/bin/basic_testing.rom b/bin/basic_testing.rom index 6d2c34fe09598e9bc988319b0afff43266036e27..abd477fa2c5f7051be49ed4b42aaba76a72c86c4 100644 GIT binary patch delta 2628 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 np74XalY4X+OF9TX=S2*Wshf)^=@y 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 delta 2759 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 delta 678 zcma)(O=uHQ5Xa~3S2v-U#U`{M>T3~ANDU>uXtlLSgDX4`dhpOw)GB-M=EW+q0sG2Q zzq0fs5(rB-WplBqLP*=Rxzr}T7z7U%M3dBj0WnbZAZUF_5j;AV_n$w%8D{3iMq{J# z33JS6Dt<2xu9l$8lZjL*w#bvUkK}9BL|x|E1zpc$yXpYV;zB0Qll~g+UMlr9c@n7E zcj$_Jm#*$R9@as^eM@AdQqK~91s`0US;ofm#RGU@#rCm^<2Bn$mszh|%l5YIatHHr zD~4gX3wr#6mOQb~2t9c~Q)jCQR@!F1w3vPB zy~XDdD!JpGzX6^4>`ovZk#ChPrICajpt4vj2<0D4xd!l?y<$Nu??wR-00$rd$bcl^ zIgkXz$;=cb01yTvDpcPSkyUO-r$0pku2hpG-(|#H< zC&P0uxih+bl|G4FqmLt#^ikwGeHghyAFzL7h4(LdwykLWKcZpR)j*8aHMiIZ=xMvb zlE!T7(9Suwj+Vw74&H27z3jDzN_)*t>u6i1PLJbfl@CA^$Fp&>h=8kerX(yMJ|WJ O0|Vjk;EPwn(4jxMp%k-mT8jOVDy$%|i1ZKC3U00V6AmO)@-7k+3>vdGXqg z5R!T^O~clYASdC_=beA{Al@+O(g`@V19yqU>?$${yy z3uadKISfJBEBR!P3?;dy8#JG4)4Zxh^Qg6&TctIZN1*;Qu6tdfR0d6~ zDU&Z5v{6JC=VAtDY-1=ITO|@AH&{xVmcp~61;=j^lapYQ6uT6@GddgoGUfOwi;=66 zD2po13f!fVc1^zK_<i3`!4@D~p+{QgGiRnCUjEAZTYl!oH6RTPEt0-hMTN0m1OM$9R`vUK^la>sH z1zy=v=|Wyt%@fs<7C_6TI2++5UJi^?6$SxOcv#uNLki#_FUIExA1fH6=mI}XEc@p2 zI`bbnKC^`D_UgRfoWvE)X_tr;v?SSCNaa-v^eI8m*d6g@!<{vP6+8s!uYcS4#FE0hr@ zX(;9u)T#i}^4)zy?E0kDrv>Qq7U&qt_3}W1z zcVQ+Gm9yk<7cb3gnSdp;x|VkP_>{qt>MLFBz;!bIoT5!4Du?Y@PC?dakj8VN$Kk~o zdW0BLle8fR1lV#X-YjZ;xN4lE^fqP98= zVqm~W20N{!wAMz9_bo`$q9|D@X*Wf1K}Ayqm65AuadEnINxWaWEZ!?!6z{^X zg4690Zb=o?^JeyI9Z*k${=_iKPSOb>Rvjn#?Oe{ei1WTDq7 z{q56lzO+|@6it-pR_c5}?zDS{aV5=pbuW2Og@(Lij3upRBb$864hpw8=UhgLc`}`eg7i$pYR+KGN7{4v%qm_2oPronj<4EKZ#MD6+%)1cQnqi}VTa44 zV-pe%V~DgSW1YMnTR#$XhhbzkuF`vOK~G+yQuKmt<(n zreEWek%=L)1kCckOWDp8;rjc2ym~7%Exx>+%^#8?;^>3MyHY$Je{|1ovCUrLm^)XK zwqs-~W6wFKIdm5jGto5ZBhQ|X&2n;-m1}7ot)~sNQStWI(%KleQD-yVKjZ$YE6BkC z?*v}3_YQCgA_#dr2s?SmFMvYVE^vExLlG2vN}#lC4-|T#oF#jqVjomi!F~(}st-b8 z4IHY4I#dt*9%w*~;A?^kKLjA!3=*_Jur&y6?T6tA1VbI2u=gkk$Cz|QLwYayw1BkY zWY6m_$u&zb9XIFJMm-kkU1a}B4yR{i+BHCBh1^)sE6I~t#gM~BSJ)6k>n`u05RT)D zsR3`lpZbl!AfkbRt#*wwN>n**l$WaVhB)bBkG|nbtFqyGD`u@_(W|JAePh+m;K|MZ fUL>4U9aZk%KhO2>Cr(}r1SP3eI{aeU*;(-irJ1CY delta 724 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 literal 0 HcmV?d00001 From 54a1c6addddd28cf71dd52f28be1a26b9e80ead4 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 8 Mar 2020 13:07:51 +0100 Subject: [PATCH 30/57] partial fix for multiplication breakage after rework --- c64/basic/math/mul_FAC2_FAC1.s | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/c64/basic/math/mul_FAC2_FAC1.s b/c64/basic/math/mul_FAC2_FAC1.s index 39fb256e..7f4c1ae0 100644 --- a/c64/basic/math/mul_FAC2_FAC1.s +++ b/c64/basic/math/mul_FAC2_FAC1.s @@ -60,7 +60,7 @@ mul_FAC2_FAC1: bcs !+ lda RESHO+1 sbc #$00 - bcs set_FAC1_zero + bcc set_FAC1_zero sta RESHO+1 !: lda RESHO+1 @@ -72,6 +72,7 @@ mul_FAC2_FAC1: // Multiply the mantissas jsr muldiv_RESHO_set_0 + clc // XXX maybe we should preserve .X on stack? this will not cost us too much From f51a7125561c9d5dce6109ebf74bdba7eefaf408 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 8 Mar 2020 13:22:44 +0100 Subject: [PATCH 31/57] floating point multiplication fix --- STATUS.md | 2 +- c64/basic/math/mul_FAC2_FAC1.s | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/STATUS.md b/STATUS.md index 2183672c..e8871678 100644 --- a/STATUS.md +++ b/STATUS.md @@ -199,7 +199,7 @@ Floating point mathematical routines - not official, but well known and broadly | `$B947` | `inv_FAC1_mantissa` | NOT DONE | | | `$B9EA` | `log_FAC1` | NOT DONE | | | `$BA28` | `mul_MEM_FAC1` | DONE | | -| `$BA2B` | `mul_FAC2_FAC1` | PARTIAL | needs retest after rework | +| `$BA2B` | `mul_FAC2_FAC1` | DONE | | | `$BA8C` | `mov_MEM_FAC2` | DONE | | | `$BA90` | `get_FAC2_via_INDEX` | NOT DONE | | | `$BAE2` | `mul10_FAC1` | DONE | | diff --git a/c64/basic/math/mul_FAC2_FAC1.s b/c64/basic/math/mul_FAC2_FAC1.s index 7f4c1ae0..20cafdd0 100644 --- a/c64/basic/math/mul_FAC2_FAC1.s +++ b/c64/basic/math/mul_FAC2_FAC1.s @@ -44,7 +44,7 @@ mul_FAC2_FAC1: eor FAC2_sign sta FAC1_sign - // Add the exponents (subtract the bias) XXX subroutines should be common with DIV + // Add the exponents (subtract the bias) - XXX can this be optimized somehow? jsr muldiv_RESHO_set_0 @@ -55,7 +55,7 @@ mul_FAC2_FAC1: jsr muldiv_RESHO_01_add_A lda RESHO+0 - sbc #($80 - $08) // we need to correct double BIAS and shifted mantissa + sbc #$80 // we need to correct double BIAS sta RESHO+0 bcs !+ lda RESHO+1 @@ -126,7 +126,6 @@ mul_FAC2_FAC1: adc #$08 bcs_16 set_FAC1_max // branch if overflow sta FAC1_exponent - jmp normal_FAC1 mul_FAC2_FAC1_by_A: From 2cd65c31441631e07e0345c0de73c243aab3b5af Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 8 Mar 2020 18:25:31 +0100 Subject: [PATCH 32/57] fixed some bugs with floating point division --- c64/basic/math/bb12.div_FAC2_FAC1.s | 18 +++++++++++------- c64/basic/math/div_FAC1_denorm.s | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/c64/basic/math/bb12.div_FAC2_FAC1.s b/c64/basic/math/bb12.div_FAC2_FAC1.s index 5532ca46..74f08e81 100644 --- a/c64/basic/math/bb12.div_FAC2_FAC1.s +++ b/c64/basic/math/bb12.div_FAC2_FAC1.s @@ -44,7 +44,7 @@ div_FAC2_FAC1: // Subtract the exponents - lda #($80 + $08) // correction for bias and shifted mantissa + lda #$80 // correction for bias sta RESHO+0 lda #$00 sta RESHO+1 @@ -55,14 +55,18 @@ div_FAC2_FAC1: lda RESHO+0 sec sbc FAC1_exponent + sta RESHO+0 bcs !+ lda RESHO+1 sbc #$00 + sta RESHO+1 bcc_16 set_FAC1_zero // result too low, set 0 and quit !: - lda RESHO+1 - bcc_16 set_FAC1_max // overflow + bne_16 set_FAC1_max // overflow + + lda RESHO+0 + sta FAC1_exponent // Divide the mantissas @@ -72,13 +76,13 @@ div_FAC2_FAC1: // Copy the result to FAC1 - XXX we probably already have similar code somewhere... - lda FAC2_mantissa+3 + lda RESHO+3 sta FAC1_mantissa+3 - lda FAC2_mantissa+2 + lda RESHO+2 sta FAC1_mantissa+2 - lda FAC2_mantissa+1 + lda RESHO+1 sta FAC1_mantissa+1 - lda FAC2_mantissa+0 + lda RESHO+0 sta FAC1_mantissa+0 lda #$00 diff --git a/c64/basic/math/div_FAC1_denorm.s b/c64/basic/math/div_FAC1_denorm.s index 5c40c4a8..4f93c876 100644 --- a/c64/basic/math/div_FAC1_denorm.s +++ b/c64/basic/math/div_FAC1_denorm.s @@ -63,7 +63,7 @@ div_FAC1_denorm_by_bit: ror FAC1_mantissa+3 ror FACOV - bcc div_FAC1_denorm_done // branch always + bcc div_FAC1_denorm_by_bit // branch always div_FAC1_denorm_done: From d7b8b958a079255c157f9d68b3296ee3c1a6b25d Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 8 Mar 2020 21:49:01 +0100 Subject: [PATCH 33/57] corrected wrong source of mantissa during division --- c64/basic/math/bb12.div_FAC2_FAC1.s | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/c64/basic/math/bb12.div_FAC2_FAC1.s b/c64/basic/math/bb12.div_FAC2_FAC1.s index 74f08e81..a32747c9 100644 --- a/c64/basic/math/bb12.div_FAC2_FAC1.s +++ b/c64/basic/math/bb12.div_FAC2_FAC1.s @@ -76,13 +76,13 @@ div_FAC2_FAC1: // Copy the result to FAC1 - XXX we probably already have similar code somewhere... - lda RESHO+3 + sta FAC2_mantissa+3 sta FAC1_mantissa+3 - lda RESHO+2 + sta FAC2_mantissa+2 sta FAC1_mantissa+2 - lda RESHO+1 + sta FAC2_mantissa+1 sta FAC1_mantissa+1 - lda RESHO+0 + sta FAC2_mantissa+0 sta FAC1_mantissa+0 lda #$00 From da68d8c44e2c0b33e71774685f0b1db5af5fa0bc Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Tue, 10 Mar 2020 20:33:23 +0100 Subject: [PATCH 34/57] updated KickAssembler to 5.13 --- assembler/KickAss.jar | Bin 625225 -> 625471 bytes assembler/KickAssembler.pdf | Bin 785388 -> 785388 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/assembler/KickAss.jar b/assembler/KickAss.jar index 3adf7b5e541ab80f17780106e7ed0b96d311401b..30bff10277d78fc080ec0183e09c420119a5ec52 100644 GIT binary patch delta 35137 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 aSPwNzNyBLQ=oT&yDNFo}J-4BIn*2W+IyYAU delta 34449 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 Z`~=4tDn6zsHYZjEN(Zw}rHG`B{tqYrQ=I?+ diff --git a/assembler/KickAssembler.pdf b/assembler/KickAssembler.pdf index 43d11e7383fd6047fc398940437781a6ea4a353e..6e471c0c62fa7974c561aa952f73df66275c3cce 100644 GIT binary patch delta 195 zcmaF!UH{E@{R#UyjSY;Aj7$tn%{HDm#=~o@YhWB=WMpMxU}b8yc{cAgMpU86b^JD{ zBF)G7+mG`z0x=U1GXpUT5VHa?8xXStF$WNH0x{S2v~p hI2yY;ni;vd8k-op8M-=|n^@Q>*bq`O{m^f2EdWomIoSXJ delta 195 zcmaF!UH{E@{R#Uy4UG(pj7&^T%{QJn#=~o^8X8)dI2jmPIvJRn8aUZ0*bq`O{m^f2EdW#MIkx}+ From b94a87a420f424d23317b8b82d7a3e77bb3f7865 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 14 Mar 2020 21:04:21 +0100 Subject: [PATCH 35/57] fix for PI symbol in Mega65 cchargen --- doc/Development.md | 3 +-- tools/patch_chargen.cc | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/Development.md b/doc/Development.md index 27ab1690..bc4c8ad7 100644 --- a/doc/Development.md +++ b/doc/Development.md @@ -63,8 +63,7 @@ Bits 3 and 4 are extension to the original variable, compatible with the C128 RO Mega65 build starts in legacy mode, which is intended to be reasonably compatible with the C64 ROMs. However, a native Mega65 mode is planned too, to make it easier to utilise extra features of this machine. Soo far the following has been done: -- Slightly different chargen. On C64 machines prewssing C= + G or C= + M key combinations produces the same visual result as C= + H or C= + N, respectively - despite keycap printing suggests they should produce tinner bars. This was intentional change in the C64 ROMs (compared to VIC-20), to prevent colour problems on 80s era TVs. Screen font used in the legacy mode duplicates this change, but the font intended for native mode has this change reverted back. - +- Slightly different chargen. On C64 machines pressing C= + G or C= + M key combinations produces the same visual result as C= + H or C= + N, respectively - despite keycap printing suggests they should produce tinner bars. This was intentional change in the C64 ROMs (compared to VIC-20), to prevent colour problems on 80s era TVs. Screen font used in the legacy mode duplicates this change, but the font intended for native mode has this change reverted back. Additionally, the π sign is available for lower/upper case set too. ## Tinkering with OpenROMs diff --git a/tools/patch_chargen.cc b/tools/patch_chargen.cc index 425b813a..49bef286 100644 --- a/tools/patch_chargen.cc +++ b/tools/patch_chargen.cc @@ -101,6 +101,11 @@ void processFont() fileContent[0x65 * 8 + 2048 + idx] = 0b10000000; // upper/lower case fileContent[0xE5 * 8 + 0 + idx] = 0b01111111; // inversed fileContent[0xE5 * 8 + 2048 + idx] = 0b01111111; // upper/lower case, inversed + + // PI character restoration for upper/lower case set + + fileContent[0x5E * 8 + 2048 + idx] = fileContent[0x5E * 8 + idx]; + fileContent[0xDE * 8 + 2048 + idx] = fileContent[0xDE * 8 + idx]; } // Remove old file From 0e538dd81de508c737463b05549883cb5a9f45e7 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Fri, 20 Mar 2020 18:43:56 +0100 Subject: [PATCH 36/57] fix for mantissa division --- c64/basic/math/div_mantissas.s | 45 ++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/c64/basic/math/div_mantissas.s b/c64/basic/math/div_mantissas.s index 0e50d6c9..d7771710 100644 --- a/c64/basic/math/div_mantissas.s +++ b/c64/basic/math/div_mantissas.s @@ -5,7 +5,7 @@ // Math package - mantissa division, based on code by Verz // // divident: FAC2_mantissa, divisor: FAC1_mantissa, result: FAC2_mantissa, remainder: RESHO -// temporary storage: INDEX+0, INDEX+1, INDEX+2, INDEX+3 +// temporary storage: INDEX+0, INDEX+1, INDEX+2, INDEX+3, .Y // // RESHO (remainder) should be set to 0 before // @@ -36,38 +36,51 @@ div_mantissas_loop: rol RESHO+1 rol RESHO+0 - // Subtract divisor to see if it fits in + // Subtract divisor from the remainder, result to INDEX and .Y - lda RESHO+4 sec + lda RESHO+4 + sbc FACOV + tay + + lda RESHO+3 sbc FAC1_mantissa+3 sta INDEX+3 - lda RESHO+3 + lda RESHO+2 sbc FAC1_mantissa+2 sta INDEX+2 - lda RESHO+2 + lda RESHO+1 sbc FAC1_mantissa+1 sta INDEX+1 - lda RESHO+1 + lda RESHO+0 sbc FAC1_mantissa+0 + + bcc div_mantissas_skip // if Carry is not set then divisor did not fit in remainder yet sta INDEX+0 - lda RESHO+0 - sbc #$00 - bcc div_mantissas_skip // if Carry is not set then divisor did not fit in yet + // Save subtraction result as new remainder - sta RESHO+0 // else save substraction result as new remainder, - lda INDEX+0 - sta RESHO+1 - lda INDEX+1 - sta RESHO+2 - lda INDEX+3 + tya sta RESHO+4 - inc FAC2_mantissa+3 // and INCrement result cause divisor fit in 1 times + lda INDEX+3 + sta RESHO+3 + + lda INDEX+2 + sta RESHO+2 + + lda INDEX+1 + sta RESHO+1 + + lda INDEX+0 + sta RESHO+0 + + // Increment result cause divisor fit in 1 times + + inc FAC2_mantissa+3 // FALLTROUGH From c535815a2330eab8fcb739cfc35ca1dedd105bfe Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Fri, 20 Mar 2020 19:11:08 +0100 Subject: [PATCH 37/57] fixed bug in copying mantissas --- c64/basic/math/bb12.div_FAC2_FAC1.s | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/c64/basic/math/bb12.div_FAC2_FAC1.s b/c64/basic/math/bb12.div_FAC2_FAC1.s index a32747c9..563422b1 100644 --- a/c64/basic/math/bb12.div_FAC2_FAC1.s +++ b/c64/basic/math/bb12.div_FAC2_FAC1.s @@ -76,13 +76,13 @@ div_FAC2_FAC1: // Copy the result to FAC1 - XXX we probably already have similar code somewhere... - sta FAC2_mantissa+3 + lda FAC2_mantissa+3 sta FAC1_mantissa+3 - sta FAC2_mantissa+2 + lda FAC2_mantissa+2 sta FAC1_mantissa+2 - sta FAC2_mantissa+1 + lda FAC2_mantissa+1 sta FAC1_mantissa+1 - sta FAC2_mantissa+0 + lda FAC2_mantissa+0 sta FAC1_mantissa+0 lda #$00 From 5a66a1b4d850731221e03e1eba90691425a00359 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Fri, 20 Mar 2020 19:33:24 +0100 Subject: [PATCH 38/57] moved some math routines to separate directory --- c64/basic/{math => math_mov}/bba2.interop | 0 c64/basic/{math => math_mov}/bba2.mov_MEM_FAC1.jmp.s | 0 c64/basic/{math => math_mov}/bbc7.interop | 0 c64/basic/{math => math_mov}/bbc7.mov_r_FAC1_TMP2.s | 0 c64/basic/{math => math_mov}/bbca.interop | 0 c64/basic/{math => math_mov}/bbca.mov_r_FAC1_TMP1.s | 0 c64/basic/{math => math_mov}/bbd0.interop | 0 c64/basic/{math => math_mov}/bbd0.mov_r_FAC1_VAR.s | 0 c64/basic/{math => math_mov}/bbd4.interop | 0 c64/basic/{math => math_mov}/bbd4.mov_r_FAC1_MEM.s | 0 c64/basic/{math => math_mov}/bbfc.interop | 0 c64/basic/{math => math_mov}/bbfc.mov_FAC2_FAC1.s | 0 c64/basic/{math => math_mov}/bc0c.interop | 0 c64/basic/{math => math_mov}/bc0c.mov_r_FAC1_FAC2.s | 0 c64/basic/{math => math_mov}/bc0f.interop | 0 c64/basic/{math => math_mov}/bc0f.mov_FAC1_FAC2.jmp.s | 0 c64/basic/{math => math_mov}/mov_FAC1_FAC2.s | 0 c64/basic/{math => math_mov}/mov_FAC1_MEM.s | 0 c64/basic/{math => math_mov}/mov_FAC2_FAC1.s | 0 c64/basic/{math => math_mov}/mov_MEM_FAC1.s | 0 c64/basic/{math => math_mov}/mov_MEM_FAC2.s | 0 c64/basic/{math => math_mov}/mov_r_FAC1_TMP1.s | 0 c64/basic/{math => math_mov}/mov_r_FAC1_TMP2.s | 0 23 files changed, 0 insertions(+), 0 deletions(-) rename c64/basic/{math => math_mov}/bba2.interop (100%) rename c64/basic/{math => math_mov}/bba2.mov_MEM_FAC1.jmp.s (100%) rename c64/basic/{math => math_mov}/bbc7.interop (100%) rename c64/basic/{math => math_mov}/bbc7.mov_r_FAC1_TMP2.s (100%) rename c64/basic/{math => math_mov}/bbca.interop (100%) rename c64/basic/{math => math_mov}/bbca.mov_r_FAC1_TMP1.s (100%) rename c64/basic/{math => math_mov}/bbd0.interop (100%) rename c64/basic/{math => math_mov}/bbd0.mov_r_FAC1_VAR.s (100%) rename c64/basic/{math => math_mov}/bbd4.interop (100%) rename c64/basic/{math => math_mov}/bbd4.mov_r_FAC1_MEM.s (100%) rename c64/basic/{math => math_mov}/bbfc.interop (100%) rename c64/basic/{math => math_mov}/bbfc.mov_FAC2_FAC1.s (100%) rename c64/basic/{math => math_mov}/bc0c.interop (100%) rename c64/basic/{math => math_mov}/bc0c.mov_r_FAC1_FAC2.s (100%) rename c64/basic/{math => math_mov}/bc0f.interop (100%) rename c64/basic/{math => math_mov}/bc0f.mov_FAC1_FAC2.jmp.s (100%) rename c64/basic/{math => math_mov}/mov_FAC1_FAC2.s (100%) rename c64/basic/{math => math_mov}/mov_FAC1_MEM.s (100%) rename c64/basic/{math => math_mov}/mov_FAC2_FAC1.s (100%) rename c64/basic/{math => math_mov}/mov_MEM_FAC1.s (100%) rename c64/basic/{math => math_mov}/mov_MEM_FAC2.s (100%) rename c64/basic/{math => math_mov}/mov_r_FAC1_TMP1.s (100%) rename c64/basic/{math => math_mov}/mov_r_FAC1_TMP2.s (100%) diff --git a/c64/basic/math/bba2.interop b/c64/basic/math_mov/bba2.interop similarity index 100% rename from c64/basic/math/bba2.interop rename to c64/basic/math_mov/bba2.interop diff --git a/c64/basic/math/bba2.mov_MEM_FAC1.jmp.s b/c64/basic/math_mov/bba2.mov_MEM_FAC1.jmp.s similarity index 100% rename from c64/basic/math/bba2.mov_MEM_FAC1.jmp.s rename to c64/basic/math_mov/bba2.mov_MEM_FAC1.jmp.s diff --git a/c64/basic/math/bbc7.interop b/c64/basic/math_mov/bbc7.interop similarity index 100% rename from c64/basic/math/bbc7.interop rename to c64/basic/math_mov/bbc7.interop diff --git a/c64/basic/math/bbc7.mov_r_FAC1_TMP2.s b/c64/basic/math_mov/bbc7.mov_r_FAC1_TMP2.s similarity index 100% rename from c64/basic/math/bbc7.mov_r_FAC1_TMP2.s rename to c64/basic/math_mov/bbc7.mov_r_FAC1_TMP2.s diff --git a/c64/basic/math/bbca.interop b/c64/basic/math_mov/bbca.interop similarity index 100% rename from c64/basic/math/bbca.interop rename to c64/basic/math_mov/bbca.interop diff --git a/c64/basic/math/bbca.mov_r_FAC1_TMP1.s b/c64/basic/math_mov/bbca.mov_r_FAC1_TMP1.s similarity index 100% rename from c64/basic/math/bbca.mov_r_FAC1_TMP1.s rename to c64/basic/math_mov/bbca.mov_r_FAC1_TMP1.s diff --git a/c64/basic/math/bbd0.interop b/c64/basic/math_mov/bbd0.interop similarity index 100% rename from c64/basic/math/bbd0.interop rename to c64/basic/math_mov/bbd0.interop diff --git a/c64/basic/math/bbd0.mov_r_FAC1_VAR.s b/c64/basic/math_mov/bbd0.mov_r_FAC1_VAR.s similarity index 100% rename from c64/basic/math/bbd0.mov_r_FAC1_VAR.s rename to c64/basic/math_mov/bbd0.mov_r_FAC1_VAR.s diff --git a/c64/basic/math/bbd4.interop b/c64/basic/math_mov/bbd4.interop similarity index 100% rename from c64/basic/math/bbd4.interop rename to c64/basic/math_mov/bbd4.interop diff --git a/c64/basic/math/bbd4.mov_r_FAC1_MEM.s b/c64/basic/math_mov/bbd4.mov_r_FAC1_MEM.s similarity index 100% rename from c64/basic/math/bbd4.mov_r_FAC1_MEM.s rename to c64/basic/math_mov/bbd4.mov_r_FAC1_MEM.s diff --git a/c64/basic/math/bbfc.interop b/c64/basic/math_mov/bbfc.interop similarity index 100% rename from c64/basic/math/bbfc.interop rename to c64/basic/math_mov/bbfc.interop diff --git a/c64/basic/math/bbfc.mov_FAC2_FAC1.s b/c64/basic/math_mov/bbfc.mov_FAC2_FAC1.s similarity index 100% rename from c64/basic/math/bbfc.mov_FAC2_FAC1.s rename to c64/basic/math_mov/bbfc.mov_FAC2_FAC1.s diff --git a/c64/basic/math/bc0c.interop b/c64/basic/math_mov/bc0c.interop similarity index 100% rename from c64/basic/math/bc0c.interop rename to c64/basic/math_mov/bc0c.interop diff --git a/c64/basic/math/bc0c.mov_r_FAC1_FAC2.s b/c64/basic/math_mov/bc0c.mov_r_FAC1_FAC2.s similarity index 100% rename from c64/basic/math/bc0c.mov_r_FAC1_FAC2.s rename to c64/basic/math_mov/bc0c.mov_r_FAC1_FAC2.s diff --git a/c64/basic/math/bc0f.interop b/c64/basic/math_mov/bc0f.interop similarity index 100% rename from c64/basic/math/bc0f.interop rename to c64/basic/math_mov/bc0f.interop diff --git a/c64/basic/math/bc0f.mov_FAC1_FAC2.jmp.s b/c64/basic/math_mov/bc0f.mov_FAC1_FAC2.jmp.s similarity index 100% rename from c64/basic/math/bc0f.mov_FAC1_FAC2.jmp.s rename to c64/basic/math_mov/bc0f.mov_FAC1_FAC2.jmp.s diff --git a/c64/basic/math/mov_FAC1_FAC2.s b/c64/basic/math_mov/mov_FAC1_FAC2.s similarity index 100% rename from c64/basic/math/mov_FAC1_FAC2.s rename to c64/basic/math_mov/mov_FAC1_FAC2.s diff --git a/c64/basic/math/mov_FAC1_MEM.s b/c64/basic/math_mov/mov_FAC1_MEM.s similarity index 100% rename from c64/basic/math/mov_FAC1_MEM.s rename to c64/basic/math_mov/mov_FAC1_MEM.s diff --git a/c64/basic/math/mov_FAC2_FAC1.s b/c64/basic/math_mov/mov_FAC2_FAC1.s similarity index 100% rename from c64/basic/math/mov_FAC2_FAC1.s rename to c64/basic/math_mov/mov_FAC2_FAC1.s diff --git a/c64/basic/math/mov_MEM_FAC1.s b/c64/basic/math_mov/mov_MEM_FAC1.s similarity index 100% rename from c64/basic/math/mov_MEM_FAC1.s rename to c64/basic/math_mov/mov_MEM_FAC1.s diff --git a/c64/basic/math/mov_MEM_FAC2.s b/c64/basic/math_mov/mov_MEM_FAC2.s similarity index 100% rename from c64/basic/math/mov_MEM_FAC2.s rename to c64/basic/math_mov/mov_MEM_FAC2.s diff --git a/c64/basic/math/mov_r_FAC1_TMP1.s b/c64/basic/math_mov/mov_r_FAC1_TMP1.s similarity index 100% rename from c64/basic/math/mov_r_FAC1_TMP1.s rename to c64/basic/math_mov/mov_r_FAC1_TMP1.s diff --git a/c64/basic/math/mov_r_FAC1_TMP2.s b/c64/basic/math_mov/mov_r_FAC1_TMP2.s similarity index 100% rename from c64/basic/math/mov_r_FAC1_TMP2.s rename to c64/basic/math_mov/mov_r_FAC1_TMP2.s From 46c4516354775315a4bf35416706eeff7e204d91 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 21 Mar 2020 15:03:49 +0100 Subject: [PATCH 39/57] added missing path to Makefile --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 1768da54..3478231d 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,7 @@ SRCDIR_BASIC = $(SRCDIR_COMMON) \ c64/basic/init \ c64/basic/math \ c64/basic/math_consts \ + c64/basic/math_mov \ c64/basic/print \ c64/basic/rom_revision From 2c768252861a626a7376dd3b756056e35165b812 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 21 Mar 2020 15:20:39 +0100 Subject: [PATCH 40/57] fix for FAC1 denormalization --- c64/basic/math/div_FAC1_denorm.s | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/c64/basic/math/div_FAC1_denorm.s b/c64/basic/math/div_FAC1_denorm.s index 4f93c876..fb1150f9 100644 --- a/c64/basic/math/div_FAC1_denorm.s +++ b/c64/basic/math/div_FAC1_denorm.s @@ -17,12 +17,12 @@ div_FAC1_denorm: bne div_FAC1_denorm_by_bit // branch if last byte of mantissa is non-zero lda FAC1_exponent - cmp #$09 - bcc div_FAC1_denorm_by_bit // branch if not suitable to decrement exponent by 8 + cmp #$F8 + bcs div_FAC1_denorm_by_bit // branch if not suitable to increment exponent by 8 - // Decrement exponent + // Increment exponent - sbc #$08 // Carry already set here + adc #$08 // Carry already clear sta FAC1_exponent // Move mantissa bytes @@ -47,12 +47,12 @@ div_FAC1_denorm_by_bit: bne div_FAC1_denorm_done // branch if lowest bit of mantissa is already 1 lda FAC1_exponent - cmp #$02 - bcc div_FAC1_denorm_done // branch if not suitable to decrement exponent + cmp #$FF + beq div_FAC1_denorm_done // branch if not suitable to decrement exponent // Decrement exponent - dec FAC1_exponent + inc FAC1_exponent // Move mantissa bits From e16118a331b123baa65e6ad51d256c8bd86724f4 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 21 Mar 2020 15:53:40 +0100 Subject: [PATCH 41/57] reversed botched attempt to increase FP division precission --- c64/basic/math/bb12.div_FAC2_FAC1.s | 5 +---- c64/basic/math/div_FAC1_denorm.s | 15 ++++++++------- c64/basic/math/div_mantissas.s | 18 +++++------------- 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/c64/basic/math/bb12.div_FAC2_FAC1.s b/c64/basic/math/bb12.div_FAC2_FAC1.s index 563422b1..583572dc 100644 --- a/c64/basic/math/bb12.div_FAC2_FAC1.s +++ b/c64/basic/math/bb12.div_FAC2_FAC1.s @@ -37,7 +37,7 @@ div_FAC2_FAC1: beq_16 set_FAC1_zero // Multiply signs - + lda FAC1_sign eor FAC2_sign sta FAC1_sign @@ -85,9 +85,6 @@ div_FAC2_FAC1: lda FAC2_mantissa+0 sta FAC1_mantissa+0 - lda #$00 - sta FACOV - // Normalize and quit jmp normal_FAC1 diff --git a/c64/basic/math/div_FAC1_denorm.s b/c64/basic/math/div_FAC1_denorm.s index fb1150f9..228eb88f 100644 --- a/c64/basic/math/div_FAC1_denorm.s +++ b/c64/basic/math/div_FAC1_denorm.s @@ -3,17 +3,21 @@ // #LAYOUT# * * #IGNORE // -// Math package - denormalize FAC1 mantissa and adapt its exponent accordingly, -// so that division is more precise +// Math package - denormalize FAC1 mantissa and adapt its exponent accordingly // // XXX test this div_FAC1_denorm: + // Set FACOV to 0, no need for increased precision here + + lda #$00 + sta FACOV + // Start by moving whole bytes, if possible - lda FACOV + lda FAC1_mantissa+3 bne div_FAC1_denorm_by_bit // branch if last byte of mantissa is non-zero lda FAC1_exponent @@ -27,8 +31,6 @@ div_FAC1_denorm: // Move mantissa bytes - lda FAC1_mantissa+3 - sta FACOV lda FAC1_mantissa+2 sta FAC1_mantissa+3 lda FAC1_mantissa+1 @@ -42,7 +44,7 @@ div_FAC1_denorm: div_FAC1_denorm_by_bit: - lda FACOV + lda FAC1_mantissa+3 and #$01 bne div_FAC1_denorm_done // branch if lowest bit of mantissa is already 1 @@ -61,7 +63,6 @@ div_FAC1_denorm_by_bit: ror FAC1_mantissa+1 ror FAC1_mantissa+2 ror FAC1_mantissa+3 - ror FACOV bcc div_FAC1_denorm_by_bit // branch always diff --git a/c64/basic/math/div_mantissas.s b/c64/basic/math/div_mantissas.s index d7771710..06c274aa 100644 --- a/c64/basic/math/div_mantissas.s +++ b/c64/basic/math/div_mantissas.s @@ -2,10 +2,10 @@ // #LAYOUT# * BASIC_0 #TAKE // #LAYOUT# * * #IGNORE -// Math package - mantissa division, based on code by Verz +// Math package - 32-bit mantissa division, based on code by Verz // -// divident: FAC2_mantissa, divisor: FAC1_mantissa, result: FAC2_mantissa, remainder: RESHO -// temporary storage: INDEX+0, INDEX+1, INDEX+2, INDEX+3, .Y +// divident: FAC2_mantissa, divisor: FAC1_mantissa (without FACOV), result: FAC2_mantissa, remainder: RESHO +// temporary storage: INDEX+0, INDEX+1, INDEX+2, INDEX+3 // // RESHO (remainder) should be set to 0 before // @@ -15,7 +15,7 @@ div_mantissas: - ldx #40 // repeat for each bit + ldx #32 // repeat for each bit // FALLTROUGH @@ -24,13 +24,12 @@ div_mantissas_loop: // Multiply divident by 2, msb -> Carry asl FAC2_mantissa+3 - rol FAC2_mantissa+2 + rol FAC2_mantissa+2 rol FAC2_mantissa+1 rol FAC2_mantissa+0 // Multiply remainder by 2, lsb <- Carry - rol RESHO+4 rol RESHO+3 rol RESHO+2 rol RESHO+1 @@ -39,10 +38,6 @@ div_mantissas_loop: // Subtract divisor from the remainder, result to INDEX and .Y sec - lda RESHO+4 - sbc FACOV - tay - lda RESHO+3 sbc FAC1_mantissa+3 sta INDEX+3 @@ -63,9 +58,6 @@ div_mantissas_loop: // Save subtraction result as new remainder - tya - sta RESHO+4 - lda INDEX+3 sta RESHO+3 From 922c881a232a41b6b2da8807ba052722a8c196fd Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 21 Mar 2020 16:14:38 +0100 Subject: [PATCH 42/57] fix for exponent manipulation during division --- c64/basic/math/bb12.div_FAC2_FAC1.s | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/c64/basic/math/bb12.div_FAC2_FAC1.s b/c64/basic/math/bb12.div_FAC2_FAC1.s index 583572dc..77b1d61f 100644 --- a/c64/basic/math/bb12.div_FAC2_FAC1.s +++ b/c64/basic/math/bb12.div_FAC2_FAC1.s @@ -44,26 +44,24 @@ div_FAC2_FAC1: // Subtract the exponents - lda #$80 // correction for bias + lda #$62 // correction for bias and FAC2 digits sta RESHO+0 lda #$00 sta RESHO+1 - lda FAC2_exponent + lda FAC2_exponent // add FAC2 exponent to temporary variable jsr muldiv_RESHO_01_add_A - lda RESHO+0 - sec - sbc FAC1_exponent - sta RESHO+0 - bcs !+ + lda RESHO+0 // subtract FAC1 exponent from temporary variable + sec + sbc FAC1_exponent + sta RESHO+0 + bcs !+ + dec RESHO+1 + !: - lda RESHO+1 - sbc #$00 - sta RESHO+1 - bcc_16 set_FAC1_zero // result too low, set 0 and quit -!: - bne_16 set_FAC1_max // overflow + lda RESHO+1 + bmi_16 set_FAC1_zero // result too low, set 0 and quit lda RESHO+0 sta FAC1_exponent @@ -71,6 +69,7 @@ div_FAC2_FAC1: // Divide the mantissas jsr div_FAC1_denorm + jsr muldiv_RESHO_set_0 jsr div_mantissas From a76b3e21b0d1c0b5b044be3aa5c17f10644877ba Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 21 Mar 2020 16:35:55 +0100 Subject: [PATCH 43/57] floating point division works now --- STATUS.md | 6 +++--- c64/basic/math/bb12.div_FAC2_FAC1.s | 6 +----- c64/basic/math/div_FAC1_denorm.s | 13 +++++-------- c64/basic/math/muldiv_RESHO_helpers.s | 1 + 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/STATUS.md b/STATUS.md index e8871678..de1ef7a8 100644 --- a/STATUS.md +++ b/STATUS.md @@ -203,9 +203,9 @@ Floating point mathematical routines - not official, but well known and broadly | `$BA8C` | `mov_MEM_FAC2` | DONE | | | `$BA90` | `get_FAC2_via_INDEX` | NOT DONE | | | `$BAE2` | `mul10_FAC1` | DONE | | -| `$BAFE` | `div10_FAC1_p` | PARTIAL | needs `div_FAC2_FAC1` | -| `$BB0F` | `div_MEM_FAC1` | PARTIAL | needs `div_FAC2_FAC1` | -| `$BB12` | `div_FAC2_FAC1` | PARTIAL | not tested yet | +| `$BAFE` | `div10_FAC1_p` | DONE | | +| `$BB0F` | `div_MEM_FAC1` | DONE | | +| `$BB12` | `div_FAC2_FAC1` | DONE | | | `$BBA2` | `mov_MEM_FAC1` | DONE | | | `$BBA6` | `get_FAC2_via_INDEX` | NOT DONE | | | `$BBC7` | `mov_r_FAC1_TMP2` | PARTIAL | not fully tested yet | diff --git a/c64/basic/math/bb12.div_FAC2_FAC1.s b/c64/basic/math/bb12.div_FAC2_FAC1.s index 77b1d61f..5bbf09d9 100644 --- a/c64/basic/math/bb12.div_FAC2_FAC1.s +++ b/c64/basic/math/bb12.div_FAC2_FAC1.s @@ -22,8 +22,6 @@ // - https://codebase64.org/doku.php?id=base:kernal_floating_point_mathematics // -// XXX test this code - div_FAC2_FAC1: // 'Pamiętaj, cholero - nie dziel przez zero!' - ancient polish proverb @@ -44,7 +42,7 @@ div_FAC2_FAC1: // Subtract the exponents - lda #$62 // correction for bias and FAC2 digits + lda #$A0 // correction for bias and FAC2 digits sta RESHO+0 lda #$00 sta RESHO+1 @@ -67,9 +65,7 @@ div_FAC2_FAC1: sta FAC1_exponent // Divide the mantissas - jsr div_FAC1_denorm - jsr muldiv_RESHO_set_0 jsr div_mantissas diff --git a/c64/basic/math/div_FAC1_denorm.s b/c64/basic/math/div_FAC1_denorm.s index 228eb88f..9e8bc371 100644 --- a/c64/basic/math/div_FAC1_denorm.s +++ b/c64/basic/math/div_FAC1_denorm.s @@ -3,11 +3,9 @@ // #LAYOUT# * * #IGNORE // -// Math package - denormalize FAC1 mantissa and adapt its exponent accordingly +// Math package - denormalize FAC1 mantissa and adapt its exponent accordingly for division // -// XXX test this - div_FAC1_denorm: // Set FACOV to 0, no need for increased precision here @@ -21,12 +19,12 @@ div_FAC1_denorm: bne div_FAC1_denorm_by_bit // branch if last byte of mantissa is non-zero lda FAC1_exponent - cmp #$F8 - bcs div_FAC1_denorm_by_bit // branch if not suitable to increment exponent by 8 + cmp #$08 + bcc div_FAC1_denorm_by_bit // branch if not suitable to increment exponent by 8 // Increment exponent - adc #$08 // Carry already clear + sbc #$08 // Carry already sec sta FAC1_exponent // Move mantissa bytes @@ -49,12 +47,11 @@ div_FAC1_denorm_by_bit: bne div_FAC1_denorm_done // branch if lowest bit of mantissa is already 1 lda FAC1_exponent - cmp #$FF beq div_FAC1_denorm_done // branch if not suitable to decrement exponent // Decrement exponent - inc FAC1_exponent + dec FAC1_exponent // Move mantissa bits diff --git a/c64/basic/math/muldiv_RESHO_helpers.s b/c64/basic/math/muldiv_RESHO_helpers.s index fef81a7b..7f73037f 100644 --- a/c64/basic/math/muldiv_RESHO_helpers.s +++ b/c64/basic/math/muldiv_RESHO_helpers.s @@ -18,6 +18,7 @@ muldiv_RESHO_set_0: rts + muldiv_RESHO_01_add_A: clc From dad5d219453dbc9daad5d31dc1da3ca166666a29 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Tue, 5 May 2020 20:13:29 +0200 Subject: [PATCH 44/57] added JiffyDOS byte read error detection --- c64/kernal/errors.s | 11 +++++++++++ c64/kernal/iec_fast/jiffydos_rx_byte.s | 10 +++++++++- c64/kernal/iec_fast/jiffydos_tx_byte.s | 5 +++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/c64/kernal/errors.s b/c64/kernal/errors.s index e1642238..e7bc9547 100644 --- a/c64/kernal/errors.s +++ b/c64/kernal/errors.s @@ -75,6 +75,17 @@ kernalerror_ILLEGAL_DEVICE_NUMBER: // FALLTROUGH +#if CONFIG_IEC_JIFFYDOS + +kernalerror_IEC_TIMEOUT_READ: + + lda #K_STS_TIMEOUT_READ + skip_2_bytes_trash_nvz + + // FALLTROUGH + +#endif // CONFIG_IEC_JIFFYDOS + kernalerror_TOP_MEM_RS232: lda #K_ERR_TOP_MEM_RS232 diff --git a/c64/kernal/iec_fast/jiffydos_rx_byte.s b/c64/kernal/iec_fast/jiffydos_rx_byte.s index 13406df8..01473045 100644 --- a/c64/kernal/iec_fast/jiffydos_rx_byte.s +++ b/c64/kernal/iec_fast/jiffydos_rx_byte.s @@ -86,8 +86,11 @@ jiffydos_rx_byte: // If CLK line active - success bvc jiffydos_rx_byte_end - // XXX the DATA line can probably be used to distinguish between file not found error and normal stream EOI + // EOI or error, released DATA (highest byte set to 1) means error - see protocol analysis by Michael Steil, step R7a + lda CIA2_PRA + bmi jiffydos_rx_byte_error + // EOI - no error jsr kernalstatus_EOI // FALLTROUGH @@ -109,5 +112,10 @@ jiffydos_rx_byte_end: // End byte reception jmp iec_rx_end +jiffydos_rx_byte_error: + + jsr kernalerror_IEC_TIMEOUT_READ + bcs jiffydos_rx_byte_end // branch always + #endif // CONFIG_IEC_JIFFYDOS diff --git a/c64/kernal/iec_fast/jiffydos_tx_byte.s b/c64/kernal/iec_fast/jiffydos_tx_byte.s index d600cc3f..e3ddcd06 100644 --- a/c64/kernal/iec_fast/jiffydos_tx_byte.s +++ b/c64/kernal/iec_fast/jiffydos_tx_byte.s @@ -100,6 +100,11 @@ jiffydos_tx_byte_wait_eoi: sta CIA2_PRA jsr iec_wait20us lda C3PO + + // According to protocol analysis by Michael Steil (step S8) we should pull the DATA here + // to signal there was no error; but DATA pulled by the controller is a normal state + // (which should be stored in C3PO), so there is nothing to do here. + jmp jiffydos_tx_byte_finalize From 37a4df415cdd7ace2bb1776fc93faa092f509a1b Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 7 May 2020 18:39:24 +0200 Subject: [PATCH 45/57] started work on better JiffyDOS LOAD routine --- c64/kernal/iec_fast/jiffydos_load.s | 79 ++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/c64/kernal/iec_fast/jiffydos_load.s b/c64/kernal/iec_fast/jiffydos_load.s index 0fc3a11b..3a4f1fed 100644 --- a/c64/kernal/iec_fast/jiffydos_load.s +++ b/c64/kernal/iec_fast/jiffydos_load.s @@ -6,7 +6,6 @@ // JiffyDOS protocol support for IEC - optimized load loop // - #if CONFIG_IEC_JIFFYDOS && !CONFIG_MEMORY_MODEL_60K @@ -20,12 +19,88 @@ jiffydos_load: +/* XXX NEW version, not yet finished + + // + // JiffyDOS protocol support for IEC - optimized load loop + // + // Based on description from https://github.com/mist64/cbmbus_doc + // + + // First we need to switch the device to optimized LOAD protocol, + // by making it talk on channel 1 instead of 0 + + jsr UNTLK + + lda FA + jsr TALK + // XXX bcs load_iec_err + + lda #$61 // ask to talk on channel 1 + sta TBTCNT + jsr iec_tx_command + // XXX bcs load_iec_error + // XXX if not on JiffyDOS protoccol, report error + // Timing is critical, do not allow interrupts sei #if CONFIG_IEC_JIFFYDOS_BLANK - // Preserve register with screen status (blank/visibe) + // Preserve register with screen status (blank/visible) + lda VIC_SCROLY + sta TBTCNT + + // Blank screen to make sure no sprite/badline will interrupt + jsr screen_off + +#else + + // Store previous sprite status in temporary variable + jsr jiffydos_prepare + sta TBTCNT + +#endif + + // FALLTROUGH + +jiffydos_load_mode_escape: + + // We are now in escape mode - release DATA so that we can read it + jsr iec_release_clk_data // XXX maybe release just data? + + // Wait till device tells us whether this is EOI/error + jsr iec_wait_for_clk_release + + // Check DATA line - if pulled, there is more data + bit CIA2_PRA + bpl jiffydos_load_mode_receive + + // XXX check for error + + + +jiffydos_load_mode_receive: + + + // Preserve 3 lowest bits of CIA2_PRA XXX deduplicate this + + lda CIA2_PRA + and #%00000111 + sta C3PO + + // XXX read data + +*/ + + + + // Timing is critical, do not allow interrupts + sei + +#if CONFIG_IEC_JIFFYDOS_BLANK + + // Preserve register with screen status (blank/visible) lda VIC_SCROLY sta TBTCNT From 31b3bc38c932b36bee82a03d60174cb9c872cc51 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Tue, 26 May 2020 22:21:23 +0200 Subject: [PATCH 46/57] handle all 4 SIDs on Mega65, tape turbo SFX should play on both left and right channels --- CONFIG.md | 4 ++-- c64/,,config_mega65.s | 2 +- c64/aliases/,aliases_config.s | 4 ++++ c64/aliases/,aliases_hardware.s | 9 +++++++++ c64/kernal/init/fda3.ioinit.s | 17 +++++++++++++++-- c64/kernal/tape/tape_common_autodetect.s | 5 +++++ c64/kernal/tape/tape_common_clean_sid.s | 15 +++++++++++++++ c64/kernal/tape/tape_turbo_get_bit.s | 10 ++++++++++ 8 files changed, 61 insertions(+), 5 deletions(-) diff --git a/CONFIG.md b/CONFIG.md index 48a6e652..35ae74b1 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -187,7 +187,7 @@ The SID support in the ROM is very limited - it only disables the sound during s ### `CONFIG_SID_2ND` and `CONFIG_SID_3RD` -Each of them add support for one additional SID - addresses should be given in `CONFIG_SID_2ND_ADDRESS` and `CONFIG_SID_3RD_ADDRESS`, respectively. +Each of them add support for one additional SID - addresses should be given in `CONFIG_SID_2ND_ADDRESS` and `CONFIG_SID_3RD_ADDRESS`, respectively. Do not use when `CONFIG_MB_MEGA_65` is selected - the motherboard support code already knows the SID locations. Each of these options needs 3 bytes in KERNAL segment. @@ -195,7 +195,7 @@ Each of these options needs 3 bytes in KERNAL segment. Cause the system to support SIDs in `$D4xx` and `$D5xx` ranges, respectively. -Each of them needs a couple of bytes in KERNAL segment - but they can share some code, and `$D4xx` range support replaces the standard `$D400` address handling, so exact amount depends on the exact configuration. +Each of them needs a couple of bytes in KERNAL segment - but they can share some code, and `$D4xx` range support replaces the standard `$D400` address handling, so exact amount depends on the exact configuration. Do not use when `CONFIG_MB_MEGA_65` is selected - the motherboard support code already knows the SID locations. ## Keyboard diff --git a/c64/,,config_mega65.s b/c64/,,config_mega65.s index 6bd9ee5c..d21b369f 100644 --- a/c64/,,config_mega65.s +++ b/c64/,,config_mega65.s @@ -58,7 +58,7 @@ // Multiple SID support -#define CONFIG_SID_2ND +// #define CONFIG_SID_2ND .const CONFIG_SID_2ND_ADDRESS = $D440 // #define CONFIG_SID_3RD diff --git a/c64/aliases/,aliases_config.s b/c64/aliases/,aliases_config.s index 57fb1c9f..752a452e 100644 --- a/c64/aliases/,aliases_config.s +++ b/c64/aliases/,aliases_config.s @@ -42,6 +42,10 @@ #if !CONFIG_PLATFORM_COMMODORE_64 && CONFIG_BRAND_ULTIMATE_64 && .error "CONFIG_BRAND_ULTIMATE_64 can only be used with CONFIG_PLATFORM_COMMODORE_64" #endif + +#if CONFIG_MB_MEGA_65 && (CONFIG_SID_2ND || CONFIG_SID_3RD || CONFIG_SID_D4XX || CONFIG_SID_D5XX) + .error "CONFIG_MB_MEGA_65 cannot be used with CONFIG_SID_*" +#endif } diff --git a/c64/aliases/,aliases_hardware.s b/c64/aliases/,aliases_hardware.s index e7a7a51c..f03458c9 100644 --- a/c64/aliases/,aliases_hardware.s +++ b/c64/aliases/,aliases_hardware.s @@ -83,6 +83,15 @@ .label __SID_BASE = $D400 // base address of the chip +#if CONFIG_MB_MEGA_65 + + .label __SID_R1_OFFSET = $00 // right SID 1, $D400 + .label __SID_R2_OFFSET = $20 // right SID 2, $D420 + .label __SID_L1_OFFSET = $40 // left SID 1, $D440 + .label __SID_L2_OFFSET = $60 // left SID 2, $D460 + +#endif + .label SID_FRELO1 = $D400 .label SID_FREHI1 = $D401 .label SID_PWLO1 = $D402 diff --git a/c64/kernal/init/fda3.ioinit.s b/c64/kernal/init/fda3.ioinit.s index 35d07223..b5cfc31d 100644 --- a/c64/kernal/init/fda3.ioinit.s +++ b/c64/kernal/init/fda3.ioinit.s @@ -59,10 +59,12 @@ IOINIT: // Now silence the SID chip(s), depending on the configuration - we want them silent ASAP // - // First the standard chip (skip if it is covered by whole $D4XX range) - lda #$00 +#if !CONFIG_MB_MEGA65 + + // First the standard chip (skip if it is covered by whole $D4XX range) + #if !CONFIG_SID_D4XX sta SID_SIGVOL #endif // !CONFIG_SID_D4XX @@ -100,6 +102,17 @@ IOINIT: #endif // CONFIG_SID_D4XX || CONFIG_SID_D5XX +#else + + // Mega65 specific handling - it contains 4 SIDs + + sta SID_SIGVOL + __SID_R1_OFFSET + sta SID_SIGVOL + __SID_R2_OFFSET + sta SID_SIGVOL + __SID_L1_OFFSET + sta SID_SIGVOL + __SID_L2_OFFSET + +#endif // CONFIG_MB_MEGA65 + // // Now continue the CIAs initialization // diff --git a/c64/kernal/tape/tape_common_autodetect.s b/c64/kernal/tape/tape_common_autodetect.s index 5ea9aebe..07f60842 100644 --- a/c64/kernal/tape/tape_common_autodetect.s +++ b/c64/kernal/tape/tape_common_autodetect.s @@ -17,7 +17,12 @@ tape_common_autodetect: lda #$0B sta VIC_EXTCOL lda #$00 +#if CONFIG_MB_MEGA65 + sta SID_SIGVOL + __SID_R1_OFFSET + sta SID_SIGVOL + __SID_L1_OFFSET +#else sta SID_SIGVOL +#endif // FALLTROUGH diff --git a/c64/kernal/tape/tape_common_clean_sid.s b/c64/kernal/tape/tape_common_clean_sid.s index a320faef..f91b8c6e 100644 --- a/c64/kernal/tape/tape_common_clean_sid.s +++ b/c64/kernal/tape/tape_common_clean_sid.s @@ -15,7 +15,22 @@ tape_clean_sid: lda #$00 ldy #$1C !: + +#if CONFIG_MB_MEGA65 + + // It should be safer than cleaning whole $D400-D47C range + + sta __SID_BASE + __SID_R1_OFFSET, y + sta __SID_BASE + __SID_R2_OFFSET, y + sta __SID_BASE + __SID_L1_OFFSET, y + sta __SID_BASE + __SID_L2_OFFSET, y + +#else + sta __SID_BASE, y + +#endif + dey bpl !- diff --git a/c64/kernal/tape/tape_turbo_get_bit.s b/c64/kernal/tape/tape_turbo_get_bit.s index a903a4d5..f2718cff 100644 --- a/c64/kernal/tape/tape_turbo_get_bit.s +++ b/c64/kernal/tape/tape_turbo_get_bit.s @@ -23,7 +23,12 @@ tape_turbo_get_bit: sta __turbo_half_S // store half of the last measurement result for short pulse lda #$01 +#if CONFIG_MB_MEGA65 + sta SID_SIGVOL + __SID_R1_OFFSET + sta SID_SIGVOL + __SID_L1_OFFSET +#else sta SID_SIGVOL +#endif lda #$06 sta VIC_EXTCOL sec @@ -34,7 +39,12 @@ tape_turbo_get_bit: sta __turbo_half_L // store half of the last measurement result for long pulse lda #$00 +#if CONFIG_MB_MEGA65 + sta SID_SIGVOL + __SID_R1_OFFSET + sta SID_SIGVOL + __SID_L1_OFFSET +#else sta SID_SIGVOL +#endif sta VIC_EXTCOL clc rts From 3476aed27767691e3f9174b8e5bab7eea2cdf189 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Tue, 26 May 2020 22:28:10 +0200 Subject: [PATCH 47/57] updated KickAssembler to 5.15 --- assembler/KickAss.jar | Bin 625471 -> 625707 bytes assembler/KickAssembler.pdf | Bin 785388 -> 785388 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/assembler/KickAss.jar b/assembler/KickAss.jar index 30bff10277d78fc080ec0183e09c420119a5ec52..1ea5cc88703c8e7822bfa34b2397dcbfe38f4439 100644 GIT binary patch delta 52554 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 O4e4azum@SP)&B$h7?!U9 delta 52825 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 V#QmFUGW@lKMcIXI!2qkM}YohUnx* zeoG9&=2QIbr}!Cxmss(WMyJt1s2>qkM}YohUnx* zeoG9&=2QIbr}!Cxm Date: Sat, 30 May 2020 15:44:06 +0200 Subject: [PATCH 48/57] for Mega65 disable the extended stack on cold/warm restart --- c64/aliases/,aliases_cpu.s | 5 +++++ c64/kernal/init/fce2.hw_entry_reset.s | 12 +++++++++--- c64/kernal/interrupts/fe66.default_brk_handler.s | 10 ++++++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/c64/aliases/,aliases_cpu.s b/c64/aliases/,aliases_cpu.s index b45f73f3..755b6dda 100644 --- a/c64/aliases/,aliases_cpu.s +++ b/c64/aliases/,aliases_cpu.s @@ -69,6 +69,11 @@ #if HAS_OPCODES_65CE02 +// CPU flags support + +.pseudocommand cle { .byte $02 } +.pseudocommand see { .byte $03 } + // .B register support .pseudocommand tab { .byte $5B } diff --git a/c64/kernal/init/fce2.hw_entry_reset.s b/c64/kernal/init/fce2.hw_entry_reset.s index 0d36a2d6..2ada16d4 100644 --- a/c64/kernal/init/fce2.hw_entry_reset.s +++ b/c64/kernal/init/fce2.hw_entry_reset.s @@ -11,10 +11,16 @@ hw_entry_reset: // The GPL program at https://github.com/Klaus2m5/6502_65C02_functional_tests/blob/master/6502_functional_test.a65 // uses the similar initial reset sequence, affirmed by c64 PRG p269 - sei // disable the interrupts, as fast as possible - they are disabled in case of HW reset, - // but this routine can be also called manually + sei // disable the interrupts, as fast as possible - they are disabled in case of HW reset, + // but this routine can be also called manually - cld // required for all CPUs - due to possibility of manual call + cld // required for all CPUs - due to possibility of manual call + +#if HAS_OPCODES_65CE02 + + see // disable extended stack + +#endif ldx #$FF txs diff --git a/c64/kernal/interrupts/fe66.default_brk_handler.s b/c64/kernal/interrupts/fe66.default_brk_handler.s index 668462f3..782a0d6b 100644 --- a/c64/kernal/interrupts/fe66.default_brk_handler.s +++ b/c64/kernal/interrupts/fe66.default_brk_handler.s @@ -12,11 +12,17 @@ default_brk_handler: #if CONFIG_PLATFORM_COMMODORE_64 ldx #$00 - sta VIC_SCROLX // turn the display off - we want as little screen artifacts as possible + sta VIC_SCROLX // turn the display off - we want as little screen artifacts as possible #endif - cld // make sure this dangerous flag is disabled + cld // make sure this dangerous flag is disabled + +#if HAS_OPCODES_65CE02 + + see // disable extended stack + +#endif jsr JRESTOR jsr JIOINIT From 4e4f2f1565b2425454d8d06dd12d11291b6b46e9 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 30 May 2020 15:52:54 +0200 Subject: [PATCH 49/57] added RMBx and SMBx instructions of 65CE02 --- c64/aliases/,aliases_cpu.s | 116 ++++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/c64/aliases/,aliases_cpu.s b/c64/aliases/,aliases_cpu.s index 755b6dda..38a321dc 100644 --- a/c64/aliases/,aliases_cpu.s +++ b/c64/aliases/,aliases_cpu.s @@ -104,7 +104,121 @@ .byte $E3, arg } -// additional addressing modes +// Zero page bit handling + +.pseudocommand rmb0 addr +{ + .var arg = addr.getValue() + .if (arg > $FF) .error "RMB0 requires zeropage address" + .byte $07, arg +} + +.pseudocommand rmb1 addr +{ + .var arg = addr.getValue() + .if (arg > $FF) .error "RMB1 requires zeropage address" + .byte $17, arg +} + +.pseudocommand rmb2 addr +{ + .var arg = addr.getValue() + .if (arg > $FF) .error "RMB2 requires zeropage address" + .byte $27, arg +} + +.pseudocommand rmb3 addr +{ + .var arg = addr.getValue() + .if (arg > $FF) .error "RMB3 requires zeropage address" + .byte $37, arg +} + +.pseudocommand rmb4 addr +{ + .var arg = addr.getValue() + .if (arg > $FF) .error "RMB4 requires zeropage address" + .byte $47, arg +} + +.pseudocommand rmb5 addr +{ + .var arg = addr.getValue() + .if (arg > $FF) .error "RMB5 requires zeropage address" + .byte $57, arg +} + +.pseudocommand rmb6 addr +{ + .var arg = addr.getValue() + .if (arg > $FF) .error "RMB6 requires zeropage address" + .byte $67, arg +} + +.pseudocommand rmb7 addr +{ + .var arg = addr.getValue() + .if (arg > $FF) .error "RMB7 requires zeropage address" + .byte $77, arg +} + +.pseudocommand smb0 addr +{ + .var arg = addr.getValue() + .if (arg > $FF) .error "SMB0 requires zeropage address" + .byte $87, arg +} + +.pseudocommand smb1 addr +{ + .var arg = addr.getValue() + .if (arg > $FF) .error "SMB1 requires zeropage address" + .byte $97, arg +} + +.pseudocommand smb2 addr +{ + .var arg = addr.getValue() + .if (arg > $FF) .error "SMB2 requires zeropage address" + .byte $A7, arg +} + +.pseudocommand smb3 addr +{ + .var arg = addr.getValue() + .if (arg > $FF) .error "SMB3 requires zeropage address" + .byte $B7, arg +} + +.pseudocommand smb4 addr +{ + .var arg = addr.getValue() + .if (arg > $FF) .error "SMB4 requires zeropage address" + .byte $C7, arg +} + +.pseudocommand smb5 addr +{ + .var arg = addr.getValue() + .if (arg > $FF) .error "SMB5 requires zeropage address" + .byte $D7, arg +} + +.pseudocommand smb6 addr +{ + .var arg = addr.getValue() + .if (arg > $FF) .error "SMB6 requires zeropage address" + .byte $E7, arg +} + +.pseudocommand smb7 addr +{ + .var arg = addr.getValue() + .if (arg > $FF) .error "SMB7 requires zeropage address" + .byte $F7, arg +} + +// Additional addressing modes .pseudocommand jsr_ind addr { From 0b9ee76e2f536e24e6063d74fa8f5bb5e6224c64 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 31 May 2020 19:20:35 +0200 Subject: [PATCH 50/57] tweaked Mega65 tape settings for tape adapters --- c64/,,config_mega65.s | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/c64/,,config_mega65.s b/c64/,,config_mega65.s index d21b369f..5799194a 100644 --- a/c64/,,config_mega65.s +++ b/c64/,,config_mega65.s @@ -51,8 +51,8 @@ #define CONFIG_TAPE_NORMAL #define CONFIG_TAPE_TURBO #define CONFIG_TAPE_AUTODETECT -// #define CONFIG_TAPE_NO_KEY_SENSE -// #define CONFIG_TAPE_NO_MOTOR_CONTROL +#define CONFIG_TAPE_NO_KEY_SENSE +#define CONFIG_TAPE_NO_MOTOR_CONTROL // #define CONFIG_TAPE_NO_ERROR_CORRECTION @@ -114,7 +114,7 @@ #define CONFIG_PANIC_SCREEN #define CONFIG_DOS_WEDGE -// #define CONFIG_TAPE_WEDGE +#define CONFIG_TAPE_WEDGE #define CONFIG_BCD_SAFE_INTERRUPTS From 9168115679638165ff1b18f80e1048042a6c1e4a Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 31 May 2020 20:27:51 +0200 Subject: [PATCH 51/57] preparation for no-badline tape loading on Mega65 --- c64/kernal/assets/kernal_messages.s | 11 +++++++++++ c64/kernal/board_m65/mega65_imports.s | 1 + c64/kernal/tape/tape_common.s | 9 +++++++++ c64/kernal/tape/tape_common_screen.s | 3 +++ 4 files changed, 24 insertions(+) diff --git a/c64/kernal/assets/kernal_messages.s b/c64/kernal/assets/kernal_messages.s index 3808770d..6825712f 100644 --- a/c64/kernal/assets/kernal_messages.s +++ b/c64/kernal/assets/kernal_messages.s @@ -21,6 +21,9 @@ #if CONFIG_TAPE_NORMAL || CONFIG_TAPE_TURBO .label __MSG_KERNAL_PRESS_PLAY = __msg_kernalplay - __msg_kernal_first .label __MSG_KERNAL_FOUND = __msg_kernalfound - __msg_kernal_first +#if CONFIG_MB_MEGA_65 +.label __MSG_KERNAL_OK_SEARCHING = __msg_kernaloksearching - __msg_kernal_first +#endif #endif #if CONFIG_SHOW_PAL_NTSC @@ -78,6 +81,14 @@ __msg_kernalfound: .text "FOUND" .byte $80 + $20 // end of string mark + space +#if CONFIG_MB_MEGA_65 + +__msg_kernaloksearching: + .text "OK, SEARCHING" + .byte $80 + $0D // end of string mark + return + +#endif + #endif #if CONFIG_SHOW_PAL_NTSC diff --git a/c64/kernal/board_m65/mega65_imports.s b/c64/kernal/board_m65/mega65_imports.s index d06b0bdb..cd63f523 100644 --- a/c64/kernal/board_m65/mega65_imports.s +++ b/c64/kernal/board_m65/mega65_imports.s @@ -45,6 +45,7 @@ .label print_return = KERNAL_0.proxy_K1_print_return .label __MSG_KERNAL_PRESS_PLAY = KERNAL_0.__MSG_KERNAL_PRESS_PLAY +.label __MSG_KERNAL_OK_SEARCHING = KERNAL_0.__MSG_KERNAL_OK_SEARCHING .label __MSG_KERNAL_FOUND = KERNAL_0.__MSG_KERNAL_FOUND #endif diff --git a/c64/kernal/tape/tape_common.s b/c64/kernal/tape/tape_common.s index 94d125b0..851f0eeb 100644 --- a/c64/kernal/tape/tape_common.s +++ b/c64/kernal/tape/tape_common.s @@ -73,6 +73,15 @@ tape_wait_play_loop: bit CIA1_ICR // $DC0D beq !- +#endif + +#if CONFIG_MB_MEGA_65 + + // Display confirmation + + ldx #__MSG_KERNAL_OK_SEARCHING + jsr print_kernal_message + #endif // FALLTROUGH diff --git a/c64/kernal/tape/tape_common_screen.s b/c64/kernal/tape/tape_common_screen.s index aaf7a150..2d0ef177 100644 --- a/c64/kernal/tape/tape_common_screen.s +++ b/c64/kernal/tape/tape_common_screen.s @@ -11,6 +11,9 @@ #if CONFIG_TAPE_NORMAL || CONFIG_TAPE_TURBO +// XXX for Mega65 do not disable screen, just disable badline emulation + + tape_screen_on_motor_off: jsr tape_motor_off From df00cc507d3a94fb3006847093fafc397cbd4c0e Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 31 May 2020 21:17:30 +0200 Subject: [PATCH 52/57] improved tape adapter handling --- CONFIG.md | 2 +- c64/kernal/tape/tape_common.s | 35 ++++++++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/CONFIG.md b/CONFIG.md index 35ae74b1..f548ee4f 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -167,7 +167,7 @@ Needs about 100 more bytes in KERNAL segment. ### `CONFIG_TAPE_NO_KEY_SENSE` -Enable this option if you are using a tape interface adapter with some audio signal source connected. These adapters lack key sense functionality, so the computer is unable to tell whether Play got pressed or not - with this option ROM will assume Play got pressed after impulses start arriving from the tape. +Enable this option if you are using a tape interface adapter with some audio signal source connected. These adapters lack key sense functionality, so the computer is unable to tell whether Play got pressed or not - this option changes the ROM behaviour, so that it can detect Play pressed when impulses start arriving from the tape. ### `CONFIG_TAPE_NO_MOTOR_CONTROL` diff --git a/c64/kernal/tape/tape_common.s b/c64/kernal/tape/tape_common.s index 851f0eeb..fa813aef 100644 --- a/c64/kernal/tape/tape_common.s +++ b/c64/kernal/tape/tape_common.s @@ -61,20 +61,49 @@ tape_wait_play_loop: #else + // The ROM is configured for tape adapter without the key sense - but it is still + // possible, that regular Datasette or Tapuino is connected + + lda CPU_R6510 + and #$10 + beq tape_wait_first_pulse // branch if button reported pressed, most likely really no key sense + + // We have key sense - perform regular waiting +!: + jsr STOP + bcs tape_break_error + + lda CPU_R6510 + and #$10 + beq !- + +tape_wait_first_pulse: + // We have no key sense - so just turn the motor on and wait for the first pulse jsr tape_motor_on - lda #$10 !: + jsr STOP + bcs tape_break_error + + lda #$10 bit CIA1_ICR // $DC0D bne !- !: + jsr STOP + bcs tape_break_error + + lda #$10 bit CIA1_ICR // $DC0D beq !- #endif + // FALLTROUGH + +tape_wait_play_done: + #if CONFIG_MB_MEGA_65 // Display confirmation @@ -84,10 +113,6 @@ tape_wait_play_loop: #endif - // FALLTROUGH - -tape_wait_play_done: - // Prepare for reading lda #$01 From 1f5f43b211974ac2c2edc4721ab281486bc423e3 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 31 May 2020 22:55:00 +0200 Subject: [PATCH 53/57] no-badline tape loading for Mega65, some macro fixes --- c64/aliases/,aliases_config.s | 6 ++--- c64/aliases/,aliases_hardware.s | 2 ++ c64/kernal/assets/kernal_messages.s | 6 +++-- c64/kernal/board_m65/mega65_imports.s | 3 +-- c64/kernal/board_m65/mega65_unhide.s | 24 +++++++++++++++++++ c64/kernal/init/fda3.ioinit.s | 4 ++-- c64/kernal/keyboard/scnkey.s | 8 ++----- c64/kernal/screen/screen_off.s | 2 +- c64/kernal/screen/screen_on.s | 3 ++- c64/kernal/tape/tape_common_autodetect.s | 2 +- c64/kernal/tape/tape_common_clean_sid.s | 2 +- c64/kernal/tape/tape_common_screen.s | 30 ++++++++++++++++++++++++ c64/kernal/tape/tape_turbo_get_bit.s | 4 ++-- 13 files changed, 75 insertions(+), 21 deletions(-) create mode 100644 c64/kernal/board_m65/mega65_unhide.s diff --git a/c64/aliases/,aliases_config.s b/c64/aliases/,aliases_config.s index 752a452e..ebf44ae2 100644 --- a/c64/aliases/,aliases_config.s +++ b/c64/aliases/,aliases_config.s @@ -112,9 +112,9 @@ #if ROM_LAYOUT_M65 && !CONFIG_CPU_M65_45GS02 .error "Mega65 ROM layout requires CONFIG_CPU_M65_45GS02" #endif -//#if ROM_LAYOUT_M65 && !CONFIG_MB_MEGA_65 -// .error "Mega65 ROM layout requires CONFIG_MB_MEGA_65" -//#endif +#if ROM_LAYOUT_M65 && !CONFIG_MB_MEGA_65 + .error "Mega65 ROM layout requires CONFIG_MB_MEGA_65" +#endif .var selected = 0; diff --git a/c64/aliases/,aliases_hardware.s b/c64/aliases/,aliases_hardware.s index f03458c9..bdd0f5e5 100644 --- a/c64/aliases/,aliases_hardware.s +++ b/c64/aliases/,aliases_hardware.s @@ -186,6 +186,8 @@ .const C65_EXTKEYS_PR = $D607 .const C65_EXTKEYS_DDR = $D608 + .const M65_BADL_SLI = $D710 + #endif diff --git a/c64/kernal/assets/kernal_messages.s b/c64/kernal/assets/kernal_messages.s index 6825712f..3c876dc9 100644 --- a/c64/kernal/assets/kernal_messages.s +++ b/c64/kernal/assets/kernal_messages.s @@ -84,8 +84,10 @@ __msg_kernalfound: #if CONFIG_MB_MEGA_65 __msg_kernaloksearching: - .text "OK, SEARCHING" - .byte $80 + $0D // end of string mark + return + .text "OK" + .byte $0D, $0D + .text "SEARCHIN" + .byte $80 + $47 // end of string mark + 'G' #endif diff --git a/c64/kernal/board_m65/mega65_imports.s b/c64/kernal/board_m65/mega65_imports.s index cd63f523..e09cabb0 100644 --- a/c64/kernal/board_m65/mega65_imports.s +++ b/c64/kernal/board_m65/mega65_imports.s @@ -25,8 +25,7 @@ #if CONFIG_TAPE_NORMAL || CONFIG_TAPE_TURBO -.label screen_on = KERNAL_0.screen_on -.label screen_off = KERNAL_0.screen_off +.label mega65_unhide = KERNAL_0.mega65_unhide .label tape_motor_on = KERNAL_0.tape_motor_on .label tape_motor_off = KERNAL_0.tape_motor_off diff --git a/c64/kernal/board_m65/mega65_unhide.s b/c64/kernal/board_m65/mega65_unhide.s new file mode 100644 index 00000000..3fa9b1c9 --- /dev/null +++ b/c64/kernal/board_m65/mega65_unhide.s @@ -0,0 +1,24 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# X16 * #IGNORE +// #LAYOUT# * KERNAL_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Routine to unhide Mega65 extra registers +// + + +#if CONFIG_KEYBOARD_C65 || (CONFIG_MB_MEGA_65 && (CONFIG_TAPE_NORMAL || CONFIG_TAPE_TURBO)) + + +mega65_unhide: + + lda #$A5 + sta VIC_KEY + lda #$96 + sta VIC_KEY + + rts + + +#endif diff --git a/c64/kernal/init/fda3.ioinit.s b/c64/kernal/init/fda3.ioinit.s index b5cfc31d..9e67a661 100644 --- a/c64/kernal/init/fda3.ioinit.s +++ b/c64/kernal/init/fda3.ioinit.s @@ -61,7 +61,7 @@ IOINIT: lda #$00 -#if !CONFIG_MB_MEGA65 +#if !CONFIG_MB_MEGA_65 // First the standard chip (skip if it is covered by whole $D4XX range) @@ -111,7 +111,7 @@ IOINIT: sta SID_SIGVOL + __SID_L1_OFFSET sta SID_SIGVOL + __SID_L2_OFFSET -#endif // CONFIG_MB_MEGA65 +#endif // CONFIG_MB_MEGA_65 // // Now continue the CIAs initialization diff --git a/c64/kernal/keyboard/scnkey.s b/c64/kernal/keyboard/scnkey.s index 12161598..ae1421ff 100644 --- a/c64/kernal/keyboard/scnkey.s +++ b/c64/kernal/keyboard/scnkey.s @@ -48,14 +48,10 @@ SCNKEY: // mode when done. This is not ideal, but as MEGA65s start C65 mode with VIC-IV IO mode // selected anyway, it should not be a big problem in practice. - lda #$A5 - sta VIC_KEY - lda #$96 - sta VIC_KEY - + jsr mega65_unhide jsr scnkey_viciv_mode - sta VIC_KEY + sta VIC_KEY // hide Mega65 registers rts scnkey_viciv_mode: diff --git a/c64/kernal/screen/screen_off.s b/c64/kernal/screen/screen_off.s index f7ef6d62..133127a3 100644 --- a/c64/kernal/screen/screen_off.s +++ b/c64/kernal/screen/screen_off.s @@ -8,7 +8,7 @@ // -#if CONFIG_TAPE_NORMAL || CONFIG_TAPE_TURBO || (CONFIG_IEC_JIFFYDOS && !CONFIG_MEMORY_MODEL_60K) +#if ((CONFIG_TAPE_NORMAL || CONFIG_TAPE_TURBO) && !CONFIG_MB_MEGA_65) || (CONFIG_IEC_JIFFYDOS && !CONFIG_MEMORY_MODEL_60K) screen_off: diff --git a/c64/kernal/screen/screen_on.s b/c64/kernal/screen/screen_on.s index 6d49d4a4..22853c22 100644 --- a/c64/kernal/screen/screen_on.s +++ b/c64/kernal/screen/screen_on.s @@ -8,7 +8,7 @@ // -#if CONFIG_TAPE_NORMAL || CONFIG_TAPE_TURBO +#if (CONFIG_TAPE_NORMAL || CONFIG_TAPE_TURBO) && !CONFIG_MB_MEGA_65 screen_on: @@ -19,4 +19,5 @@ screen_on: rts + #endif diff --git a/c64/kernal/tape/tape_common_autodetect.s b/c64/kernal/tape/tape_common_autodetect.s index 07f60842..bad0c45e 100644 --- a/c64/kernal/tape/tape_common_autodetect.s +++ b/c64/kernal/tape/tape_common_autodetect.s @@ -17,7 +17,7 @@ tape_common_autodetect: lda #$0B sta VIC_EXTCOL lda #$00 -#if CONFIG_MB_MEGA65 +#if CONFIG_MB_MEGA_65 sta SID_SIGVOL + __SID_R1_OFFSET sta SID_SIGVOL + __SID_L1_OFFSET #else diff --git a/c64/kernal/tape/tape_common_clean_sid.s b/c64/kernal/tape/tape_common_clean_sid.s index f91b8c6e..41083007 100644 --- a/c64/kernal/tape/tape_common_clean_sid.s +++ b/c64/kernal/tape/tape_common_clean_sid.s @@ -16,7 +16,7 @@ tape_clean_sid: ldy #$1C !: -#if CONFIG_MB_MEGA65 +#if CONFIG_MB_MEGA_65 // It should be safer than cleaning whole $D400-D47C range diff --git a/c64/kernal/tape/tape_common_screen.s b/c64/kernal/tape/tape_common_screen.s index 2d0ef177..19264dee 100644 --- a/c64/kernal/tape/tape_common_screen.s +++ b/c64/kernal/tape/tape_common_screen.s @@ -21,8 +21,23 @@ tape_screen_on_motor_off: lda COLSTORE sta VIC_EXTCOL +#if !CONFIG_MB_MEGA_65 + jmp screen_on +#else + + // On Mega65 just reenable badline emulation + + lda #$FF + sta M65_BADL_SLI + sta VIC_KEY + + rts + +#endif + + tape_screen_off_motor_on: // We do not want interrupts and CHROUT reenables them @@ -36,7 +51,22 @@ tape_screen_off_motor_on: lda VIC_EXTCOL sta COLSTORE +#if !CONFIG_MB_MEGA_65 + jsr screen_off + +#else + + // On Mega65 we do not have to turn the screen off; + // it is enough to disable badline emulation + + jsr mega65_unhide + lda #$00 + sta M65_BADL_SLI + +#endif + + jmp tape_motor_on #endif diff --git a/c64/kernal/tape/tape_turbo_get_bit.s b/c64/kernal/tape/tape_turbo_get_bit.s index f2718cff..d2cf4f6a 100644 --- a/c64/kernal/tape/tape_turbo_get_bit.s +++ b/c64/kernal/tape/tape_turbo_get_bit.s @@ -23,7 +23,7 @@ tape_turbo_get_bit: sta __turbo_half_S // store half of the last measurement result for short pulse lda #$01 -#if CONFIG_MB_MEGA65 +#if CONFIG_MB_MEGA_65 sta SID_SIGVOL + __SID_R1_OFFSET sta SID_SIGVOL + __SID_L1_OFFSET #else @@ -39,7 +39,7 @@ tape_turbo_get_bit: sta __turbo_half_L // store half of the last measurement result for long pulse lda #$00 -#if CONFIG_MB_MEGA65 +#if CONFIG_MB_MEGA_65 sta SID_SIGVOL + __SID_R1_OFFSET sta SID_SIGVOL + __SID_L1_OFFSET #else From 5d45c166e73a2c4111cb62c01958f21f45487e44 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 1 Jun 2020 15:26:05 +0200 Subject: [PATCH 54/57] support for LOAD command without parameters, some cleanup --- CREDITS.md | 1 + Makefile | 17 ++++--- STATUS.md | 2 +- c64/basic/commands/cmd_load.s | 26 +++++++++- c64/kernal/iec_fast/jiffydos_load.s | 75 +---------------------------- 5 files changed, 37 insertions(+), 84 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index bbf59ede..d4bef889 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -19,6 +19,7 @@ * Jochen Adler - for the JiffyDOS protocol reverse engineering * H2Obsession - for the JiffyDOS protocol description on [his page](https://sites.google.com/site/h2obsession/CBM/C128/JiffySoft128) * SD2IEC team - the project [source code](https://github.com/rkrajnc/sd2iec) helped a lot when adding IEC and JiffyDOS support +* Luigi Di Fraia - for his tape formats [description](https://www.luigidifraia.com/c64/docs/tapeloaders.html) * slark - for his screen codes / PETSCII description at [slark.me](https://slark.me) * silverdr - for the floating point routines [description](https://codebase64.org/doku.php?id=base:kernal_floating_point_mathematics) * the [C64 Wiki](https://www.c64-wiki.com) contributors diff --git a/Makefile b/Makefile index 3478231d..2181f8c2 100644 --- a/Makefile +++ b/Makefile @@ -140,11 +140,14 @@ HYBRID_WARNING = "*** WARNING *** Distributing kernal_hybrid.rom violates both o GIT_COMMIT:= $(shell git log -1 --pretty='%h' | tr '[:lower:]' '[:upper:]') -# Rules - main +# Rules - main XXX fast build does not always succeed, not yet clear, why -.PHONY: all clean updatebin +.PHONY: all fast clean updatebin all: + $(MAKE) $(TARGET_LIST) $(EXT_TARGET_LIST) + +fast: $(MAKE) -j64 --output-sync=target $(TARGET_LIST) $(EXT_TARGET_LIST) clean: @@ -223,7 +226,7 @@ $(DIR_M65)/kernal.seg_1 $(DIR_M65)/KERNAL_1_combined.vs $(DIR_M65)/KERNAL_1_comb $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_KERNAL) $(CFG_M65) $(DIR_M65)/KERNAL_0_combined.sym $(DIR_X16)/basic.seg_1 $(DIR_X16)/BASIC_1_combined.vs $(DIR_X16)/BASIC_1_combined.sym: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_BASIC) $(CFG_X16) $(DIR_M65)/KERNAL_0_combined.sym $(DIR_X16)/BASIC_0_combined.sym + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_BASIC) $(CFG_X16) $(DIR_X16)/KERNAL_0_combined.sym $(DIR_X16)/BASIC_0_combined.sym $(DIR_X16)/kernal.seg_1 $(DIR_X16)/KERNAL_1_combined.vs $(DIR_X16)/KERNAL_1_combined.sym: \ $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_KERNAL) $(CFG_X16) $(DIR_X16)/KERNAL_0_combined.sym @@ -298,22 +301,22 @@ $(DIR_M65)/kernal.seg_1 $(DIR_M65)/KERNAL_1_combined.vs $(DIR_M65)/KERNAL_1_comb $(DIR_X16)/OUTB_0.BIN $(DIR_X16)/BASIC_0_combined.vs $(DIR_X16)/BASIC_0_combined.sym: @mkdir -p $(DIR_X16) @rm -f $@* $(DIR_X16)/BASIC_0* - @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r X16 -s BASIC_0 -i BASIC_0-mega65 -o OUTB_0.BIN -d $(DIR_X16) -l c000 -h e4d2 $(CFG_X16) $(SRCDIR_BASIC) $(GEN_BASIC) + @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r X16 -s BASIC_0 -i BASIC_0-x16 -o OUTB_0.BIN -d $(DIR_X16) -l c000 -h e4d2 $(CFG_X16) $(SRCDIR_BASIC) $(GEN_BASIC) $(DIR_X16)/OUTK_0.BIN $(DIR_X16)/KERNAL_0_combined.vs $(DIR_X16)/KERNAL_0_combined.sym: @mkdir -p $(DIR_X16) @rm -f $@* $(DIR_X16)/KERNAL_0* - @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r X16 -s KERNAL_0 -i KERNAL_0-mega65 -o OUTK_0.BIN -d $(DIR_X16) -l e4d3 -h ffff $(CFG_X16) $(SRCDIR_KERNAL) $(GEN_KERNAL) + @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r X16 -s KERNAL_0 -i KERNAL_0-x16 -o OUTK_0.BIN -d $(DIR_X16) -l e4d3 -h ffff $(CFG_X16) $(SRCDIR_KERNAL) $(GEN_KERNAL) $(DIR_X16)/basic.seg_1 $(DIR_X16)/BASIC_1_combined.vs $(DIR_X16)/BASIC_1_combined.sym: @mkdir -p $(DIR_X16) @rm -f $@* $(DIR_X16)/basic.seg_1 $(DIR_X16)/BASIC_1* - @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r X16 -s BASIC_1 -i BASIC_1-mega65 -o basic.seg_1 -d $(DIR_X16) -l a000 -h bfff $(CFG_X16) $(SRCDIR_BASIC) $(GEN_BASIC) + @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r X16 -s BASIC_1 -i BASIC_1-x16 -o basic.seg_1 -d $(DIR_X16) -l a000 -h bfff $(CFG_X16) $(SRCDIR_BASIC) $(GEN_BASIC) $(DIR_X16)/kernal.seg_1 $(DIR_X16)/KERNAL_1_combined.vs $(DIR_X16)/KERNAL_1_combined.sym: @mkdir -p $(DIR_X16) @rm -f $@* $(DIR_X16)/kernal.seg_1 $(DIR_X16)/KERNAL_1* - @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r X16 -s KERNAL_1 -i KERNAL_1-mega65 -o kernal.seg_1 -d $(DIR_X16) -l a000 -h bfff $(CFG_X16) $(SRCDIR_KERNAL) $(GEN_KERNAL) + @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r X16 -s KERNAL_1 -i KERNAL_1-x16 -o kernal.seg_1 -d $(DIR_X16) -l a000 -h bfff $(CFG_X16) $(SRCDIR_KERNAL) $(GEN_KERNAL) # Rules - BASIC and KERNAL diff --git a/STATUS.md b/STATUS.md index de1ef7a8..e8013b30 100644 --- a/STATUS.md +++ b/STATUS.md @@ -98,7 +98,7 @@ The following ROM features are currently missing: | Driver | Status | Remarks | | :----------------: | :------: | :------------------------------------------------: | | standard | DONE | | -| JiffyDOS | DONE | | +| JiffyDOS | PARTIAL | LOAD needs improvement for better performance | | DolphinDOS | DONE | | | CIA burst mod | NOT DONE | | | Mega65 burst | NOT DONE | | diff --git a/c64/basic/commands/cmd_load.s b/c64/basic/commands/cmd_load.s index 17f1fee7..756da06b 100644 --- a/c64/basic/commands/cmd_load.s +++ b/c64/basic/commands/cmd_load.s @@ -20,11 +20,33 @@ cmd_load: lda #$00 sta FNLEN - // Without tape support, LOAD must have a filename - // (This also skips any leading spaces) + // Check for the file name jsr basic_end_of_statement_check bcc !+ + +#if CONFIG_TAPE_NORMAL || CONFIG_TAPE_TURBO + + // No file name given, just load the first file from tape + + ldx #$00 + stx SA // secondary address +#if CONFIG_TAPE_NORMAL + inx // 1 - for normal tape format +#else + ldx #$07 // 7 - for turbo tape format +#endif + stx FA // device number + bne cmd_load_got_secondaryaddress // branch always + +#else + + // Without tape support, LOAD must have a filename + // (This also skips any leading spaces) + jmp do_MISSING_FILENAME_error + +#endif + !: jsr basic_fetch_and_consume_character cmp #$22 diff --git a/c64/kernal/iec_fast/jiffydos_load.s b/c64/kernal/iec_fast/jiffydos_load.s index 3a4f1fed..f8487e42 100644 --- a/c64/kernal/iec_fast/jiffydos_load.s +++ b/c64/kernal/iec_fast/jiffydos_load.s @@ -19,80 +19,7 @@ jiffydos_load: -/* XXX NEW version, not yet finished - - // - // JiffyDOS protocol support for IEC - optimized load loop - // - // Based on description from https://github.com/mist64/cbmbus_doc - // - - // First we need to switch the device to optimized LOAD protocol, - // by making it talk on channel 1 instead of 0 - - jsr UNTLK - - lda FA - jsr TALK - // XXX bcs load_iec_err - - lda #$61 // ask to talk on channel 1 - sta TBTCNT - jsr iec_tx_command - // XXX bcs load_iec_error - // XXX if not on JiffyDOS protoccol, report error - - // Timing is critical, do not allow interrupts - sei - -#if CONFIG_IEC_JIFFYDOS_BLANK - - // Preserve register with screen status (blank/visible) - lda VIC_SCROLY - sta TBTCNT - - // Blank screen to make sure no sprite/badline will interrupt - jsr screen_off - -#else - - // Store previous sprite status in temporary variable - jsr jiffydos_prepare - sta TBTCNT - -#endif - - // FALLTROUGH - -jiffydos_load_mode_escape: - - // We are now in escape mode - release DATA so that we can read it - jsr iec_release_clk_data // XXX maybe release just data? - - // Wait till device tells us whether this is EOI/error - jsr iec_wait_for_clk_release - - // Check DATA line - if pulled, there is more data - bit CIA2_PRA - bpl jiffydos_load_mode_receive - - // XXX check for error - - - -jiffydos_load_mode_receive: - - - // Preserve 3 lowest bits of CIA2_PRA XXX deduplicate this - - lda CIA2_PRA - and #%00000111 - sta C3PO - - // XXX read data - -*/ - + // XXX implement JiffyDOS optimized LOAD protocol, this one is ineffective // Timing is critical, do not allow interrupts From 7a92eb2e62c63efba6ec2b69232b9d97ce1a305d Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 1 Jun 2020 15:37:17 +0200 Subject: [PATCH 55/57] added defaults for LOAD when no tape support is present --- c64/basic/commands/cmd_load.s | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/c64/basic/commands/cmd_load.s b/c64/basic/commands/cmd_load.s index 756da06b..08d2b93c 100644 --- a/c64/basic/commands/cmd_load.s +++ b/c64/basic/commands/cmd_load.s @@ -40,10 +40,17 @@ cmd_load: #else - // Without tape support, LOAD must have a filename - // (This also skips any leading spaces) + // Without tape support, try to load the first file from disk - jmp do_MISSING_FILENAME_error + lda #$01 // name length + ldx #cmd_load_default_filename + jsr JSETNAM + jmp got_filename + +cmd_load_default_filename: + + .text "*" #endif From 6a61d93a03905e1eb0f603ac495d4d2af472d982 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 1 Jun 2020 15:58:54 +0200 Subject: [PATCH 56/57] tweaked configuration, updated binaries --- bin/basic_generic.rom | Bin 8192 -> 8192 bytes bin/basic_testing.rom | Bin 8192 -> 8192 bytes bin/basic_ultimate64.rom | Bin 8192 -> 8192 bytes bin/kernal_generic.rom | Bin 8192 -> 8192 bytes bin/kernal_testing.rom | Bin 8192 -> 8192 bytes bin/kernal_ultimate64.rom | Bin 8192 -> 8192 bytes bin/mega65.rom | Bin 131072 -> 131072 bytes bin/mega65_pxlfont.rom | Bin 131072 -> 131072 bytes c64/,,config_mega65.s | 2 +- 9 files changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/basic_generic.rom b/bin/basic_generic.rom index 3818f62c7cfff7a7ec4d8684462b8e4b9504eabe..906796474fb0b9639cb96e6d3ff3001157544d34 100644 GIT binary patch delta 1010 zcmcgrT}+c#82-K%SW9g}iK{KGa7<>2nIY(fAGfP8TlRokngx zw+ktty17k7$9MpRZd!*_tIqB#^@8ZV=OpJm&pB`M zyzhIS(^Az^>Ken6NO{9NahuJLh0W2Gh#i{dqR8GElz$ z+dz3|6FGf`gy^;0P3cq$H6P`wecYj*hlhHj+v!@(qMUtQ6CvRXx>r-8m%2LUw|^MT zYG2y%vBZ&EDb;$COaud(2Ym2^HlR2d!3A8zCH#ON(T@R0;g0ZS{DdnQ#7u9v`zo$s zMc2=`jv+*G12^#tj)qj>U-2w-3%}uaZ0-I7w{Zt|F^qe-k3TVjzc3154C9!<13bhe zrVzv5_y>>h7;!woznI2T%p61l&+r^cyueGm!hd*;6u2?|JsfyBRiQ84zO0;V*1*kUb)uWOA5PuoHv)u8<$EljL)#$ zvrKC6M$#e5*+a6E`EtCR988AB1z*fYHycgVW>nKXMuRSykSfW|R8uEuJ4ZrOzD4wV zgFcJ(SW*w`K z$fhOS2-_>V*dDQweJMKGZqXsM_R^TK+$0=7Z?lnaMr2=kQp6o0ZD;)&awkk;J+#kM zm2O?iw4LrRDx*iupBB7RXS&{GB5lVh^HN2%oK7=yMa|59Mdi^?szf_$l!cwLutRjp zw~qKQb1mVcI%bb+2kZv7!|il8x?P@0TWuY`#=50sd1>j2(q(i<(ZVw3&kn@%eMA;v h0kZiK^UI5@B|qca^{}r*H`^uJ|6Sfsl8MahVA0k_F-}Vmjy{S5;Ofm#@@mg62C7eIr;yeJWrlW zem!+Pb+XB@Ia+RP7utkYp+%?^Dui;uAqc#(M)A=yUZHsDDqgO5=t}NT+_aPnlbYaC zD)3V3;45i4FQb(c?PKE)o$-1@t5%m**rTj%OY>5)o=iR9A3VvP)|0A{xZU`(e&=y2 z$l2U6sga+n)sAVscz2i!)J6V&#RJ4YNIFwN-Gsn>3$%BE_AJoudClr_IxQM!L?5f& z(i^KCY$o@m9f#vSg!xZxh#2E{7RPkmJFyG9u?L@_0iWXwNXda@Blcn+zQjKx$>AnAv1Z5x zH$3pd2S4_sFOi*W#=FD;w4fD@!)<6s2M!{DuW$&5@imU%D30McPT(X?p%Yy=jc)Yd z49?;l&V%9tE}|Egx^Wp-a23~Z9XAj}2sgpdhj0F;7qT?Oxurs@9gU}#jTti64CmX; zJTOkU>nBsNV3OT7SXcbU0~OlwTs5Q%E_v#*`rUqy-|P4J13`_Gz0L2^(Ih)!ZOTe3 zViylt%GkeF(}tIkKSuzj-)av`ne$4&!fhOMolKYZ$xRz z$#&T6%xN>RHk;LwR;2ahm)Yh)68@fyzK)i#AFX+rf$!PYF`vEGNXj6NNz7!}8p>VH zt`>wFd#NC4R0a=_nO9t>QCzZVj!V7xMB)xP117njP`MQ)N_ zVrYcRS+VJ5QKB~GG1BlCm(@?Di1if{yLjuN(@8G=uEG_ZCH@o%esh$)lY;j)$ZV2UGEBZMT&-hMwzW%&Qrkb(Zrrq|>Z9uFkE_?Prs5TB LZ($Alp;-J6L@wS; diff --git a/bin/basic_testing.rom b/bin/basic_testing.rom index abd477fa2c5f7051be49ed4b42aaba76a72c86c4..d062189e146a7dee053d1bcbe5b07b170668b96b 100644 GIT binary patch delta 1792 zcmZuyeQZ-z6o36#+pXK$ZEn1=(cJ;A>poypJL`lo2WFML%#WZX2IRF{Yd6#oBZ&@h zCHizijKwQqbD~Y%Eo~>#w}p?bTbT(geIuF|0x^n_FV`?x!b9Q*5vb>NVEBWV*LzRz zJ?GrtJ?H$+^EP{%qnTI3LX%tdYcAzXR2A@DJab)^byQaJ?&@CY?8yJ(@GxFoZue-oPg^E7y6sil~m5XDQzgoSB%x@atowf^(p2 zmuRvDy&6Fq#(m0U1##Uccibnp-zPigWxOhDyMo=5=fEa?aTB7)Ajn4nzAr04eJ~o( zelR9(M6DrVaT+G+=3-y~Q1U3VX$TjZY6~Mn!G{J5MfG4!usTek zvnib&neckk7++AUz+dJ}DaVgtckY-P(ol?-8tPgnIcu2b8g^NFBK{Og4tqi#;S*8G zok@tX@Vk)BggC;O=2(hilMYe7G|S2WYNSkv;-3J(#?mZ{Cv~^*NBJviG`vvdtA)I3 zA+IV%!;>?j>06`XV4i~0qOT4TonZ8-m`D)Wcziv7p)wf7IRz!{!6@8a%jt=Z%O2DR zwMjkE3+Ld#z5E2F_-T?CXRaisvc*4w`soXlR4_d;$y*GPUY>_-UoxR{5Qc}x6U6p&0B>#qH;PRJ57Moi^&EiIowCPtellJ zbW&*xzQ+o+w-!LR0ySDKlGFqaBteoG-ntf^$VBWI1YY(kEfEY-L8Q-q!60P;V$J-P zCzL+YAZ5ZKhgkI1i2P$*BZ)pcZKl*kln1XD z;CSobT<{Nzi^^7D^Fons5513I6{^7P9}C}P3^Cw?OiM!v-Q?#gV8cv0(XC6Q!Zzao zGAgHlhDH^0GMuJi(Q#lRqArlvITv}2>mZxCcGAT;nLT6pYH``h2e+a*xDcF5F<*>B zUE4=VG=rD&14wRHJX(5{pwzzp~* zeEG>LF*j)uvyzpfCTSL-A5^mVf|59*D`GzYF{OJ{mo;xdT;9~PW>P)R(XJ?z}O ze%g2wWO)6m07V~mZe73Ed8OC*7xB1W;XK46LJvgC<4Ff`7_T$K!MkczX|2DBr;78i zH1TwC9=~eTNp7DX!y?M_wFf+Ir)o}194oFzj56>bgw)C_ASIEmJ)}c^A*kNI0xx~ zl(a)ioLoEXI;CHT%c2nTpzG&MIcT@j-R|yiyL_|kvoA<%o_=ZBBXxBRb@g~t*&^Ik qVygx{4RJq{;@s>`TjWWLT(hP*zap?w{vuFNf;-6FPXIn&R{kHpwGRXU delta 1834 zcmZuyeQZ-z6u*71Ydbn@2Mjt2+hstzZcvK~Oaz?{W$FzQP1G0-Zy#-jlel0^bf}w& zSL+9%^Zp?O(WdSeUpLrmo3O20w;F})Em5CDWBiH^?G#<&i)h67@jMS^-#xFlvA0nvweCpN+V=V$@pbwh_SN|UzFME(=i_w^#V}pV1I2c_hSwI`=xXjS zw$d8zJBMO!>f<%k&sWo0zLwU_?w!`grR*+ir)5QOj@$M3lJ?_BP#ZOoY#vZ|gLwHY zelf#7E!j}tG>P*mMa1JH+A%L3gGavQx-Hs}^IGQ_U6trvfakFqw~ zYHRd7nPo58cGd>xcc67cs1evHemxC`eD*)rb>Xo8tNbWa~p*MP7OLM3jfq--kPtzWHTy`F>z z@RNf$Z{UIv6Un24W~ksCo)|C(5Yl!Zx0vF7vS$!~KE^AcifocEQ626QMIx&PfPK zvn|l?w?-rh|2?Fx(@UY(zhS4+AbBJyjuPE?P*AaE1KyA$Ln_j3>K0w_NDUJ23&Egr z^EUX%kh1eX`#PjIsXei)7Nqi$(wyI|G=sYYk)04A00BgDGHFHx=I?Mw){!BcV*`#V zhb>n&x^VQXJp0ITz7N+kUhZYLRIS)>d*-NMiB7xEcaXVsG#Xt{=!t#Z5%&W~MRUUH z$s@~?Et#We-eysT9jsa@RA$(Ts)yKX?yc)CWYoIYdLWe@NF|aB8UC?Wb;4~qUT&dw z{N{1)P~9<+q>{KU%MAB&;ZTNo%f0P~GH_4r)X5#Rtlycm&pNqN{X!GT3t7PYtawZ- z{xEgAO#3D2oc;#si>LF&V*!`$G^P3v)EUagdoSvmWh&rO5eTrePLsXaL(oMTNhtfu z;sw@l(t662xVHE^88?>5ZP1-lda3EwXO{A-wiG zzDK{An@pf%c;5tj!n2*7Ty``2+jAAz;nIG-7pi{*s_&$2{9)P(j$NcL$DXQgs3xzE z1D~5mxl)qW7bUQ{EYsNkGgsiiLH3S!t3bz?;eCjWdv0P!R&1=i(ylevOOTygQQT2T zL(cy{666ec!_ZNf&}h=UIyJgUYTix9_5VyW8(bz*F)=$#j68eXxxV6#iR6<0 z3eDQTE?EyF|HN=K1In;7SJG=Du%9ZoF1+h*efzEV2CoT)t_^KsyQ^2W#hs(CW)CAV z>i#`$9epEvSVW-8V|;H YFW5>JSTS(15lsAPK7W(h*VU{31=r{zH2?qr diff --git a/bin/basic_ultimate64.rom b/bin/basic_ultimate64.rom index 8e91115e8c407a6d6ab1a48c0c4d9a63a7b59f5c..57b76a751621d318b6f05f829a95df31d3135c22 100644 GIT binary patch delta 909 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 QpIyomkom=%L4GREe&3+G`^UaBbMN>5 z`riBf_4$5x6znJsvyvi{|- z%+!hH#jPin^N$<(C&eN-DjbGPZ+hf2p1KuD?;#&bTUi5kepK$5?cMxQfhK|^;-I=q8H~cT(Dr# zf+h2xUNJwHy8l&LVtb>d=%d25ur66$gO|B$dVVKM+D0N5H~x|M)$^Da2T6L^YPDX* z9z3}U!J)ELAFgQzu#az2Nf`*E*RXh8X1e5v0! zMOMKI(j+jR8IleP}D$5}vd$;6>gMlM1W*jJDaPHP_L{3VXQutA4a~+^!W& z*#(kHuyRHt9(Qv1WtlXDXB7O_TTk~?AInE;+##Hk3;2d zG04}6uTDKmg`0gGCmbpIod2ApX^d=%PdJ95X-3eT!zJV|n%sz=ohW7!4?6#LNs~qE zH+w3iF*D`(j;g&uwKnOcVQ~lVM;Azpb|tMRrP_?`<0I%DH`?Y!<@eC$QM(F{PN2L| z5NUM6OjVz3MXFI~o5Ca&P)$wJAh^&;IU<{u)FRD0l*5Pb*)Lck8{cprpy+mXRG_Og zv`F#$(YjIl9XN$3x@bQPAMHm4{gMx6Y;f%6eo!RN58@YsmBlDUHrmXY_2o?Ukcg_U zRIs->>uEUwECo;b*(o@{SRo4Rh0BMKjVy}HO5Np0)syxVWb%tt6_WHEP%vYPK)d|p zy~tehj#{U}LXaGdG$iSQD)@2ynVpXE297_y^Q-bNIW&v7B3~uzqW%#5rgA}_Q`@Up z>8GfbkvCmvn;YG9VH?Sd-u=>9kI`m4D*UxrI94pw7YoOWYl|- zUK((`#z0Jit_uS&spU|kD>T5l0a6?LB0Wsx*yq=y2S%5tu45tcagOIf#N~LnHr5p0 z#>q@Rr{~DD2yM*nJ@IJ=;;Q$mrt6;meU0h$()FdO^J2ns(MP*R?z!Cq18%n;zA^U@ zd50}6+T^d0{4I@=Th9rdGSkwD|1=?Vw&@|BT(|m^5gK+kWx|_3@U-siV0&R$!H&S* z&X!Iwlkbo&;ipMK+{_ro%kU`|;M+1rLy;}XsSNRxKPNwt#9t3-S=iU60zUI5rrhux z`6+JR_HGY&6jD!CBGv;6Sg9yRj-A?3HrS?;LmGOG;cLNp^c*x01JEik^0PwV9_Rnz zkTk{NA?N>a*oT({lmi3K|2letQ;Tr27cRGFDJBUCkx0z(Gcy#IzQdK($4Q{>v`O%e zYz@EH90a#l=pS9^eIia76MA}Z-}Bg0LeJ1+zOb9_joDvlLuU&R#fr(IKd>V z^`ef$TgO3QYmLlSfa%Yl0iAs3Y@+b$A!|)jBq-s!Q#eyw$_Nd$uQ7t7b`#UOvj$*0 z^tJ?-p0m7*w+tNalEcL5cp14ApOSQ82pjxhnVlVImbWI~*K)Ttv zdE!}q58CRpFR(P3)#aZ+R)Ey%s*r9U{-j;{=H&Zu{NFErF4N0pYbdM*^ zg7zx3ab!3tFK65(hk+wkPJnd|cb>Yz#-lgK6q_JeQK8biO3-!W4`lHj=uPsH{^7zO zeD(s=>_z@bQ))vmGA%lMQ1}}1*Dc{2r7b@Qi>5?KEzpIdq<-8wCLDo;_%+aw$Z!?; zyM7U!LIV1X>19gvp;eyZ2cBy~b!10e&UO``wSvTo+ZwA9Bz%5cs0-m!`nYnYOhI_S z`KvDUx))X$Ndt92F+MwP(TLQ2c5~SYz-M-9g)kdPZ*ekFuEpa_NjEbD$)%+%L&IBCV8U zPNgL4g?NN2?S{BP!D909jK{WzawJS&yshUVLV8qZVberb=t2EsWpF!~s>=m^NSCY_ ztWxy=T+ltJcMLy%7g|W17LBA4>cA@=_X*aOywx5KYQzigDu#fJ4|{I9+S%_*Livh~ zfSkKP$&)zM<^{Oc%K+QfPR9+3^*8C|0F+j&3j*&qsqaR52FtoE!F`DF5Laq0{T)e7 zI~UV6Xo=e$({1^1x2_v+Bkr_cF|fWm-H`KZCG?EO5)8#Doz2RuB@b;GfO^vIQpQlL z(R>rS?8GO1=m+V+PzX61+9kT!c diff --git a/bin/kernal_testing.rom b/bin/kernal_testing.rom index 116124da7c94c35c1e3363d3a67b10b8344c86d7..bf78fb729004e79d6bc4adc112f4b90913a05b09 100644 GIT binary patch delta 2607 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 delta 2513 zcmY*a4^R~66~En;KX>I|MTCQ(d<29$v;=D*I2|KaQ!h7PLS{@SS{%FL7*}h|OsbQn zV=K7t>YqDs^KeaSq<@__Z$HyQ4kOr=A?{voQ z?0)mUZ{K_0`}2G6)m7D15kI$*5y*LNu2V?1DJ48psW_w(#V$FNV#%%)NyVy3Dr!s* zm1wCUhh_=cwZu@d#)gXQg6WwDEj$x2X&m0x*VHQRkwmm=SWfD#J@{sjp8^_Q4=0;! zy|ugEJXm{oKmSk>H*b(cMbucEfYuI&HYywWF?^!!30p~w>yaXsNTOg<#BGx3;e55G zZ7sDXkQUUaC)z(`qN%>L{{*5M6ZA*5(MrMXH1>O*l6=fiH>=5ncAsn}|YNdS|H zx&kwFbs$PtJ1Bh#3&gpPFhtjA8Oiqmd65C@} zrcpCoa$G>GZW$jgzt!({c9(;!*e)0xwymiki}P=h_3Rt0>kD#%eUQET+%vHU5`Wq! z&%?hN7D$t&mOMYJHGfH2Md>eAmM(tE*C5XxO3_lx-F@I(zcwjU3T?-{$07Zn=(vCy z>kC9pe8-w_ma7~5Jfv|!?SVkH&t9>PLv9^#*sL?mw}{Th1L&;jb*Ap|UQlQ+yO9>u=90akksox5wilS$w&>W>qoF*%

m`fzpysNS|V#h}#VCYk${`kbGu*w)ljTlA^#qGSIZj2kHfl+>ddpa4OOT%ytWgeL zK{{D~W?!EmovQckJ1v;1>gxRdx;nI!tV!9Ky<bZk3o6#TI24#v4#y~L(aD6hF!^Q#yaV4zUh3QxM=ep{E-cf-Ud`~GPv z<2==Zr&vI~FbF|*3aGhC@~Tnk2)-GS=PWV}zMdA;9s@wog~w=lnCwb*T1*7A*trVb^0u12qXXCz2EI#Za;&D>LFJ@fi0Dpq{GpU-Lx5tPIo_Yv40sH47-`wBJ%V6}P$EJ8JBW!Wc@3WxuWhX$ zT{Dy>D~AIdn0fngEDs#cB*U{8{&Y|`lG&^`Ad^uBJ9Kb@ro~fLK?59(d9#U?T0oyo zfCU$ks`Lzq^8bls#YOT*o)I~WE5;202Yoh?2(OR8WnFe7T(K}T6Hod}Og;H7edV5` zkpredfR)mW=S*M{F`-*VI$KmuIxK*%X5MiPI0P`+>!$pEi2h$sfm=D$Z^G3RUbo)@ zZe&sARLeS6Io+~}ReUXPv;FmMD5cnK8>2Qs-i2%Qw(B%O&A?LFdxfs{+qFz(LL;qn zG7?>S{S~N@zBvzynssyr>Nk)CS9~#r3XH5Z-of4wcx1p){j~v>o~s!)#{7gA6_7`B zU*KK3zZis?ru*x!@IwHZip&@JWjYi|L)#%VISts{I!6AGxrA9tx-(x{phQC+n6j-} zLP*Aw5v4VdqdijOK(z*CD#=nSy{Ar)ysQ_qXTq}IGi%==lrjd;2=CV>+YSXa9nFw; zvK;9@sT{s>kiE8# zz|)3=ubT#x>y-WKdIMTU3bON=N95(~WviBlahIYK#P9aX$8$=j6(=)`}SGVl#8 zq|I1^{LQs;6q3s)Ls6G;xHkeV6t#rWu`t?AzRF(oBOuylx&~y+*&}2+yM#GL>^X(d zabL~(l=)T9gPc-^nIwg|7ul>kIhTj>e;eLz=eCz{+ZS>8hljW@j4dOcf5|4{ N=T(Y+>xX~S{{iT~mfQdU diff --git a/bin/kernal_ultimate64.rom b/bin/kernal_ultimate64.rom index 702969f8867f3ee3fb29556ea5018d79ac3f2437..b0d12b364f7eaa373496c56bcc807390c07454d5 100644 GIT binary patch delta 3059 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 delta 3092 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 MUi#;MiT=_51-P5WGXMYp delta 5723 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 delta 5723 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 Date: Mon, 1 Jun 2020 19:57:08 +0200 Subject: [PATCH 57/57] explained similarities >3 --- strings/02A90160 | 3 +++ strings/066D266C266B266A | 3 +++ strings/06702665266426632662 | 3 +++ strings/06E6A1D0 | 3 +++ strings/268562A5 | 3 +++ strings/26A90085 | 3 +++ strings/288529A5 | 3 +++ strings/2CA9022CA9 | 3 +++ strings/38E56185 | 3 +++ strings/4C67B820 | 3 +++ strings/4C6AB820 | 3 +++ strings/61F006A566 | 3 +++ strings/666366646665 | 3 +++ strings/6BE56385 | 3 +++ strings/7060A561F0 | 3 +++ strings/8526852785288529 | 3 +++ strings/A420D2FF | 3 +++ strings/A5278563A5 | 3 +++ strings/A5288564A5 | 3 +++ strings/A5298565 | 3 +++ strings/A561F0FB | 3 +++ strings/A569D0034C | 3 +++ strings/B7A000B1 | 3 +++ strings/E0A90085 | 3 +++ strings/E220C0FFB0 | 3 +++ strings/F006A56649FF8566608138AA3B29 | 3 +++ strings/FF20BBEE | 3 +++ 27 files changed, 81 insertions(+) create mode 100644 strings/02A90160 create mode 100644 strings/066D266C266B266A create mode 100644 strings/06702665266426632662 create mode 100644 strings/06E6A1D0 create mode 100644 strings/268562A5 create mode 100644 strings/26A90085 create mode 100644 strings/288529A5 create mode 100644 strings/2CA9022CA9 create mode 100644 strings/38E56185 create mode 100644 strings/4C67B820 create mode 100644 strings/4C6AB820 create mode 100644 strings/61F006A566 create mode 100644 strings/666366646665 create mode 100644 strings/6BE56385 create mode 100644 strings/7060A561F0 create mode 100644 strings/8526852785288529 create mode 100644 strings/A420D2FF create mode 100644 strings/A5278563A5 create mode 100644 strings/A5288564A5 create mode 100644 strings/A5298565 create mode 100644 strings/A561F0FB create mode 100644 strings/A569D0034C create mode 100644 strings/B7A000B1 create mode 100644 strings/E0A90085 create mode 100644 strings/E220C0FFB0 create mode 100644 strings/F006A56649FF8566608138AA3B29 create mode 100644 strings/FF20BBEE diff --git a/strings/02A90160 b/strings/02A90160 new file mode 100644 index 00000000..e968c27e --- /dev/null +++ b/strings/02A90160 @@ -0,0 +1,3 @@ +$02 + LDA #$01 + RTS + +End of subroutine putting $01 into accumulator + some part. Trivial - not copyrightable. diff --git a/strings/066D266C266B266A b/strings/066D266C266B266A new file mode 100644 index 00000000..02122454 --- /dev/null +++ b/strings/066D266C266B266A @@ -0,0 +1,3 @@ +ASL $6D + ROL $6C + ROL $6B + ROL $6A + +Arithmetic shift left of 32-bit value. Trivial - not copyrightable. diff --git a/strings/06702665266426632662 b/strings/06702665266426632662 new file mode 100644 index 00000000..4706747d --- /dev/null +++ b/strings/06702665266426632662 @@ -0,0 +1,3 @@ +ASL $70 + ROL $65 + ROL $64 + ROL $63 + ROL $62 + +Arithmetic shift left of 40-bit value. Trivial - not copyrightable. diff --git a/strings/06E6A1D0 b/strings/06E6A1D0 new file mode 100644 index 00000000..1130f260 --- /dev/null +++ b/strings/06E6A1D0 @@ -0,0 +1,3 @@ +$06 + INC $A1 + BNE (offset does not match) + +Instruction + some parts. Trivial - not copyrightable. diff --git a/strings/268562A5 b/strings/268562A5 new file mode 100644 index 00000000..5b20f62c --- /dev/null +++ b/strings/268562A5 @@ -0,0 +1,3 @@ +$26 + STA $62 + LDA (zeropage address does not match) + +Instruction + some parts. Trivial - not copyrightable. diff --git a/strings/26A90085 b/strings/26A90085 new file mode 100644 index 00000000..a6115ffd --- /dev/null +++ b/strings/26A90085 @@ -0,0 +1,3 @@ +$26 + LDA #$00 + STA (zeropage address does not match) + +Instruction + some parts. Trivial - not copyrightable. diff --git a/strings/288529A5 b/strings/288529A5 new file mode 100644 index 00000000..981d1241 --- /dev/null +++ b/strings/288529A5 @@ -0,0 +1,3 @@ +$28 + STA $29 + LDA (zeropage address does not match) + +Instruction + some parts. Trivial - not copyrightable. diff --git a/strings/2CA9022CA9 b/strings/2CA9022CA9 new file mode 100644 index 00000000..35f257c1 --- /dev/null +++ b/strings/2CA9022CA9 @@ -0,0 +1,3 @@ +$2C + LDA #$02 + BIT (to skip 2 bytes) + LDA (value does not match) + +Part of the common 6502 trick to set accumulator value depending on jump address. Not creative - not copyrightable. diff --git a/strings/38E56185 b/strings/38E56185 new file mode 100644 index 00000000..b5a11760 --- /dev/null +++ b/strings/38E56185 @@ -0,0 +1,3 @@ +SEC + SBC $61 + STA (zeropage address does not match) + +Small piece of code subtracting two values. Trivial -not copyrightable. diff --git a/strings/4C67B820 b/strings/4C67B820 new file mode 100644 index 00000000..e6a66941 --- /dev/null +++ b/strings/4C67B820 @@ -0,0 +1,3 @@ +JMP $B867 + JSR (address does not match) + +Jump to a well-known routine + some part. Trivial - not copyrightable. diff --git a/strings/4C6AB820 b/strings/4C6AB820 new file mode 100644 index 00000000..2e7d4182 --- /dev/null +++ b/strings/4C6AB820 @@ -0,0 +1,3 @@ +JMP $B86A + JSR (address does not match) + +Jump to a well-known routine + some part. Trivial - not copyrightable. diff --git a/strings/61F006A566 b/strings/61F006A566 new file mode 100644 index 00000000..65dfe904 --- /dev/null +++ b/strings/61F006A566 @@ -0,0 +1,3 @@ +$61 + BEQ (offset matches) + LDA $66 + +Conditional jump + retrieving zeropage variable + part of one more instruction. Trivial - not copyrightable. diff --git a/strings/666366646665 b/strings/666366646665 new file mode 100644 index 00000000..97516ea2 --- /dev/null +++ b/strings/666366646665 @@ -0,0 +1,3 @@ +ROR $63 + ROR $64 + ROR $65 + +Rotating right a multi-byte value. Trivial - not copyrightable. diff --git a/strings/6BE56385 b/strings/6BE56385 new file mode 100644 index 00000000..f7b25ef9 --- /dev/null +++ b/strings/6BE56385 @@ -0,0 +1,3 @@ +$6B + STA $6D + LDA (zeropage address does not match) + +Instruction + some parts. Trivial - not copyrightable. diff --git a/strings/7060A561F0 b/strings/7060A561F0 new file mode 100644 index 00000000..561705f1 --- /dev/null +++ b/strings/7060A561F0 @@ -0,0 +1,3 @@ +$70 + RTS + LDA $61 + BEQ (offset does not match) + +Jump depending whether zeropage variable is 0 or not + some small part (return + a byte) of previous routine. Trivial - not copyrightable. diff --git a/strings/8526852785288529 b/strings/8526852785288529 new file mode 100644 index 00000000..0b810b27 --- /dev/null +++ b/strings/8526852785288529 @@ -0,0 +1,3 @@ +STA $26 + STA $27 + STA $28 + STA $29 + +Part of code clearing 32-bit value. Trivial - not copyrightable. diff --git a/strings/A420D2FF b/strings/A420D2FF new file mode 100644 index 00000000..66609749 --- /dev/null +++ b/strings/A420D2FF @@ -0,0 +1,3 @@ +$A4 + JSR $FFD2 + +Call of a documented routine + some part. Trivial - not copyrightable. diff --git a/strings/A5278563A5 b/strings/A5278563A5 new file mode 100644 index 00000000..a1423910 --- /dev/null +++ b/strings/A5278563A5 @@ -0,0 +1,3 @@ +LDA $27 + STA $63 + LDA (zeropage address does not match) + +Part of code copying one floating point value to anotheer one. Trivial - not copyrightable. diff --git a/strings/A5288564A5 b/strings/A5288564A5 new file mode 100644 index 00000000..4149d6f3 --- /dev/null +++ b/strings/A5288564A5 @@ -0,0 +1,3 @@ +LDA $28 + STA $64 + LDA (zeropage address does not match) + +Part of code copying one floating point value to anotheer one. Trivial - not copyrightable. diff --git a/strings/A5298565 b/strings/A5298565 new file mode 100644 index 00000000..301d0212 --- /dev/null +++ b/strings/A5298565 @@ -0,0 +1,3 @@ +LDA $29 + STA $65 + +Part of code copying one floating point value to anotheer one. Trivial - not copyrightable. diff --git a/strings/A561F0FB b/strings/A561F0FB new file mode 100644 index 00000000..4c9abe4f --- /dev/null +++ b/strings/A561F0FB @@ -0,0 +1,3 @@ +LDA $61 + BEQ (offset matches) + +Jump depending whether zeropage variable is 0 or not. Trivial - not copyrightable. diff --git a/strings/A569D0034C b/strings/A569D0034C new file mode 100644 index 00000000..998098c2 --- /dev/null +++ b/strings/A569D0034C @@ -0,0 +1,3 @@ +LDA $69 + BNE (skip the JMP) + JMP (address does not match) + +Far jump (address does not match) depending whether zeropage variable is 0 or not. Trivial - not copyrightable. diff --git a/strings/B7A000B1 b/strings/B7A000B1 new file mode 100644 index 00000000..6c9dd366 --- /dev/null +++ b/strings/B7A000B1 @@ -0,0 +1,3 @@ +$B7 + LDY #$00 + LDA (...), Y (zeropage address does not match) + +Instruction + some parts. Trivial - not copyrightable. diff --git a/strings/E0A90085 b/strings/E0A90085 new file mode 100644 index 00000000..5a60cbc6 --- /dev/null +++ b/strings/E0A90085 @@ -0,0 +1,3 @@ +$E0 + LDA #$00 + STA (zeropage address does not match) + +Instruction + some parts. Trivial - not copyrightable. diff --git a/strings/E220C0FFB0 b/strings/E220C0FFB0 new file mode 100644 index 00000000..4e52ecef --- /dev/null +++ b/strings/E220C0FFB0 @@ -0,0 +1,3 @@ +$E2 + JSR $FFC0 + BCS (offset does not match) + +Call of a documented routine + some parts. Trivial - not copyrightable. diff --git a/strings/F006A56649FF8566608138AA3B29 b/strings/F006A56649FF8566608138AA3B29 new file mode 100644 index 00000000..783d54ed --- /dev/null +++ b/strings/F006A56649FF8566608138AA3B29 @@ -0,0 +1,3 @@ +BEQ (offset matches) + LDA $66 + EOR #$FF + STA $66 + RTS + floating point constant 1.0 / log_e(2.0) + +Most of a trivial routine to toggle floating point variable sign + floating point constant (generated by a special tool). The addresses has to remain as they are for compatibility. Not creative - not copyrightable. diff --git a/strings/FF20BBEE b/strings/FF20BBEE new file mode 100644 index 00000000..cf8be179 --- /dev/null +++ b/strings/FF20BBEE @@ -0,0 +1,3 @@ +$FF + JSR $EEBB + +Instruction + some part. Trivial - not copyrightable.