From e06046e82e58a29da3a908fb4d799affe382ef5e Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Tue, 2 Jun 2020 15:27:16 +0200 Subject: [PATCH 001/103] started work on integrated head align tool --- c64/,,config_custom.s | 5 +- c64/,,config_cx16.s | 1 + c64/,,config_generic.s | 1 + c64/,,config_mega65.s | 7 +- c64/,,config_testing.s | 1 + c64/,,config_ultimate64.s | 1 + c64/aliases/,aliases_config.s | 3 + c64/aliases/,aliases_hardware.s | 4 + c64/basic/,imports.s | 4 + c64/basic/commands/cmd_load.s | 23 +--- c64/basic/wedge_tape.s | 23 +++- .../board_m65/4000.mega65_vectable_kernal_1.s | 6 + c64/kernal/board_m65/mega65_proxies.s | 1 - ...ect_load_tape.s => mega65_redirect_tape.s} | 13 ++- c64/kernal/screen/e8ea.screen_scroll_up.s | 2 +- c64/kernal/screen/screen_calculate_pnt_user.s | 2 +- c64/kernal/tape/load_tape_normal.s | 1 + c64/kernal/tape/load_tape_turbo.s | 1 + c64/kernal/tape/tape_common.s | 9 ++ c64/kernal/tape/tape_head_align.s | 109 ++++++++++++++++++ 20 files changed, 187 insertions(+), 30 deletions(-) rename c64/kernal/board_m65/{mega65_redirect_load_tape.s => mega65_redirect_tape.s} (74%) create mode 100644 c64/kernal/tape/tape_head_align.s diff --git a/c64/,,config_custom.s b/c64/,,config_custom.s index d5983fcb..d98e0103 100644 --- a/c64/,,config_custom.s +++ b/c64/,,config_custom.s @@ -54,9 +54,9 @@ // #define CONFIG_IEC_BURST_CIA2 // please keep disabled for now // #define CONFIG_IEC_BURST_SOFT // please keep disabled for now -#define CONFIG_TAPE_NORMAL +// #define CONFIG_TAPE_NORMAL #define CONFIG_TAPE_TURBO -#define CONFIG_TAPE_AUTODETECT +// #define CONFIG_TAPE_AUTODETECT // #define CONFIG_TAPE_NO_KEY_SENSE // #define CONFIG_TAPE_NO_MOTOR_CONTROL // #define CONFIG_TAPE_NO_ERROR_CORRECTION @@ -124,6 +124,7 @@ #define CONFIG_PANIC_SCREEN #define CONFIG_DOS_WEDGE #define CONFIG_TAPE_WEDGE +#define CONFIG_TAPE_HEAD_ALIGN // XXX work in progress #define CONFIG_BCD_SAFE_INTERRUPTS diff --git a/c64/,,config_cx16.s b/c64/,,config_cx16.s index 828f0e73..cda04d71 100644 --- a/c64/,,config_cx16.s +++ b/c64/,,config_cx16.s @@ -117,6 +117,7 @@ // #define CONFIG_PANIC_SCREEN // #define CONFIG_DOS_WEDGE // #define CONFIG_TAPE_WEDGE +// #define CONFIG_TAPE_HEAD_ALIGN // XXX work in progress #define CONFIG_BCD_SAFE_INTERRUPTS diff --git a/c64/,,config_generic.s b/c64/,,config_generic.s index b74339af..74cee7a8 100644 --- a/c64/,,config_generic.s +++ b/c64/,,config_generic.s @@ -115,6 +115,7 @@ #define CONFIG_PANIC_SCREEN #define CONFIG_DOS_WEDGE #define CONFIG_TAPE_WEDGE +// #define CONFIG_TAPE_HEAD_ALIGN // XXX work in progress #define CONFIG_BCD_SAFE_INTERRUPTS diff --git a/c64/,,config_mega65.s b/c64/,,config_mega65.s index 60826470..a4089233 100644 --- a/c64/,,config_mega65.s +++ b/c64/,,config_mega65.s @@ -96,11 +96,11 @@ .const CONFIG_KEYCMD_HELP = @"LIST" -.const CONFIG_KEYCMD_F9 = @"REM F9" +.const CONFIG_KEYCMD_F9 = @"BOOT" .const CONFIG_KEYCMD_F10 = @"REM F10" -.const CONFIG_KEYCMD_F11 = @"REM F11" +.const CONFIG_KEYCMD_F11 = @"MONITOR" .const CONFIG_KEYCMD_F12 = @"REM F12" -.const CONFIG_KEYCMD_F13 = @"REM F13" +.const CONFIG_KEYCMD_F13 = @"\$5FH" .const CONFIG_KEYCMD_F14 = @"REM F14" @@ -115,6 +115,7 @@ #define CONFIG_PANIC_SCREEN #define CONFIG_DOS_WEDGE #define CONFIG_TAPE_WEDGE +// #define CONFIG_TAPE_HEAD_ALIGN // XXX work in progress #define CONFIG_BCD_SAFE_INTERRUPTS diff --git a/c64/,,config_testing.s b/c64/,,config_testing.s index d6743178..afe531bf 100644 --- a/c64/,,config_testing.s +++ b/c64/,,config_testing.s @@ -115,6 +115,7 @@ #define CONFIG_PANIC_SCREEN #define CONFIG_DOS_WEDGE #define CONFIG_TAPE_WEDGE +// #define CONFIG_TAPE_HEAD_ALIGN // XXX work in progress #define CONFIG_BCD_SAFE_INTERRUPTS diff --git a/c64/,,config_ultimate64.s b/c64/,,config_ultimate64.s index 9cbd6819..707b1939 100644 --- a/c64/,,config_ultimate64.s +++ b/c64/,,config_ultimate64.s @@ -115,6 +115,7 @@ #define CONFIG_PANIC_SCREEN #define CONFIG_DOS_WEDGE #define CONFIG_TAPE_WEDGE +// #define CONFIG_TAPE_HEAD_ALIGN // XXX work in progress #define CONFIG_BCD_SAFE_INTERRUPTS diff --git a/c64/aliases/,aliases_config.s b/c64/aliases/,aliases_config.s index ebf44ae2..7dbc16f9 100644 --- a/c64/aliases/,aliases_config.s +++ b/c64/aliases/,aliases_config.s @@ -298,6 +298,9 @@ #if CONFIG_TAPE_WEDGE && !CONFIG_TAPE_TURBO .error "CONFIG_TAPE_WEDGE requires CONFIG_TAPE_TURBO" #endif +#if !CONFIG_TAPE_WEDGE && CONFIG_TAPE_HEAD_ALIGN + .error "CONFIG_TAPE_HEAD_ALIGN requires CONFIG_TAPE_WEDGE" +#endif } diff --git a/c64/aliases/,aliases_hardware.s b/c64/aliases/,aliases_hardware.s index bdd0f5e5..74e8b6d3 100644 --- a/c64/aliases/,aliases_hardware.s +++ b/c64/aliases/,aliases_hardware.s @@ -125,6 +125,10 @@ .label SID_RANDOM = $D41B .label SID_ENV3 = $D41C + // Color COLOR_RAM + + .label COLOR_RAM = $D800 + // CIA #1 registers .label __CIA1_BASE = $DC00 // base address of the chip diff --git a/c64/basic/,imports.s b/c64/basic/,imports.s index 8c7b7643..e7b92c3e 100644 --- a/c64/basic/,imports.s +++ b/c64/basic/,imports.s @@ -50,3 +50,7 @@ #if CONFIG_SHOW_PAL_NTSC .label print_pal_ntsc = KERNAL().print_pal_ntsc #endif + +#if CONFIG_TAPE_HEAD_ALIGN +.label tape_head_align = KERNAL().tape_head_align +#endif diff --git a/c64/basic/commands/cmd_load.s b/c64/basic/commands/cmd_load.s index 08d2b93c..ad49632b 100644 --- a/c64/basic/commands/cmd_load.s +++ b/c64/basic/commands/cmd_load.s @@ -22,25 +22,9 @@ cmd_load: // Check for the file name jsr basic_end_of_statement_check - bcc !+ + bcc cmd_load_fetch_filename -#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, try to load the first file from disk + // Try to load the first file from disk lda #$01 // name length ldx #$D800 + lda #>COLOR_RAM sta PNT+1 sta USER+1 diff --git a/c64/kernal/screen/screen_calculate_pnt_user.s b/c64/kernal/screen/screen_calculate_pnt_user.s index 4fc409fa..75603fc1 100644 --- a/c64/kernal/screen/screen_calculate_pnt_user.s +++ b/c64/kernal/screen/screen_calculate_pnt_user.s @@ -50,7 +50,7 @@ screen_calculate_USER: sec sbc HIBASE clc - adc #>$d800 + adc #>COLOR_RAM sta USER+1 rts diff --git a/c64/kernal/tape/load_tape_normal.s b/c64/kernal/tape/load_tape_normal.s index c53dabdb..a3d08d45 100644 --- a/c64/kernal/tape/load_tape_normal.s +++ b/c64/kernal/tape/load_tape_normal.s @@ -45,6 +45,7 @@ load_tape_normal: // Start playing jsr tape_common_prepare_cia jsr tape_ask_play + jsr tape_prepare_reading // FALLTROUGH diff --git a/c64/kernal/tape/load_tape_turbo.s b/c64/kernal/tape/load_tape_turbo.s index 7c421e90..0bf65d07 100644 --- a/c64/kernal/tape/load_tape_turbo.s +++ b/c64/kernal/tape/load_tape_turbo.s @@ -32,6 +32,7 @@ load_tape_auto: // Start playing jsr tape_common_prepare_cia jsr tape_ask_play + jsr tape_prepare_reading // FALLTROUGH diff --git a/c64/kernal/tape/tape_common.s b/c64/kernal/tape/tape_common.s index fa813aef..75e49567 100644 --- a/c64/kernal/tape/tape_common.s +++ b/c64/kernal/tape/tape_common.s @@ -104,6 +104,15 @@ tape_wait_first_pulse: tape_wait_play_done: + rts + + +// +// Prepare screen / tape motor for reading +// + +tape_prepare_reading: + #if CONFIG_MB_MEGA_65 // Display confirmation diff --git a/c64/kernal/tape/tape_head_align.s b/c64/kernal/tape/tape_head_align.s new file mode 100644 index 00000000..bb98ddea --- /dev/null +++ b/c64/kernal/tape/tape_head_align.s @@ -0,0 +1,109 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 KERNAL_1 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Tape (normal) helper routine - reading speed calibration +// +// Needs pulse length in .A +// + + +#if CONFIG_TAPE_HEAD_ALIGN + + +tape_head_align: + +#if (ROM_LAYOUT_M65 && SEGMENT_KERNAL_0) + + jsr map_KERNAL_1 + jsr_ind VK1__tape_head_align + jmp map_NORMAL + +#else + + // Start by asking for tape playback + + // jsr tape_ask_play + + // Disable interrupts + + sei + + // Set IO to default values + + jsr IOINIT + jsr cint_legacy + + // Clear color data ($0800) + + ldy #$00 +!: + lda #($10 + $06) // XXX synchronize colors with setup_vicii + + sta $0800, y + sta $0900, y + sta $0A00, y + sta $0B00, y + + iny + bne !- + + // Clear bitmap data ($2000) + + lda #$20 + sta SAL+1 + tya // put 0 to .A + sta SAL+0 +!: + sta (SAL), y + iny + bne !- + + inc SAL+1 + ldx SAL+1 + cpx #$40 + bne !- + + // Set graphics mode + + lda #$28 // graphic memory start at $2000, color at $0800 + sta VIC_YMCSB + + lda #$3B // set bit 5 to enable graphic mode + sta VIC_SCROLY + + // Set tape timing + + // XXX + +tape_head_align_loop_1: + + // XXX waste pulse + +tape_head_align_loop_2: + + // XXX get pulse + // XXX put pulse + // XXX check time; if not enough passed - next iteration tape_head_align_loop2 + // XXX check for STOP key; if pressed, quit + // XXX scroll + + jmp tape_head_align_loop_1 + +tape_head_align_quit: + + // Clear screen, restore old display settings + + jsr cint_legacy + + // XXX restore COLOR, VIC_EXTCOL, VIC_BGCOL0, CIA2_PRA + + cli + rts // XXX perform new after quit + + +#endif // ROM layout + + +#endif // CONFIG_TAPE_HEAD_ALIGN From 839e67ab8e6b38e9bdb9c3de745c9211b3a330f3 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Tue, 2 Jun 2020 15:28:53 +0200 Subject: [PATCH 002/103] removed testing build from release --- Makefile | 2 +- bin/basic_testing.rom | Bin 8192 -> 0 bytes bin/kernal_testing.rom | Bin 8192 -> 0 bytes 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 bin/basic_testing.rom delete mode 100644 bin/kernal_testing.rom diff --git a/Makefile b/Makefile index 2181f8c2..9fc2abcc 100644 --- a/Makefile +++ b/Makefile @@ -130,7 +130,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_M65_x_PXL) $(TARGET_LIST_U64) +REL_TARGET_LIST = $(TARGET_LIST_GEN) $(TARGET_M65_x) $(TARGET_M65_x_PXL) $(TARGET_LIST_U64) # Misc strings diff --git a/bin/basic_testing.rom b/bin/basic_testing.rom deleted file mode 100644 index d062189e146a7dee053d1bcbe5b07b170668b96b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8192 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 diff --git a/bin/kernal_testing.rom b/bin/kernal_testing.rom deleted file mode 100644 index bf78fb729004e79d6bc4adc112f4b90913a05b09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8192 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 K{QZxAlm83T+7aXc From 175465f6c7c9e858c36d79536df3d363bb9f74d9 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Tue, 2 Jun 2020 20:35:20 +0200 Subject: [PATCH 003/103] head align tool starts working --- c64/kernal/tape/tape_common_get_pulse.s | 2 +- c64/kernal/tape/tape_common_prepare_cia.s | 5 + c64/kernal/tape/tape_head_align.s | 385 +++++++++++++++++++++- 3 files changed, 375 insertions(+), 17 deletions(-) diff --git a/c64/kernal/tape/tape_common_get_pulse.s b/c64/kernal/tape/tape_common_get_pulse.s index b194ccd7..3cfccf75 100644 --- a/c64/kernal/tape/tape_common_get_pulse.s +++ b/c64/kernal/tape/tape_common_get_pulse.s @@ -26,7 +26,7 @@ tape_common_get_pulse: ldx #%01010001 // start timer, force latch reload, count timer A underflows stx CIA2_CRB // $DD0F - cmp __pulse_threshold // sdefault pulse check + cmp __pulse_threshold // default pulse check rts diff --git a/c64/kernal/tape/tape_common_prepare_cia.s b/c64/kernal/tape/tape_common_prepare_cia.s index d4d6302c..dd9eb3c5 100644 --- a/c64/kernal/tape/tape_common_prepare_cia.s +++ b/c64/kernal/tape/tape_common_prepare_cia.s @@ -42,6 +42,11 @@ tape_common_prepare_cia: // Setup CIA #2 timers ldx #$03 // set timer A to 4 ticks + + // FALLTROUGH + +tape_common_prepare_cia_by_x: // entry point for head align tool + stx CIA2_TIMALO // $DD04 ldx #$00 stx CIA2_TIMAHI // $DD05 diff --git a/c64/kernal/tape/tape_head_align.s b/c64/kernal/tape/tape_head_align.s index bb98ddea..6bbfb526 100644 --- a/c64/kernal/tape/tape_head_align.s +++ b/c64/kernal/tape/tape_head_align.s @@ -12,6 +12,18 @@ #if CONFIG_TAPE_HEAD_ALIGN +.label __ha_start = 3 // starting row of the chart + +// Helper tables + +.label __ha_offsets = $1000; +.label __ha_masks = $1100; + +// Helper variables + +.label __ha_counter = $1200; // 3 bytes + + tape_head_align: #if (ROM_LAYOUT_M65 && SEGMENT_KERNAL_0) @@ -22,24 +34,24 @@ tape_head_align: #else - // Start by asking for tape playback + // Start by asking for playback - // jsr tape_ask_play + // XXX jsr tape_ask_play - // Disable interrupts + // Disable interrupts, set proper I/O values sei - - // Set IO to default values - jsr IOINIT jsr cint_legacy + jsr tape_motor_on + ldx #$02 // set timer A to 3 ticks + jsr tape_common_prepare_cia_by_x // Clear color data ($0800) ldy #$00 !: - lda #($10 + $06) // XXX synchronize colors with setup_vicii + lda #($01 * $10 + $06) // XXX synchronize colors with setup_vicii sta $0800, y sta $0900, y @@ -49,6 +61,15 @@ tape_head_align: iny bne !- + // Make sure the row where the chart is created is not visible + + lda #($06 * $10 + $06) // XXX synchronize colors with setup_vicii + ldy #$28 +!: + sta $0800 + __ha_start * 40 - 1, y + dey + bne !- + // Clear bitmap data ($2000) lda #$20 @@ -73,23 +94,92 @@ tape_head_align: lda #$3B // set bit 5 to enable graphic mode sta VIC_SCROLY - // Set tape timing + // Prepare lookup tables - to speed drawing, we are going to use two of them: + // - byte offset table will tell us which byte in memory to alter + // - mask will allow us to quickly put the pixel - // XXX + ldx #$00 // loop index + ldy #$00 // temporary value for mask calculation +!: + // Byte offset is simple, just zero the 3 least significant bits + + txa + and #%11111000 + sta __ha_offsets, x + + // Mask changes with each iteration, use our temporary value in .Y + + tya + clc + ror + bne !+ + lda #%10000000 +!: + tay + sta __ha_masks, x + + // Next iteration + + inx + bne !-- tape_head_align_loop_1: - // XXX waste pulse + // XXX check for STOP key, possibly terminate + + // Scroll the whole chart one line down + + ldx #$00 +!: + jsr tape_head_align_scroll_column + + txa + clc + adc #$08 + tax + bne !- + + // XXX draw helper lines + + // Initialize counter + + lda #$80 + sta __ha_counter + 1 + lda #$00 + sta __ha_counter + 0 + sta __ha_counter + 2 + + // Skip 2 pulses, these measurements will be too imprecise + + jsr tape_head_align_get_pulse + jsr tape_head_align_get_pulse tape_head_align_loop_2: - // XXX get pulse - // XXX put pulse - // XXX check time; if not enough passed - next iteration tape_head_align_loop2 - // XXX check for STOP key; if pressed, quit - // XXX scroll + // Retrieve actual pulse length - jmp tape_head_align_loop_1 + jsr tape_head_align_get_pulse + cmp #$FF + beq tape_head_align_drawn // skip drawing for too long pulses + + // Put pulse on the screen; center the chart horizontaly, with some margin from top + + .label __ha_chart = $2000 + 8 * (40 * __ha_start + 4) + + tax + lda __ha_offsets, x + tay + lda __ha_masks, x + ora __ha_chart + 7, y + sta __ha_chart + 7, y + + // FALLTROUGH + +tape_head_align_drawn: + + lda __ha_counter + 2 + beq tape_head_align_loop_2 + bne tape_head_align_loop_1 tape_head_align_quit: @@ -102,6 +192,269 @@ tape_head_align_quit: cli rts // XXX perform new after quit +tape_head_align_get_pulse: + + // This routine differs a lot from the one used to read pulse during tape reading: + // - it is not as precise + // - it terminates when timer reaches $FF + // - it updates + + lda #$10 +!: + // Loop to detect signal + + ldy CIA2_TIMBLO // $DD06 + bit CIA1_ICR // $DC0D + bne !+ + + cpy #$FF + bne !- +!: + // Start timer again, force latch reload, count timer A underflows + + ldx #%01010001 + stx CIA2_CRB // $DD0F + + // Update time counter + + tya + clc + adc __ha_counter + 0 + sta __ha_counter + 0 + bcc !+ + inc __ha_counter + 1 + bne !+ + inc __ha_counter + 2 +!: + // Return with time elapsed + + tya + rts + +tape_head_align_scroll_column: + + // XXX autogenerate this code somewhere + + lda __ha_chart + 9 * (8 * 40) + 6, x + sta __ha_chart + 9 * (8 * 40) + 7, x + + lda __ha_chart + 9 * (8 * 40) + 5, x + sta __ha_chart + 9 * (8 * 40) + 6, x + + lda __ha_chart + 9 * (8 * 40) + 4, x + sta __ha_chart + 9 * (8 * 40) + 5, x + + lda __ha_chart + 9 * (8 * 40) + 3, x + sta __ha_chart + 9 * (8 * 40) + 4, x + + lda __ha_chart + 9 * (8 * 40) + 2, x + sta __ha_chart + 9 * (8 * 40) + 3, x + + lda __ha_chart + 9 * (8 * 40) + 1, x + sta __ha_chart + 9 * (8 * 40) + 2, x + + lda __ha_chart + 9 * (8 * 40) + 0, x + sta __ha_chart + 9 * (8 * 40) + 1, x + + lda __ha_chart + 8 * (8 * 40) + 7, x + sta __ha_chart + 9 * (8 * 40) + 0, x + + lda __ha_chart + 8 * (8 * 40) + 6, x + sta __ha_chart + 8 * (8 * 40) + 7, x + + lda __ha_chart + 8 * (8 * 40) + 5, x + sta __ha_chart + 8 * (8 * 40) + 6, x + + lda __ha_chart + 8 * (8 * 40) + 4, x + sta __ha_chart + 8 * (8 * 40) + 5, x + + lda __ha_chart + 8 * (8 * 40) + 3, x + sta __ha_chart + 8 * (8 * 40) + 4, x + + lda __ha_chart + 8 * (8 * 40) + 2, x + sta __ha_chart + 8 * (8 * 40) + 3, x + + lda __ha_chart + 8 * (8 * 40) + 1, x + sta __ha_chart + 8 * (8 * 40) + 2, x + + lda __ha_chart + 8 * (8 * 40) + 0, x + sta __ha_chart + 8 * (8 * 40) + 1, x + + lda __ha_chart + 7 * (8 * 40) + 7, x + sta __ha_chart + 8 * (8 * 40) + 0, x + + lda __ha_chart + 7 * (8 * 40) + 6, x + sta __ha_chart + 7 * (8 * 40) + 7, x + + lda __ha_chart + 7 * (8 * 40) + 5, x + sta __ha_chart + 7 * (8 * 40) + 6, x + + lda __ha_chart + 7 * (8 * 40) + 4, x + sta __ha_chart + 7 * (8 * 40) + 5, x + + lda __ha_chart + 7 * (8 * 40) + 3, x + sta __ha_chart + 7 * (8 * 40) + 4, x + + lda __ha_chart + 7 * (8 * 40) + 2, x + sta __ha_chart + 7 * (8 * 40) + 3, x + + lda __ha_chart + 7 * (8 * 40) + 1, x + sta __ha_chart + 7 * (8 * 40) + 2, x + + lda __ha_chart + 7 * (8 * 40) + 0, x + sta __ha_chart + 7 * (8 * 40) + 1, x + + lda __ha_chart + 6 * (8 * 40) + 7, x + sta __ha_chart + 7 * (8 * 40) + 0, x + + lda __ha_chart + 6 * (8 * 40) + 6, x + sta __ha_chart + 6 * (8 * 40) + 7, x + + lda __ha_chart + 6 * (8 * 40) + 5, x + sta __ha_chart + 6 * (8 * 40) + 6, x + + lda __ha_chart + 6 * (8 * 40) + 4, x + sta __ha_chart + 6 * (8 * 40) + 5, x + + lda __ha_chart + 6 * (8 * 40) + 3, x + sta __ha_chart + 6 * (8 * 40) + 4, x + + lda __ha_chart + 6 * (8 * 40) + 2, x + sta __ha_chart + 6 * (8 * 40) + 3, x + + lda __ha_chart + 6 * (8 * 40) + 1, x + sta __ha_chart + 6 * (8 * 40) + 2, x + + lda __ha_chart + 6 * (8 * 40) + 0, x + sta __ha_chart + 6 * (8 * 40) + 1, x + + lda __ha_chart + 5 * (8 * 40) + 7, x + sta __ha_chart + 6 * (8 * 40) + 0, x + + lda __ha_chart + 5 * (8 * 40) + 6, x + sta __ha_chart + 5 * (8 * 40) + 7, x + + lda __ha_chart + 5 * (8 * 40) + 5, x + sta __ha_chart + 5 * (8 * 40) + 6, x + + lda __ha_chart + 5 * (8 * 40) + 4, x + sta __ha_chart + 5 * (8 * 40) + 5, x + + lda __ha_chart + 5 * (8 * 40) + 3, x + sta __ha_chart + 5 * (8 * 40) + 4, x + + lda __ha_chart + 5 * (8 * 40) + 2, x + sta __ha_chart + 5 * (8 * 40) + 3, x + + lda __ha_chart + 5 * (8 * 40) + 1, x + sta __ha_chart + 5 * (8 * 40) + 2, x + + lda __ha_chart + 5 * (8 * 40) + 0, x + sta __ha_chart + 5 * (8 * 40) + 1, x + + lda __ha_chart + 4 * (8 * 40) + 7, x + sta __ha_chart + 5 * (8 * 40) + 0, x + + lda __ha_chart + 4 * (8 * 40) + 6, x + sta __ha_chart + 4 * (8 * 40) + 7, x + + lda __ha_chart + 4 * (8 * 40) + 5, x + sta __ha_chart + 4 * (8 * 40) + 6, x + + lda __ha_chart + 4 * (8 * 40) + 4, x + sta __ha_chart + 4 * (8 * 40) + 5, x + + lda __ha_chart + 4 * (8 * 40) + 3, x + sta __ha_chart + 4 * (8 * 40) + 4, x + + lda __ha_chart + 4 * (8 * 40) + 2, x + sta __ha_chart + 4 * (8 * 40) + 3, x + + lda __ha_chart + 4 * (8 * 40) + 1, x + sta __ha_chart + 4 * (8 * 40) + 2, x + + lda __ha_chart + 4 * (8 * 40) + 0, x + sta __ha_chart + 4 * (8 * 40) + 1, x + + lda __ha_chart + 3 * (8 * 40) + 7, x + sta __ha_chart + 4 * (8 * 40) + 0, x + + lda __ha_chart + 3 * (8 * 40) + 6, x + sta __ha_chart + 3 * (8 * 40) + 7, x + + lda __ha_chart + 3 * (8 * 40) + 5, x + sta __ha_chart + 3 * (8 * 40) + 6, x + + lda __ha_chart + 3 * (8 * 40) + 4, x + sta __ha_chart + 3 * (8 * 40) + 5, x + + lda __ha_chart + 3 * (8 * 40) + 3, x + sta __ha_chart + 3 * (8 * 40) + 4, x + + lda __ha_chart + 3 * (8 * 40) + 2, x + sta __ha_chart + 3 * (8 * 40) + 3, x + + lda __ha_chart + 3 * (8 * 40) + 1, x + sta __ha_chart + 3 * (8 * 40) + 2, x + + lda __ha_chart + 3 * (8 * 40) + 0, x + sta __ha_chart + 3 * (8 * 40) + 1, x + + lda __ha_chart + 2 * (8 * 40) + 7, x + sta __ha_chart + 3 * (8 * 40) + 0, x + + lda __ha_chart + 2 * (8 * 40) + 6, x + sta __ha_chart + 2 * (8 * 40) + 7, x + + lda __ha_chart + 2 * (8 * 40) + 5, x + sta __ha_chart + 2 * (8 * 40) + 6, x + + lda __ha_chart + 2 * (8 * 40) + 4, x + sta __ha_chart + 2 * (8 * 40) + 5, x + + lda __ha_chart + 2 * (8 * 40) + 3, x + sta __ha_chart + 2 * (8 * 40) + 4, x + + lda __ha_chart + 2 * (8 * 40) + 2, x + sta __ha_chart + 2 * (8 * 40) + 3, x + + lda __ha_chart + 2 * (8 * 40) + 1, x + sta __ha_chart + 2 * (8 * 40) + 2, x + + lda __ha_chart + 2 * (8 * 40) + 0, x + sta __ha_chart + 2 * (8 * 40) + 1, x + + lda __ha_chart + 1 * (8 * 40) + 7, x + sta __ha_chart + 2 * (8 * 40) + 0, x + + lda __ha_chart + 1 * (8 * 40) + 6, x + sta __ha_chart + 1 * (8 * 40) + 7, x + + lda __ha_chart + 1 * (8 * 40) + 5, x + sta __ha_chart + 1 * (8 * 40) + 6, x + + lda __ha_chart + 1 * (8 * 40) + 4, x + sta __ha_chart + 1 * (8 * 40) + 5, x + + lda __ha_chart + 1 * (8 * 40) + 3, x + sta __ha_chart + 1 * (8 * 40) + 4, x + + lda __ha_chart + 1 * (8 * 40) + 2, x + sta __ha_chart + 1 * (8 * 40) + 3, x + + lda __ha_chart + 1 * (8 * 40) + 1, x + sta __ha_chart + 1 * (8 * 40) + 2, x + + lda __ha_chart + 1 * (8 * 40) + 0, x + sta __ha_chart + 1 * (8 * 40) + 1, x + + lda __ha_chart + 0 * (8 * 40) + 7, x + sta __ha_chart + 1 * (8 * 40) + 0, x + + lda #$00 + sta __ha_chart + 0 * (8 * 40) + 7, x + + rts #endif // ROM layout From db9d6e7b60069e0af260e00acc62ece18c39fa12 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Tue, 2 Jun 2020 23:06:13 +0200 Subject: [PATCH 004/103] autogenerated scrolling code for head align tool --- c64/,,config_custom.s | 8 +- c64/aliases/,aliases_config.s | 16 ++ c64/basic/,imports.s | 2 + c64/basic/commands/cmd_load.s | 8 +- c64/kernal/assets/filename_any.s | 8 + c64/kernal/init/cint_screen_keyboard.s | 2 +- c64/kernal/init/e5a0.setup_vicii.s | 12 +- c64/kernal/tape/load_tape_normal.s | 1 - c64/kernal/tape/load_tape_turbo.s | 1 - c64/kernal/tape/tape_common.s | 9 - c64/kernal/tape/tape_head_align.s | 301 ++------------------ c64/kernal/tape/tape_head_align_gen_code.s | 132 +++++++++ c64/kernal/tape/tape_head_align_get_pulse.s | 52 ++++ 13 files changed, 241 insertions(+), 311 deletions(-) create mode 100644 c64/kernal/assets/filename_any.s create mode 100644 c64/kernal/tape/tape_head_align_gen_code.s create mode 100644 c64/kernal/tape/tape_head_align_get_pulse.s diff --git a/c64/,,config_custom.s b/c64/,,config_custom.s index d98e0103..bb93e633 100644 --- a/c64/,,config_custom.s +++ b/c64/,,config_custom.s @@ -46,10 +46,10 @@ // I/O devices #define CONFIG_IEC -#define CONFIG_IEC_DOLPHINDOS -#define CONFIG_IEC_DOLPHINDOS_FAST -#define CONFIG_IEC_JIFFYDOS -#define CONFIG_IEC_JIFFYDOS_BLANK +//#define CONFIG_IEC_DOLPHINDOS +//#define CONFIG_IEC_DOLPHINDOS_FAST +//#define CONFIG_IEC_JIFFYDOS +//#define CONFIG_IEC_JIFFYDOS_BLANK // #define CONFIG_IEC_BURST_CIA1 // please keep disabled for now // #define CONFIG_IEC_BURST_CIA2 // please keep disabled for now // #define CONFIG_IEC_BURST_SOFT // please keep disabled for now diff --git a/c64/aliases/,aliases_config.s b/c64/aliases/,aliases_config.s index 7dbc16f9..62ac4682 100644 --- a/c64/aliases/,aliases_config.s +++ b/c64/aliases/,aliases_config.s @@ -344,6 +344,22 @@ } + +// Setup colors + +#if CONFIG_COLORS_BRAND && CONFIG_BRAND_ULTIMATE_64 + + .const CONFIG_COLOR_BG = $00 + .const CONFIG_COLOR_TXT = $01 + +#else + + .const CONFIG_COLOR_BG = $06 + .const CONFIG_COLOR_TXT = $01 + +#endif + + // Function for printing out build features .var feature_new_line = false diff --git a/c64/basic/,imports.s b/c64/basic/,imports.s index e7b92c3e..20eaa980 100644 --- a/c64/basic/,imports.s +++ b/c64/basic/,imports.s @@ -54,3 +54,5 @@ #if CONFIG_TAPE_HEAD_ALIGN .label tape_head_align = KERNAL().tape_head_align #endif + +.label filename_any = KERNAL().filename_any diff --git a/c64/basic/commands/cmd_load.s b/c64/basic/commands/cmd_load.s index ad49632b..2572b1e5 100644 --- a/c64/basic/commands/cmd_load.s +++ b/c64/basic/commands/cmd_load.s @@ -27,15 +27,11 @@ cmd_load: // Try to load the first file from disk lda #$01 // name length - ldx #cmd_load_default_filename + ldx #filename_any jsr JSETNAM jmp got_filename -cmd_load_default_filename: - - .text "*" - cmd_load_fetch_filename: jsr basic_fetch_and_consume_character diff --git a/c64/kernal/assets/filename_any.s b/c64/kernal/assets/filename_any.s new file mode 100644 index 00000000..c8524439 --- /dev/null +++ b/c64/kernal/assets/filename_any.s @@ -0,0 +1,8 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * KERNAL_0 #TAKE +// #LAYOUT# * * #IGNORE + + +filename_any: + + .text "*" diff --git a/c64/kernal/init/cint_screen_keyboard.s b/c64/kernal/init/cint_screen_keyboard.s index ad2241c3..27d54408 100644 --- a/c64/kernal/init/cint_screen_keyboard.s +++ b/c64/kernal/init/cint_screen_keyboard.s @@ -60,7 +60,7 @@ cint_screen_keyboard: #endif // Set current colour for text (Computes Mapping the 64 p215) - ldx #$01 // default is light blue ($0E), but we use a different one + ldx #CONFIG_COLOR_TXT stx COLOR // Set maximum keyboard buffer size (Computes Mapping the 64 p215) diff --git a/c64/kernal/init/e5a0.setup_vicii.s b/c64/kernal/init/e5a0.setup_vicii.s index 93b54949..538576e9 100644 --- a/c64/kernal/init/e5a0.setup_vicii.s +++ b/c64/kernal/init/e5a0.setup_vicii.s @@ -60,20 +60,10 @@ setup_vicii: // We use a different colour scheme of white text on all blue by default, // but brand-specific color scheme can also be enabled -#if CONFIG_COLORS_BRAND && CONFIG_BRAND_ULTIMATE_64 - - lda #$00 + lda #CONFIG_COLOR_BG sta VIC_EXTCOL sta VIC_BGCOL0 -#else - - lda #$06 - sta VIC_EXTCOL - sta VIC_BGCOL0 - -#endif - // Setup default I/O devices jmp clrchn_reset diff --git a/c64/kernal/tape/load_tape_normal.s b/c64/kernal/tape/load_tape_normal.s index a3d08d45..c53dabdb 100644 --- a/c64/kernal/tape/load_tape_normal.s +++ b/c64/kernal/tape/load_tape_normal.s @@ -45,7 +45,6 @@ load_tape_normal: // Start playing jsr tape_common_prepare_cia jsr tape_ask_play - jsr tape_prepare_reading // FALLTROUGH diff --git a/c64/kernal/tape/load_tape_turbo.s b/c64/kernal/tape/load_tape_turbo.s index 0bf65d07..7c421e90 100644 --- a/c64/kernal/tape/load_tape_turbo.s +++ b/c64/kernal/tape/load_tape_turbo.s @@ -32,7 +32,6 @@ load_tape_auto: // Start playing jsr tape_common_prepare_cia jsr tape_ask_play - jsr tape_prepare_reading // FALLTROUGH diff --git a/c64/kernal/tape/tape_common.s b/c64/kernal/tape/tape_common.s index 75e49567..fa813aef 100644 --- a/c64/kernal/tape/tape_common.s +++ b/c64/kernal/tape/tape_common.s @@ -104,15 +104,6 @@ tape_wait_first_pulse: tape_wait_play_done: - rts - - -// -// Prepare screen / tape motor for reading -// - -tape_prepare_reading: - #if CONFIG_MB_MEGA_65 // Display confirmation diff --git a/c64/kernal/tape/tape_head_align.s b/c64/kernal/tape/tape_head_align.s index 6bbfb526..a669a2a1 100644 --- a/c64/kernal/tape/tape_head_align.s +++ b/c64/kernal/tape/tape_head_align.s @@ -1,11 +1,10 @@ // #LAYOUT# STD * #TAKE +// #LAYOUT# M65 KERNAL_0 #TAKE // #LAYOUT# M65 KERNAL_1 #TAKE // #LAYOUT# * * #IGNORE // -// Tape (normal) helper routine - reading speed calibration -// -// Needs pulse length in .A +// Tape head alignemnt tool // @@ -13,6 +12,7 @@ .label __ha_start = 3 // starting row of the chart +.label __ha_rows = 20 // number of rows for scrolling // Helper tables @@ -21,7 +21,13 @@ // Helper variables -.label __ha_counter = $1200; // 3 bytes +.label __ha_lda_addr = $1200; // 2 bytes, for code generator +.label __ha_sta_addr = $1202; // 2 bytes, for code generator +.label __ha_counter = $1204; // 3 bytes + +// Generated code location + +.label __ha_scroll = $1300; tape_head_align: @@ -34,24 +40,23 @@ tape_head_align: #else - // Start by asking for playback - - // XXX jsr tape_ask_play - // Disable interrupts, set proper I/O values sei + jsr CLALL jsr IOINIT jsr cint_legacy - jsr tape_motor_on + ldx #$02 // set timer A to 3 ticks jsr tape_common_prepare_cia_by_x + jsr tape_motor_on + // Clear color data ($0800) ldy #$00 !: - lda #($01 * $10 + $06) // XXX synchronize colors with setup_vicii + lda #(CONFIG_COLOR_TXT * $10 + CONFIG_COLOR_BG) sta $0800, y sta $0900, y @@ -61,9 +66,9 @@ tape_head_align: iny bne !- - // Make sure the row where the chart is created is not visible + // Make sure the row where the chart is being created is not visible - lda #($06 * $10 + $06) // XXX synchronize colors with setup_vicii + lda #(CONFIG_COLOR_BG * $10 + CONFIG_COLOR_BG) ldy #$28 !: sta $0800 + __ha_start * 40 - 1, y @@ -88,7 +93,7 @@ tape_head_align: // Set graphics mode - lda #$28 // graphic memory start at $2000, color at $0800 + lda #$28 // graphics start at $2000, color at $0800 sta VIC_YMCSB lda #$3B // set bit 5 to enable graphic mode @@ -123,6 +128,10 @@ tape_head_align: inx bne !-- + // Generate helpercode for screen scrolling + + jsr tape_head_align_gen_code + tape_head_align_loop_1: // XXX check for STOP key, possibly terminate @@ -131,7 +140,7 @@ tape_head_align_loop_1: ldx #$00 !: - jsr tape_head_align_scroll_column + jsr __ha_scroll // scroll one column down, using fast generated code txa clc @@ -192,270 +201,6 @@ tape_head_align_quit: cli rts // XXX perform new after quit -tape_head_align_get_pulse: - - // This routine differs a lot from the one used to read pulse during tape reading: - // - it is not as precise - // - it terminates when timer reaches $FF - // - it updates - - lda #$10 -!: - // Loop to detect signal - - ldy CIA2_TIMBLO // $DD06 - bit CIA1_ICR // $DC0D - bne !+ - - cpy #$FF - bne !- -!: - // Start timer again, force latch reload, count timer A underflows - - ldx #%01010001 - stx CIA2_CRB // $DD0F - - // Update time counter - - tya - clc - adc __ha_counter + 0 - sta __ha_counter + 0 - bcc !+ - inc __ha_counter + 1 - bne !+ - inc __ha_counter + 2 -!: - // Return with time elapsed - - tya - rts - -tape_head_align_scroll_column: - - // XXX autogenerate this code somewhere - - lda __ha_chart + 9 * (8 * 40) + 6, x - sta __ha_chart + 9 * (8 * 40) + 7, x - - lda __ha_chart + 9 * (8 * 40) + 5, x - sta __ha_chart + 9 * (8 * 40) + 6, x - - lda __ha_chart + 9 * (8 * 40) + 4, x - sta __ha_chart + 9 * (8 * 40) + 5, x - - lda __ha_chart + 9 * (8 * 40) + 3, x - sta __ha_chart + 9 * (8 * 40) + 4, x - - lda __ha_chart + 9 * (8 * 40) + 2, x - sta __ha_chart + 9 * (8 * 40) + 3, x - - lda __ha_chart + 9 * (8 * 40) + 1, x - sta __ha_chart + 9 * (8 * 40) + 2, x - - lda __ha_chart + 9 * (8 * 40) + 0, x - sta __ha_chart + 9 * (8 * 40) + 1, x - - lda __ha_chart + 8 * (8 * 40) + 7, x - sta __ha_chart + 9 * (8 * 40) + 0, x - - lda __ha_chart + 8 * (8 * 40) + 6, x - sta __ha_chart + 8 * (8 * 40) + 7, x - - lda __ha_chart + 8 * (8 * 40) + 5, x - sta __ha_chart + 8 * (8 * 40) + 6, x - - lda __ha_chart + 8 * (8 * 40) + 4, x - sta __ha_chart + 8 * (8 * 40) + 5, x - - lda __ha_chart + 8 * (8 * 40) + 3, x - sta __ha_chart + 8 * (8 * 40) + 4, x - - lda __ha_chart + 8 * (8 * 40) + 2, x - sta __ha_chart + 8 * (8 * 40) + 3, x - - lda __ha_chart + 8 * (8 * 40) + 1, x - sta __ha_chart + 8 * (8 * 40) + 2, x - - lda __ha_chart + 8 * (8 * 40) + 0, x - sta __ha_chart + 8 * (8 * 40) + 1, x - - lda __ha_chart + 7 * (8 * 40) + 7, x - sta __ha_chart + 8 * (8 * 40) + 0, x - - lda __ha_chart + 7 * (8 * 40) + 6, x - sta __ha_chart + 7 * (8 * 40) + 7, x - - lda __ha_chart + 7 * (8 * 40) + 5, x - sta __ha_chart + 7 * (8 * 40) + 6, x - - lda __ha_chart + 7 * (8 * 40) + 4, x - sta __ha_chart + 7 * (8 * 40) + 5, x - - lda __ha_chart + 7 * (8 * 40) + 3, x - sta __ha_chart + 7 * (8 * 40) + 4, x - - lda __ha_chart + 7 * (8 * 40) + 2, x - sta __ha_chart + 7 * (8 * 40) + 3, x - - lda __ha_chart + 7 * (8 * 40) + 1, x - sta __ha_chart + 7 * (8 * 40) + 2, x - - lda __ha_chart + 7 * (8 * 40) + 0, x - sta __ha_chart + 7 * (8 * 40) + 1, x - - lda __ha_chart + 6 * (8 * 40) + 7, x - sta __ha_chart + 7 * (8 * 40) + 0, x - - lda __ha_chart + 6 * (8 * 40) + 6, x - sta __ha_chart + 6 * (8 * 40) + 7, x - - lda __ha_chart + 6 * (8 * 40) + 5, x - sta __ha_chart + 6 * (8 * 40) + 6, x - - lda __ha_chart + 6 * (8 * 40) + 4, x - sta __ha_chart + 6 * (8 * 40) + 5, x - - lda __ha_chart + 6 * (8 * 40) + 3, x - sta __ha_chart + 6 * (8 * 40) + 4, x - - lda __ha_chart + 6 * (8 * 40) + 2, x - sta __ha_chart + 6 * (8 * 40) + 3, x - - lda __ha_chart + 6 * (8 * 40) + 1, x - sta __ha_chart + 6 * (8 * 40) + 2, x - - lda __ha_chart + 6 * (8 * 40) + 0, x - sta __ha_chart + 6 * (8 * 40) + 1, x - - lda __ha_chart + 5 * (8 * 40) + 7, x - sta __ha_chart + 6 * (8 * 40) + 0, x - - lda __ha_chart + 5 * (8 * 40) + 6, x - sta __ha_chart + 5 * (8 * 40) + 7, x - - lda __ha_chart + 5 * (8 * 40) + 5, x - sta __ha_chart + 5 * (8 * 40) + 6, x - - lda __ha_chart + 5 * (8 * 40) + 4, x - sta __ha_chart + 5 * (8 * 40) + 5, x - - lda __ha_chart + 5 * (8 * 40) + 3, x - sta __ha_chart + 5 * (8 * 40) + 4, x - - lda __ha_chart + 5 * (8 * 40) + 2, x - sta __ha_chart + 5 * (8 * 40) + 3, x - - lda __ha_chart + 5 * (8 * 40) + 1, x - sta __ha_chart + 5 * (8 * 40) + 2, x - - lda __ha_chart + 5 * (8 * 40) + 0, x - sta __ha_chart + 5 * (8 * 40) + 1, x - - lda __ha_chart + 4 * (8 * 40) + 7, x - sta __ha_chart + 5 * (8 * 40) + 0, x - - lda __ha_chart + 4 * (8 * 40) + 6, x - sta __ha_chart + 4 * (8 * 40) + 7, x - - lda __ha_chart + 4 * (8 * 40) + 5, x - sta __ha_chart + 4 * (8 * 40) + 6, x - - lda __ha_chart + 4 * (8 * 40) + 4, x - sta __ha_chart + 4 * (8 * 40) + 5, x - - lda __ha_chart + 4 * (8 * 40) + 3, x - sta __ha_chart + 4 * (8 * 40) + 4, x - - lda __ha_chart + 4 * (8 * 40) + 2, x - sta __ha_chart + 4 * (8 * 40) + 3, x - - lda __ha_chart + 4 * (8 * 40) + 1, x - sta __ha_chart + 4 * (8 * 40) + 2, x - - lda __ha_chart + 4 * (8 * 40) + 0, x - sta __ha_chart + 4 * (8 * 40) + 1, x - - lda __ha_chart + 3 * (8 * 40) + 7, x - sta __ha_chart + 4 * (8 * 40) + 0, x - - lda __ha_chart + 3 * (8 * 40) + 6, x - sta __ha_chart + 3 * (8 * 40) + 7, x - - lda __ha_chart + 3 * (8 * 40) + 5, x - sta __ha_chart + 3 * (8 * 40) + 6, x - - lda __ha_chart + 3 * (8 * 40) + 4, x - sta __ha_chart + 3 * (8 * 40) + 5, x - - lda __ha_chart + 3 * (8 * 40) + 3, x - sta __ha_chart + 3 * (8 * 40) + 4, x - - lda __ha_chart + 3 * (8 * 40) + 2, x - sta __ha_chart + 3 * (8 * 40) + 3, x - - lda __ha_chart + 3 * (8 * 40) + 1, x - sta __ha_chart + 3 * (8 * 40) + 2, x - - lda __ha_chart + 3 * (8 * 40) + 0, x - sta __ha_chart + 3 * (8 * 40) + 1, x - - lda __ha_chart + 2 * (8 * 40) + 7, x - sta __ha_chart + 3 * (8 * 40) + 0, x - - lda __ha_chart + 2 * (8 * 40) + 6, x - sta __ha_chart + 2 * (8 * 40) + 7, x - - lda __ha_chart + 2 * (8 * 40) + 5, x - sta __ha_chart + 2 * (8 * 40) + 6, x - - lda __ha_chart + 2 * (8 * 40) + 4, x - sta __ha_chart + 2 * (8 * 40) + 5, x - - lda __ha_chart + 2 * (8 * 40) + 3, x - sta __ha_chart + 2 * (8 * 40) + 4, x - - lda __ha_chart + 2 * (8 * 40) + 2, x - sta __ha_chart + 2 * (8 * 40) + 3, x - - lda __ha_chart + 2 * (8 * 40) + 1, x - sta __ha_chart + 2 * (8 * 40) + 2, x - - lda __ha_chart + 2 * (8 * 40) + 0, x - sta __ha_chart + 2 * (8 * 40) + 1, x - - lda __ha_chart + 1 * (8 * 40) + 7, x - sta __ha_chart + 2 * (8 * 40) + 0, x - - lda __ha_chart + 1 * (8 * 40) + 6, x - sta __ha_chart + 1 * (8 * 40) + 7, x - - lda __ha_chart + 1 * (8 * 40) + 5, x - sta __ha_chart + 1 * (8 * 40) + 6, x - - lda __ha_chart + 1 * (8 * 40) + 4, x - sta __ha_chart + 1 * (8 * 40) + 5, x - - lda __ha_chart + 1 * (8 * 40) + 3, x - sta __ha_chart + 1 * (8 * 40) + 4, x - - lda __ha_chart + 1 * (8 * 40) + 2, x - sta __ha_chart + 1 * (8 * 40) + 3, x - - lda __ha_chart + 1 * (8 * 40) + 1, x - sta __ha_chart + 1 * (8 * 40) + 2, x - - lda __ha_chart + 1 * (8 * 40) + 0, x - sta __ha_chart + 1 * (8 * 40) + 1, x - - lda __ha_chart + 0 * (8 * 40) + 7, x - sta __ha_chart + 1 * (8 * 40) + 0, x - - lda #$00 - sta __ha_chart + 0 * (8 * 40) + 7, x - - rts - #endif // ROM layout diff --git a/c64/kernal/tape/tape_head_align_gen_code.s b/c64/kernal/tape/tape_head_align_gen_code.s new file mode 100644 index 00000000..072dc6c3 --- /dev/null +++ b/c64/kernal/tape/tape_head_align_gen_code.s @@ -0,0 +1,132 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 KERNAL_1 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Tape head alignemnt tool - helper code generator +// + + +#if CONFIG_TAPE_HEAD_ALIGN + + +tape_head_align_gen_code: + + // Setup generated code start address + + lda #<__ha_scroll + sta SAL+0 + lda #>__ha_scroll + sta SAL+1 + + // Setup initial source and destination addresses + + ldy #<(__ha_chart + __ha_rows * (8 * 40) + 6) + sty __ha_lda_addr + 0 + iny + sty __ha_sta_addr + 0 + + ldy #>(__ha_chart + __ha_rows * (8 * 40) + 6) + sty __ha_lda_addr + 1 + sty __ha_sta_addr + 1 + + // Emit code to move 7 rows of one 8x8 cell +!: + ldx #$07 +!: + jsr tape_head_align_gen_code_emit_pair + + dec __ha_lda_addr + 0 + dec __ha_sta_addr + 0 + + dex + bne !- + + // Emit code to fetch a top row from the cell above + + inc __ha_lda_addr + 0 + sec + lda __ha_lda_addr + 0 + sbc #<(8 * 40 - 7) + sta __ha_lda_addr + 0 + lda __ha_lda_addr + 1 + sbc #>(8 * 40 - 7) + + sta __ha_lda_addr + 1 + + jsr tape_head_align_gen_code_emit_pair + + // Prepare addresses for the next iteration + + lda __ha_lda_addr + 0 + sta __ha_sta_addr + 0 + lda __ha_lda_addr + 1 + sta __ha_sta_addr + 1 + + dec __ha_lda_addr + 0 + + // Now, new iteration - if needed + + lda __ha_sta_addr + 0 + cmp #<(__ha_chart + 7) + bne !-- + lda __ha_sta_addr + 1 + cmp #>(__ha_chart + 7) + bne !-- + + // Last pair to be generated starts from LDA #$00 + + lda #$A9 + jsr tape_head_align_gen_code_emit_byte + lda #$00 + jsr tape_head_align_gen_code_emit_byte + + jsr tape_head_align_gen_code_emit_sta + + // Emit RTS and quit + + lda #$60 + jmp tape_head_align_gen_code_emit_byte + + + +tape_head_align_gen_code_emit_pair: + + lda #$BD // LDA absolute, x + jsr tape_head_align_gen_code_emit_byte + + lda __ha_lda_addr + 0 + jsr tape_head_align_gen_code_emit_byte + lda __ha_lda_addr + 1 + jsr tape_head_align_gen_code_emit_byte + + // FALLTROUGH + +tape_head_align_gen_code_emit_sta: + + lda #$9D // STA absolute, x + jsr tape_head_align_gen_code_emit_byte + + lda __ha_sta_addr + 0 + jsr tape_head_align_gen_code_emit_byte + lda __ha_sta_addr + 1 + + // FALLTROUGH + +tape_head_align_gen_code_emit_byte: + + ldy #$00 + sta (SAL), y +#if HAS_OPCODES_65CE02 + inw SAL +#else + inc SAL+0 + bne !+ + inc SAL+1 +!: +#endif + + rts + + +#endif // CONFIG_TAPE_HEAD_ALIGN diff --git a/c64/kernal/tape/tape_head_align_get_pulse.s b/c64/kernal/tape/tape_head_align_get_pulse.s new file mode 100644 index 00000000..15739ef9 --- /dev/null +++ b/c64/kernal/tape/tape_head_align_get_pulse.s @@ -0,0 +1,52 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 KERNAL_1 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Tape head alignemnt tool - helper routine for reading pulses +// + + +#if CONFIG_TAPE_HEAD_ALIGN + + +tape_head_align_get_pulse: + + // This routine differs a lot from the one used to read pulse during tape reading: + // - it is not as precise + // - it terminates when timer reaches $FF + // - it updates + + lda #$10 +!: + // Loop to detect signal + + ldy CIA2_TIMBLO // $DD06 + bit CIA1_ICR // $DC0D + bne !+ + + cpy #$FF + bne !- +!: + // Start timer again, force latch reload, count timer A underflows + + ldx #%01010001 + stx CIA2_CRB // $DD0F + + // Update time counter + + tya + clc + adc __ha_counter + 0 + sta __ha_counter + 0 + bcc !+ + inc __ha_counter + 1 + bne !+ + inc __ha_counter + 2 +!: + // Return with time elapsed + + tya + rts + +#endif // CONFIG_TAPE_HEAD_ALIGN From 0b13ce175eed15ac419c72e110fcb6de1f080eb3 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 3 Jun 2020 16:43:21 +0200 Subject: [PATCH 005/103] added helper marks for head align tool, use CIA for stable timing --- c64/,,config_custom.s | 8 +- c64/kernal/init/fda3.ioinit.s | 12 +- c64/kernal/tape/tape_head_align.s | 135 +++++++++++++++++--- c64/kernal/tape/tape_head_align_get_pulse.s | 14 +- 4 files changed, 129 insertions(+), 40 deletions(-) diff --git a/c64/,,config_custom.s b/c64/,,config_custom.s index bb93e633..d98e0103 100644 --- a/c64/,,config_custom.s +++ b/c64/,,config_custom.s @@ -46,10 +46,10 @@ // I/O devices #define CONFIG_IEC -//#define CONFIG_IEC_DOLPHINDOS -//#define CONFIG_IEC_DOLPHINDOS_FAST -//#define CONFIG_IEC_JIFFYDOS -//#define CONFIG_IEC_JIFFYDOS_BLANK +#define CONFIG_IEC_DOLPHINDOS +#define CONFIG_IEC_DOLPHINDOS_FAST +#define CONFIG_IEC_JIFFYDOS +#define CONFIG_IEC_JIFFYDOS_BLANK // #define CONFIG_IEC_BURST_CIA1 // please keep disabled for now // #define CONFIG_IEC_BURST_CIA2 // please keep disabled for now // #define CONFIG_IEC_BURST_SOFT // please keep disabled for now diff --git a/c64/kernal/init/fda3.ioinit.s b/c64/kernal/init/fda3.ioinit.s index 9e67a661..f6398b4d 100644 --- a/c64/kernal/init/fda3.ioinit.s +++ b/c64/kernal/init/fda3.ioinit.s @@ -138,26 +138,26 @@ IOINIT: // Checked using VICE that original ROM initializes timers this way ldx #$08 - stx CIA1_CRB // $DC0F - stx CIA2_CRA // $DD0E - stx CIA2_CRB // $DD0F + stx CIA1_CRB // $DC0F + stx CIA2_CRA // $DD0E + stx CIA2_CRB // $DD0F // Set VIC-II bank - at least the 'Operacja Proboszcz' game needs this within IOINIT // Checked on original ROMs, that it sets bit #2 (RS-232 output) high ldx #%00000111 // XXX adapt this to IEC idle state, JMP at the end won't be needed - stx CIA2_PRA // $DD00 + stx CIA2_PRA // $DD00 // Put something sane in the IRQ timer jsr setup_irq_timer // Enable timer A to run continuously (http://codebase64.org/doku.php?id=base:timerinterrupts) ldx #$11 - stx CIA1_CRA // $DC0E + stx CIA1_CRA // $DC0E // Enable timer interrupt ldx #$81 - stx CIA1_ICR // $DC0D + stx CIA1_ICR // $DC0D #if CONFIG_IEC diff --git a/c64/kernal/tape/tape_head_align.s b/c64/kernal/tape/tape_head_align.s index a669a2a1..53e46861 100644 --- a/c64/kernal/tape/tape_head_align.s +++ b/c64/kernal/tape/tape_head_align.s @@ -11,8 +11,8 @@ #if CONFIG_TAPE_HEAD_ALIGN -.label __ha_start = 3 // starting row of the chart -.label __ha_rows = 20 // number of rows for scrolling +.label __ha_start = 12 // starting row of the chart +.label __ha_rows = 10 // number of rows for scrolling // Helper tables @@ -23,7 +23,7 @@ .label __ha_lda_addr = $1200; // 2 bytes, for code generator .label __ha_sta_addr = $1202; // 2 bytes, for code generator -.label __ha_counter = $1204; // 3 bytes +.label __ha_gfxflag = $1204; // Generated code location @@ -50,6 +50,10 @@ tape_head_align: ldx #$02 // set timer A to 3 ticks jsr tape_common_prepare_cia_by_x + ldx #$FF // timer to control scroll speed + stx CIA1_TIMBLO // $DC06 + stx CIA1_TIMBHI // $DC07 + jsr tape_motor_on // Clear color data ($0800) @@ -69,9 +73,10 @@ tape_head_align: // Make sure the row where the chart is being created is not visible lda #(CONFIG_COLOR_BG * $10 + CONFIG_COLOR_BG) - ldy #$28 + ldy #$22 !: - sta $0800 + __ha_start * 40 - 1, y + sta $0800 + __ha_start * 40 + 2, y + // sta $0800 + __ha_start * 40 + 2 + (__ha_rows + 1) * 40, y dey bne !- @@ -128,14 +133,34 @@ tape_head_align: inx bne !-- - // Generate helpercode for screen scrolling + // Initialize flag for additional GFX effects + + stx __ha_gfxflag + + // Generate helper code for screen scrolling jsr tape_head_align_gen_code + // Scroll several times to fill-in the screen + + ldx #(__ha_rows * 8) +!: + phx_trash_a + jsr tape_head_align_scroll_gfx + plx_trash_a + + dex + bne !- + tape_head_align_loop_1: // XXX check for STOP key, possibly terminate + // Launch the timer + + ldx #%00011001 // start timer, one-shot force latch reload, count system ticks + stx CIA1_CRB // $DC0F + // Scroll the whole chart one line down ldx #$00 @@ -148,15 +173,9 @@ tape_head_align_loop_1: tax bne !- - // XXX draw helper lines + // Draw helpers and decorators - // Initialize counter - - lda #$80 - sta __ha_counter + 1 - lda #$00 - sta __ha_counter + 0 - sta __ha_counter + 2 + jsr tape_head_align_apply_gfx // Skip 2 pulses, these measurements will be too imprecise @@ -186,9 +205,12 @@ tape_head_align_loop_2: tape_head_align_drawn: - lda __ha_counter + 2 - beq tape_head_align_loop_2 - bne tape_head_align_loop_1 + lda CIA1_TIMBLO + and CIA1_TIMBHI + eor #$FF + + bne tape_head_align_loop_2 + beq tape_head_align_loop_1 tape_head_align_quit: @@ -201,6 +223,85 @@ tape_head_align_quit: cli rts // XXX perform new after quit + + + +// XXX size-optimize code below + +tape_head_align_scroll_gfx: + + ldx #(8 * 0) + jsr __ha_scroll + ldx #(8 * 1) + jsr __ha_scroll + ldx #(8 * 6) + jsr __ha_scroll + ldx #(8 * 13) + jsr __ha_scroll + ldx #(8 * 21) + jsr __ha_scroll + ldx #(8 * 30) + jsr __ha_scroll + ldx #(8 * 31) + jsr __ha_scroll + + // FALLTROUGH + +tape_head_align_apply_gfx: + + // Apply GFX effects XXX improve it + + lda __ha_gfxflag + inc __ha_gfxflag + and #%00001100 + bne !+ + ldy #%11110001 + lda #%10001111 + bne !++ +!: + ldy #%00000001 + lda #%10000000 +!: + ora __ha_chart + 7 + 8 * 0 + sta __ha_chart + 7 + 8 * 0 + + tya + ora __ha_chart + 7 + 8 * 31 + sta __ha_chart + 7 + 8 * 31 + + // Draw helper lines + + lda __ha_gfxflag + and #%00000010 + beq !+ + + lda #%00010000 + ora __ha_chart + 7 + 8 * 1 + sta __ha_chart + 7 + 8 * 1 + + lda #%00001000 + ora __ha_chart + 7 + 8 * 30 + sta __ha_chart + 7 + 8 * 30 + + // For normal XXX check values + + lda #%00000100 + ora __ha_chart + 7 + 8 * 6 + sta __ha_chart + 7 + 8 * 6 + + lda #%00010000 + ora __ha_chart + 7 + 8 * 13 + sta __ha_chart + 7 + 8 * 13 + + // For turbo XXX check values + + lda #%01000000 + ora __ha_chart + 7 + 8 * 21 + sta __ha_chart + 7 + 8 * 21 +!: + rts + + #endif // ROM layout diff --git a/c64/kernal/tape/tape_head_align_get_pulse.s b/c64/kernal/tape/tape_head_align_get_pulse.s index 15739ef9..03d04d7c 100644 --- a/c64/kernal/tape/tape_head_align_get_pulse.s +++ b/c64/kernal/tape/tape_head_align_get_pulse.s @@ -12,10 +12,9 @@ tape_head_align_get_pulse: - // This routine differs a lot from the one used to read pulse during tape reading: + // This routine differs from the one used to read pulse during tape reading: // - it is not as precise // - it terminates when timer reaches $FF - // - it updates lda #$10 !: @@ -33,17 +32,6 @@ tape_head_align_get_pulse: ldx #%01010001 stx CIA2_CRB // $DD0F - // Update time counter - - tya - clc - adc __ha_counter + 0 - sta __ha_counter + 0 - bcc !+ - inc __ha_counter + 1 - bne !+ - inc __ha_counter + 2 -!: // Return with time elapsed tya From 753603e5633c1a31bb6a01e37dd88663d069a5a3 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 3 Jun 2020 17:49:31 +0200 Subject: [PATCH 006/103] more head alignment tool tweaks --- c64/kernal/tape/tape_head_align.s | 69 +++++++++++-------------------- 1 file changed, 24 insertions(+), 45 deletions(-) diff --git a/c64/kernal/tape/tape_head_align.s b/c64/kernal/tape/tape_head_align.s index 53e46861..cc84745d 100644 --- a/c64/kernal/tape/tape_head_align.s +++ b/c64/kernal/tape/tape_head_align.s @@ -11,7 +11,7 @@ #if CONFIG_TAPE_HEAD_ALIGN -.label __ha_start = 12 // starting row of the chart +.label __ha_start = 11 // starting row of the chart .label __ha_rows = 10 // number of rows for scrolling // Helper tables @@ -72,11 +72,11 @@ tape_head_align: // Make sure the row where the chart is being created is not visible - lda #(CONFIG_COLOR_BG * $10 + CONFIG_COLOR_BG) - ldy #$22 + lda #(CONFIG_COLOR_TXT * $10 + CONFIG_COLOR_TXT) + ldy #$24 !: - sta $0800 + __ha_start * 40 + 2, y - // sta $0800 + __ha_start * 40 + 2 + (__ha_rows + 1) * 40, y + sta $0800 + __ha_start * 40 + 1, y + sta $0800 + __ha_start * 40 + 1 + (__ha_rows + 1) * 40, y dey bne !- @@ -141,20 +141,13 @@ tape_head_align: jsr tape_head_align_gen_code - // Scroll several times to fill-in the screen - - ldx #(__ha_rows * 8) -!: - phx_trash_a - jsr tape_head_align_scroll_gfx - plx_trash_a - - dex - bne !- - tape_head_align_loop_1: - // XXX check for STOP key, possibly terminate + jsr udtim_keyboard + jsr STOP + bcs tape_head_align_quit + + // XXX check for STOP, go to tape_head_align_quit // Launch the timer @@ -212,47 +205,33 @@ tape_head_align_drawn: bne tape_head_align_loop_2 beq tape_head_align_loop_1 + + tape_head_align_quit: - // Clear screen, restore old display settings + // It makes no sense to return to system, as we already destroyed + // a lot of memory; fust clear initial BASIC text area to prevent + // data recovery attempts, and reset - jsr cint_legacy + ldx #$00 + txa +!: + sta $0800, x + inx + bne !- - // XXX restore COLOR, VIC_EXTCOL, VIC_BGCOL0, CIA2_PRA - - cli - rts // XXX perform new after quit + jmp hw_entry_reset - -// XXX size-optimize code below - -tape_head_align_scroll_gfx: - - ldx #(8 * 0) - jsr __ha_scroll - ldx #(8 * 1) - jsr __ha_scroll - ldx #(8 * 6) - jsr __ha_scroll - ldx #(8 * 13) - jsr __ha_scroll - ldx #(8 * 21) - jsr __ha_scroll - ldx #(8 * 30) - jsr __ha_scroll - ldx #(8 * 31) - jsr __ha_scroll - - // FALLTROUGH - tape_head_align_apply_gfx: // Apply GFX effects XXX improve it lda __ha_gfxflag inc __ha_gfxflag + clc + adc #$08 and #%00001100 bne !+ ldy #%11110001 From 023a21c3ef6f7e20660f56eccb0ac1172aa55def Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 3 Jun 2020 19:12:09 +0200 Subject: [PATCH 007/103] moved pulse probilng to raster interrupt routine --- c64/kernal/tape/tape_head_align.s | 102 +++++++++++++++----- c64/kernal/tape/tape_head_align_get_pulse.s | 13 ++- c64/kernal/tape/tape_head_align_irq.s | 54 +++++++++++ 3 files changed, 140 insertions(+), 29 deletions(-) create mode 100644 c64/kernal/tape/tape_head_align_irq.s diff --git a/c64/kernal/tape/tape_head_align.s b/c64/kernal/tape/tape_head_align.s index cc84745d..d645bd9e 100644 --- a/c64/kernal/tape/tape_head_align.s +++ b/c64/kernal/tape/tape_head_align.s @@ -10,20 +10,25 @@ #if CONFIG_TAPE_HEAD_ALIGN +// XXX for Mega65 it can be done more easily, by just disabling the badlines -.label __ha_start = 11 // starting row of the chart -.label __ha_rows = 10 // number of rows for scrolling + +.label __ha_start = 11 // starting row of the chart +.label __ha_rows = 10 // number of rows for scrolling // Helper tables -.label __ha_offsets = $1000; -.label __ha_masks = $1100; +.label __ha_offsets = $1000; +.label __ha_masks = $1100; // Helper variables -.label __ha_lda_addr = $1200; // 2 bytes, for code generator -.label __ha_sta_addr = $1202; // 2 bytes, for code generator -.label __ha_gfxflag = $1204; +.label __ha_lda_addr = $1200; // 2 bytes, for code generator +.label __ha_sta_addr = $1202; // 2 bytes, for code generator +.label __ha_pulses = $1204; // 16 bytes +.label __ha_gfxflag = $1214; // 1 byte +.label __ha_loopcnt = $1215; // 1 byte + // Generated code location @@ -42,8 +47,8 @@ tape_head_align: // Disable interrupts, set proper I/O values - sei jsr CLALL + sei jsr IOINIT jsr cint_legacy @@ -133,22 +138,49 @@ tape_head_align: inx bne !-- - // Initialize flag for additional GFX effects + // Initialize flag for additional GFX effects and the pulse lengths - stx __ha_gfxflag + lda #$00 + ldx #$10 +!: + sta __ha_pulses, x + dex + bpl !- // Generate helper code for screen scrolling jsr tape_head_align_gen_code + // Provide new IRQ routine address + + lda #tape_head_align_irq + sta CINV+1 + + // Setup raster interrupt routine - see https://www.c64-wiki.com/wiki/Raster_interrupt + + lda #%01111111 // prevent CIA from generating interrupts + sta CIA1_ICR // $DC0D + + and VIC_SCROLY // clear the highest bit of RASTER + sta VIC_SCROLY // $D011 + + lda #$FF // setup interrupt on line 255, near no-badline area + sta VIC_RASTER + + lda #%00000001 // enable raster interrupts + sta VIC_IRQMSK // $D01A + cli + tape_head_align_loop_1: + // Check for STOP key + jsr udtim_keyboard jsr STOP bcs tape_head_align_quit - // XXX check for STOP, go to tape_head_align_quit - // Launch the timer ldx #%00011001 // start timer, one-shot force latch reload, count system ticks @@ -175,24 +207,26 @@ tape_head_align_loop_1: jsr tape_head_align_get_pulse jsr tape_head_align_get_pulse + // FALLTROUGH + tape_head_align_loop_2: - // Retrieve actual pulse length + // Draw pulses - jsr tape_head_align_get_pulse + ldx #$00 +!: + stx __ha_loopcnt + + lda __ha_pulses, x cmp #$FF - beq tape_head_align_drawn // skip drawing for too long pulses + beq tape_head_align_drawn // $FF - end of pulses to draw - // Put pulse on the screen; center the chart horizontaly, with some margin from top + jsr tape_head_align_draw_pulse - .label __ha_chart = $2000 + 8 * (40 * __ha_start + 4) - - tax - lda __ha_offsets, x - tay - lda __ha_masks, x - ora __ha_chart + 7, y - sta __ha_chart + 7, y + ldx __ha_loopcnt + inx + cpx #$10 + bne !- // FALLTROUGH @@ -224,9 +258,27 @@ tape_head_align_quit: + +tape_head_align_draw_pulse: + + // Put pulse on the screen; center the chart horizontaly, with some margin from top + + .label __ha_chart = $2000 + 8 * (40 * __ha_start + 4) + + tax + lda __ha_offsets, x + tay + lda __ha_masks, x + ora __ha_chart + 7, y + sta __ha_chart + 7, y +!: + rts + + + tape_head_align_apply_gfx: - // Apply GFX effects XXX improve it + // Apply GFX effects lda __ha_gfxflag inc __ha_gfxflag diff --git a/c64/kernal/tape/tape_head_align_get_pulse.s b/c64/kernal/tape/tape_head_align_get_pulse.s index 03d04d7c..c1811238 100644 --- a/c64/kernal/tape/tape_head_align_get_pulse.s +++ b/c64/kernal/tape/tape_head_align_get_pulse.s @@ -15,6 +15,7 @@ tape_head_align_get_pulse: // This routine differs from the one used to read pulse during tape reading: // - it is not as precise // - it terminates when timer reaches $FF + // - ir returns value in .Y lda #$10 !: @@ -27,14 +28,18 @@ tape_head_align_get_pulse: cpy #$FF bne !- !: + // FALLTROUGH + +tape_head_align_get_pulse_start_timer: + // Start timer again, force latch reload, count timer A underflows - ldx #%01010001 - stx CIA2_CRB // $DD0F + lda #%01010001 + sta CIA2_CRB // $DD0F - // Return with time elapsed + // Return with time elapsed in .Y - tya rts + #endif // CONFIG_TAPE_HEAD_ALIGN diff --git a/c64/kernal/tape/tape_head_align_irq.s b/c64/kernal/tape/tape_head_align_irq.s new file mode 100644 index 00000000..92535a56 --- /dev/null +++ b/c64/kernal/tape/tape_head_align_irq.s @@ -0,0 +1,54 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 KERNAL_1 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Tape head alignemnt tool - interrupt routine +// + + +#if CONFIG_TAPE_HEAD_ALIGN + + +tape_head_align_irq: + + // inc $d020 // XXX for debug only + + // Acknowledge interrupt + + asl VIC_IRQ + + // Clear table of pulses stored + + lda #$FF + ldy #$0F +!: + sta __ha_pulses, y + dey + bpl !- + + // Ignore 2 first pulses, they can be garbage + + jsr tape_head_align_get_pulse + jsr tape_head_align_get_pulse + + // Now, we can retrieve a pulse for real + + ldx #$00 +!: + jsr tape_head_align_get_pulse + tya + sta __ha_pulses, x + + // XXX terminate ion case VIC_RASTER went too far + + inx + cpx #$10 + bne !- + + // dec $d020 // XXX for debug only + + jmp return_from_interrupt + + +#endif // CONFIG_TAPE_HEAD_ALIGN From cefa6ec1fb68fd04dfc9773136d8ccad5646de02 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 4 Jun 2020 15:41:04 +0200 Subject: [PATCH 008/103] fixed distrubances in head align tool --- c64/kernal/tape/tape_head_align.s | 118 ++++--------------- c64/kernal/tape/tape_head_align_apply_gfx.s | 70 +++++++++++ c64/kernal/tape/tape_head_align_draw_pulse.s | 29 +++++ c64/kernal/tape/tape_head_align_get_pulse.s | 4 +- c64/kernal/tape/tape_head_align_irq.s | 28 +++-- 5 files changed, 147 insertions(+), 102 deletions(-) create mode 100644 c64/kernal/tape/tape_head_align_apply_gfx.s create mode 100644 c64/kernal/tape/tape_head_align_draw_pulse.s diff --git a/c64/kernal/tape/tape_head_align.s b/c64/kernal/tape/tape_head_align.s index d645bd9e..adb750ae 100644 --- a/c64/kernal/tape/tape_head_align.s +++ b/c64/kernal/tape/tape_head_align.s @@ -12,6 +12,13 @@ // XXX for Mega65 it can be done more easily, by just disabling the badlines +// XXX consider "PRESS PLAY ON TAPE" before start, with option to stop +// XXX add some text explaining what tool it is ('head align chart', or something similar) +// XXX make tape wedge (and this tool) available also without tape turbo support +// XXX create separate configuration for tape users +// XXX block NMIs +// XXX fix Mega65 build compilation issues + .label __ha_start = 11 // starting row of the chart .label __ha_rows = 10 // number of rows for scrolling @@ -25,9 +32,9 @@ .label __ha_lda_addr = $1200; // 2 bytes, for code generator .label __ha_sta_addr = $1202; // 2 bytes, for code generator -.label __ha_pulses = $1204; // 16 bytes -.label __ha_gfxflag = $1214; // 1 byte -.label __ha_loopcnt = $1215; // 1 byte +.label __ha_pulses = $1204; // 64 bytes +.label __ha_gfxflag = $1244; // 1 byte +.label __ha_loopcnt = $1245; // 1 byte // Generated code location @@ -75,16 +82,6 @@ tape_head_align: iny bne !- - // Make sure the row where the chart is being created is not visible - - lda #(CONFIG_COLOR_TXT * $10 + CONFIG_COLOR_TXT) - ldy #$24 -!: - sta $0800 + __ha_start * 40 + 1, y - sta $0800 + __ha_start * 40 + 1 + (__ha_rows + 1) * 40, y - dey - bne !- - // Clear bitmap data ($2000) lda #$20 @@ -101,6 +98,19 @@ tape_head_align: cpx #$40 bne !- + // Make sure the row where the chart is being created is not visible + + lda #(CONFIG_COLOR_TXT * $10 + CONFIG_COLOR_TXT) + ldy #$24 +!: + sta $0800 + __ha_start * 40 + 1, y + sta $0800 + __ha_start * 40 + 1 + (__ha_rows + 1) * 40, y + + dey + bne !- + + + // Set graphics mode lda #$28 // graphics start at $2000, color at $0800 @@ -141,7 +151,7 @@ tape_head_align: // Initialize flag for additional GFX effects and the pulse lengths lda #$00 - ldx #$10 + ldx #$40 !: sta __ha_pulses, x dex @@ -166,7 +176,7 @@ tape_head_align: and VIC_SCROLY // clear the highest bit of RASTER sta VIC_SCROLY // $D011 - lda #$FF // setup interrupt on line 255, near no-badline area + lda #$F3 // the last raster where badline can occur, this is 100% safe start sta VIC_RASTER lda #%00000001 // enable raster interrupts @@ -225,7 +235,7 @@ tape_head_align_loop_2: ldx __ha_loopcnt inx - cpx #$10 + cpx #$40 bne !- // FALLTROUGH @@ -257,82 +267,6 @@ tape_head_align_quit: jmp hw_entry_reset - - -tape_head_align_draw_pulse: - - // Put pulse on the screen; center the chart horizontaly, with some margin from top - - .label __ha_chart = $2000 + 8 * (40 * __ha_start + 4) - - tax - lda __ha_offsets, x - tay - lda __ha_masks, x - ora __ha_chart + 7, y - sta __ha_chart + 7, y -!: - rts - - - -tape_head_align_apply_gfx: - - // Apply GFX effects - - lda __ha_gfxflag - inc __ha_gfxflag - clc - adc #$08 - and #%00001100 - bne !+ - ldy #%11110001 - lda #%10001111 - bne !++ -!: - ldy #%00000001 - lda #%10000000 -!: - ora __ha_chart + 7 + 8 * 0 - sta __ha_chart + 7 + 8 * 0 - - tya - ora __ha_chart + 7 + 8 * 31 - sta __ha_chart + 7 + 8 * 31 - - // Draw helper lines - - lda __ha_gfxflag - and #%00000010 - beq !+ - - lda #%00010000 - ora __ha_chart + 7 + 8 * 1 - sta __ha_chart + 7 + 8 * 1 - - lda #%00001000 - ora __ha_chart + 7 + 8 * 30 - sta __ha_chart + 7 + 8 * 30 - - // For normal XXX check values - - lda #%00000100 - ora __ha_chart + 7 + 8 * 6 - sta __ha_chart + 7 + 8 * 6 - - lda #%00010000 - ora __ha_chart + 7 + 8 * 13 - sta __ha_chart + 7 + 8 * 13 - - // For turbo XXX check values - - lda #%01000000 - ora __ha_chart + 7 + 8 * 21 - sta __ha_chart + 7 + 8 * 21 -!: - rts - - #endif // ROM layout diff --git a/c64/kernal/tape/tape_head_align_apply_gfx.s b/c64/kernal/tape/tape_head_align_apply_gfx.s new file mode 100644 index 00000000..0f46157e --- /dev/null +++ b/c64/kernal/tape/tape_head_align_apply_gfx.s @@ -0,0 +1,70 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 KERNAL_1 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Tape head alignemnt tool - draw helper symbols +// + + +#if CONFIG_TAPE_HEAD_ALIGN + + +tape_head_align_apply_gfx: + + // Apply GFX effects + + lda __ha_gfxflag + inc __ha_gfxflag + clc + adc #$08 + and #%00001100 + bne !+ + ldy #%11110001 + lda #%10001111 + bne !++ +!: + ldy #%00000001 + lda #%10000000 +!: + ora __ha_chart + 7 + 8 * 0 + sta __ha_chart + 7 + 8 * 0 + + tya + ora __ha_chart + 7 + 8 * 31 + sta __ha_chart + 7 + 8 * 31 + + // Draw helper lines + + lda __ha_gfxflag + and #%00000010 + beq !+ + + lda #%00010000 + ora __ha_chart + 7 + 8 * 1 + sta __ha_chart + 7 + 8 * 1 + + lda #%00001000 + ora __ha_chart + 7 + 8 * 30 + sta __ha_chart + 7 + 8 * 30 + + // For normal + + lda #%00000001 + ora __ha_chart + 7 + 8 * 6 + sta __ha_chart + 7 + 8 * 6 + + lda #%00000001 + ora __ha_chart + 7 + 8 * 13 + sta __ha_chart + 7 + 8 * 13 + + // For turbo + + lda #%00010000 + ora __ha_chart + 7 + 8 * 21 + sta __ha_chart + 7 + 8 * 21 +!: + rts + + +#endif diff --git a/c64/kernal/tape/tape_head_align_draw_pulse.s b/c64/kernal/tape/tape_head_align_draw_pulse.s new file mode 100644 index 00000000..813d0d0a --- /dev/null +++ b/c64/kernal/tape/tape_head_align_draw_pulse.s @@ -0,0 +1,29 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 KERNAL_1 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Tape head alignemnt tool - draw pulses +// + + +#if CONFIG_TAPE_HEAD_ALIGN + + +tape_head_align_draw_pulse: + + // Put pulse on the screen; center the chart horizontaly, with some margin from top + + .label __ha_chart = $2000 + 8 * (40 * __ha_start + 4) + + tax + lda __ha_offsets, x + tay + lda __ha_masks, x + ora __ha_chart + 7, y + sta __ha_chart + 7, y +!: + rts + + +#endif diff --git a/c64/kernal/tape/tape_head_align_get_pulse.s b/c64/kernal/tape/tape_head_align_get_pulse.s index c1811238..71b22e8e 100644 --- a/c64/kernal/tape/tape_head_align_get_pulse.s +++ b/c64/kernal/tape/tape_head_align_get_pulse.s @@ -3,7 +3,7 @@ // #LAYOUT# * * #IGNORE // -// Tape head alignemnt tool - helper routine for reading pulses +// Tape head alignemnt tool - reading pulses from tape // @@ -15,7 +15,7 @@ tape_head_align_get_pulse: // This routine differs from the one used to read pulse during tape reading: // - it is not as precise // - it terminates when timer reaches $FF - // - ir returns value in .Y + // - it returns value in .Y lda #$10 !: diff --git a/c64/kernal/tape/tape_head_align_irq.s b/c64/kernal/tape/tape_head_align_irq.s index 92535a56..c269b22a 100644 --- a/c64/kernal/tape/tape_head_align_irq.s +++ b/c64/kernal/tape/tape_head_align_irq.s @@ -12,8 +12,6 @@ tape_head_align_irq: - // inc $d020 // XXX for debug only - // Acknowledge interrupt asl VIC_IRQ @@ -21,7 +19,7 @@ tape_head_align_irq: // Clear table of pulses stored lda #$FF - ldy #$0F + ldy #$3F !: sta __ha_pulses, y dey @@ -32,21 +30,35 @@ tape_head_align_irq: jsr tape_head_align_get_pulse jsr tape_head_align_get_pulse - // Now, we can retrieve a pulse for real + // Now, we can retrieve a pulse for the charts ldx #$00 !: jsr tape_head_align_get_pulse + + // If we approached badlines again - we cannot use this measurement anymore + + lda VIC_SCROLY + bmi !+ // branch if lower border + + lda VIC_RASTER + cmp #$33 // first line where badline can occur + bcs tape_head_align_irq_end +!: + // Store measurement + tya sta __ha_pulses, x - // XXX terminate ion case VIC_RASTER went too far + // Next iteration inx - cpx #$10 - bne !- + cpx #$40 + bne !-- - // dec $d020 // XXX for debug only + // FALLTROUGH + +tape_head_align_irq_end: jmp return_from_interrupt From d8248db843131a7805d28ffb714da2a4817d8434 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 4 Jun 2020 17:32:55 +0200 Subject: [PATCH 009/103] added help text for head align tool --- c64/,,config_custom.s | 8 +- c64/kernal/tape/tape_head_align.s | 13 ++- c64/kernal/tape/tape_head_align_help.s | 133 +++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 9 deletions(-) create mode 100644 c64/kernal/tape/tape_head_align_help.s diff --git a/c64/,,config_custom.s b/c64/,,config_custom.s index d98e0103..bb93e633 100644 --- a/c64/,,config_custom.s +++ b/c64/,,config_custom.s @@ -46,10 +46,10 @@ // I/O devices #define CONFIG_IEC -#define CONFIG_IEC_DOLPHINDOS -#define CONFIG_IEC_DOLPHINDOS_FAST -#define CONFIG_IEC_JIFFYDOS -#define CONFIG_IEC_JIFFYDOS_BLANK +//#define CONFIG_IEC_DOLPHINDOS +//#define CONFIG_IEC_DOLPHINDOS_FAST +//#define CONFIG_IEC_JIFFYDOS +//#define CONFIG_IEC_JIFFYDOS_BLANK // #define CONFIG_IEC_BURST_CIA1 // please keep disabled for now // #define CONFIG_IEC_BURST_CIA2 // please keep disabled for now // #define CONFIG_IEC_BURST_SOFT // please keep disabled for now diff --git a/c64/kernal/tape/tape_head_align.s b/c64/kernal/tape/tape_head_align.s index adb750ae..c191977c 100644 --- a/c64/kernal/tape/tape_head_align.s +++ b/c64/kernal/tape/tape_head_align.s @@ -13,14 +13,13 @@ // XXX for Mega65 it can be done more easily, by just disabling the badlines // XXX consider "PRESS PLAY ON TAPE" before start, with option to stop -// XXX add some text explaining what tool it is ('head align chart', or something similar) // XXX make tape wedge (and this tool) available also without tape turbo support // XXX create separate configuration for tape users // XXX block NMIs // XXX fix Mega65 build compilation issues -.label __ha_start = 11 // starting row of the chart +.label __ha_start = 12 // starting row of the chart .label __ha_rows = 10 // number of rows for scrolling // Helper tables @@ -34,7 +33,7 @@ .label __ha_sta_addr = $1202; // 2 bytes, for code generator .label __ha_pulses = $1204; // 64 bytes .label __ha_gfxflag = $1244; // 1 byte -.label __ha_loopcnt = $1245; // 1 byte +.label __ha_storage = $1245; // 1 byte // Generated code location @@ -98,6 +97,10 @@ tape_head_align: cpx #$40 bne !- + // Print help message + + jsr tape_head_align_print_help + // Make sure the row where the chart is being created is not visible lda #(CONFIG_COLOR_TXT * $10 + CONFIG_COLOR_TXT) @@ -225,7 +228,7 @@ tape_head_align_loop_2: ldx #$00 !: - stx __ha_loopcnt + stx __ha_storage lda __ha_pulses, x cmp #$FF @@ -233,7 +236,7 @@ tape_head_align_loop_2: jsr tape_head_align_draw_pulse - ldx __ha_loopcnt + ldx __ha_storage inx cpx #$40 bne !- diff --git a/c64/kernal/tape/tape_head_align_help.s b/c64/kernal/tape/tape_head_align_help.s new file mode 100644 index 00000000..76939d14 --- /dev/null +++ b/c64/kernal/tape/tape_head_align_help.s @@ -0,0 +1,133 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 KERNAL_1 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Tape head alignemnt tool - prints out a help message on screen +// + + +#if CONFIG_TAPE_HEAD_ALIGN + + +tape_head_align_print_help: + + // Make screen font visible + + lda CPU_R6510 + pha + and #%11111011 + sta CPU_R6510 + + // Print help message + + ldy #$00 + + // Retrieve address +!: + lda tape_head_align_help_text, y + iny + cmp #$FF + beq tape_head_align_print_end + sta EAL+0 + + lda tape_head_align_help_text, y + iny + sta EAL+1 +!: + // Retrieve and print character + + lda tape_head_align_help_text, y + iny + cmp #$FF + beq !-- + + sty __ha_storage + jsr tape_head_align_print_char + ldy __ha_storage + + bne !- // branch alwats + + +tape_head_align_print_end: + + // Restore normal memory configuration and quit + + pla + sta CPU_R6510 + rts + +tape_head_align_print_string: + + + +tape_head_align_print_char: + + // Calculate start address of character in .A + + sta SAL+0 + lda #$00 + sta SAL+1 + + asl SAL+0 + rol SAL+1 + asl SAL+0 + rol SAL+1 + asl SAL+0 + rol SAL+1 + + clc + lda SAL+1 + adc #$D0 + sta SAL+1 + + // Print out the character + + ldy #$07 +!: + lda (SAL), y + sta (EAL), y + dey + bpl !- + + // Prepare EAL for the next character + + lda EAL+0 + clc + adc #$08 + sta EAL+0 + bne !+ + inc EAL+1 +!: + rts + + +// +// Strings to print +// + +.encoding "screencode_upper" + + +tape_head_align_help_text: + + .word $2000 + (40 * 8) * 1 + 8 * 2 + .text "ADJUST HEAD FOR MINIMUM SIGNAL NOISE" + .byte $FF + + .word $2000 + (40 * 8) * 5 + 8 * 2 + .text "IF THE DECK HAS A PITCH (SPEED) KNOB" + .byte $FF + + .word $2000 + (40 * 8) * 6 + 8 * 6 + .text "USE IT TO PLACE DOTTED LINES" + .byte $FF + + .word $2000 + (40 * 8) * 7 + 8 * 3 + .text "EXACTLY HALF A WAY BETWEEN SIGNALS" + .byte $FF + + .byte $FF + + +#endif From 2277942bb9ced0a6ba2c0c4270f31aa38e43a856 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 4 Jun 2020 17:59:30 +0200 Subject: [PATCH 010/103] head align tool improvements --- c64/kernal/tape/tape_head_align.s | 2 +- c64/kernal/tape/tape_head_align_help.s | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/c64/kernal/tape/tape_head_align.s b/c64/kernal/tape/tape_head_align.s index c191977c..77d0bea0 100644 --- a/c64/kernal/tape/tape_head_align.s +++ b/c64/kernal/tape/tape_head_align.s @@ -20,7 +20,7 @@ .label __ha_start = 12 // starting row of the chart -.label __ha_rows = 10 // number of rows for scrolling +.label __ha_rows = 11 // number of rows for scrolling // Helper tables diff --git a/c64/kernal/tape/tape_head_align_help.s b/c64/kernal/tape/tape_head_align_help.s index 76939d14..ae89065b 100644 --- a/c64/kernal/tape/tape_head_align_help.s +++ b/c64/kernal/tape/tape_head_align_help.s @@ -111,19 +111,19 @@ tape_head_align_print_char: tape_head_align_help_text: - .word $2000 + (40 * 8) * 1 + 8 * 2 + .word $2000 + (40 * 8) * 0 + 8 * 2 .text "ADJUST HEAD FOR MINIMUM SIGNAL NOISE" .byte $FF - .word $2000 + (40 * 8) * 5 + 8 * 2 - .text "IF THE DECK HAS A PITCH (SPEED) KNOB" + .word $2000 + (40 * 8) * 4 + 8 * 2 + .text "IF THE DECK HAS A PITCH (TAPE SPEED)" .byte $FF - .word $2000 + (40 * 8) * 6 + 8 * 6 - .text "USE IT TO PLACE DOTTED LINES" + .word $2000 + (40 * 8) * 5 + 8 * 1 + .text "CONTROL - USE IT TO PLACE DOTTED LINES" .byte $FF - .word $2000 + (40 * 8) * 7 + 8 * 3 + .word $2000 + (40 * 8) * 6 + 8 * 3 .text "EXACTLY HALF A WAY BETWEEN SIGNALS" .byte $FF From 405789cdfe3d9253446a503cb3a7372e0101ce80 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 4 Jun 2020 20:53:02 +0200 Subject: [PATCH 011/103] head align tool minor improvements --- CONFIG.md | 4 ++-- c64/,,config_custom.s | 2 +- c64/,,config_cx16.s | 2 +- c64/,,config_generic.s | 2 +- c64/,,config_mega65.s | 2 +- c64/,,config_testing.s | 2 +- c64/,,config_ultimate64.s | 2 +- c64/aliases/,aliases_config.s | 4 ++-- c64/basic/wedge_tape.s | 5 +++++ c64/kernal/tape/tape_head_align.s | 3 +-- c64/kernal/tape/tape_head_align_apply_gfx.s | 12 ++-------- c64/kernal/tape/tape_head_align_help.s | 25 ++++++++++++++------- 12 files changed, 35 insertions(+), 30 deletions(-) diff --git a/CONFIG.md b/CONFIG.md index f548ee4f..94bd18ec 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -283,9 +283,9 @@ Feature needs about 330 bytes in BASIC segment. If unsure - enable. ### `CONFIG_TAPE_WEDGE` -If enabled, a simple DOS wedge is available from the direct mode for turbo tape loading - supports `←L` only +If enabled, a simple DOS wedge is available from the direct mode for tape loading - supports `←L` only. -Feature needs about 5 bytes in BASIC segment. If unsure - enable. +Feature needs few bytes in BASIC segment. If unsure - enable. ### `CONFIG_BCD_SAFE_INTERRUPTS` diff --git a/c64/,,config_custom.s b/c64/,,config_custom.s index bb93e633..c5bdaf1c 100644 --- a/c64/,,config_custom.s +++ b/c64/,,config_custom.s @@ -124,7 +124,7 @@ #define CONFIG_PANIC_SCREEN #define CONFIG_DOS_WEDGE #define CONFIG_TAPE_WEDGE -#define CONFIG_TAPE_HEAD_ALIGN // XXX work in progress +#define CONFIG_TAPE_HEAD_ALIGN #define CONFIG_BCD_SAFE_INTERRUPTS diff --git a/c64/,,config_cx16.s b/c64/,,config_cx16.s index cda04d71..0643ac68 100644 --- a/c64/,,config_cx16.s +++ b/c64/,,config_cx16.s @@ -117,7 +117,7 @@ // #define CONFIG_PANIC_SCREEN // #define CONFIG_DOS_WEDGE // #define CONFIG_TAPE_WEDGE -// #define CONFIG_TAPE_HEAD_ALIGN // XXX work in progress +// #define CONFIG_TAPE_HEAD_ALIGN #define CONFIG_BCD_SAFE_INTERRUPTS diff --git a/c64/,,config_generic.s b/c64/,,config_generic.s index 74cee7a8..711d06b5 100644 --- a/c64/,,config_generic.s +++ b/c64/,,config_generic.s @@ -115,7 +115,7 @@ #define CONFIG_PANIC_SCREEN #define CONFIG_DOS_WEDGE #define CONFIG_TAPE_WEDGE -// #define CONFIG_TAPE_HEAD_ALIGN // XXX work in progress +// #define CONFIG_TAPE_HEAD_ALIGN #define CONFIG_BCD_SAFE_INTERRUPTS diff --git a/c64/,,config_mega65.s b/c64/,,config_mega65.s index a4089233..985b5857 100644 --- a/c64/,,config_mega65.s +++ b/c64/,,config_mega65.s @@ -115,7 +115,7 @@ #define CONFIG_PANIC_SCREEN #define CONFIG_DOS_WEDGE #define CONFIG_TAPE_WEDGE -// #define CONFIG_TAPE_HEAD_ALIGN // XXX work in progress +// #define CONFIG_TAPE_HEAD_ALIGN #define CONFIG_BCD_SAFE_INTERRUPTS diff --git a/c64/,,config_testing.s b/c64/,,config_testing.s index afe531bf..1b50ed8b 100644 --- a/c64/,,config_testing.s +++ b/c64/,,config_testing.s @@ -115,7 +115,7 @@ #define CONFIG_PANIC_SCREEN #define CONFIG_DOS_WEDGE #define CONFIG_TAPE_WEDGE -// #define CONFIG_TAPE_HEAD_ALIGN // XXX work in progress +// #define CONFIG_TAPE_HEAD_ALIGN #define CONFIG_BCD_SAFE_INTERRUPTS diff --git a/c64/,,config_ultimate64.s b/c64/,,config_ultimate64.s index 707b1939..6fc5a03e 100644 --- a/c64/,,config_ultimate64.s +++ b/c64/,,config_ultimate64.s @@ -115,7 +115,7 @@ #define CONFIG_PANIC_SCREEN #define CONFIG_DOS_WEDGE #define CONFIG_TAPE_WEDGE -// #define CONFIG_TAPE_HEAD_ALIGN // XXX work in progress +// #define CONFIG_TAPE_HEAD_ALIGN #define CONFIG_BCD_SAFE_INTERRUPTS diff --git a/c64/aliases/,aliases_config.s b/c64/aliases/,aliases_config.s index 62ac4682..0a652064 100644 --- a/c64/aliases/,aliases_config.s +++ b/c64/aliases/,aliases_config.s @@ -295,8 +295,8 @@ // Check that features are configured correctly { -#if CONFIG_TAPE_WEDGE && !CONFIG_TAPE_TURBO - .error "CONFIG_TAPE_WEDGE requires CONFIG_TAPE_TURBO" +#if CONFIG_TAPE_WEDGE && !CONFIG_TAPE_TURBO && !CONFIG_TAPE_NORMAL + .error "CONFIG_TAPE_WEDGE requires CONFIG_TAPE_TURBO or CONFIG_TAPE_NORMAL" #endif #if !CONFIG_TAPE_WEDGE && CONFIG_TAPE_HEAD_ALIGN .error "CONFIG_TAPE_HEAD_ALIGN requires CONFIG_TAPE_WEDGE" diff --git a/c64/basic/wedge_tape.s b/c64/basic/wedge_tape.s index a777ff6b..b6ad6076 100644 --- a/c64/basic/wedge_tape.s +++ b/c64/basic/wedge_tape.s @@ -38,7 +38,12 @@ wedge_arrow_L: sta FNLEN ldy #$01 +#if CONFIG_TAPE_TURBO ldx #$07 // turbo tape device +#else + tdx #$01 // normal tape device +#endif + jsr JSETFLS ldy TXTTAB+1 diff --git a/c64/kernal/tape/tape_head_align.s b/c64/kernal/tape/tape_head_align.s index 77d0bea0..b0d38594 100644 --- a/c64/kernal/tape/tape_head_align.s +++ b/c64/kernal/tape/tape_head_align.s @@ -13,8 +13,7 @@ // XXX for Mega65 it can be done more easily, by just disabling the badlines // XXX consider "PRESS PLAY ON TAPE" before start, with option to stop -// XXX make tape wedge (and this tool) available also without tape turbo support -// XXX create separate configuration for tape users +// XXX document CONFIG_TAPE_HEAD_ALIGN option // XXX block NMIs // XXX fix Mega65 build compilation issues diff --git a/c64/kernal/tape/tape_head_align_apply_gfx.s b/c64/kernal/tape/tape_head_align_apply_gfx.s index 0f46157e..f4091d68 100644 --- a/c64/kernal/tape/tape_head_align_apply_gfx.s +++ b/c64/kernal/tape/tape_head_align_apply_gfx.s @@ -40,15 +40,7 @@ tape_head_align_apply_gfx: and #%00000010 beq !+ - lda #%00010000 - ora __ha_chart + 7 + 8 * 1 - sta __ha_chart + 7 + 8 * 1 - - lda #%00001000 - ora __ha_chart + 7 + 8 * 30 - sta __ha_chart + 7 + 8 * 30 - - // For normal + // For 'normal' lda #%00000001 ora __ha_chart + 7 + 8 * 6 @@ -58,7 +50,7 @@ tape_head_align_apply_gfx: ora __ha_chart + 7 + 8 * 13 sta __ha_chart + 7 + 8 * 13 - // For turbo + // For 'turbo' lda #%00010000 ora __ha_chart + 7 + 8 * 21 diff --git a/c64/kernal/tape/tape_head_align_help.s b/c64/kernal/tape/tape_head_align_help.s index ae89065b..b5c14ca2 100644 --- a/c64/kernal/tape/tape_head_align_help.s +++ b/c64/kernal/tape/tape_head_align_help.s @@ -111,23 +111,32 @@ tape_head_align_print_char: tape_head_align_help_text: - .word $2000 + (40 * 8) * 0 + 8 * 2 - .text "ADJUST HEAD FOR MINIMUM SIGNAL NOISE" + // Each string consists of: + // - destination (start byte) address + // - text in screencodes + / - $FF to mark end + + .word $2000 + (40 * 8) * 0 + 8 * 1 + .text "COMPUTER HAS TO TELL THE SIGNALS APART" .byte $FF - .word $2000 + (40 * 8) * 4 + 8 * 2 + .word $2000 + (40 * 8) * 3 + 8 * 6 + .text "ALIGN HEAD FOR MINIMUM NOISE" + .byte $FF + + .word $2000 + (40 * 8) * 6 + 8 * 2 .text "IF THE DECK HAS A PITCH (TAPE SPEED)" .byte $FF - .word $2000 + (40 * 8) * 5 + 8 * 1 - .text "CONTROL - USE IT TO PLACE DOTTED LINES" + .word $2000 + (40 * 8) * 7 + 8 * 1 + .text "CONTROL, TWEAK IT SO THAT DOTTED LINES" .byte $FF - .word $2000 + (40 * 8) * 6 + 8 * 3 - .text "EXACTLY HALF A WAY BETWEEN SIGNALS" + .word $2000 + (40 * 8) * 8 + 8 * 5 + .text "ARE HALF A WAY BETWEEN SIGNALS" .byte $FF - .byte $FF + .byte $FF // end of strings #endif From 1c118d9bc9b98dc7e831a3d1f192a2ff3deb064b Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 4 Jun 2020 20:59:12 +0200 Subject: [PATCH 012/103] compilation fixes --- c64/,,config_custom.s | 12 ++++++------ c64/basic/wedge_tape.s | 2 +- c64/kernal/tape/tape_head_align_help.s | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/c64/,,config_custom.s b/c64/,,config_custom.s index c5bdaf1c..adef8403 100644 --- a/c64/,,config_custom.s +++ b/c64/,,config_custom.s @@ -46,10 +46,10 @@ // I/O devices #define CONFIG_IEC -//#define CONFIG_IEC_DOLPHINDOS -//#define CONFIG_IEC_DOLPHINDOS_FAST -//#define CONFIG_IEC_JIFFYDOS -//#define CONFIG_IEC_JIFFYDOS_BLANK +// #define CONFIG_IEC_DOLPHINDOS +// #define CONFIG_IEC_DOLPHINDOS_FAST +// #define CONFIG_IEC_JIFFYDOS +// #define CONFIG_IEC_JIFFYDOS_BLANK // #define CONFIG_IEC_BURST_CIA1 // please keep disabled for now // #define CONFIG_IEC_BURST_CIA2 // please keep disabled for now // #define CONFIG_IEC_BURST_SOFT // please keep disabled for now @@ -87,8 +87,8 @@ // #define CONFIG_KEY_REPEAT_DEFAULT // #define CONFIG_KEY_REPEAT_ALWAYS #define CONFIG_KEY_FAST_SCAN -#define CONFIG_JOY1_CURSOR -#define CONFIG_JOY2_CURSOR +// #define CONFIG_JOY1_CURSOR +// #define CONFIG_JOY2_CURSOR #define CONFIG_PROGRAMMABLE_KEYS diff --git a/c64/basic/wedge_tape.s b/c64/basic/wedge_tape.s index b6ad6076..705e41ad 100644 --- a/c64/basic/wedge_tape.s +++ b/c64/basic/wedge_tape.s @@ -41,7 +41,7 @@ wedge_arrow_L: #if CONFIG_TAPE_TURBO ldx #$07 // turbo tape device #else - tdx #$01 // normal tape device + ldx #$01 // normal tape device #endif jsr JSETFLS diff --git a/c64/kernal/tape/tape_head_align_help.s b/c64/kernal/tape/tape_head_align_help.s index b5c14ca2..0143f2b8 100644 --- a/c64/kernal/tape/tape_head_align_help.s +++ b/c64/kernal/tape/tape_head_align_help.s @@ -114,7 +114,7 @@ tape_head_align_help_text: // Each string consists of: // - destination (start byte) address // - text in screencodes - / - $FF to mark end + // - $FF to mark end .word $2000 + (40 * 8) * 0 + 8 * 1 .text "COMPUTER HAS TO TELL THE SIGNALS APART" From f8e57f1cf26a486371e7090d395827169c622081 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 4 Jun 2020 22:19:10 +0200 Subject: [PATCH 013/103] safer NMI handling --- c64/basic/wedge_tape.s | 5 +- .../interrupts/ea81.return_from_interrupt.s | 4 ++ c64/kernal/interrupts/hw_entry_nmi.s | 9 ++- c64/kernal/interrupts/nmi_lock.s | 60 +++++++++++++++++++ c64/kernal/memory/vector_real.s | 5 +- c64/kernal/panic.s | 13 +++- c64/kernal/tape/load_tape_normal.s | 3 + c64/kernal/tape/load_tape_turbo.s | 3 + c64/kernal/tape/tape_common.s | 14 ++++- c64/kernal/tape/tape_head_align.s | 17 ++++-- 10 files changed, 114 insertions(+), 19 deletions(-) create mode 100644 c64/kernal/interrupts/nmi_lock.s diff --git a/c64/basic/wedge_tape.s b/c64/basic/wedge_tape.s index 705e41ad..13dee5aa 100644 --- a/c64/basic/wedge_tape.s +++ b/c64/basic/wedge_tape.s @@ -56,7 +56,10 @@ wedge_arrow_L: wedge_arrow_H: jsr tape_head_align - jmp basic_main_loop + + jsr print_return + ldx #B_ERR_BREAK + jmp do_basic_error #endif diff --git a/c64/kernal/interrupts/ea81.return_from_interrupt.s b/c64/kernal/interrupts/ea81.return_from_interrupt.s index 4a834206..9372d84d 100644 --- a/c64/kernal/interrupts/ea81.return_from_interrupt.s +++ b/c64/kernal/interrupts/ea81.return_from_interrupt.s @@ -20,4 +20,8 @@ return_from_interrupt: plx_trash_a pla + // FALLTROUGH + +return_from_interrupt_rti: + rti diff --git a/c64/kernal/interrupts/hw_entry_nmi.s b/c64/kernal/interrupts/hw_entry_nmi.s index 2ed19829..225f9397 100644 --- a/c64/kernal/interrupts/hw_entry_nmi.s +++ b/c64/kernal/interrupts/hw_entry_nmi.s @@ -5,17 +5,16 @@ hw_entry_nmi: - sei // do not allow IRQ to interfere, see https://www.c64-wiki.com/wiki/Interrupt + sei // do not allow IRQ to interfere, see https://www.c64-wiki.com/wiki/Interrupt #if CONFIG_CPU_MOS_6502 && CONFIG_BCD_SAFE_INTERRUPTS - cld // clear decimal flag to allow using it without disabling interrupts + cld // clear decimal flag to allow using it without disabling interrupts #endif // Call interrupt routine (only if initialised) pha - lda NMINV - ora NMINV+1 - beq !+ + lda NMINV+1 // consider zeropage NMI address as uninitialized vector + beq !+ // this allows safer interrupt vector modifications pla jmp (NMINV) !: diff --git a/c64/kernal/interrupts/nmi_lock.s b/c64/kernal/interrupts/nmi_lock.s new file mode 100644 index 00000000..0b1462ee --- /dev/null +++ b/c64/kernal/interrupts/nmi_lock.s @@ -0,0 +1,60 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * KERNAL_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Routine to lock NMI interrupts, using a trick described here: +// - https://codebase64.org/doku.php?id=base:nmi_lock +// + + +#if CONFIG_TAPE_HEAD_ALIGN + + +// XXX consider broader usage of this method to make IO safer + + +nmi_lock: + + // We will have to change NMI vector to point empty routine, + // which will not acknowledge the interrupt - thus preventing + // the NMI to be triggered again + + // Our code considers zeropage address invalid, so put + // it there as a preparation + + ldx #$00 + stx NMINV+1 + + // We can now safelly replace the vector + + lda #return_from_interrupt_rti + sta NMINV+1 + + // Stop timer A + + stx CIA2_CRA // $DD0E + + // Set timer A to 0, after starting NMI will occur immediately + + stx CIA2_TIMALO // $DD04 + stx CIA2_TIMAHI // $DD05 + + // Set timer A as source for NMI + + lda #$81 + sta CIA2_ICR // $DD0D + + // Start timer A to trigger the NMI + + lda #$01 + sta CIA2_CRA // $DD0E + + // All done. Unmaskable interrupts are now masked. + + rts + + +#endif diff --git a/c64/kernal/memory/vector_real.s b/c64/kernal/memory/vector_real.s index 1d5e379b..9440fa34 100644 --- a/c64/kernal/memory/vector_real.s +++ b/c64/kernal/memory/vector_real.s @@ -23,6 +23,9 @@ vector_real: sty MEMUSS + 1 stx MEMUSS + 0 + lda #$00 + sta NMINV + 1 // our routine considers this a disabled interrupt + // Select routine variant - store or restore vectors ldy #$1F bcc vector_restore @@ -30,7 +33,7 @@ vector_real: lda CINV, y sta (MEMUSS), y - bcs vector_end_loop // branch always + bcs vector_end_loop // branch always vector_restore: lda (MEMUSS), y diff --git a/c64/kernal/panic.s b/c64/kernal/panic.s index aa37b876..7e2ef9c4 100644 --- a/c64/kernal/panic.s +++ b/c64/kernal/panic.s @@ -22,11 +22,18 @@ panic: jsr setup_vicii jsr clear_screen - // Disable NMIs - our routine checks for NULL vector + // Disable NMIs + +#if CONFIG_TAPE_HEAD_ALIGN + + jsr nmi_lock + +#else lda #$00 - sta NMINV+0 - sta NMINV+1 + sta NMINV + 1 // our routine does not allow zeropage vectors + +#endif // Display KERNAL PANIC message diff --git a/c64/kernal/tape/load_tape_normal.s b/c64/kernal/tape/load_tape_normal.s index c53dabdb..c1ecd776 100644 --- a/c64/kernal/tape/load_tape_normal.s +++ b/c64/kernal/tape/load_tape_normal.s @@ -45,6 +45,9 @@ load_tape_normal: // Start playing jsr tape_common_prepare_cia jsr tape_ask_play +#if CONFIG_TAPE_HEAD_ALIGN + jsr tape_prepare_reading +#endif // FALLTROUGH diff --git a/c64/kernal/tape/load_tape_turbo.s b/c64/kernal/tape/load_tape_turbo.s index 7c421e90..fe20438e 100644 --- a/c64/kernal/tape/load_tape_turbo.s +++ b/c64/kernal/tape/load_tape_turbo.s @@ -32,6 +32,9 @@ load_tape_auto: // Start playing jsr tape_common_prepare_cia jsr tape_ask_play +#if CONFIG_TAPE_HEAD_ALIGN + jsr tape_prepare_reading +#endif // FALLTROUGH diff --git a/c64/kernal/tape/tape_common.s b/c64/kernal/tape/tape_common.s index fa813aef..f254dc43 100644 --- a/c64/kernal/tape/tape_common.s +++ b/c64/kernal/tape/tape_common.s @@ -104,6 +104,17 @@ tape_wait_first_pulse: tape_wait_play_done: + lda #$01 + sta CAS1 // set the interlock + +#if CONFIG_TAPE_HEAD_ALIGN + + rts + +tape_prepare_reading: + +#endif // CONFIG_TAPE_HEAD_ALIGN + #if CONFIG_MB_MEGA_65 // Display confirmation @@ -115,9 +126,6 @@ tape_wait_play_done: // Prepare for reading - lda #$01 - sta CAS1 // set the interlock - jsr print_return jmp tape_screen_off_motor_on diff --git a/c64/kernal/tape/tape_head_align.s b/c64/kernal/tape/tape_head_align.s index b0d38594..756d9ec0 100644 --- a/c64/kernal/tape/tape_head_align.s +++ b/c64/kernal/tape/tape_head_align.s @@ -12,9 +12,7 @@ // XXX for Mega65 it can be done more easily, by just disabling the badlines -// XXX consider "PRESS PLAY ON TAPE" before start, with option to stop // XXX document CONFIG_TAPE_HEAD_ALIGN option -// XXX block NMIs // XXX fix Mega65 build compilation issues @@ -50,12 +48,22 @@ tape_head_align: #else + // Make sure user really wants to launch the tool + + jsr tape_ask_play + // Disable interrupts, set proper I/O values jsr CLALL + sei + jsr IOINIT - jsr cint_legacy + jsr CINT + + jsr nmi_lock + + // Prepare CIA timers ldx #$02 // set timer A to 3 ticks jsr tape_common_prepare_cia_by_x @@ -111,8 +119,6 @@ tape_head_align: dey bne !- - - // Set graphics mode lda #$28 // graphics start at $2000, color at $0800 @@ -252,7 +258,6 @@ tape_head_align_drawn: beq tape_head_align_loop_1 - tape_head_align_quit: // It makes no sense to return to system, as we already destroyed From 17fbf220db0ea7b3564f68a2d9b806a8861d0e47 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 4 Jun 2020 22:41:47 +0200 Subject: [PATCH 014/103] initial head align tool adaptations for Mega65 ROM layout --- c64/kernal/board_m65/mega65_imports.s | 11 +++++++++++ c64/kernal/tape/tape_head_align.s | 12 ------------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/c64/kernal/board_m65/mega65_imports.s b/c64/kernal/board_m65/mega65_imports.s index e09cabb0..25399d18 100644 --- a/c64/kernal/board_m65/mega65_imports.s +++ b/c64/kernal/board_m65/mega65_imports.s @@ -8,7 +8,11 @@ #import "KERNAL_0_combined.sym" +.label CLALL = KERNAL_0.CLALL .label STOP = KERNAL_0.STOP + +.label hw_entry_reset = KERNAL_0.hw_entry_reset +.label return_from_interrupt = KERNAL_0.return_from_interrupt .label clrchn_reset = KERNAL_0.clrchn_reset .label udtim_keyboard = KERNAL_0.udtim_keyboard @@ -55,3 +59,10 @@ .label tape_normal_byte_store = KERNAL_0.tape_normal_byte_store #endif + + +#if CONFIG_TAPE_HEAD_ALIGN + +.label nmi_lock = KERNAL_0.nmi_lock + +#endif diff --git a/c64/kernal/tape/tape_head_align.s b/c64/kernal/tape/tape_head_align.s index 756d9ec0..a5f05d70 100644 --- a/c64/kernal/tape/tape_head_align.s +++ b/c64/kernal/tape/tape_head_align.s @@ -1,5 +1,4 @@ // #LAYOUT# STD * #TAKE -// #LAYOUT# M65 KERNAL_0 #TAKE // #LAYOUT# M65 KERNAL_1 #TAKE // #LAYOUT# * * #IGNORE @@ -40,14 +39,6 @@ tape_head_align: -#if (ROM_LAYOUT_M65 && SEGMENT_KERNAL_0) - - jsr map_KERNAL_1 - jsr_ind VK1__tape_head_align - jmp map_NORMAL - -#else - // Make sure user really wants to launch the tool jsr tape_ask_play @@ -274,7 +265,4 @@ tape_head_align_quit: jmp hw_entry_reset -#endif // ROM layout - - #endif // CONFIG_TAPE_HEAD_ALIGN From c5d7bb250fe4a6e719ac9dad31226d3217381729 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 4 Jun 2020 23:05:37 +0200 Subject: [PATCH 015/103] head align tool is now finished --- CONFIG.md | 6 ++++++ Makefile | 4 ++-- STATUS.md | 1 + c64/,,config_mega65.s | 2 +- c64/kernal/board_m65/mega65_imports.s | 2 +- c64/kernal/board_m65/mega65_proxies.s | 11 +++++++++++ c64/kernal/init/fce2.hw_entry_reset.s | 6 ++++++ c64/kernal/tape/tape_head_align.s | 5 +---- doc/Development.md | 4 ++++ 9 files changed, 33 insertions(+), 8 deletions(-) diff --git a/CONFIG.md b/CONFIG.md index 94bd18ec..b91f3301 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -287,6 +287,12 @@ If enabled, a simple DOS wedge is available from the direct mode for tape loadin Feature needs few bytes in BASIC segment. If unsure - enable. +### `CONFIG_TAPE_HEAD_ALIGN` + +If enabled, embeds a tape head align tool into the ROM, it can be started with `←H`. Requires `CONFIG_TAPE_WEDGE`. + +Feature needs nearly 1 KB bytes in KERNAL segment. Only recomended for machines with extended ROM, like Mega65. + ### `CONFIG_BCD_SAFE_INTERRUPTS` On the most widespread CPUs the D flag is not cleared upon entering interrupts. Since the original Kernal does not clear it either, it's not safe to use BCD processor mode without disabling the interrupts first. This option makes sure the D flag is disabled at the start of the interrupt - this allows some optimizations in the code. diff --git a/Makefile b/Makefile index 9fc2abcc..8581ffa6 100644 --- a/Makefile +++ b/Makefile @@ -436,8 +436,8 @@ 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) $(TARGET_M65_PXL) - ../xemu/build/bin/xmega65.native -dmarev 2 -forcerom -loadrom $(TARGET_M65_x) +test_mega65: $(TARGET_M65_x) $(TARGET_M65_x_PXL) + ../xemu/build/bin/xmega65.native -dmarev 2 -forcerom -loadrom $(TARGET_M65_x_PXL) test_cx16: $(TARGET_X16_x) ../x16-emulator/x16emu -rom $(TARGET_X16_x) diff --git a/STATUS.md b/STATUS.md index e8013b30..7957672e 100644 --- a/STATUS.md +++ b/STATUS.md @@ -15,6 +15,7 @@ Here are the features of the Open ROMs not found in the original ROMs from the 8 * normal tape load error log is limited by free stack space only (no artificial limitation like in original ROMs) * tape format autodetection; normal vs turbo is mostly transparent to user * improved support for tape adapters (for using regular casette players and other audio devices instead of Datasette) and emulators +* built-in tape head align tool (only feasible to use on machines with extended memory, like Mega65) * extended `LOAD` command * start/end addresses are displayed, in the Final cartridge style diff --git a/c64/,,config_mega65.s b/c64/,,config_mega65.s index 985b5857..1d8e77e5 100644 --- a/c64/,,config_mega65.s +++ b/c64/,,config_mega65.s @@ -115,7 +115,7 @@ #define CONFIG_PANIC_SCREEN #define CONFIG_DOS_WEDGE #define CONFIG_TAPE_WEDGE -// #define CONFIG_TAPE_HEAD_ALIGN +#define CONFIG_TAPE_HEAD_ALIGN #define CONFIG_BCD_SAFE_INTERRUPTS diff --git a/c64/kernal/board_m65/mega65_imports.s b/c64/kernal/board_m65/mega65_imports.s index 25399d18..0588fa89 100644 --- a/c64/kernal/board_m65/mega65_imports.s +++ b/c64/kernal/board_m65/mega65_imports.s @@ -8,7 +8,6 @@ #import "KERNAL_0_combined.sym" -.label CLALL = KERNAL_0.CLALL .label STOP = KERNAL_0.STOP .label hw_entry_reset = KERNAL_0.hw_entry_reset @@ -63,6 +62,7 @@ #if CONFIG_TAPE_HEAD_ALIGN +.label CLALL = KERNAL_0.proxy_K1_CLALL .label nmi_lock = KERNAL_0.nmi_lock #endif diff --git a/c64/kernal/board_m65/mega65_proxies.s b/c64/kernal/board_m65/mega65_proxies.s index 9585775d..cf274435 100644 --- a/c64/kernal/board_m65/mega65_proxies.s +++ b/c64/kernal/board_m65/mega65_proxies.s @@ -56,3 +56,14 @@ proxy_K1_print_return: jmp map_KERNAL_1 #endif + + +#if CONFIG_TAPE_HEAD_ALIGN + +proxy_K1_CLALL: + + jsr map_NORMAL + jsr CLALL + jmp map_KERNAL_1 + +#endif diff --git a/c64/kernal/init/fce2.hw_entry_reset.s b/c64/kernal/init/fce2.hw_entry_reset.s index 2ada16d4..c968391d 100644 --- a/c64/kernal/init/fce2.hw_entry_reset.s +++ b/c64/kernal/init/fce2.hw_entry_reset.s @@ -25,6 +25,12 @@ hw_entry_reset: ldx #$FF txs +#if ROM_LAYOUT_M65 + + jsr map_NORMAL // we want normal memory mapping + +#endif + #if CONFIG_PLATFORM_COMMODORE_64 // The following routine is based on reading the public KERNAL jumptable routine diff --git a/c64/kernal/tape/tape_head_align.s b/c64/kernal/tape/tape_head_align.s index a5f05d70..7466331e 100644 --- a/c64/kernal/tape/tape_head_align.s +++ b/c64/kernal/tape/tape_head_align.s @@ -11,9 +11,6 @@ // XXX for Mega65 it can be done more easily, by just disabling the badlines -// XXX document CONFIG_TAPE_HEAD_ALIGN option -// XXX fix Mega65 build compilation issues - .label __ha_start = 12 // starting row of the chart .label __ha_rows = 11 // number of rows for scrolling @@ -50,7 +47,7 @@ tape_head_align: sei jsr IOINIT - jsr CINT + // jsr CINT jsr nmi_lock diff --git a/doc/Development.md b/doc/Development.md index bc4c8ad7..95054f28 100644 --- a/doc/Development.md +++ b/doc/Development.md @@ -59,6 +59,10 @@ 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). +#### NMI vector modification + +Before modifying NMI vector, set it's high byte to 0. The ROM routine considers such address invalid and won't try to call the custom code, thus preventing a crash if interrupt happens in the worst possible moment. + #### 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: From 580cd6594152709a51858ae68d594ec22ef47536 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Fri, 5 Jun 2020 20:16:34 +0200 Subject: [PATCH 016/103] started work on VERIFY and SAVE commands --- STATUS.md | 6 +- c64/aliases/,aliases_ram_lowmem.s | 2 +- c64/basic/commands/cmd_load.s | 141 ------------------ c64/basic/commands/cmd_load_verify.s | 191 +++++++++++++++++++++++++ c64/basic/commands/cmd_save.s | 29 ++++ c64/basic/commands/cmd_unimplemented.s | 4 - c64/basic/wedge_tape.s | 2 +- 7 files changed, 225 insertions(+), 150 deletions(-) delete mode 100644 c64/basic/commands/cmd_load.s create mode 100644 c64/basic/commands/cmd_load_verify.s create mode 100644 c64/basic/commands/cmd_save.s diff --git a/STATUS.md b/STATUS.md index 7957672e..1bf8b632 100644 --- a/STATUS.md +++ b/STATUS.md @@ -17,13 +17,13 @@ Here are the features of the Open ROMs not found in the original ROMs from the 8 * improved support for tape adapters (for using regular casette players and other audio devices instead of Datasette) and emulators * built-in tape head align tool (only feasible to use on machines with extended memory, like Mega65) -* extended `LOAD` command +* extended / tweaked `LOAD` / `VERIFY` commands * start/end addresses are displayed, in the Final cartridge style * command with just the file name tries to use the last device if it's number seems sane; otherwise uses 8 - * secondary address over 255 is considered a start address + * command without parameters tries to load first file from drive chosen as above * uses RAM under ROM and I/O: 61438 bytes free -* cold/warm start silences multiple SID chips - all $D4xx and $D5xx addresses, configured addresses +* cold/warm start silences multiple SID chips * warm start due to BRK prints out the instruction address diff --git a/c64/aliases/,aliases_ram_lowmem.s b/c64/aliases/,aliases_ram_lowmem.s index f6f9e3ac..2f1cbb06 100644 --- a/c64/aliases/,aliases_ram_lowmem.s +++ b/c64/aliases/,aliases_ram_lowmem.s @@ -17,7 +17,7 @@ .label CHARAC = $07 // [!] our implementation might be different XXX give more details .label ENDCHR = $08 // [!] our implementation might be different XXX give more details .label TRMPOS = $09 // -- NOT IMPLEMENTED -- - .label VERCKB = $0A // -- NOT IMPLEMENTED -- + .label VERCKB = $0A // flag used by BASIC, 0 - LOAD, 1 - VERIFY .label COUNT = $0B // [!] our implementation might be different XXX give more details .label DIMFLG = $0C // [!] our implementation might be different XXX give more details .label VALTYP = $0D // -- NOT IMPLEMENTED -- diff --git a/c64/basic/commands/cmd_load.s b/c64/basic/commands/cmd_load.s deleted file mode 100644 index 2572b1e5..00000000 --- a/c64/basic/commands/cmd_load.s +++ /dev/null @@ -1,141 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - - -cmd_load: - - // Parse filename - // (we can tell the KERNAL where it is in memory directly, since the - // KERNAL will be able to peek under ROMs to read it, since it will have - // to be able to peek under the ROMs for SAVE and VERIFY). - // Parse optional device # - // Parse optional secondary address - - // XXX - C64 BASIC apparently does not clear variables after a LOAD in the - // middle of a program. For safety, we do. - jsr basic_do_clr - - // Set filename and length - lda #$00 - sta FNLEN - - // Check for the file name - jsr basic_end_of_statement_check - bcc cmd_load_fetch_filename - - // Try to load the first file from disk - - lda #$01 // name length - ldx #filename_any - jsr JSETNAM - jmp got_filename - -cmd_load_fetch_filename: - - jsr basic_fetch_and_consume_character - cmp #$22 - beq !+ - jmp do_SYNTAX_error -!: - // Filename starts here so set pointer - lda TXTPTR+0 - sta FNADDR+0 - lda TXTPTR+1 - sta FNADDR+1 - - // Now search for end of line or closing quote - // so that we know the length of the filename -getting_filename: - jsr basic_fetch_and_consume_character - cmp #$22 - beq got_filename - cmp #$00 - bne !+ - jsr basic_unconsume_character - - jmp got_filename -!: - inc FNLEN - jmp getting_filename - -got_filename: - - // Now fetch the file number, start from the default one - jsr select_device - stx FA - jsr injest_comma - bcs got_devicenumber - - jsr basic_parse_line_number - lda LINNUM+1 - beq !+ - jmp do_ILLEGAL_QUANTITY_error -!: - lda LINNUM+0 - sta FA - -got_devicenumber: - - // Now fetch the secondary address - lda #$00 - sta SA - jsr injest_comma - bcs cmd_load_got_secondaryaddress - jsr basic_parse_line_number - lda LINNUM+1 - bne !+ - lda LINNUM+0 - sta SA - jmp cmd_load_got_secondaryaddress -!: - // Second parameter is above 255, this can not be a secondary address - // Use it as load address instead - // XXX temporary syntax, it would be better to use something - // XXX like 'LOAD"FILE",8 TO 49152' - ldx LINNUM+0 - ldy LINNUM+1 - bne got_loadaddress - -cmd_load_got_secondaryaddress: // input for tape wedge - ldy TXTTAB+1 - ldx TXTTAB+0 - -got_loadaddress: - lda #$00 // LOAD not verify - jsr JLOAD - php - pha - jsr print_return - pla - plp - bcc load_no_error - - // A = KERNAL error code, which also almost match - // basic ERROR codes - tax - dex - bpl !+ - ldx #B_ERR_BREAK -!: - jmp do_basic_error - -load_no_error: - // $YYXX is the last loaded address, so store it - stx VARTAB+0 - sty VARTAB+1 - - // Now relink the loaded program, as we cannot trust the line - // links supplied. For example, the VICE virtual drive emulation - // always supplies $0101 as the address of the next line. - jsr LINKPRG - - // After LOADing, we either start the program from the beginning, - // or go back to the READY prompt if LOAD was called from direct mode. - - // Reset to start of program - jsr init_oldtxt - - // XXX - should run program if LOAD was used in program mode - jmp basic_main_loop diff --git a/c64/basic/commands/cmd_load_verify.s b/c64/basic/commands/cmd_load_verify.s new file mode 100644 index 00000000..6b639766 --- /dev/null +++ b/c64/basic/commands/cmd_load_verify.s @@ -0,0 +1,191 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + + +cmd_verify: + + // LOAD and VERIFY are very similar, from BASIC perspective there is almost no difference; + // just different parameter passed to Kernal and different error message in case of failure + + lda #$01 // mark operation as VERIFY + skip_2_bytes_trash_nvz + +cmd_load: + + lda #$00 // mark operation as LOAD + sta VERCKB + + // C64 BASIC apparently does not clear variables after a LOAD in the + // middle of a program. For safety, we do. + jsr basic_do_clr + + // Set default device and secondary address; channel is not important now + + jsr select_device + ldy #$00 // secondary address + jsr JSETFLS + + // Check if file name is supplied + + jsr basic_end_of_statement_check + bcs cmd_load_no_filename + + // Fetch the file name + + jsr cmd_load_fetch_filename + + // Try to fetch secondary address + + jsr cmd_load_fetch_dev_secondary + jmp cmd_load_got_params + +cmd_load_no_filename: + + // If no file name is supplied, try to load first file from disc + + lda #$01 // name length + ldx #filename_any + jsr JSETNAM + + // FALLTROUGH + +cmd_load_got_params: // input for tape wedge + + // Perform loading + + ldy TXTTAB+1 + ldx TXTTAB+0 + lda VERCKB // LOAD or VERIFY + + jsr JLOAD + + // Handle result + + php + pha + jsr print_return + pla + plp + bcc cmd_load_no_error + + // .A = KERNAL error code, also almost matches BASIC error codes + + tax + dex + bpl !+ + ldx #B_ERR_BREAK +!: + jmp do_basic_error + +cmd_load_no_error: + + // Store last loaded address + + stx VARTAB+0 + sty VARTAB+1 + + // Now relink the loaded program, as we cannot trust the line + // links supplied. For example, the VICE virtual drive emulation + // always supplies $0101 as the address of the next line + + jsr LINKPRG + + // Now we either start the program from the beginning, + // or go back to the READY prompt if LOAD was called from direct mode. + + // Reset to start of program + jsr init_oldtxt + + // XXX - should run program if LOAD was used in program mode + jmp basic_main_loop + + + + + + +// XXX move functions below to separate files, change names to neuytral + + + + +cmd_load_fetch_filename: + + // Search for opening quote + + jsr basic_fetch_and_consume_character + cmp #$22 + bne_16 do_SYNTAX_error +!: + // Filename starts here so set pointer + + lda TXTPTR+0 + sta FNADDR+0 + lda TXTPTR+1 + sta FNADDR+1 + + // Now search for end of line or closing quote + // so that we know the length of the filename + + lda #$00 + sta FNLEN +!: + jsr basic_fetch_and_consume_character + cmp #$22 + beq cmd_load_fetch_filename_done + cmp #$00 + beq !+ + + inc FNLEN + bne !- + +!: + jsr basic_unconsume_character + + // FALLTROUGH + +cmd_load_fetch_filename_done: + + rts + + + + +cmd_load_fetch_dev_secondary: + + // Fetch the device number + + jsr injest_comma + bcs cmd_load_fetch_dev_secondary + + jsr basic_parse_line_number + lda LINNUM+1 + bne_16 do_ILLEGAL_QUANTITY_error + + lda LINNUM+0 + sta FA + + // FALLTROUGH + +cmd_load_fetch_secondary: + + // Fetch secondary address + + jsr injest_comma + bcs cmd_load_fetch_dev_secondary_done + + jsr basic_parse_line_number + lda LINNUM+1 + bne_16 do_ILLEGAL_QUANTITY_error + + lda LINNUM+0 + sta SA + + // FALLTROUGH + +cmd_load_fetch_dev_secondary_done: + + rts diff --git a/c64/basic/commands/cmd_save.s b/c64/basic/commands/cmd_save.s new file mode 100644 index 00000000..b8982ace --- /dev/null +++ b/c64/basic/commands/cmd_save.s @@ -0,0 +1,29 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +cmd_save: + + // Set default device and secondary address; channel is not important now + + jsr select_device + ldy #$00 // secondary address + jsr JSETFLS + + // Check if file name is supplied + + jsr basic_end_of_statement_check + bcs_16 do_MISSING_FILENAME_error + + // Fetch the file name + + jsr cmd_load_fetch_filename + + + + + + // XXX - finish the implementation + + jmp basic_main_loop diff --git a/c64/basic/commands/cmd_unimplemented.s b/c64/basic/commands/cmd_unimplemented.s index 59407688..7331765e 100644 --- a/c64/basic/commands/cmd_unimplemented.s +++ b/c64/basic/commands/cmd_unimplemented.s @@ -39,10 +39,6 @@ cmd_on: nop cmd_wait: nop -cmd_save: - nop -cmd_verify: - nop cmd_def: nop cmd_poke: diff --git a/c64/basic/wedge_tape.s b/c64/basic/wedge_tape.s index 13dee5aa..6b540c04 100644 --- a/c64/basic/wedge_tape.s +++ b/c64/basic/wedge_tape.s @@ -49,7 +49,7 @@ wedge_arrow_L: ldy TXTTAB+1 ldx TXTTAB+0 - jmp cmd_load_got_secondaryaddress + jmp cmd_load_got_params #if CONFIG_TAPE_HEAD_ALIGN From 0436b5c62e7faa75665511763b85e30f2d67bcdf Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Fri, 5 Jun 2020 22:26:08 +0200 Subject: [PATCH 017/103] small cleanup in BASIC --- Makefile | 4 +- c64/basic/basic_execute_line.s | 180 +--------------------- c64/basic/commands/cmd_load_verify.s | 91 +---------- c64/basic/commands/cmd_run.s | 2 +- c64/basic/commands/cmd_save.s | 8 +- c64/basic/commands/cmd_sys.s | 2 +- c64/basic/commands/command_jumptable.s | 155 +++++++++++++++++++ c64/basic/engine/end_of_statement_check.s | 41 +++++ c64/basic/engine/fetch_device_secondary.s | 44 ++++++ c64/basic/engine/fetch_file_name.s | 58 +++++++ c64/basic/{ => engine}/injest_comma.s | 12 +- c64/basic/{ => wedge}/wedge_dos.s | 0 c64/basic/{ => wedge}/wedge_tape.s | 0 13 files changed, 319 insertions(+), 278 deletions(-) create mode 100644 c64/basic/commands/command_jumptable.s create mode 100644 c64/basic/engine/end_of_statement_check.s create mode 100644 c64/basic/engine/fetch_device_secondary.s create mode 100644 c64/basic/engine/fetch_file_name.s rename c64/basic/{ => engine}/injest_comma.s (53%) rename c64/basic/{ => wedge}/wedge_dos.s (100%) rename c64/basic/{ => wedge}/wedge_tape.s (100%) diff --git a/Makefile b/Makefile index 8581ffa6..7730af5e 100644 --- a/Makefile +++ b/Makefile @@ -16,12 +16,14 @@ SRCDIR_BASIC = $(SRCDIR_COMMON) \ c64/basic/board_m65 \ c64/basic/board_x16 \ c64/basic/commands \ + c64/basic/engine \ c64/basic/init \ c64/basic/math \ c64/basic/math_consts \ c64/basic/math_mov \ c64/basic/print \ - c64/basic/rom_revision + c64/basic/rom_revision \ + c64/basic/wedge SRCDIR_KERNAL = $(SRCDIR_COMMON) \ c64/kernal \ diff --git a/c64/basic/basic_execute_line.s b/c64/basic/basic_execute_line.s index 9268327a..b7b6196c 100644 --- a/c64/basic/basic_execute_line.s +++ b/c64/basic/basic_execute_line.s @@ -6,34 +6,6 @@ // after first checking that we have a colon // or $00 char -basic_end_of_statement_check: - ldy #0 - -#if CONFIG_MEMORY_MODEL_60K - ldx # Date: Fri, 5 Jun 2020 22:47:22 +0200 Subject: [PATCH 018/103] number-related syntax checking fix, small cleanup in BASIC --- c64/basic/{ => ,stubs}/basic_adray1.s | 0 c64/basic/{ => ,stubs}/basic_adray2.s | 0 c64/basic/basic_execute_line.s | 31 ++------------------ c64/basic/engine/end_of_statement_check.s | 2 +- c64/basic/engine/fetch_character.s | 35 +++++++++++++++++++++++ c64/basic/engine/fetch_device_secondary.s | 2 ++ c64/basic/engine/fetch_file_name.s | 14 ++++----- c64/basic/engine/injest_comma.s | 4 +-- c64/basic/engine/injest_spaces.s | 18 ++++++++++++ c64/basic/engine/unconsume_character.s | 20 +++++++++++++ c64/basic/injest_number.s | 4 +-- 11 files changed, 89 insertions(+), 41 deletions(-) rename c64/basic/{ => ,stubs}/basic_adray1.s (100%) rename c64/basic/{ => ,stubs}/basic_adray2.s (100%) create mode 100644 c64/basic/engine/fetch_character.s create mode 100644 c64/basic/engine/injest_spaces.s create mode 100644 c64/basic/engine/unconsume_character.s diff --git a/c64/basic/basic_adray1.s b/c64/basic/,stubs/basic_adray1.s similarity index 100% rename from c64/basic/basic_adray1.s rename to c64/basic/,stubs/basic_adray1.s diff --git a/c64/basic/basic_adray2.s b/c64/basic/,stubs/basic_adray2.s similarity index 100% rename from c64/basic/basic_adray2.s rename to c64/basic/,stubs/basic_adray2.s diff --git a/c64/basic/basic_execute_line.s b/c64/basic/basic_execute_line.s index b7b6196c..f062b4a8 100644 --- a/c64/basic/basic_execute_line.s +++ b/c64/basic/basic_execute_line.s @@ -73,7 +73,7 @@ basic_execute_statement: pha // Now consume the character - jsr basic_consume_character + jsr consume_character rts @@ -92,38 +92,11 @@ not_a_token: jmp do_SYNTAX_error basic_skip_char: - jsr basic_consume_character + jsr consume_character jmp basic_execute_statement -basic_fetch_and_consume_character: - ldy #0 -#if CONFIG_MEMORY_MODEL_60K - ldx # Date: Fri, 5 Jun 2020 23:25:56 +0200 Subject: [PATCH 019/103] faster command jumptable handling in BASIC, added 65C02 optimized version --- c64/basic/basic_execute_line.s | 29 +- c64/basic/commands/command_jumptable.s | 566 +++++++++++++++++++------ 2 files changed, 457 insertions(+), 138 deletions(-) diff --git a/c64/basic/basic_execute_line.s b/c64/basic/basic_execute_line.s index f062b4a8..3120eb63 100644 --- a/c64/basic/basic_execute_line.s +++ b/c64/basic/basic_execute_line.s @@ -63,20 +63,31 @@ basic_execute_statement: cmp #$7f bcc not_a_token - // It is a token: So get the jump table entry for it, push it on the stack - // and then RTS to start it. - asl - tax - lda command_jumptable+1,x - pha - lda command_jumptable+0,x - pha - // Now consume the character + // It is a token - consume this character + jsr consume_character + +#if !HAS_OPCODES_65C02 + + // Get the jump table entry for it, push it on the stack, and then RTS to start it. + + tax + lda command_jumptable_hi - $80, x + pha + lda command_jumptable_lo - $80, x + pha rts +#else // HAS_OPCODES_65C02 + + asl + tax + jmp (command_jumptable, x) + +#endif + not_a_token: // Space, which we can also just ignore cmp #$20 diff --git a/c64/basic/commands/command_jumptable.s b/c64/basic/commands/command_jumptable.s index f45137cf..0f72c98c 100644 --- a/c64/basic/commands/command_jumptable.s +++ b/c64/basic/commands/command_jumptable.s @@ -7,149 +7,457 @@ // +#if !HAS_OPCODES_65C02 + + +command_jumptable_lo: + + // $80 - $8F + .byte <(cmd_end-1) + .byte <(cmd_for-1) + .byte <(cmd_next-1) + .byte <(cmd_data-1) + .byte <(cmd_inputhash-1) + .byte <(cmd_input-1) + .byte <(cmd_dim-1) + .byte <(cmd_read-1) + .byte <(cmd_let-1) + .byte <(cmd_goto-1) + .byte <(cmd_run-1) + .byte <(cmd_if-1) + .byte <(cmd_restore-1) + .byte <(cmd_gosub-1) + .byte <(cmd_return-1) + .byte <(cmd_rem-1) + + // $90-$9F + .byte <(cmd_stop-1) + .byte <(cmd_on-1) + .byte <(cmd_wait-1) + .byte <(cmd_load-1) + .byte <(cmd_save-1) + .byte <(cmd_verify-1) + .byte <(cmd_def-1) + .byte <(cmd_poke-1) + .byte <(cmd_printhash-1) + .byte <(cmd_print-1) + .byte <(cmd_cont-1) + .byte <(cmd_list-1) + .byte <(cmd_clr-1) + .byte <(cmd_cmd-1) + .byte <(cmd_sys-1) + .byte <(cmd_open-1) + + // $A0-$AF + .byte <(cmd_close-1) + .byte <(cmd_get-1) + .byte <(cmd_new-1) + .byte <(cmd_tab-1) + .byte <(cmd_to-1) + .byte <(cmd_fn-1) + .byte <(cmd_spc-1) + .byte <(cmd_then-1) + .byte <(cmd_not-1) + .byte <(cmd_step-1) + .byte <(cmd_plus-1) + .byte <(cmd_minus-1) + .byte <(cmd_mult-1) + .byte <(cmd_div-1) + .byte <(cmd_exponent-1) + .byte <(cmd_and-1) + + // $B0-$BF + .byte <(cmd_or-1) + .byte <(cmd_greater-1) + .byte <(cmd_equal-1) + .byte <(cmd_less-1) + .byte <(cmd_sgn-1) + .byte <(cmd_int-1) + .byte <(cmd_abs-1) + .byte <(cmd_usr-1) + .byte <(cmd_fre-1) + .byte <(cmd_pos-1) + .byte <(cmd_sqr-1) + .byte <(cmd_rnd-1) + .byte <(cmd_log-1) + .byte <(cmd_exp-1) + .byte <(cmd_cos-1) + .byte <(cmd_sin-1) + + // $C0-$CF + .byte <(cmd_tan-1) + .byte <(cmd_atn-1) + .byte <(cmd_peek-1) + .byte <(cmd_len-1) + .byte <(cmd_str-1) + .byte <(cmd_val-1) + .byte <(cmd_asc-1) + .byte <(cmd_chr-1) + .byte <(cmd_left-1) + .byte <(cmd_right-1) + .byte <(cmd_mid-1) + .byte <(cmd_go-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + + // $D0-$DF + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + + // $E0-$EF + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + + // $F0-$FF + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + .byte <(cmd_unimplemented-1) + + +command_jumptable_hi: + + // $80 - $8F + .byte >(cmd_end-1) + .byte >(cmd_for-1) + .byte >(cmd_next-1) + .byte >(cmd_data-1) + .byte >(cmd_inputhash-1) + .byte >(cmd_input-1) + .byte >(cmd_dim-1) + .byte >(cmd_read-1) + .byte >(cmd_let-1) + .byte >(cmd_goto-1) + .byte >(cmd_run-1) + .byte >(cmd_if-1) + .byte >(cmd_restore-1) + .byte >(cmd_gosub-1) + .byte >(cmd_return-1) + .byte >(cmd_rem-1) + + // $90-$9F + .byte >(cmd_stop-1) + .byte >(cmd_on-1) + .byte >(cmd_wait-1) + .byte >(cmd_load-1) + .byte >(cmd_save-1) + .byte >(cmd_verify-1) + .byte >(cmd_def-1) + .byte >(cmd_poke-1) + .byte >(cmd_printhash-1) + .byte >(cmd_print-1) + .byte >(cmd_cont-1) + .byte >(cmd_list-1) + .byte >(cmd_clr-1) + .byte >(cmd_cmd-1) + .byte >(cmd_sys-1) + .byte >(cmd_open-1) + + // $A0-$AF + .byte >(cmd_close-1) + .byte >(cmd_get-1) + .byte >(cmd_new-1) + .byte >(cmd_tab-1) + .byte >(cmd_to-1) + .byte >(cmd_fn-1) + .byte >(cmd_spc-1) + .byte >(cmd_then-1) + .byte >(cmd_not-1) + .byte >(cmd_step-1) + .byte >(cmd_plus-1) + .byte >(cmd_minus-1) + .byte >(cmd_mult-1) + .byte >(cmd_div-1) + .byte >(cmd_exponent-1) + .byte >(cmd_and-1) + + // $B0-$BF + .byte >(cmd_or-1) + .byte >(cmd_greater-1) + .byte >(cmd_equal-1) + .byte >(cmd_less-1) + .byte >(cmd_sgn-1) + .byte >(cmd_int-1) + .byte >(cmd_abs-1) + .byte >(cmd_usr-1) + .byte >(cmd_fre-1) + .byte >(cmd_pos-1) + .byte >(cmd_sqr-1) + .byte >(cmd_rnd-1) + .byte >(cmd_log-1) + .byte >(cmd_exp-1) + .byte >(cmd_cos-1) + .byte >(cmd_sin-1) + + // $C0-$CF + .byte >(cmd_tan-1) + .byte >(cmd_atn-1) + .byte >(cmd_peek-1) + .byte >(cmd_len-1) + .byte >(cmd_str-1) + .byte >(cmd_val-1) + .byte >(cmd_asc-1) + .byte >(cmd_chr-1) + .byte >(cmd_left-1) + .byte >(cmd_right-1) + .byte >(cmd_mid-1) + .byte >(cmd_go-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + + // $D0-$DF + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + + // $E0-$EF + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + + // $F0-$FF + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + .byte >(cmd_unimplemented-1) + + +#else // HAS_OPCODES_65C02 + +__before_command_jumptable: + +.if (mod(*, $2) == 1) { brk } // align code so that vector never crosses page boundary + command_jumptable: // $80 - $8F - .word cmd_end-1 - .word cmd_for-1 - .word cmd_next-1 - .word cmd_data-1 - .word cmd_inputhash-1 - .word cmd_input-1 - .word cmd_dim-1 - .word cmd_read-1 - .word cmd_let-1 - .word cmd_goto-1 - .word cmd_run-1 - .word cmd_if-1 - .word cmd_restore-1 - .word cmd_gosub-1 - .word cmd_return-1 - .word cmd_rem-1 + .word cmd_end + .word cmd_for + .word cmd_next + .word cmd_data + .word cmd_inputhash + .word cmd_input + .word cmd_dim + .word cmd_read + .word cmd_let + .word cmd_goto + .word cmd_run + .word cmd_if + .word cmd_restore + .word cmd_gosub + .word cmd_return + .word cmd_rem // $90-$9F - .word cmd_stop-1 - .word cmd_on-1 - .word cmd_wait-1 - .word cmd_load-1 - .word cmd_save-1 - .word cmd_verify-1 - .word cmd_def-1 - .word cmd_poke-1 - .word cmd_printhash-1 - .word cmd_print-1 - .word cmd_cont-1 - .word cmd_list-1 - .word cmd_clr-1 - .word cmd_cmd-1 - .word cmd_sys-1 - .word cmd_open-1 + .word cmd_stop + .word cmd_on + .word cmd_wait + .word cmd_load + .word cmd_save + .word cmd_verify + .word cmd_def + .word cmd_poke + .word cmd_printhash + .word cmd_print + .word cmd_cont + .word cmd_list + .word cmd_clr + .word cmd_cmd + .word cmd_sys + .word cmd_open // $A0-$AF - .word cmd_close-1 - .word cmd_get-1 - .word cmd_new-1 - .word cmd_tab-1 - .word cmd_to-1 - .word cmd_fn-1 - .word cmd_spc-1 - .word cmd_then-1 - .word cmd_not-1 - .word cmd_step-1 - .word cmd_plus-1 - .word cmd_minus-1 - .word cmd_mult-1 - .word cmd_div-1 - .word cmd_exponent-1 - .word cmd_and-1 + .word cmd_close + .word cmd_get + .word cmd_new + .word cmd_tab + .word cmd_to + .word cmd_fn + .word cmd_spc + .word cmd_then + .word cmd_not + .word cmd_step + .word cmd_plus + .word cmd_minus + .word cmd_mult + .word cmd_div + .word cmd_exponent + .word cmd_and // $B0-$BF - .word cmd_or-1 - .word cmd_greater-1 - .word cmd_equal-1 - .word cmd_less-1 - .word cmd_sgn-1 - .word cmd_int-1 - .word cmd_abs-1 - .word cmd_usr-1 - .word cmd_fre-1 - .word cmd_pos-1 - .word cmd_sqr-1 - .word cmd_rnd-1 - .word cmd_log-1 - .word cmd_exp-1 - .word cmd_cos-1 - .word cmd_sin-1 + .word cmd_or + .word cmd_greater + .word cmd_equal + .word cmd_less + .word cmd_sgn + .word cmd_int + .word cmd_abs + .word cmd_usr + .word cmd_fre + .word cmd_pos + .word cmd_sqr + .word cmd_rnd + .word cmd_log + .word cmd_exp + .word cmd_cos + .word cmd_sin // $C0-$CF - .word cmd_tan-1 - .word cmd_atn-1 - .word cmd_peek-1 - .word cmd_len-1 - .word cmd_str-1 - .word cmd_val-1 - .word cmd_asc-1 - .word cmd_chr-1 - .word cmd_left-1 - .word cmd_right-1 - .word cmd_mid-1 - .word cmd_go-1 - // Undefined tokens - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 + .word cmd_tan + .word cmd_atn + .word cmd_peek + .word cmd_len + .word cmd_str + .word cmd_val + .word cmd_asc + .word cmd_chr + .word cmd_left + .word cmd_right + .word cmd_mid + .word cmd_go + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented // $D0-$DF - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented // $E0-$EF - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented // $F0-$FF - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 - .word cmd_unimplemented-1 + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + .word cmd_unimplemented + + // Make sure routine size is always the same - build system limitation + +.if (__before_command_jumptable == command_jumptable) { brk } + +#endif From f560e26c651cef5557d2df89f1d0329c14f4f35d Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Fri, 5 Jun 2020 23:49:43 +0200 Subject: [PATCH 020/103] small size optimization in BASIC code --- c64/basic/commands/cmd_load_verify.s | 15 ++++----------- c64/basic/engine/end_of_statement_check.s | 4 ++-- c64/basic/wedge/wedge_tape.s | 6 +++--- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/c64/basic/commands/cmd_load_verify.s b/c64/basic/commands/cmd_load_verify.s index c95db67c..ba07cfdf 100644 --- a/c64/basic/commands/cmd_load_verify.s +++ b/c64/basic/commands/cmd_load_verify.s @@ -17,10 +17,6 @@ cmd_load: lda #$00 // mark operation as LOAD sta VERCKB - // C64 BASIC apparently does not clear variables after a LOAD in the - // middle of a program. For safety, we do. - jsr basic_do_clr - // Set default device and secondary address; channel is not important now jsr select_device @@ -83,6 +79,10 @@ cmd_load_no_error: stx VARTAB+0 sty VARTAB+1 + // C64 BASIC apparently does not clear variables after a LOAD in the + // middle of a program. For safety, we do. + jsr basic_do_clr + // Now relink the loaded program, as we cannot trust the line // links supplied. For example, the VICE virtual drive emulation // always supplies $0101 as the address of the next line @@ -97,10 +97,3 @@ cmd_load_no_error: // XXX - should run program if LOAD was used in program mode jmp basic_main_loop - - - - - - -// XXX move functions below to separate files, change names to neuytral diff --git a/c64/basic/engine/end_of_statement_check.s b/c64/basic/engine/end_of_statement_check.s index 6367e274..75ca63d8 100644 --- a/c64/basic/engine/end_of_statement_check.s +++ b/c64/basic/engine/end_of_statement_check.s @@ -9,7 +9,7 @@ end_of_statement_check: - ldy #0 + ldy #$00 #if CONFIG_MEMORY_MODEL_60K ldx # Date: Sat, 6 Jun 2020 10:09:25 +0200 Subject: [PATCH 021/103] use macros for CPU-specific jumptable generation --- c64/aliases/,aliases_cpu.s | 37 ++ c64/basic/commands/command_jumptable.s | 591 +++++------------- .../screen/chrout_screen_jumptable_codes.s | 104 ++- 3 files changed, 236 insertions(+), 496 deletions(-) diff --git a/c64/aliases/,aliases_cpu.s b/c64/aliases/,aliases_cpu.s index 38a321dc..4f26aefe 100644 --- a/c64/aliases/,aliases_cpu.s +++ b/c64/aliases/,aliases_cpu.s @@ -42,6 +42,43 @@ +// +// Macros for generating jumptables +// + + +#if !HAS_OPCODES_65C02 + +.macro put_jumptable_lo(list) +{ + .for (var i = 0; i < list.size(); i++) + { + .byte mod((list.get(i) - 1), $100) + } +} + +.macro put_jumptable_hi(list) +{ + .for (var i = 0; i < list.size(); i++) + { + .byte floor((list.get(i) - 1) / $100) + } +} + +#else // HAS_OPCODES_65C02 + +.macro put_jumptable(list) +{ + .for (var i = 0; i < list.size(); i++) + { + .word list.get(i) + } +} + +#endif + + + // // Trick to skip a 2-byte instruction // diff --git a/c64/basic/commands/command_jumptable.s b/c64/basic/commands/command_jumptable.s index 0f72c98c..99d2a98f 100644 --- a/c64/basic/commands/command_jumptable.s +++ b/c64/basic/commands/command_jumptable.s @@ -7,457 +7,190 @@ // +.const command_list = List().add( + + // $80 - $8F + + cmd_end, + cmd_for, + cmd_next, + cmd_data, + cmd_inputhash, + cmd_input, + cmd_dim, + cmd_read, + cmd_let, + cmd_goto, + cmd_run, + cmd_if, + cmd_restore, + cmd_gosub, + cmd_return, + cmd_rem, + + // $90-$9F + + cmd_stop, + cmd_on, + cmd_wait, + cmd_load, + cmd_save, + cmd_verify, + cmd_def, + cmd_poke, + cmd_printhash, + cmd_print, + cmd_cont, + cmd_list, + cmd_clr, + cmd_cmd, + cmd_sys, + cmd_open, + + // $A0-$AF + + cmd_close, + cmd_get, + cmd_new, + cmd_tab, + cmd_to, + cmd_fn, + cmd_spc, + cmd_then, + cmd_not, + cmd_step, + cmd_plus, + cmd_minus, + cmd_mult, + cmd_div, + cmd_exponent, + cmd_and, + + // $B0-$BF + + cmd_or, + cmd_greater, + cmd_equal, + cmd_less, + cmd_sgn, + cmd_int, + cmd_abs, + cmd_usr, + cmd_fre, + cmd_pos, + cmd_sqr, + cmd_rnd, + cmd_log, + cmd_exp, + cmd_cos, + cmd_sin, + + // $C0-$CF + + cmd_tan, + cmd_atn, + cmd_peek, + cmd_len, + cmd_str, + cmd_val, + cmd_asc, + cmd_chr, + cmd_left, + cmd_right, + cmd_mid, + cmd_go, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + + // $D0-$DF + + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + + // $E0-$EF + + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + + // $F0-$FF + + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented, + cmd_unimplemented +) + + + #if !HAS_OPCODES_65C02 command_jumptable_lo: - // $80 - $8F - .byte <(cmd_end-1) - .byte <(cmd_for-1) - .byte <(cmd_next-1) - .byte <(cmd_data-1) - .byte <(cmd_inputhash-1) - .byte <(cmd_input-1) - .byte <(cmd_dim-1) - .byte <(cmd_read-1) - .byte <(cmd_let-1) - .byte <(cmd_goto-1) - .byte <(cmd_run-1) - .byte <(cmd_if-1) - .byte <(cmd_restore-1) - .byte <(cmd_gosub-1) - .byte <(cmd_return-1) - .byte <(cmd_rem-1) - - // $90-$9F - .byte <(cmd_stop-1) - .byte <(cmd_on-1) - .byte <(cmd_wait-1) - .byte <(cmd_load-1) - .byte <(cmd_save-1) - .byte <(cmd_verify-1) - .byte <(cmd_def-1) - .byte <(cmd_poke-1) - .byte <(cmd_printhash-1) - .byte <(cmd_print-1) - .byte <(cmd_cont-1) - .byte <(cmd_list-1) - .byte <(cmd_clr-1) - .byte <(cmd_cmd-1) - .byte <(cmd_sys-1) - .byte <(cmd_open-1) - - // $A0-$AF - .byte <(cmd_close-1) - .byte <(cmd_get-1) - .byte <(cmd_new-1) - .byte <(cmd_tab-1) - .byte <(cmd_to-1) - .byte <(cmd_fn-1) - .byte <(cmd_spc-1) - .byte <(cmd_then-1) - .byte <(cmd_not-1) - .byte <(cmd_step-1) - .byte <(cmd_plus-1) - .byte <(cmd_minus-1) - .byte <(cmd_mult-1) - .byte <(cmd_div-1) - .byte <(cmd_exponent-1) - .byte <(cmd_and-1) - - // $B0-$BF - .byte <(cmd_or-1) - .byte <(cmd_greater-1) - .byte <(cmd_equal-1) - .byte <(cmd_less-1) - .byte <(cmd_sgn-1) - .byte <(cmd_int-1) - .byte <(cmd_abs-1) - .byte <(cmd_usr-1) - .byte <(cmd_fre-1) - .byte <(cmd_pos-1) - .byte <(cmd_sqr-1) - .byte <(cmd_rnd-1) - .byte <(cmd_log-1) - .byte <(cmd_exp-1) - .byte <(cmd_cos-1) - .byte <(cmd_sin-1) - - // $C0-$CF - .byte <(cmd_tan-1) - .byte <(cmd_atn-1) - .byte <(cmd_peek-1) - .byte <(cmd_len-1) - .byte <(cmd_str-1) - .byte <(cmd_val-1) - .byte <(cmd_asc-1) - .byte <(cmd_chr-1) - .byte <(cmd_left-1) - .byte <(cmd_right-1) - .byte <(cmd_mid-1) - .byte <(cmd_go-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - - // $D0-$DF - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - - // $E0-$EF - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - - // $F0-$FF - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) - .byte <(cmd_unimplemented-1) + put_jumptable_lo(command_list) command_jumptable_hi: - // $80 - $8F - .byte >(cmd_end-1) - .byte >(cmd_for-1) - .byte >(cmd_next-1) - .byte >(cmd_data-1) - .byte >(cmd_inputhash-1) - .byte >(cmd_input-1) - .byte >(cmd_dim-1) - .byte >(cmd_read-1) - .byte >(cmd_let-1) - .byte >(cmd_goto-1) - .byte >(cmd_run-1) - .byte >(cmd_if-1) - .byte >(cmd_restore-1) - .byte >(cmd_gosub-1) - .byte >(cmd_return-1) - .byte >(cmd_rem-1) - - // $90-$9F - .byte >(cmd_stop-1) - .byte >(cmd_on-1) - .byte >(cmd_wait-1) - .byte >(cmd_load-1) - .byte >(cmd_save-1) - .byte >(cmd_verify-1) - .byte >(cmd_def-1) - .byte >(cmd_poke-1) - .byte >(cmd_printhash-1) - .byte >(cmd_print-1) - .byte >(cmd_cont-1) - .byte >(cmd_list-1) - .byte >(cmd_clr-1) - .byte >(cmd_cmd-1) - .byte >(cmd_sys-1) - .byte >(cmd_open-1) - - // $A0-$AF - .byte >(cmd_close-1) - .byte >(cmd_get-1) - .byte >(cmd_new-1) - .byte >(cmd_tab-1) - .byte >(cmd_to-1) - .byte >(cmd_fn-1) - .byte >(cmd_spc-1) - .byte >(cmd_then-1) - .byte >(cmd_not-1) - .byte >(cmd_step-1) - .byte >(cmd_plus-1) - .byte >(cmd_minus-1) - .byte >(cmd_mult-1) - .byte >(cmd_div-1) - .byte >(cmd_exponent-1) - .byte >(cmd_and-1) - - // $B0-$BF - .byte >(cmd_or-1) - .byte >(cmd_greater-1) - .byte >(cmd_equal-1) - .byte >(cmd_less-1) - .byte >(cmd_sgn-1) - .byte >(cmd_int-1) - .byte >(cmd_abs-1) - .byte >(cmd_usr-1) - .byte >(cmd_fre-1) - .byte >(cmd_pos-1) - .byte >(cmd_sqr-1) - .byte >(cmd_rnd-1) - .byte >(cmd_log-1) - .byte >(cmd_exp-1) - .byte >(cmd_cos-1) - .byte >(cmd_sin-1) - - // $C0-$CF - .byte >(cmd_tan-1) - .byte >(cmd_atn-1) - .byte >(cmd_peek-1) - .byte >(cmd_len-1) - .byte >(cmd_str-1) - .byte >(cmd_val-1) - .byte >(cmd_asc-1) - .byte >(cmd_chr-1) - .byte >(cmd_left-1) - .byte >(cmd_right-1) - .byte >(cmd_mid-1) - .byte >(cmd_go-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - - // $D0-$DF - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - - // $E0-$EF - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - - // $F0-$FF - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) - .byte >(cmd_unimplemented-1) + put_jumptable_hi(command_list) #else // HAS_OPCODES_65C02 + __before_command_jumptable: .if (mod(*, $2) == 1) { brk } // align code so that vector never crosses page boundary command_jumptable: - // $80 - $8F - .word cmd_end - .word cmd_for - .word cmd_next - .word cmd_data - .word cmd_inputhash - .word cmd_input - .word cmd_dim - .word cmd_read - .word cmd_let - .word cmd_goto - .word cmd_run - .word cmd_if - .word cmd_restore - .word cmd_gosub - .word cmd_return - .word cmd_rem - - // $90-$9F - .word cmd_stop - .word cmd_on - .word cmd_wait - .word cmd_load - .word cmd_save - .word cmd_verify - .word cmd_def - .word cmd_poke - .word cmd_printhash - .word cmd_print - .word cmd_cont - .word cmd_list - .word cmd_clr - .word cmd_cmd - .word cmd_sys - .word cmd_open - - // $A0-$AF - .word cmd_close - .word cmd_get - .word cmd_new - .word cmd_tab - .word cmd_to - .word cmd_fn - .word cmd_spc - .word cmd_then - .word cmd_not - .word cmd_step - .word cmd_plus - .word cmd_minus - .word cmd_mult - .word cmd_div - .word cmd_exponent - .word cmd_and - - // $B0-$BF - .word cmd_or - .word cmd_greater - .word cmd_equal - .word cmd_less - .word cmd_sgn - .word cmd_int - .word cmd_abs - .word cmd_usr - .word cmd_fre - .word cmd_pos - .word cmd_sqr - .word cmd_rnd - .word cmd_log - .word cmd_exp - .word cmd_cos - .word cmd_sin - - // $C0-$CF - .word cmd_tan - .word cmd_atn - .word cmd_peek - .word cmd_len - .word cmd_str - .word cmd_val - .word cmd_asc - .word cmd_chr - .word cmd_left - .word cmd_right - .word cmd_mid - .word cmd_go - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - - // $D0-$DF - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - - // $E0-$EF - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - - // $F0-$FF - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented - .word cmd_unimplemented + put_jumptable(command_list) // Make sure routine size is always the same - build system limitation .if (__before_command_jumptable == command_jumptable) { brk } + #endif diff --git a/c64/kernal/screen/chrout_screen_jumptable_codes.s b/c64/kernal/screen/chrout_screen_jumptable_codes.s index 66e56e74..1f4fe7b3 100644 --- a/c64/kernal/screen/chrout_screen_jumptable_codes.s +++ b/c64/kernal/screen/chrout_screen_jumptable_codes.s @@ -40,59 +40,49 @@ __chrout_screen_jumptable_quote_guard: __chrout_screen_jumptable_codes_end: + +.const chrout_list = List().add( + + chrout_screen_CLR, + chrout_screen_HOME, + chrout_screen_SHIFT_OFF, + chrout_screen_SHIFT_ON, + chrout_screen_TXT, + chrout_screen_GFX, + chrout_screen_RVS_OFF, + chrout_screen_RVS_ON, + chrout_screen_CRSR_RIGHT, + chrout_screen_CRSR_LEFT, + chrout_screen_CRSR_DOWN, + chrout_screen_CRSR_UP, + chrout_screen_INS, +#if CONFIG_EDIT_STOPQUOTE + chrout_screen_STOP, +#endif +#if CONFIG_EDIT_TABULATORS + chrout_screen_TAB_BW, + chrout_screen_TAB_FW, +#endif + chrout_screen_DEL, + chrout_screen_RETURN +) + + #if !HAS_OPCODES_65C02 + chrout_screen_jumptable_lo: - .byte <(chrout_screen_CLR - 1) - .byte <(chrout_screen_HOME - 1) - .byte <(chrout_screen_SHIFT_OFF - 1) - .byte <(chrout_screen_SHIFT_ON - 1) - .byte <(chrout_screen_TXT - 1) - .byte <(chrout_screen_GFX - 1) - .byte <(chrout_screen_RVS_OFF - 1) - .byte <(chrout_screen_RVS_ON - 1) - .byte <(chrout_screen_CRSR_RIGHT - 1) - .byte <(chrout_screen_CRSR_LEFT - 1) - .byte <(chrout_screen_CRSR_DOWN - 1) - .byte <(chrout_screen_CRSR_UP - 1) - .byte <(chrout_screen_INS - 1) -#if CONFIG_EDIT_STOPQUOTE - .byte <(chrout_screen_STOP - 1) -#endif -#if CONFIG_EDIT_TABULATORS - .byte <(chrout_screen_TAB_BW - 1) - .byte <(chrout_screen_TAB_FW - 1) -#endif - .byte <(chrout_screen_DEL - 1) - .byte <(chrout_screen_RETURN - 1) + put_jumptable_lo(chrout_list) + chrout_screen_jumptable_hi: - .byte >(chrout_screen_CLR - 1) - .byte >(chrout_screen_HOME - 1) - .byte >(chrout_screen_SHIFT_OFF - 1) - .byte >(chrout_screen_SHIFT_ON - 1) - .byte >(chrout_screen_TXT - 1) - .byte >(chrout_screen_GFX - 1) - .byte >(chrout_screen_RVS_OFF - 1) - .byte >(chrout_screen_RVS_ON - 1) - .byte >(chrout_screen_CRSR_RIGHT - 1) - .byte >(chrout_screen_CRSR_LEFT - 1) - .byte >(chrout_screen_CRSR_DOWN - 1) - .byte >(chrout_screen_CRSR_UP - 1) - .byte >(chrout_screen_INS - 1) -#if CONFIG_EDIT_STOPQUOTE - .byte >(chrout_screen_STOP - 1) -#endif -#if CONFIG_EDIT_TABULATORS - .byte >(chrout_screen_TAB_BW - 1) - .byte >(chrout_screen_TAB_FW - 1) -#endif - .byte >(chrout_screen_DEL - 1) - .byte >(chrout_screen_RETURN - 1) + put_jumptable_hi(chrout_list) + + +#else // HAS_OPCODES_65C02 -#else __before_chrout_screen_jumptable: @@ -100,31 +90,11 @@ __before_chrout_screen_jumptable: chrout_screen_jumptable: - .word chrout_screen_CLR - .word chrout_screen_HOME - .word chrout_screen_SHIFT_OFF - .word chrout_screen_SHIFT_ON - .word chrout_screen_TXT - .word chrout_screen_GFX - .word chrout_screen_RVS_OFF - .word chrout_screen_RVS_ON - .word chrout_screen_CRSR_RIGHT - .word chrout_screen_CRSR_LEFT - .word chrout_screen_CRSR_DOWN - .word chrout_screen_CRSR_UP - .word chrout_screen_INS -#if CONFIG_EDIT_STOPQUOTE - .word chrout_screen_STOP -#endif -#if CONFIG_EDIT_TABULATORS - .word chrout_screen_TAB_BW - .word chrout_screen_TAB_FW -#endif - .word chrout_screen_DEL - .word chrout_screen_RETURN + put_jumptable(chrout_list) // Make sure routine size is always the same - build system limitation .if (__before_chrout_screen_jumptable == chrout_screen_jumptable) { brk } + #endif From 6b8c9ded30fff3026c299c113bf96a99d8bfe6da Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 6 Jun 2020 12:57:03 +0200 Subject: [PATCH 022/103] fixes and optimizations of BASIC error reporting --- c64/basic/basic_do_error.s | 41 ----------------- c64/basic/basic_main_loop.s | 2 +- c64/basic/commands/cmd_load_verify.s | 11 +---- .../{do_basic_error.s => engine/do_error.s} | 45 ++++++++++++++----- c64/basic/engine/fetch_character.s | 11 ++++- c64/basic/wedge/wedge_dos.s | 5 +-- c64/basic/wedge/wedge_tape.s | 3 +- tools/compress_text.c | 2 +- 8 files changed, 49 insertions(+), 71 deletions(-) delete mode 100644 c64/basic/basic_do_error.s rename c64/basic/{do_basic_error.s => engine/do_error.s} (86%) diff --git a/c64/basic/basic_do_error.s b/c64/basic/basic_do_error.s deleted file mode 100644 index f4f21fd4..00000000 --- a/c64/basic/basic_do_error.s +++ /dev/null @@ -1,41 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - -// 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 - jsr JCHROUT - - // Print main part of error message - plx_trash_a - jsr print_packed_message - - // Print ERROR at end - jsr print_space - ldx #33 - jsr print_packed_message - - // XXX print IN if not in direct mode - - // XXX print line number if not in direct mode - - jsr print_return - jsr print_return - - // Reset stack, and go back to main loop - ldx #$FE - txs - jmp basic_main_loop diff --git a/c64/basic/basic_main_loop.s b/c64/basic/basic_main_loop.s index 575a98e5..e0abca56 100644 --- a/c64/basic/basic_main_loop.s +++ b/c64/basic/basic_main_loop.s @@ -31,7 +31,7 @@ read_line_loop: bcc !+ // Report STRING TOO LONG error (Computes Mapping the 64 p93) ldx #22 - jmp basic_do_error + jmp do_basic_error !: sta BUF,x inx diff --git a/c64/basic/commands/cmd_load_verify.s b/c64/basic/commands/cmd_load_verify.s index ba07cfdf..5ba69324 100644 --- a/c64/basic/commands/cmd_load_verify.s +++ b/c64/basic/commands/cmd_load_verify.s @@ -61,16 +61,7 @@ cmd_load_got_params: // input for tape wedge jsr print_return pla plp - bcc cmd_load_no_error - - // .A = KERNAL error code, also almost matches BASIC error codes - - tax - dex - bpl !+ - ldx #B_ERR_BREAK -!: - jmp do_basic_error + bcs_16 do_kernal_error cmd_load_no_error: diff --git a/c64/basic/do_basic_error.s b/c64/basic/engine/do_error.s similarity index 86% rename from c64/basic/do_basic_error.s rename to c64/basic/engine/do_error.s index 6bf58362..c64ee734 100644 --- a/c64/basic/do_basic_error.s +++ b/c64/basic/engine/do_error.s @@ -32,6 +32,22 @@ // message. This compares favourably to the 3 bytes per error // message that the $2C method would result in. + +do_kernal_error: // .A = KERNAL error code, also almost matches BASIC error codes + + // Convert to BASIC error code + + tax + dex + bpl do_basic_error + + // FALLTROUGN + +do_BREAK_error: + + ldx #B_ERR_BREAK + bpl do_basic_error // branch always + do_NOT_IMPLEMENTED_error: .byte $E6 do_MEMORY_CORRUPT_error: @@ -107,7 +123,8 @@ do_FILE_OPEN_error: do_TO_MANY_FILES_error: .byte $EA - // Now get the error # and restore $E6 to its correct value + // Now get the error id and restore $E6 to its correct value + lda $E6 pha and #$80 @@ -121,39 +138,39 @@ do_TO_MANY_FILES_error: // Restore $EA to correct value in case the NOP above is used // as an argument to the preceeding INC $nn (opcode $E6). + lda $EA and #$80 sta $EA - // FALL THROUGH + // FALLTHROUGH - // Error # in X +do_basic_error: // error code in .X -do_basic_error: // "?" txa pha jsr print_return - lda #$3f + lda #$3F jsr JCHROUT pla tax - // Error message text + // Error message text + " ERROR" + jsr print_packed_message - // A space between error name and word error - jsr print_space - - // "ERROR" ldx #33 jsr print_packed_message + // Check if direct mode + lda CURLIN+1 - cmp #$ff + cmp #$FF beq !+ // We were in a program, so show IN + ldx #31 jsr print_packed_message @@ -162,10 +179,14 @@ do_basic_error: jsr print_integer !: // New lines + jsr print_return lda #$00 jsr JCHROUT - // XXX - Restore stack depth first? + // Reset stack, and go back to main loop + + ldx #$FE + txs jmp basic_main_loop diff --git a/c64/basic/engine/fetch_character.s b/c64/basic/engine/fetch_character.s index 5edb7984..ddef18b5 100644 --- a/c64/basic/engine/fetch_character.s +++ b/c64/basic/engine/fetch_character.s @@ -28,8 +28,17 @@ consume_character: // Advance basic text pointer +#if !HAS_OPCODES_65CE02 + inc TXTPTR+0 bne !+ inc TXTPTR+1 !: - rts \ No newline at end of file + +#else // HAS_OPCODES_65CE02 + + inw TXTPTR + +#endif + + rts diff --git a/c64/basic/wedge/wedge_dos.s b/c64/basic/wedge/wedge_dos.s index 7b7db2a6..ca493471 100644 --- a/c64/basic/wedge/wedge_dos.s +++ b/c64/basic/wedge/wedge_dos.s @@ -241,9 +241,8 @@ wedge_dos_clean_exit: wedge_dos_basic_error: pha jsr JCLALL - plx_trash_a - dex - jmp do_basic_error + pla + jmp do_kernal_error wedge_dos_setnam: // Now determine the length of the 'file' name diff --git a/c64/basic/wedge/wedge_tape.s b/c64/basic/wedge/wedge_tape.s index 5f5c5fac..ac89415d 100644 --- a/c64/basic/wedge/wedge_tape.s +++ b/c64/basic/wedge/wedge_tape.s @@ -58,8 +58,7 @@ wedge_arrow_H: jsr tape_head_align jsr print_return - ldx #B_ERR_BREAK - jmp do_basic_error + jmp do_BREAK_error #endif diff --git a/tools/compress_text.c b/tools/compress_text.c index 6f7b0daf..156a56db 100644 --- a/tools/compress_text.c +++ b/tools/compress_text.c @@ -162,7 +162,7 @@ char *error_list[]={ "BREAK", // #30 " IN ", // #31 "BRK AT $", // #32 - "ERROR", // #33 // Simply the word error that is attached to the other parts of messages https://fjkraan.home.xs4all.nl/comp/apple2faq/app2asoftfaq.html + " ERROR", // #33 // Simply the word error that is attached to the other parts of messages https://fjkraan.home.xs4all.nl/comp/apple2faq/app2asoftfaq.html " BASIC BYTES FREE", // #34 // https://github.com/stefanhaustein/expressionparser "MEMORY CORRUPT", // #35 "NOT IMPLEMENTED", // #36 From f8892815346dfbccd3c868d7d0562f4c6a20d1a6 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 6 Jun 2020 13:21:10 +0200 Subject: [PATCH 023/103] another small error handling optimization --- c64/basic/engine/do_error.s | 37 +++++++++++++++---------------------- c64/basic/ready_message.s | 2 +- tools/compress_text.c | 4 ++-- 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/c64/basic/engine/do_error.s b/c64/basic/engine/do_error.s index c64ee734..86edb545 100644 --- a/c64/basic/engine/do_error.s +++ b/c64/basic/engine/do_error.s @@ -33,6 +33,19 @@ // message that the $2C method would result in. +// XXX consider reworking the two errors below to reuse '$E6' mechanism + + +do_NOT_IMPLEMENTED_error: + + ldx #36 + bpl do_basic_error // branch always + +do_MEMORY_CORRUPT_error: + + ldx #35 + bpl do_basic_error // branch always + do_kernal_error: // .A = KERNAL error code, also almost matches BASIC error codes // Convert to BASIC error code @@ -44,26 +57,7 @@ do_kernal_error: // .A = KERNAL error code, also almost ma // FALLTROUGN do_BREAK_error: - - ldx #B_ERR_BREAK - bpl do_basic_error // branch always - -do_NOT_IMPLEMENTED_error: .byte $E6 -do_MEMORY_CORRUPT_error: - .byte $E6 - // the message "BYTES FREE" - .byte $E6 - // the word ERROR - .byte $E6 - // The word "SAVING" - .byte $E6 - // The word "VERIFYING" - .byte $E6 - // The word "LOADING" - .byte $E6 - // The word "READY." - .byte $E6 do_LOAD_error: .byte $E6 do_VERIFY_error: @@ -148,13 +142,12 @@ do_TO_MANY_FILES_error: do_basic_error: // error code in .X // "?" - txa + phx_trash_a pha jsr print_return lda #$3F jsr JCHROUT - pla - tax + plx_trash_a // Error message text + " ERROR" diff --git a/c64/basic/ready_message.s b/c64/basic/ready_message.s index 9d528c38..4486bbf8 100644 --- a/c64/basic/ready_message.s +++ b/c64/basic/ready_message.s @@ -5,5 +5,5 @@ ready_message: - ldx #29 + ldx #30 jmp print_packed_message diff --git a/tools/compress_text.c b/tools/compress_text.c index 156a56db..89eaacf0 100644 --- a/tools/compress_text.c +++ b/tools/compress_text.c @@ -157,9 +157,9 @@ char *error_list[]={ "UNDEF\'D FUNCTION", // https://www.saatchiart.com/print/Painting-Undef-d-Function-3495/16167/3829193/view "VERIFY", // https://forums.openvpn.net/viewtopic.php?t=22040 "LOAD", // https://www.discogs.com/Gimmik-Load-Error/release/482462 + "BREAK", // #29 // Non-error messages - "READY.\r", // #29 // https://www.ibm.com/support/knowledgecenter/zosbasics/com.ibm.zos.zconcepts/zconc_whatistsonative.htm https://github.com/stefanhaustein/expressionparser - "BREAK", // #30 + "READY.\r", // #30 // https://www.ibm.com/support/knowledgecenter/zosbasics/com.ibm.zos.zconcepts/zconc_whatistsonative.htm https://github.com/stefanhaustein/expressionparser " IN ", // #31 "BRK AT $", // #32 " ERROR", // #33 // Simply the word error that is attached to the other parts of messages https://fjkraan.home.xs4all.nl/comp/apple2faq/app2asoftfaq.html From 2f2dda54c05c23c331258381f006ead2865bd417 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 6 Jun 2020 14:37:33 +0200 Subject: [PATCH 024/103] simplified the head alignment tool --- CONFIG.md | 2 +- c64/kernal/tape/tape_head_align.s | 56 ++++------------------ c64/kernal/tape/tape_head_align_gen_code.s | 6 +++ c64/kernal/tape/tape_head_align_help.s | 5 ++ c64/kernal/tape/tape_head_align_irq.s | 29 ++++++----- 5 files changed, 36 insertions(+), 62 deletions(-) diff --git a/CONFIG.md b/CONFIG.md index b91f3301..afeab009 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -291,7 +291,7 @@ Feature needs few bytes in BASIC segment. If unsure - enable. If enabled, embeds a tape head align tool into the ROM, it can be started with `←H`. Requires `CONFIG_TAPE_WEDGE`. -Feature needs nearly 1 KB bytes in KERNAL segment. Only recomended for machines with extended ROM, like Mega65. +Feature needs about 800 bytes in KERNAL segment. Only recomended for machines with extended ROM, like Mega65. ### `CONFIG_BCD_SAFE_INTERRUPTS` diff --git a/c64/kernal/tape/tape_head_align.s b/c64/kernal/tape/tape_head_align.s index 7466331e..ddd9123a 100644 --- a/c64/kernal/tape/tape_head_align.s +++ b/c64/kernal/tape/tape_head_align.s @@ -12,26 +12,21 @@ // XXX for Mega65 it can be done more easily, by just disabling the badlines -.label __ha_start = 12 // starting row of the chart -.label __ha_rows = 11 // number of rows for scrolling +.label __ha_start = 12 // starting row of the chart +.label __ha_rows = 11 // number of rows for scrolling // Helper tables .label __ha_offsets = $1000; .label __ha_masks = $1100; -// Helper variables - -.label __ha_lda_addr = $1200; // 2 bytes, for code generator -.label __ha_sta_addr = $1202; // 2 bytes, for code generator -.label __ha_pulses = $1204; // 64 bytes -.label __ha_gfxflag = $1244; // 1 byte -.label __ha_storage = $1245; // 1 byte - - // Generated code location -.label __ha_scroll = $1300; +.label __ha_scroll = $1300; + +// Flag for GFX effects + +.label __ha_gfxflag = $1200; // 1 byte tape_head_align: @@ -144,14 +139,9 @@ tape_head_align: inx bne !-- - // Initialize flag for additional GFX effects and the pulse lengths + // Initialize flag for additional GFX effects - lda #$00 - ldx #$40 -!: - sta __ha_pulses, x - dex - bpl !- + stx __ha_gfxflag // .X is 0 at this moment // Generate helper code for screen scrolling @@ -172,7 +162,7 @@ tape_head_align: and VIC_SCROLY // clear the highest bit of RASTER sta VIC_SCROLY // $D011 - lda #$F3 // the last raster where badline can occur, this is 100% safe start + lda #$FB // we want no badlines during the interrupt, this raster is 100% safe sta VIC_RASTER lda #%00000001 // enable raster interrupts @@ -208,36 +198,10 @@ tape_head_align_loop_1: jsr tape_head_align_apply_gfx - // Skip 2 pulses, these measurements will be too imprecise - - jsr tape_head_align_get_pulse - jsr tape_head_align_get_pulse - // FALLTROUGH tape_head_align_loop_2: - // Draw pulses - - ldx #$00 -!: - stx __ha_storage - - lda __ha_pulses, x - cmp #$FF - beq tape_head_align_drawn // $FF - end of pulses to draw - - jsr tape_head_align_draw_pulse - - ldx __ha_storage - inx - cpx #$40 - bne !- - - // FALLTROUGH - -tape_head_align_drawn: - lda CIA1_TIMBLO and CIA1_TIMBHI eor #$FF diff --git a/c64/kernal/tape/tape_head_align_gen_code.s b/c64/kernal/tape/tape_head_align_gen_code.s index 072dc6c3..f79b761a 100644 --- a/c64/kernal/tape/tape_head_align_gen_code.s +++ b/c64/kernal/tape/tape_head_align_gen_code.s @@ -10,6 +10,12 @@ #if CONFIG_TAPE_HEAD_ALIGN +// Helper variables - reuse BASIC numeric work area on zero page + +.label __ha_lda_addr = TEMPF1 + 0; // 2 bytes, for code generator +.label __ha_sta_addr = TEMPF1 + 2; // 2 bytes, for code generator + + tape_head_align_gen_code: // Setup generated code start address diff --git a/c64/kernal/tape/tape_head_align_help.s b/c64/kernal/tape/tape_head_align_help.s index 0143f2b8..a7115363 100644 --- a/c64/kernal/tape/tape_head_align_help.s +++ b/c64/kernal/tape/tape_head_align_help.s @@ -10,6 +10,11 @@ #if CONFIG_TAPE_HEAD_ALIGN +// Helper variable - reuse BASIC numeric work area on zero page + +.label __ha_storage = TEMPF1; // 1 byte + + tape_head_align_print_help: // Make screen font visible diff --git a/c64/kernal/tape/tape_head_align_irq.s b/c64/kernal/tape/tape_head_align_irq.s index c269b22a..321869b2 100644 --- a/c64/kernal/tape/tape_head_align_irq.s +++ b/c64/kernal/tape/tape_head_align_irq.s @@ -16,24 +16,19 @@ tape_head_align_irq: asl VIC_IRQ - // Clear table of pulses stored - - lda #$FF - ldy #$3F -!: - sta __ha_pulses, y - dey - bpl !- - // Ignore 2 first pulses, they can be garbage jsr tape_head_align_get_pulse jsr tape_head_align_get_pulse - // Now, we can retrieve a pulse for the charts + // Now, we can retrieve pulses for the chart ldx #$00 -!: + + // FALLTROUGH + +tape_head_align_irq_loop: + jsr tape_head_align_get_pulse // If we approached badlines again - we cannot use this measurement anymore @@ -45,16 +40,20 @@ tape_head_align_irq: cmp #$33 // first line where badline can occur bcs tape_head_align_irq_end !: - // Store measurement + // Draw pulse + cpy #$FF + beq !+ + phx_trash_a tya - sta __ha_pulses, x - + jsr tape_head_align_draw_pulse + plx_trash_a +!: // Next iteration inx cpx #$40 - bne !-- + bne tape_head_align_irq_loop // FALLTROUGH From c9b0f7cea1261dbf8a24674ce2cb199596c919cf Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 6 Jun 2020 14:47:27 +0200 Subject: [PATCH 025/103] saved few bytes in KERNAL segment --- c64/kernal/tape/tape_head_align.s | 48 ++++++++++++++-- c64/kernal/tape/tape_head_align_apply_gfx.s | 62 --------------------- 2 files changed, 44 insertions(+), 66 deletions(-) delete mode 100644 c64/kernal/tape/tape_head_align_apply_gfx.s diff --git a/c64/kernal/tape/tape_head_align.s b/c64/kernal/tape/tape_head_align.s index ddd9123a..6a0437a0 100644 --- a/c64/kernal/tape/tape_head_align.s +++ b/c64/kernal/tape/tape_head_align.s @@ -24,9 +24,9 @@ .label __ha_scroll = $1300; -// Flag for GFX effects +// Flag for GFX effects - reuse BASIC numeric work area on zero page -.label __ha_gfxflag = $1200; // 1 byte +.label __ha_gfxflag = TEMPF2; // 1 byte tape_head_align: @@ -194,10 +194,50 @@ tape_head_align_loop_1: tax bne !- - // Draw helpers and decorators + // Draw decorations - jsr tape_head_align_apply_gfx + lda __ha_gfxflag + inc __ha_gfxflag + clc + adc #$08 + and #%00001100 + bne !+ + ldy #%11110001 + lda #%10001111 + bne !++ +!: + ldy #%00000001 + lda #%10000000 +!: + ora __ha_chart + 7 + 8 * 0 + sta __ha_chart + 7 + 8 * 0 + tya + ora __ha_chart + 7 + 8 * 31 + sta __ha_chart + 7 + 8 * 31 + + // Draw helper lines + + lda __ha_gfxflag + and #%00000010 + beq !+ + + // For 'normal' + + lda #%00000001 + ora __ha_chart + 7 + 8 * 6 + sta __ha_chart + 7 + 8 * 6 + + lda #%00000001 + ora __ha_chart + 7 + 8 * 13 + sta __ha_chart + 7 + 8 * 13 + + // For 'turbo' + + lda #%00010000 + ora __ha_chart + 7 + 8 * 21 + sta __ha_chart + 7 + 8 * 21 +!: // FALLTROUGH tape_head_align_loop_2: diff --git a/c64/kernal/tape/tape_head_align_apply_gfx.s b/c64/kernal/tape/tape_head_align_apply_gfx.s deleted file mode 100644 index f4091d68..00000000 --- a/c64/kernal/tape/tape_head_align_apply_gfx.s +++ /dev/null @@ -1,62 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# M65 KERNAL_1 #TAKE -// #LAYOUT# * * #IGNORE - -// -// Tape head alignemnt tool - draw helper symbols -// - - -#if CONFIG_TAPE_HEAD_ALIGN - - -tape_head_align_apply_gfx: - - // Apply GFX effects - - lda __ha_gfxflag - inc __ha_gfxflag - clc - adc #$08 - and #%00001100 - bne !+ - ldy #%11110001 - lda #%10001111 - bne !++ -!: - ldy #%00000001 - lda #%10000000 -!: - ora __ha_chart + 7 + 8 * 0 - sta __ha_chart + 7 + 8 * 0 - - tya - ora __ha_chart + 7 + 8 * 31 - sta __ha_chart + 7 + 8 * 31 - - // Draw helper lines - - lda __ha_gfxflag - and #%00000010 - beq !+ - - // For 'normal' - - lda #%00000001 - ora __ha_chart + 7 + 8 * 6 - sta __ha_chart + 7 + 8 * 6 - - lda #%00000001 - ora __ha_chart + 7 + 8 * 13 - sta __ha_chart + 7 + 8 * 13 - - // For 'turbo' - - lda #%00010000 - ora __ha_chart + 7 + 8 * 21 - sta __ha_chart + 7 + 8 * 21 -!: - rts - - -#endif From 260efdb3c4a4ae54a685dfb206c7469b55bff18f Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 6 Jun 2020 14:53:27 +0200 Subject: [PATCH 026/103] few more bytes saved --- c64/kernal/tape/tape_head_align.s | 2 -- c64/kernal/tape/tape_head_align_draw_pulse.s | 29 -------------------- c64/kernal/tape/tape_head_align_irq.s | 16 +++++++++-- 3 files changed, 13 insertions(+), 34 deletions(-) delete mode 100644 c64/kernal/tape/tape_head_align_draw_pulse.s diff --git a/c64/kernal/tape/tape_head_align.s b/c64/kernal/tape/tape_head_align.s index 6a0437a0..690c665b 100644 --- a/c64/kernal/tape/tape_head_align.s +++ b/c64/kernal/tape/tape_head_align.s @@ -9,8 +9,6 @@ #if CONFIG_TAPE_HEAD_ALIGN -// XXX for Mega65 it can be done more easily, by just disabling the badlines - .label __ha_start = 12 // starting row of the chart .label __ha_rows = 11 // number of rows for scrolling diff --git a/c64/kernal/tape/tape_head_align_draw_pulse.s b/c64/kernal/tape/tape_head_align_draw_pulse.s deleted file mode 100644 index 813d0d0a..00000000 --- a/c64/kernal/tape/tape_head_align_draw_pulse.s +++ /dev/null @@ -1,29 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# M65 KERNAL_1 #TAKE -// #LAYOUT# * * #IGNORE - -// -// Tape head alignemnt tool - draw pulses -// - - -#if CONFIG_TAPE_HEAD_ALIGN - - -tape_head_align_draw_pulse: - - // Put pulse on the screen; center the chart horizontaly, with some margin from top - - .label __ha_chart = $2000 + 8 * (40 * __ha_start + 4) - - tax - lda __ha_offsets, x - tay - lda __ha_masks, x - ora __ha_chart + 7, y - sta __ha_chart + 7, y -!: - rts - - -#endif diff --git a/c64/kernal/tape/tape_head_align_irq.s b/c64/kernal/tape/tape_head_align_irq.s index 321869b2..878041c6 100644 --- a/c64/kernal/tape/tape_head_align_irq.s +++ b/c64/kernal/tape/tape_head_align_irq.s @@ -40,13 +40,23 @@ tape_head_align_irq_loop: cmp #$33 // first line where badline can occur bcs tape_head_align_irq_end !: - // Draw pulse + // Draw pulse on the screen cpy #$FF beq !+ + + // Center the chart horizontaly, with some margin from top + + .label __ha_chart = $2000 + 8 * (40 * __ha_start + 4) + phx_trash_a - tya - jsr tape_head_align_draw_pulse + + lda __ha_offsets, y + tax + lda __ha_masks, y + ora __ha_chart + 7, x + sta __ha_chart + 7, x + plx_trash_a !: // Next iteration From 8a16ce39346387d6d13e4c1f6c419066ab6c7dc6 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 6 Jun 2020 15:54:31 +0200 Subject: [PATCH 027/103] LOAD/VERIFY commands finished --- c64/,,config_custom.s | 2 +- c64/basic/commands/cmd_load_verify.s | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/c64/,,config_custom.s b/c64/,,config_custom.s index adef8403..84c60ab8 100644 --- a/c64/,,config_custom.s +++ b/c64/,,config_custom.s @@ -48,7 +48,7 @@ #define CONFIG_IEC // #define CONFIG_IEC_DOLPHINDOS // #define CONFIG_IEC_DOLPHINDOS_FAST -// #define CONFIG_IEC_JIFFYDOS +#define CONFIG_IEC_JIFFYDOS // #define CONFIG_IEC_JIFFYDOS_BLANK // #define CONFIG_IEC_BURST_CIA1 // please keep disabled for now // #define CONFIG_IEC_BURST_CIA2 // please keep disabled for now diff --git a/c64/basic/commands/cmd_load_verify.s b/c64/basic/commands/cmd_load_verify.s index 5ba69324..e93888dc 100644 --- a/c64/basic/commands/cmd_load_verify.s +++ b/c64/basic/commands/cmd_load_verify.s @@ -70,6 +70,11 @@ cmd_load_no_error: stx VARTAB+0 sty VARTAB+1 + // For VERIFY - this is it + + lda VERCKB + bne cmd_load_end + // C64 BASIC apparently does not clear variables after a LOAD in the // middle of a program. For safety, we do. jsr basic_do_clr @@ -86,5 +91,15 @@ cmd_load_no_error: // Reset to start of program jsr init_oldtxt - // XXX - should run program if LOAD was used in program mode + // If loading was done when running a program - run it + + ldx CURLIN+1 + inx + beq cmd_load_end // branch if direct mode + + // XXX + jmp basic_execute_from_current_line + +cmd_load_end: + jmp basic_main_loop From b008d9f4a96c4153941156ab66a3d7bbfebe2b6a Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 6 Jun 2020 17:10:37 +0200 Subject: [PATCH 028/103] implemented SAVE command --- c64/basic/commands/cmd_load_verify.s | 29 +++++++++++++++++----------- c64/basic/commands/cmd_save.s | 18 +++++++++++++++-- c64/basic/select_device.s | 2 +- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/c64/basic/commands/cmd_load_verify.s b/c64/basic/commands/cmd_load_verify.s index e93888dc..048951b4 100644 --- a/c64/basic/commands/cmd_load_verify.s +++ b/c64/basic/commands/cmd_load_verify.s @@ -28,7 +28,7 @@ cmd_load: jsr fetch_filename bcs cmd_load_no_filename - // Try to fetch secondary address + // Try to fetch device and secondary address jsr fetch_device_secondary jmp cmd_load_got_params @@ -53,15 +53,7 @@ cmd_load_got_params: // input for tape wedge lda VERCKB // LOAD or VERIFY jsr JLOAD - - // Handle result - - php - pha - jsr print_return - pla - plp - bcs_16 do_kernal_error + jsr cmd_load_save_handle_result cmd_load_no_error: @@ -97,9 +89,24 @@ cmd_load_no_error: inx beq cmd_load_end // branch if direct mode - // XXX jmp basic_execute_from_current_line cmd_load_end: jmp basic_main_loop + + +// +// Handle result from Kernal - common for LOAD/VERIFY/SAVE +// + +cmd_load_save_handle_result: + + php + pha + jsr print_return + pla + plp + bcs_16 do_kernal_error + + rts diff --git a/c64/basic/commands/cmd_save.s b/c64/basic/commands/cmd_save.s index f94bf0c5..00a61f59 100644 --- a/c64/basic/commands/cmd_save.s +++ b/c64/basic/commands/cmd_save.s @@ -8,7 +8,7 @@ cmd_save: // Set default device and secondary address; channel is not important now jsr select_device - ldy #$00 // secondary address + ldy #$00 jsr JSETFLS // Fetch the file name @@ -16,10 +16,24 @@ cmd_save: jsr fetch_filename bcs_16 do_MISSING_FILENAME_error + // Try to fetch device + jsr fetch_device_secondary + // Setup the start and end addresses + lda #TXTTAB - // XXX - finish the implementation + // Setup the end address + + ldx VARTAB+0 + ldy VARTAB+1 + + // Perform saving + + jsr JSAVE + jsr cmd_load_save_handle_result + + // The end jmp basic_main_loop diff --git a/c64/basic/select_device.s b/c64/basic/select_device.s index ba23425d..40bb8d49 100644 --- a/c64/basic/select_device.s +++ b/c64/basic/select_device.s @@ -3,7 +3,7 @@ // #LAYOUT# * * #IGNORE -select_device: +select_device: // XXX check usage, probably more can be put into this common section // Take last device number, make sure it is a drive - 8 or above. Above 30, // although illegal for IEC we also consider a drive, as they exists From 801755c9a8042b2cb3f433387489aff3395db0ca Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 6 Jun 2020 18:10:34 +0200 Subject: [PATCH 029/103] started work on PRINT command --- c64/basic/commands/cmd_print.s | 31 ++++++++++++++++++++++++++ c64/basic/commands/cmd_unimplemented.s | 2 -- 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 c64/basic/commands/cmd_print.s diff --git a/c64/basic/commands/cmd_print.s b/c64/basic/commands/cmd_print.s new file mode 100644 index 00000000..85bf7d96 --- /dev/null +++ b/c64/basic/commands/cmd_print.s @@ -0,0 +1,31 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + + +cmd_print: + + // XXX print an argument here + + + // Look for the next argument + + jsr end_of_statement_check + bcs cmd_print_new_line + + jsr fetch_character + cmp #$2C // comma + beq cmd_print + cmp #$3B // semicolon + beq cmd_print_done + +cmd_print_new_line: + + jsr print_return + + // FALLTROUGH + +cmd_print_done: + + jmp basic_main_loop diff --git a/c64/basic/commands/cmd_unimplemented.s b/c64/basic/commands/cmd_unimplemented.s index 7331765e..1280d692 100644 --- a/c64/basic/commands/cmd_unimplemented.s +++ b/c64/basic/commands/cmd_unimplemented.s @@ -45,8 +45,6 @@ cmd_poke: nop cmd_printhash: nop -cmd_print: - nop cmd_cont: nop cmd_cmd: From 48eec7d56e8bc6ccd9a1a5b1aa9503a0c4574d0a Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 6 Jun 2020 19:16:54 +0200 Subject: [PATCH 030/103] first step towards string expression evaluation --- c64/aliases/,aliases_ram_lowmem.s | 2 +- c64/basic/,stubs/ad9e.frmevl.s | 10 ----- c64/basic/commands/cmd_print.s | 50 ++++++++++++++++++++++- c64/basic/engine/ad9e.frmevl.s | 40 ++++++++++++++++++ c64/basic/{,stubs => engine}/ad9e.interop | 0 5 files changed, 89 insertions(+), 13 deletions(-) delete mode 100644 c64/basic/,stubs/ad9e.frmevl.s create mode 100644 c64/basic/engine/ad9e.frmevl.s rename c64/basic/{,stubs => engine}/ad9e.interop (100%) diff --git a/c64/aliases/,aliases_ram_lowmem.s b/c64/aliases/,aliases_ram_lowmem.s index 2f1cbb06..acb718d5 100644 --- a/c64/aliases/,aliases_ram_lowmem.s +++ b/c64/aliases/,aliases_ram_lowmem.s @@ -20,7 +20,7 @@ .label VERCKB = $0A // flag used by BASIC, 0 - LOAD, 1 - VERIFY .label COUNT = $0B // [!] our implementation might be different XXX give more details .label DIMFLG = $0C // [!] our implementation might be different XXX give more details - .label VALTYP = $0D // -- NOT IMPLEMENTED -- + .label VALTYP = $0D // expression eveluation result; $00 - float, $FF - string .label INTFLG = $0E // -- NOT IMPLEMENTED -- .label GARBFL = $0F // [!] our implementation might be different XXX give more details .label SUBFLG = $10 // -- NOT IMPLEMENTED -- diff --git a/c64/basic/,stubs/ad9e.frmevl.s b/c64/basic/,stubs/ad9e.frmevl.s deleted file mode 100644 index 46f275ed..00000000 --- a/c64/basic/,stubs/ad9e.frmevl.s +++ /dev/null @@ -1,10 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# X16 BASIC_0 #TAKE-OFFSET 2000 -// #LAYOUT# * BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - - -// XXX provide documentation and implementation - -FRMEVL: - STUB_IMPLEMENTATION() diff --git a/c64/basic/commands/cmd_print.s b/c64/basic/commands/cmd_print.s index 85bf7d96..d9fd8b16 100644 --- a/c64/basic/commands/cmd_print.s +++ b/c64/basic/commands/cmd_print.s @@ -6,8 +6,50 @@ cmd_print: - // XXX print an argument here + // First check if we have anything to print + jsr end_of_statement_check + bcs cmd_print_new_line + + cmp #$3B // semicolon + beq cmd_print_done + + jsr unconsume_character + + // FALLTROUGH + +cmd_print_loop: + + // Now evaluate the expression + + jsr FRMEVL + lda VALTYP + bpl cmd_print_float + + // FALLTROUGH + +cmd_print_string: + + // Print a string value + + ldy #$00 +!: + cpy __FAC1 + 0 + beq cmd_print_next_arg + + lda (__FAC1 + 1), y // XXX read from under ROM + jsr JCHROUT + iny + jmp !- + +cmd_print_float: + + // XXX probably we should also check INTFLG here + // XXX + + // FALLTROUGH + +cmd_print_next_arg: // Look for the next argument @@ -16,10 +58,14 @@ cmd_print: jsr fetch_character cmp #$2C // comma - beq cmd_print + beq cmd_print_loop cmp #$3B // semicolon beq cmd_print_done + // Something unexpected + + jmp do_SYNTAX_error + cmd_print_new_line: jsr print_return diff --git a/c64/basic/engine/ad9e.frmevl.s b/c64/basic/engine/ad9e.frmevl.s new file mode 100644 index 00000000..be7fb23b --- /dev/null +++ b/c64/basic/engine/ad9e.frmevl.s @@ -0,0 +1,40 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE-OFFSET 2000 +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +// Well-known BASIC routine, described in: +// +// - [CM64] Computes Mapping the Commodore 64 - page 102 +// - https://sta.c64.org/cbm64basconv.html +// +// Output: +// - VALTYP - $00 = floating number, $FF = string +// - INTFLG (XXX float/integer, probably) +// - for float: FAC1 +// - for string: __FAC1 + 0 = length, __FAC1 + 1 = pointer to string + +// XXX provide documentation and implementation + +FRMEVL: + + // XXX for now we just report dummy string + + lda #$FF + sta VALTYP + + lda #$0B + sta __FAC1 + 0 + + lda #dummy_text + sta __FAC1 + 2 + + rts + +dummy_text: + + .text "LOREM IPSUM" diff --git a/c64/basic/,stubs/ad9e.interop b/c64/basic/engine/ad9e.interop similarity index 100% rename from c64/basic/,stubs/ad9e.interop rename to c64/basic/engine/ad9e.interop From 153b34a58a2f473c9a3f7a1f1a1aec89264a1c2b Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 6 Jun 2020 21:18:20 +0200 Subject: [PATCH 031/103] PRINT can now print strings --- c64/basic/commands/cmd_load_verify.s | 2 +- c64/basic/commands/cmd_print.s | 5 ++- c64/basic/commands/cmd_save.s | 2 +- c64/basic/engine/ad9e.frmevl.s | 57 +++++++++++++++++++++------- 4 files changed, 49 insertions(+), 17 deletions(-) diff --git a/c64/basic/commands/cmd_load_verify.s b/c64/basic/commands/cmd_load_verify.s index 048951b4..3121e960 100644 --- a/c64/basic/commands/cmd_load_verify.s +++ b/c64/basic/commands/cmd_load_verify.s @@ -65,7 +65,7 @@ cmd_load_no_error: // For VERIFY - this is it lda VERCKB - bne cmd_load_end + bne_16 basic_execute_statement // C64 BASIC apparently does not clear variables after a LOAD in the // middle of a program. For safety, we do. diff --git a/c64/basic/commands/cmd_print.s b/c64/basic/commands/cmd_print.s index d9fd8b16..eb37e79f 100644 --- a/c64/basic/commands/cmd_print.s +++ b/c64/basic/commands/cmd_print.s @@ -11,6 +11,7 @@ cmd_print: jsr end_of_statement_check bcs cmd_print_new_line + jsr fetch_character cmp #$3B // semicolon beq cmd_print_done @@ -45,7 +46,7 @@ cmd_print_string: cmd_print_float: // XXX probably we should also check INTFLG here - // XXX + // XXX provide implementation // FALLTROUGH @@ -74,4 +75,4 @@ cmd_print_new_line: cmd_print_done: - jmp basic_main_loop + jmp basic_execute_statement diff --git a/c64/basic/commands/cmd_save.s b/c64/basic/commands/cmd_save.s index 00a61f59..06b9228b 100644 --- a/c64/basic/commands/cmd_save.s +++ b/c64/basic/commands/cmd_save.s @@ -36,4 +36,4 @@ cmd_save: // The end - jmp basic_main_loop + jmp basic_execute_statement diff --git a/c64/basic/engine/ad9e.frmevl.s b/c64/basic/engine/ad9e.frmevl.s index be7fb23b..40062716 100644 --- a/c64/basic/engine/ad9e.frmevl.s +++ b/c64/basic/engine/ad9e.frmevl.s @@ -19,22 +19,53 @@ FRMEVL: - // XXX for now we just report dummy string + // Check if end of statement - lda #$FF - sta VALTYP + jsr end_of_statement_check + bcs_16 do_SYNTAX_error - lda #$0B - sta __FAC1 + 0 + // Search for opening quote - lda #dummy_text - sta __FAC1 + 2 + // FALLTROUGH + +FRMEVL_fetch_string: + + // Mark return value as a string, set initial length as 0 + + ldx #$FF + stx VALTYP + + inx + stx __FAC1 + 0 + + // Set pointer to start of the string + + ldx TXTPTR + 0 + stx __FAC1 + 1 + ldx TXTPTR + 1 + stx __FAC1 + 2 +!: + // Search for closing quote + + jsr fetch_character + cmp #$22 + beq FRMEVL_done + + inc __FAC1 + 0 + bne !- + + jmp do_STRING_TOO_LONG_error + +FRMEVL_fetch_float: + + // XXX implement this + + jmp do_SYNTAX_error + +FRMEVL_done: rts - -dummy_text: - - .text "LOREM IPSUM" From e8e78baa7ff772fce171a9085866246ca38ae8e4 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 6 Jun 2020 21:39:28 +0200 Subject: [PATCH 032/103] PRINT now accepts multiple expressions without comma separator --- c64/basic/commands/cmd_print.s | 34 ++++++++++++++++++++++------------ c64/basic/engine/ad9e.frmevl.s | 3 ++- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/c64/basic/commands/cmd_print.s b/c64/basic/commands/cmd_print.s index eb37e79f..799a35ad 100644 --- a/c64/basic/commands/cmd_print.s +++ b/c64/basic/commands/cmd_print.s @@ -9,17 +9,21 @@ cmd_print: // First check if we have anything to print jsr end_of_statement_check - bcs cmd_print_new_line + bcs cmd_print_new_line_done jsr fetch_character cmp #$3B // semicolon beq cmd_print_done + // FALLTROUGH + +cmd_print_loop: + jsr unconsume_character // FALLTROUGH -cmd_print_loop: +cmd_print_after_comma: // Now evaluate the expression @@ -38,7 +42,17 @@ cmd_print_string: cpy __FAC1 + 0 beq cmd_print_next_arg - lda (__FAC1 + 1), y // XXX read from under ROM +#if CONFIG_MEMORY_MODEL_60K + + ldx #<(__FAC1 + 1) + jsr peek_under_roms + +#else // CONFIG_MEMORY_MODEL_38K + + lda (__FAC1 + 1), y + +#endif + jsr JCHROUT iny jmp !- @@ -55,19 +69,15 @@ cmd_print_next_arg: // Look for the next argument jsr end_of_statement_check - bcs cmd_print_new_line + bcs cmd_print_new_line_done - jsr fetch_character - cmp #$2C // comma - beq cmd_print_loop + cmp #$2C // comma XXX on C64 behavior is more complicated, fix it + beq cmd_print_after_comma cmp #$3B // semicolon beq cmd_print_done + bne cmd_print_loop - // Something unexpected - - jmp do_SYNTAX_error - -cmd_print_new_line: +cmd_print_new_line_done: jsr print_return diff --git a/c64/basic/engine/ad9e.frmevl.s b/c64/basic/engine/ad9e.frmevl.s index 40062716..da1f3f16 100644 --- a/c64/basic/engine/ad9e.frmevl.s +++ b/c64/basic/engine/ad9e.frmevl.s @@ -15,7 +15,8 @@ // - for float: FAC1 // - for string: __FAC1 + 0 = length, __FAC1 + 1 = pointer to string -// XXX provide documentation and implementation +// XXX finish the implementation + FRMEVL: From cdeaf05ccdeea7c7fa813592ba25967b65093822 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sat, 6 Jun 2020 22:23:24 +0200 Subject: [PATCH 033/103] fixed a bug preventing execution of multiple statements in the same line --- c64/basic/basic_execute_line.s | 73 +++++++++-------------- c64/basic/engine/end_of_statement_check.s | 2 + 2 files changed, 30 insertions(+), 45 deletions(-) diff --git a/c64/basic/basic_execute_line.s b/c64/basic/basic_execute_line.s index 3120eb63..d4cf88a0 100644 --- a/c64/basic/basic_execute_line.s +++ b/c64/basic/basic_execute_line.s @@ -2,62 +2,39 @@ // #LAYOUT# * BASIC_0 #TAKE // #LAYOUT# * * #IGNORE -// Jump back into the BASIC execute line loop -// after first checking that we have a colon -// or $00 char +// +// Tries to execute the statement, and all the subsequent ones +// basic_execute_statement: // Check for RUN/STOP + lda STKEY - bmi !+ - jmp cmd_stop + bpl_16 cmd_stop + + // Skip over any white spaces and colons (':') !: - // Skip over any white space and : - ldy #0 - -#if CONFIG_MEMORY_MODEL_60K - ldx #OLDTXT - // .byte $f0,OLDTXT - // .text ", STATEMENT PTR = $" - // .byte $f1,TXTPTR - // .byte $f0,TXTPTR - // .byte $d,0 - - // Go through the line until its end is reached. - // If we reach the end are in direct mode, then - // go back to reading input, else look for the - // next line, and advance to that, or else - // return to READY prompt because we have run out - // of program. - - // Get next char of program text, even if it is hiding under a ROM or the - // IO area. + // Check if end of the line - ldy #0 - -#if CONFIG_MEMORY_MODEL_60K - ldx # Date: Sat, 6 Jun 2020 23:10:45 +0200 Subject: [PATCH 034/103] more BASIC cleanup --- c64/basic/basic_execute_line.s | 164 --------------------- c64/basic/basic_main_loop.s | 6 +- c64/basic/commands/cmd_clr.s | 6 +- c64/basic/commands/cmd_load_verify.s | 4 +- c64/basic/commands/cmd_new.s | 4 +- c64/basic/commands/cmd_print.s | 2 +- c64/basic/commands/cmd_rem.s | 3 +- c64/basic/commands/cmd_run.s | 2 +- c64/basic/commands/cmd_save.s | 2 +- c64/basic/commands/cmd_sys.s | 2 +- c64/basic/commands/command_jumptable.s | 3 + c64/basic/engine/execute_line_statements.s | 124 ++++++++++++++++ c64/basic/{ => engine}/init_oldtxt.s | 0 c64/basic/wedge/wedge_dos.s | 2 +- 14 files changed, 142 insertions(+), 182 deletions(-) delete mode 100644 c64/basic/basic_execute_line.s create mode 100644 c64/basic/engine/execute_line_statements.s rename c64/basic/{ => engine}/init_oldtxt.s (100%) diff --git a/c64/basic/basic_execute_line.s b/c64/basic/basic_execute_line.s deleted file mode 100644 index d4cf88a0..00000000 --- a/c64/basic/basic_execute_line.s +++ /dev/null @@ -1,164 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - -// -// Tries to execute the statement, and all the subsequent ones -// - - -basic_execute_statement: - - // Check for RUN/STOP - - lda STKEY - bpl_16 cmd_stop - - // Skip over any white spaces and colons (':') -!: - jsr fetch_character - cmp #$20 // space, can be skipped - beq !- - cmp #$3A // colon, can be skipped - beq !- - - // Check if end of the line - - cmp #$00 - beq basic_end_of_line - - // Not end of the line - we actually have something to execute - - // XXX continue rework from here - - pha - jsr unconsume_character - pla - - // The checks should be done in order of frequency, so that we are as - // fast as possible. - - cmp #$7f - bcc not_a_token - - // It is a token - consume this character - - jsr consume_character - -#if !HAS_OPCODES_65C02 - - // Get the jump table entry for it, push it on the stack, and then RTS to start it. - - tax - lda command_jumptable_hi - $80, x - pha - lda command_jumptable_lo - $80, x - pha - - rts - -#else // HAS_OPCODES_65C02 - - asl - tax - jmp (command_jumptable, x) - -#endif - -not_a_token: - // Space, which we can also just ignore - cmp #$20 - beq basic_skip_char - // End of line? - cmp #$00 - beq basic_end_of_line - // :, i.e., statement separator, which we can simply ignore - cmp #$3a - beq basic_skip_char - - // If all else fails, it is a syntax error - jmp do_SYNTAX_error - -basic_skip_char: - jsr consume_character - jmp basic_execute_statement - - - - -basic_end_of_line: - - // If we reach the end are in direct mode, then - // go back to reading input, else look for the - // next line, and advance to that, or else - // return to READY prompt because we have run out - // of program. - - // XXX - If not in direct mode, then advance to next line, if there is - // one. - - // Are we in direct mode - lda CURLIN+1 - cmp #$ff - bne basic_not_direct_mode - - // Yes, we were in direct mode, so stop now - jmp basic_main_loop - -basic_not_direct_mode: - // Copy line number to previous line number - lda CURLIN+0 - sta OLDLIN+0 - lda CURLIN+1 - sta OLDLIN+1 - - // Advance the basic line pointer to the next line - jsr basic_follow_link_to_next_line - - // Are we at the end of the program? - lda OLDTXT+0 - ora OLDTXT+1 - bne basic_execute_from_current_line - - // End of program found - jmp basic_main_loop - -basic_execute_from_current_line: - // Check if pointer is null, if so, we are at the end of - // the program. - ldy #0 - jsr peek_line_pointer_null_check - bcs !+ - // End of program reached - jmp basic_main_loop -!: - // Skip pointer and line number to get address of first statement - lda OLDTXT+0 - clc - adc #4 - sta TXTPTR+0 - lda OLDTXT+1 - adc #0 - sta TXTPTR+1 - - ldy #2 - -#if CONFIG_MEMORY_MODEL_60K - ldx # Date: Sat, 6 Jun 2020 23:27:13 +0200 Subject: [PATCH 035/103] use expression parser for fetching filename --- c64/basic/basic_main_loop.s | 11 +++----- c64/basic/engine/fetch_file_name.s | 40 +++++++++--------------------- c64/basic/ready_message.s | 9 ------- 3 files changed, 16 insertions(+), 44 deletions(-) delete mode 100644 c64/basic/ready_message.s diff --git a/c64/basic/basic_main_loop.s b/c64/basic/basic_main_loop.s index 6f962dff..fd4dede5 100644 --- a/c64/basic/basic_main_loop.s +++ b/c64/basic/basic_main_loop.s @@ -6,7 +6,8 @@ basic_main_loop: // Tell user we are ready - jsr ready_message + ldx #30 + jsr print_packed_message // Enable Kernal messages lda #$80 @@ -16,7 +17,6 @@ basic_read_next_line: // Read a line of input ldx #$00 read_line_loop: - jsr JCHRIN bcs read_line_loop @@ -24,11 +24,8 @@ read_line_loop: beq got_line_of_input // Not carriage return, so try to append to line so far cpx #80 - bcc !+ - // Report STRING TOO LONG error (Computes Mapping the 64 p93) - ldx #22 - jmp do_basic_error -!: + bcs_16 do_STRING_TOO_LONG_error // see Computes Mapping the 64 p93 + sta BUF,x inx jmp read_line_loop diff --git a/c64/basic/engine/fetch_file_name.s b/c64/basic/engine/fetch_file_name.s index 9a2d4de2..ece023d2 100644 --- a/c64/basic/engine/fetch_file_name.s +++ b/c64/basic/engine/fetch_file_name.s @@ -14,40 +14,24 @@ fetch_filename: jsr end_of_statement_check bcs fetch_filename_done - // Search for opening quote + // Call the expression parser, make sure it returned a string - jsr fetch_character - cmp #$22 - bne_16 do_SYNTAX_error + jsr FRMEVL - // Filename starts here so set pointer + lda VALTYP + bpl_16 do_SYNTAX_error - lda TXTPTR+0 + // Set the filename address and pointer + + lda __FAC1+0 + sta FNLEN + + lda __FAC1+1 sta FNADDR+0 - lda TXTPTR+1 + lda __FAC1+2 sta FNADDR+1 - // Now search for end of line or closing quote - // so that we know the length of the filename - - lda #$00 - sta FNLEN -!: - jsr fetch_character - cmp #$22 - beq fetch_filename_fail - cmp #$00 - beq !+ - - inc FNLEN - bne !- - -!: - jsr unconsume_character - - // FALLTROUGH - -fetch_filename_fail: + // Mark success clc diff --git a/c64/basic/ready_message.s b/c64/basic/ready_message.s deleted file mode 100644 index 4486bbf8..00000000 --- a/c64/basic/ready_message.s +++ /dev/null @@ -1,9 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - - -ready_message: - - ldx #30 - jmp print_packed_message From 6f6dfb0ada61416ecc3782ae271638ec01b784b3 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 7 Jun 2020 04:19:07 +0200 Subject: [PATCH 036/103] skeleton of expression evaluator is now ready --- Makefile | 1 + c64/basic/engine/ad9e.frmevl.s | 135 +++++++++++++++++++++++++++++-- c64/basic/engine/injest_spaces.s | 4 +- c64/basic/operators/oper_plus.s | 42 ++++++++++ 4 files changed, 172 insertions(+), 10 deletions(-) create mode 100644 c64/basic/operators/oper_plus.s diff --git a/Makefile b/Makefile index 7730af5e..3aa682b4 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ SRCDIR_BASIC = $(SRCDIR_COMMON) \ c64/basic/math \ c64/basic/math_consts \ c64/basic/math_mov \ + c64/basic/operators \ c64/basic/print \ c64/basic/rom_revision \ c64/basic/wedge diff --git a/c64/basic/engine/ad9e.frmevl.s b/c64/basic/engine/ad9e.frmevl.s index da1f3f16..e5d27ddf 100644 --- a/c64/basic/engine/ad9e.frmevl.s +++ b/c64/basic/engine/ad9e.frmevl.s @@ -14,24 +14,62 @@ // - INTFLG (XXX float/integer, probably) // - for float: FAC1 // - for string: __FAC1 + 0 = length, __FAC1 + 1 = pointer to string +// +// Idea: +// - use a stack to reorder operations, so that they can be executed +// in a correct order +// // XXX finish the implementation FRMEVL: + // Put the sentinel to the stack + + lda #$00 + pha + + // FALLTROUGH + +FRMEVL_loop: + // Check if end of statement jsr end_of_statement_check bcs_16 do_SYNTAX_error - // Search for opening quote + // There are 4 basic possibilities: a string, a float, an opening bracket, or a token jsr fetch_character - cmp #$22 - bne FRMEVL_fetch_float + cmp #$22 // check for opening quote + beq FRMEVL_fetch_string + cmp #$28 // check for opening bracket + beq_16 do_NOT_IMPLEMENTED_error // XXX + cmp #$7F // check for a token + bcc FRMEVL_fetch_float - // FALLTROUGH + // Search for a value or unary operator, starting from the most probable + // XXX check for BASIC functions here, too + + cmp #$AB // check for unary minus + beq_16 do_NOT_IMPLEMENTED_error // XXX + cmp #$A8 // check for NOT + beq_16 do_NOT_IMPLEMENTED_error // XXX + cmp #$FF // check for PI + beq_16 do_NOT_IMPLEMENTED_error // XXX + cmp #$AA // check for unary plus (ignore this one) + beq FRMEVL_loop + + // Nothing recognized + + jmp do_SYNTAX_error + +FRMEVL_fetch_float: + + // XXX implement this + + jmp do_SYNTAX_error FRMEVL_fetch_string: @@ -54,19 +92,100 @@ FRMEVL_fetch_string: jsr fetch_character cmp #$22 - beq FRMEVL_done + beq FRMEVL_got_value inc __FAC1 + 0 bne !- jmp do_STRING_TOO_LONG_error -FRMEVL_fetch_float: +FRMEVL_got_value: - // XXX implement this + jsr end_of_statement_check + bcs FRMEVL_calculate - jmp do_SYNTAX_error + // FALLTROUGH + +FRMEVL_fetch_operator: + + // We have a value, but this is not the end of expression. We expect + // a two argument operator here. First make sure we have enough space + // on a stack - we will surely need it + + tsx + cpx #$40 // XXX is this a safe threshold? + bcc_16 do_FORMULA_TOO_COMPLEX_error + + // Now look for an operator + // XXX for now only plus operator is implemented + + jsr fetch_character + cmp #$AA // check for a plus operator + beq_16 FRMEVL_push_value_operator + + // Something unknown - consider this the end of expression + + // FALTROUGH + +FRMEVL_calculate: // this is the exit point for the operators + + // Now, we have to calculate all the operations; at this point we + // should have a value in FAC1 and (possibly) operator on the stack + + pla + beq FRMEVL_done // branch if sentinel + + // Priority can be ignored now - just jump to the operator + + // FALLTROUGH FRMEVL_done: rts + +FRMEVL_push_value_operator: + + // First push the value in FAC1/ARG1 + + ldx VALTYP + bmi FRMEVL_push_string + + // Push float + + // XXX implement this + +FRMEVL_push_string: + + // Push string - address, length, type + + lda __FAC1+1 + pha + lda __FAC1+2 + pha + + lda __FAC1+0 + pha + + txa + pha + +FRMEVL_push_operator_address: + + // Push the operator address to stack, in a form + // suitable for RTS + + // XXX add support for other operators + + lda #>(oper_plus - 1) + pha + lda #<(oper_plus - 1) + pha + + // Push operator priority + + lda #$01 // XXX add support for other operators + pha + + // Continue + + jmp FRMEVL_loop diff --git a/c64/basic/engine/injest_spaces.s b/c64/basic/engine/injest_spaces.s index 506112c6..fb018def 100644 --- a/c64/basic/engine/injest_spaces.s +++ b/c64/basic/engine/injest_spaces.s @@ -3,10 +3,10 @@ // #LAYOUT# * * #IGNORE // -// Injests all spaces. +// Injests all spaces // -// XXX get rid of this when proper number parsing is completed +// XXX get rid of this when proper number parsing is implemented injest_spaces: diff --git a/c64/basic/operators/oper_plus.s b/c64/basic/operators/oper_plus.s new file mode 100644 index 00000000..d330a88a --- /dev/null +++ b/c64/basic/operators/oper_plus.s @@ -0,0 +1,42 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +oper_plus: + + // This operator can be used either with two strings, or with two floats + // First check whether arguments match and then choose the variant + + pla + cmp VALTYP + bne_16 do_TYPE_MISMATCH_error + + lda VALTYP + bmi oper_plus_strings + + // FALLTROUGH + +oper_plus_floats: + + // XXX implement this + + jmp do_NOT_IMPLEMENTED_error + +oper_plus_strings: + + // Pull string length + + pla + sta __FAC2+0 + + // Retrieve string address + + pla + sta __FAC2+2 + pla + sta __FAC2+1 + + // XXX merge strings here + + jmp FRMEVL_calculate From fef124bceac9699a2deaa0f4dd0b9409c54f0f37 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 7 Jun 2020 04:44:31 +0200 Subject: [PATCH 037/103] expression evaluator now supports brackets --- c64/basic/engine/ad9e.frmevl.s | 25 +++++++++++++++++++++++-- c64/basic/operators/oper_plus.s | 2 +- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/c64/basic/engine/ad9e.frmevl.s b/c64/basic/engine/ad9e.frmevl.s index e5d27ddf..9bb83962 100644 --- a/c64/basic/engine/ad9e.frmevl.s +++ b/c64/basic/engine/ad9e.frmevl.s @@ -45,7 +45,7 @@ FRMEVL_loop: cmp #$22 // check for opening quote beq FRMEVL_fetch_string cmp #$28 // check for opening bracket - beq_16 do_NOT_IMPLEMENTED_error // XXX + beq_16 FRMEVL_handle_bracket cmp #$7F // check for a token bcc FRMEVL_fetch_float @@ -65,6 +65,18 @@ FRMEVL_loop: jmp do_SYNTAX_error +FRMEVL_handle_bracket: + + // Brackets are easy to handle - just call FRMEVL recursively + // and consume the closing bracket afterwards + + jsr FRMEVL + jsr fetch_character + cmp #$29 // closing bracket + beq FRMEVL_got_value + + jmp do_SYNTAX_error + FRMEVL_fetch_float: // XXX implement this @@ -125,6 +137,8 @@ FRMEVL_fetch_operator: // Something unknown - consider this the end of expression + jsr unconsume_character + // FALTROUGH FRMEVL_calculate: // this is the exit point for the operators @@ -145,7 +159,14 @@ FRMEVL_done: FRMEVL_push_value_operator: - // First push the value in FAC1/ARG1 + // First push the return address + + lda #>(FRMEVL_calculate - 1) + pha + lda #<(FRMEVL_calculate - 1) + pha + + // Push the value in FAC1/ARG1 ldx VALTYP bmi FRMEVL_push_string diff --git a/c64/basic/operators/oper_plus.s b/c64/basic/operators/oper_plus.s index d330a88a..97822b14 100644 --- a/c64/basic/operators/oper_plus.s +++ b/c64/basic/operators/oper_plus.s @@ -39,4 +39,4 @@ oper_plus_strings: // XXX merge strings here - jmp FRMEVL_calculate + rts From 3d3da4dadd9a95033ab7a20ebf5af38b048b4dc6 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 7 Jun 2020 04:48:18 +0200 Subject: [PATCH 038/103] small expression parser improveements --- c64/basic/engine/ad9e.frmevl.s | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/c64/basic/engine/ad9e.frmevl.s b/c64/basic/engine/ad9e.frmevl.s index 9bb83962..38a65a2c 100644 --- a/c64/basic/engine/ad9e.frmevl.s +++ b/c64/basic/engine/ad9e.frmevl.s @@ -45,7 +45,7 @@ FRMEVL_loop: cmp #$22 // check for opening quote beq FRMEVL_fetch_string cmp #$28 // check for opening bracket - beq_16 FRMEVL_handle_bracket + beq FRMEVL_handle_bracket cmp #$7F // check for a token bcc FRMEVL_fetch_float @@ -133,7 +133,7 @@ FRMEVL_fetch_operator: jsr fetch_character cmp #$AA // check for a plus operator - beq_16 FRMEVL_push_value_operator + beq FRMEVL_push_value_operator // Something unknown - consider this the end of expression @@ -144,12 +144,12 @@ FRMEVL_fetch_operator: FRMEVL_calculate: // this is the exit point for the operators // Now, we have to calculate all the operations; at this point we - // should have a value in FAC1 and (possibly) operator on the stack + // should have a value in FAC1 and (possibly) operator on the top of the stack pla beq FRMEVL_done // branch if sentinel - // Priority can be ignored now - just jump to the operator + // Priority does not matter at this point - just jump to the operator // FALLTROUGH @@ -166,7 +166,7 @@ FRMEVL_push_value_operator: lda #<(FRMEVL_calculate - 1) pha - // Push the value in FAC1/ARG1 + // Push the value from FAC1 ldx VALTYP bmi FRMEVL_push_string From 855d8c43d59e635ce2783491a465a6dd63659d16 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 7 Jun 2020 05:11:12 +0200 Subject: [PATCH 039/103] fixed tokenization of pi and question mark --- c64/basic/tokenise_line.s | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/c64/basic/tokenise_line.s b/c64/basic/tokenise_line.s index 0678658b..5e00a443 100644 --- a/c64/basic/tokenise_line.s +++ b/c64/basic/tokenise_line.s @@ -70,7 +70,30 @@ tokenise_char_loop: ldx $0110 lda $0200,x cmp #$22 - bne tk_not_quote + beq tk_quote + cmp #$DE + beq tk_pi + cmp #$3F + bne tk_not_special + + // FALLTROUGH + +tk_question_mark: + + lda #$99 + skip_2_bytes_trash_nvz + + // FALLTROUGH + +tk_pi: + + lda #$FF + ldx $0110 + sta $0200,x + + jmp tk_literal_char + +tk_quote: // Quote lda QTSW @@ -78,7 +101,7 @@ tokenise_char_loop: sta QTSW jmp tk_literal_char -tk_not_quote: +tk_not_special: // Check for literal characters in various ranges // (This just speeds the tokeniser up, by avoiding the packed token search // for such characters). From d7a86494326dc7bf3d8c6406bce96ac0f06c08cb Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 7 Jun 2020 11:18:00 +0200 Subject: [PATCH 040/103] added list of operators and priorities --- c64/aliases/,aliases_cpu.s | 4 +- c64/basic/engine/ad9e.frmevl.s | 17 ++++- .../operators/{oper_plus.s => oper_add.s} | 8 +- c64/basic/operators/oper_and.s | 10 +++ c64/basic/operators/oper_cmp_eq.s | 10 +++ c64/basic/operators/oper_cmp_gt.s | 10 +++ c64/basic/operators/oper_cmp_gteq.s | 10 +++ c64/basic/operators/oper_cmp_lt.s | 10 +++ c64/basic/operators/oper_cmp_lteq.s | 10 +++ c64/basic/operators/oper_cmp_neq.s | 10 +++ c64/basic/operators/oper_div.s | 10 +++ c64/basic/operators/oper_mul.s | 10 +++ c64/basic/operators/oper_or.s | 10 +++ c64/basic/operators/oper_pow.s | 10 +++ c64/basic/operators/oper_sub.s | 10 +++ c64/basic/operators/oper_unary_minus.s | 10 +++ c64/basic/operators/oper_unary_not.s | 10 +++ c64/basic/operators/operators_jumptable.s | 74 +++++++++++++++++++ 18 files changed, 232 insertions(+), 11 deletions(-) rename c64/basic/operators/{oper_plus.s => oper_add.s} (87%) create mode 100644 c64/basic/operators/oper_and.s create mode 100644 c64/basic/operators/oper_cmp_eq.s create mode 100644 c64/basic/operators/oper_cmp_gt.s create mode 100644 c64/basic/operators/oper_cmp_gteq.s create mode 100644 c64/basic/operators/oper_cmp_lt.s create mode 100644 c64/basic/operators/oper_cmp_lteq.s create mode 100644 c64/basic/operators/oper_cmp_neq.s create mode 100644 c64/basic/operators/oper_div.s create mode 100644 c64/basic/operators/oper_mul.s create mode 100644 c64/basic/operators/oper_or.s create mode 100644 c64/basic/operators/oper_pow.s create mode 100644 c64/basic/operators/oper_sub.s create mode 100644 c64/basic/operators/oper_unary_minus.s create mode 100644 c64/basic/operators/oper_unary_not.s create mode 100644 c64/basic/operators/operators_jumptable.s diff --git a/c64/aliases/,aliases_cpu.s b/c64/aliases/,aliases_cpu.s index 4f26aefe..d0f29fad 100644 --- a/c64/aliases/,aliases_cpu.s +++ b/c64/aliases/,aliases_cpu.s @@ -47,8 +47,6 @@ // -#if !HAS_OPCODES_65C02 - .macro put_jumptable_lo(list) { .for (var i = 0; i < list.size(); i++) @@ -65,7 +63,7 @@ } } -#else // HAS_OPCODES_65C02 +#if HAS_OPCODES_65C02 .macro put_jumptable(list) { diff --git a/c64/basic/engine/ad9e.frmevl.s b/c64/basic/engine/ad9e.frmevl.s index 38a65a2c..b7594b1e 100644 --- a/c64/basic/engine/ad9e.frmevl.s +++ b/c64/basic/engine/ad9e.frmevl.s @@ -25,6 +25,15 @@ FRMEVL: + // XXX we neeed FRETOP for string concatenation + + // lda VARTAB+0 + // sta FRETOP+0 + // lda VARTAB+1 + // sta FRETOP+1 + + // XXX we also need TEMMPPT, LASTPT and TEMPST + // Put the sentinel to the stack lda #$00 @@ -50,7 +59,7 @@ FRMEVL_loop: bcc FRMEVL_fetch_float // Search for a value or unary operator, starting from the most probable - // XXX check for BASIC functions here, too + // XXX check all other operators cmp #$AB // check for unary minus beq_16 do_NOT_IMPLEMENTED_error // XXX @@ -129,7 +138,7 @@ FRMEVL_fetch_operator: bcc_16 do_FORMULA_TOO_COMPLEX_error // Now look for an operator - // XXX for now only plus operator is implemented + // XXX for now only addition operator is implemented jsr fetch_character cmp #$AA // check for a plus operator @@ -197,9 +206,9 @@ FRMEVL_push_operator_address: // XXX add support for other operators - lda #>(oper_plus - 1) + lda #>(oper_add - 1) pha - lda #<(oper_plus - 1) + lda #<(oper_add - 1) pha // Push operator priority diff --git a/c64/basic/operators/oper_plus.s b/c64/basic/operators/oper_add.s similarity index 87% rename from c64/basic/operators/oper_plus.s rename to c64/basic/operators/oper_add.s index 97822b14..5593ffab 100644 --- a/c64/basic/operators/oper_plus.s +++ b/c64/basic/operators/oper_add.s @@ -3,7 +3,7 @@ // #LAYOUT# * * #IGNORE -oper_plus: +oper_add: // This operator can be used either with two strings, or with two floats // First check whether arguments match and then choose the variant @@ -13,17 +13,17 @@ oper_plus: bne_16 do_TYPE_MISMATCH_error lda VALTYP - bmi oper_plus_strings + bmi oper_add_strings // FALLTROUGH -oper_plus_floats: +oper_add_floats: // XXX implement this jmp do_NOT_IMPLEMENTED_error -oper_plus_strings: +oper_add_strings: // Pull string length diff --git a/c64/basic/operators/oper_and.s b/c64/basic/operators/oper_and.s new file mode 100644 index 00000000..fac758dc --- /dev/null +++ b/c64/basic/operators/oper_and.s @@ -0,0 +1,10 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +oper_and: + + // XXX provide implementation + + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/operators/oper_cmp_eq.s b/c64/basic/operators/oper_cmp_eq.s new file mode 100644 index 00000000..4e739dd3 --- /dev/null +++ b/c64/basic/operators/oper_cmp_eq.s @@ -0,0 +1,10 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +oper_cmp_eq: + + // XXX provide implementation + + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/operators/oper_cmp_gt.s b/c64/basic/operators/oper_cmp_gt.s new file mode 100644 index 00000000..c8229e84 --- /dev/null +++ b/c64/basic/operators/oper_cmp_gt.s @@ -0,0 +1,10 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +oper_cmp_gt: + + // XXX provide implementation + + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/operators/oper_cmp_gteq.s b/c64/basic/operators/oper_cmp_gteq.s new file mode 100644 index 00000000..c57639cd --- /dev/null +++ b/c64/basic/operators/oper_cmp_gteq.s @@ -0,0 +1,10 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +oper_cmp_gteq: + + // XXX provide implementation + + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/operators/oper_cmp_lt.s b/c64/basic/operators/oper_cmp_lt.s new file mode 100644 index 00000000..d68fbf75 --- /dev/null +++ b/c64/basic/operators/oper_cmp_lt.s @@ -0,0 +1,10 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +oper_cmp_lt: + + // XXX provide implementation + + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/operators/oper_cmp_lteq.s b/c64/basic/operators/oper_cmp_lteq.s new file mode 100644 index 00000000..abf25b23 --- /dev/null +++ b/c64/basic/operators/oper_cmp_lteq.s @@ -0,0 +1,10 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +oper_cmp_lteq: + + // XXX provide implementation + + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/operators/oper_cmp_neq.s b/c64/basic/operators/oper_cmp_neq.s new file mode 100644 index 00000000..488dac41 --- /dev/null +++ b/c64/basic/operators/oper_cmp_neq.s @@ -0,0 +1,10 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +oper_cmp_neq: + + // XXX provide implementation + + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/operators/oper_div.s b/c64/basic/operators/oper_div.s new file mode 100644 index 00000000..a1d487bd --- /dev/null +++ b/c64/basic/operators/oper_div.s @@ -0,0 +1,10 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +oper_div: + + // XXX provide implementation + + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/operators/oper_mul.s b/c64/basic/operators/oper_mul.s new file mode 100644 index 00000000..cc94590c --- /dev/null +++ b/c64/basic/operators/oper_mul.s @@ -0,0 +1,10 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +oper_mul: + + // XXX provide implementation + + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/operators/oper_or.s b/c64/basic/operators/oper_or.s new file mode 100644 index 00000000..dfce2789 --- /dev/null +++ b/c64/basic/operators/oper_or.s @@ -0,0 +1,10 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +oper_or: + + // XXX provide implementation + + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/operators/oper_pow.s b/c64/basic/operators/oper_pow.s new file mode 100644 index 00000000..229b6427 --- /dev/null +++ b/c64/basic/operators/oper_pow.s @@ -0,0 +1,10 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +oper_pow: + + // XXX provide implementation + + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/operators/oper_sub.s b/c64/basic/operators/oper_sub.s new file mode 100644 index 00000000..4f503fde --- /dev/null +++ b/c64/basic/operators/oper_sub.s @@ -0,0 +1,10 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +oper_sub: + + // XXX provide implementation + + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/operators/oper_unary_minus.s b/c64/basic/operators/oper_unary_minus.s new file mode 100644 index 00000000..f39efbed --- /dev/null +++ b/c64/basic/operators/oper_unary_minus.s @@ -0,0 +1,10 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +oper_unary_minus: + + // XXX provide implementation + + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/operators/oper_unary_not.s b/c64/basic/operators/oper_unary_not.s new file mode 100644 index 00000000..18238b09 --- /dev/null +++ b/c64/basic/operators/oper_unary_not.s @@ -0,0 +1,10 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +oper_unary_not: + + // XXX provide implementation + + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/operators/operators_jumptable.s b/c64/basic/operators/operators_jumptable.s new file mode 100644 index 00000000..8f4983a1 --- /dev/null +++ b/c64/basic/operators/operators_jumptable.s @@ -0,0 +1,74 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Jumptable and priority list for all BASIC operators +// + + +.const operator_list = List().add( + + // Tokens XXX + + oper_add, + oper_sub, + oper_mul, + oper_div, + + // Tokens XXX + + oper_and, + oper_or, + + // Tokens XXX + + oper_cmp_gt, + oper_cmp_eq, + oper_cmp_lt, + + // Combined two tokens + + oper_cmp_gteq, + oper_cmp_lteq, + oper_cmp_neq, + + // Not a token + + oper_pow, + + // Unary + + oper_unary_minus, + oper_unary_not +) + + +operator_priorities: // higher number = higher priority + + .byte $05 // oper_add + .byte $05 // oper_sub + .byte $06 // oper_mul + .byte $06 // oper_div + .byte $02 // oper_and + .byte $01 // oper_or + .byte $04 // oper_cmp_gt + .byte $04 // oper_cmp_eq + .byte $04 // oper_cmp_lt + .byte $04 // oper_cmp_gteq + .byte $04 // oper_cmp_lteq + .byte $04 // oper_cmp_neq + .byte $08 // oper_pow + .byte $07 // oper_unary_minus + .byte $03 // oper_unary_not + + + +operator_jumptable_lo: + + put_jumptable_lo(operator_list) + + +operator_jumptable_hi: + + put_jumptable_hi(operator_list) From 1b26151a3f62431435d67c45ae609e74f0218600 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 7 Jun 2020 11:22:46 +0200 Subject: [PATCH 041/103] updated KickAssembler to 5.16 --- assembler/KickAss.jar | Bin 625707 -> 625876 bytes assembler/KickAssembler.pdf | Bin 785388 -> 785420 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/assembler/KickAss.jar b/assembler/KickAss.jar index 1ea5cc88703c8e7822bfa34b2397dcbfe38f4439..77fa9f23ad450bac410db55499c2e0fdba16eee7 100644 GIT binary patch delta 35086 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 delta 35501 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 diff --git a/assembler/KickAssembler.pdf b/assembler/KickAssembler.pdf index 907579f95901e23aa40fbb9ed75e10a036cd094c..2ef23c87c70a9d6bc4c902d9d6072817ae41da4c 100644 GIT binary patch delta 34997 zcmai62Uv}N`xg~Dl$05DQWO2)LXl9BelfdVeVKzm zG)N@uC=_)RDl+2g=jv1ktyyT~SRJw?$0$6MW!o^wk$@cSFE2CAa@SWy6ZF7F5_Zq)u z$BU~QUyL`rcgn`pxTJHVF$sO9H|=iwu zH5q?Uf69n2KJQ&rQ77HM*6sRkjm4aJRfd~xcISQ<&0pQVd+l{xSc>PO?>Cl4$A@1E zh`98yiIL~x#`~Nu+�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 NDTCInySaBa_&-M!QTPA= delta 34856 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 Date: Sun, 7 Jun 2020 15:01:09 +0200 Subject: [PATCH 042/103] integrated operator recognition routine --- c64/basic/engine/ad9e.frmevl.s | 38 ++++----- c64/basic/engine/fetch_operator.s | 93 +++++++++++++++++++++++ c64/basic/operators/operators_jumptable.s | 44 +++++------ 3 files changed, 131 insertions(+), 44 deletions(-) create mode 100644 c64/basic/engine/fetch_operator.s diff --git a/c64/basic/engine/ad9e.frmevl.s b/c64/basic/engine/ad9e.frmevl.s index b7594b1e..1b4e8fc3 100644 --- a/c64/basic/engine/ad9e.frmevl.s +++ b/c64/basic/engine/ad9e.frmevl.s @@ -129,26 +129,22 @@ FRMEVL_got_value: FRMEVL_fetch_operator: - // We have a value, but this is not the end of expression. We expect - // a two argument operator here. First make sure we have enough space - // on a stack - we will surely need it + // We have a value, but this is not the end of expression. Check if + // there is an operator waiting to be served + + jsr fetch_operator + bcs FRMEVL_calculate // branch if operator not recognized + + // We have a two-argument operator - check if there is enough stack space + // XXX this can probably be checked later tsx cpx #$40 // XXX is this a safe threshold? bcc_16 do_FORMULA_TOO_COMPLEX_error - // Now look for an operator - // XXX for now only addition operator is implemented + // XXX check the priorities - either push to stack, or execute it immediately - jsr fetch_character - cmp #$AA // check for a plus operator - beq FRMEVL_push_value_operator - - // Something unknown - consider this the end of expression - - jsr unconsume_character - - // FALTROUGH + bcs FRMEVL_push_value_operator // branch always FRMEVL_calculate: // this is the exit point for the operators @@ -168,7 +164,11 @@ FRMEVL_done: FRMEVL_push_value_operator: - // First push the return address + // Move the operator ID in .Y + + tay + + // Push the return address lda #>(FRMEVL_calculate - 1) pha @@ -204,16 +204,16 @@ FRMEVL_push_operator_address: // Push the operator address to stack, in a form // suitable for RTS - // XXX add support for other operators + // XXX add support for other operators, use .Y - lda #>(oper_add - 1) + lda operator_jumptable_hi - 1, y pha - lda #<(oper_add - 1) + lda operator_jumptable_lo - 1, y pha // Push operator priority - lda #$01 // XXX add support for other operators + lda operator_priorities - 1, y pha // Continue diff --git a/c64/basic/engine/fetch_operator.s b/c64/basic/engine/fetch_operator.s new file mode 100644 index 00000000..5c55e426 --- /dev/null +++ b/c64/basic/engine/fetch_operator.s @@ -0,0 +1,93 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Fetches an operator - for the expression parser +// +// Note: does not recognize unary operators +// + + +fetch_operator: // XXX change the operator code to start from 0 + + // Retrieve the next character + + jsr fetch_character + + // Check if within range + + sec + sbc #$A9 + bcc fetch_operator_failed // branch if below 0 + beq fetch_operator_failed // branch 0 + + cmp #$0B + bcs fetch_operator_failed // branch if $0B or greater + + // Now we have to recognize '>=', '<=' and '<>' operators + + cmp #$08 + beq fetch_operator_try_gteq + + cmp #$0A + beq fetch_operator_try_lteq_neq + + // FALLTROUGH + +fetch_operator_success: + + clc + rts + +fetch_operator_failed: + + sec + rts + + +fetch_operator_try_gteq: + + // Here we distinguish between '>' and '>=' + + jsr fetch_character + cmp #$B2 // '=' + beq !+ + + // This is a '>' + + jsr unconsume_character + lda #$08 + bne fetch_operator_success // branch always +!: + // This is a '>=' + + lda #$0B + bne fetch_operator_success // branch always + + +fetch_operator_try_lteq_neq: + + // Here we distinguish between '<', '<=', and '<>' + + jsr fetch_character + cmp #$B2 // '=' + beq !+ + cmp #$B1 // '>' + beq !++ + + // This is a '<' + + jsr unconsume_character + lda #$0A + bne fetch_operator_success // branch always +!: + // This is a '<=' + + lda #$0C + bne fetch_operator_success // branch always +!: + // This is a '<>' + + lda #$0D + bne fetch_operator_success // branch always diff --git a/c64/basic/operators/operators_jumptable.s b/c64/basic/operators/operators_jumptable.s index 8f4983a1..96d35e83 100644 --- a/c64/basic/operators/operators_jumptable.s +++ b/c64/basic/operators/operators_jumptable.s @@ -9,38 +9,32 @@ .const operator_list = List().add( - // Tokens XXX + // Tokens $AA-$B0 - oper_add, - oper_sub, - oper_mul, - oper_div, + oper_add, // ID: $01 + oper_sub, // ID: $02 + oper_mul, // ID: $03 + oper_div, // ID: $04 + oper_pow, // ID: $05 + oper_and, // ID: $06 + oper_or, // ID: $07 - // Tokens XXX + // Tokens $B1-$B3 - oper_and, - oper_or, - - // Tokens XXX - - oper_cmp_gt, - oper_cmp_eq, - oper_cmp_lt, + oper_cmp_gt, // ID: $08 + oper_cmp_eq, // ID: $09 + oper_cmp_lt, // ID: $0A // Combined two tokens - oper_cmp_gteq, - oper_cmp_lteq, - oper_cmp_neq, + oper_cmp_gteq, // ID: $0B + oper_cmp_lteq, // ID: $0C + oper_cmp_neq, // ID: $0D - // Not a token + // Unary operators - oper_pow, - - // Unary - - oper_unary_minus, - oper_unary_not + oper_unary_minus, // ID: $0E + oper_unary_not // ID: $0F ) @@ -50,6 +44,7 @@ operator_priorities: // higher number = higher priority .byte $05 // oper_sub .byte $06 // oper_mul .byte $06 // oper_div + .byte $08 // oper_pow .byte $02 // oper_and .byte $01 // oper_or .byte $04 // oper_cmp_gt @@ -58,7 +53,6 @@ operator_priorities: // higher number = higher priority .byte $04 // oper_cmp_gteq .byte $04 // oper_cmp_lteq .byte $04 // oper_cmp_neq - .byte $08 // oper_pow .byte $07 // oper_unary_minus .byte $03 // oper_unary_not From 8aa3aed58613a52070199d7bbf88ff7d33519019 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 7 Jun 2020 15:04:31 +0200 Subject: [PATCH 043/103] small operator handling tweak --- c64/basic/engine/ad9e.frmevl.s | 6 ++--- c64/basic/engine/fetch_operator.s | 21 ++++++++-------- c64/basic/operators/operators_jumptable.s | 30 +++++++++++------------ 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/c64/basic/engine/ad9e.frmevl.s b/c64/basic/engine/ad9e.frmevl.s index 1b4e8fc3..e29c85e5 100644 --- a/c64/basic/engine/ad9e.frmevl.s +++ b/c64/basic/engine/ad9e.frmevl.s @@ -206,14 +206,14 @@ FRMEVL_push_operator_address: // XXX add support for other operators, use .Y - lda operator_jumptable_hi - 1, y + lda operator_jumptable_hi, y pha - lda operator_jumptable_lo - 1, y + lda operator_jumptable_lo, y pha // Push operator priority - lda operator_priorities - 1, y + lda operator_priorities, y pha // Continue diff --git a/c64/basic/engine/fetch_operator.s b/c64/basic/engine/fetch_operator.s index 5c55e426..3c87cf45 100644 --- a/c64/basic/engine/fetch_operator.s +++ b/c64/basic/engine/fetch_operator.s @@ -18,19 +18,18 @@ fetch_operator: // XXX change the operator code to start from 0 // Check if within range sec - sbc #$A9 + sbc #$AA bcc fetch_operator_failed // branch if below 0 - beq fetch_operator_failed // branch 0 - cmp #$0B - bcs fetch_operator_failed // branch if $0B or greater + cmp #$0A + bcs fetch_operator_failed // branch if $0A or greater // Now we have to recognize '>=', '<=' and '<>' operators - cmp #$08 + cmp #$07 beq fetch_operator_try_gteq - cmp #$0A + cmp #$09 beq fetch_operator_try_lteq_neq // FALLTROUGH @@ -57,12 +56,12 @@ fetch_operator_try_gteq: // This is a '>' jsr unconsume_character - lda #$08 + lda #$07 bne fetch_operator_success // branch always !: // This is a '>=' - lda #$0B + lda #$0A bne fetch_operator_success // branch always @@ -79,15 +78,15 @@ fetch_operator_try_lteq_neq: // This is a '<' jsr unconsume_character - lda #$0A + lda #$09 bne fetch_operator_success // branch always !: // This is a '<=' - lda #$0C + lda #$0B bne fetch_operator_success // branch always !: // This is a '<>' - lda #$0D + lda #$0C bne fetch_operator_success // branch always diff --git a/c64/basic/operators/operators_jumptable.s b/c64/basic/operators/operators_jumptable.s index 96d35e83..2edc0dc3 100644 --- a/c64/basic/operators/operators_jumptable.s +++ b/c64/basic/operators/operators_jumptable.s @@ -11,30 +11,30 @@ // Tokens $AA-$B0 - oper_add, // ID: $01 - oper_sub, // ID: $02 - oper_mul, // ID: $03 - oper_div, // ID: $04 - oper_pow, // ID: $05 - oper_and, // ID: $06 - oper_or, // ID: $07 + oper_add, // ID: $00 + oper_sub, // ID: $01 + oper_mul, // ID: $02 + oper_div, // ID: $03 + oper_pow, // ID: $04 + oper_and, // ID: $05 + oper_or, // ID: $06 // Tokens $B1-$B3 - oper_cmp_gt, // ID: $08 - oper_cmp_eq, // ID: $09 - oper_cmp_lt, // ID: $0A + oper_cmp_gt, // ID: $07 + oper_cmp_eq, // ID: $08 + oper_cmp_lt, // ID: $09 // Combined two tokens - oper_cmp_gteq, // ID: $0B - oper_cmp_lteq, // ID: $0C - oper_cmp_neq, // ID: $0D + oper_cmp_gteq, // ID: $0A + oper_cmp_lteq, // ID: $0B + oper_cmp_neq, // ID: $0C // Unary operators - oper_unary_minus, // ID: $0E - oper_unary_not // ID: $0F + oper_unary_minus, // ID: $0D + oper_unary_not // ID: $0E ) From 42e4402afa4f72bcbaa2fb1bd1b7b6a921cce15c Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 7 Jun 2020 15:40:32 +0200 Subject: [PATCH 044/103] expression evaluation optimizations --- c64/basic/engine/ad9e.frmevl.s | 55 +++++++++++++--------------------- c64/basic/operators/oper_add.s | 2 +- 2 files changed, 22 insertions(+), 35 deletions(-) diff --git a/c64/basic/engine/ad9e.frmevl.s b/c64/basic/engine/ad9e.frmevl.s index e29c85e5..fd7f4475 100644 --- a/c64/basic/engine/ad9e.frmevl.s +++ b/c64/basic/engine/ad9e.frmevl.s @@ -34,7 +34,7 @@ FRMEVL: // XXX we also need TEMMPPT, LASTPT and TEMPST - // Put the sentinel to the stack + // Push the sentinel to the stack lda #$00 pha @@ -123,7 +123,7 @@ FRMEVL_fetch_string: FRMEVL_got_value: jsr end_of_statement_check - bcs FRMEVL_calculate + bcs FRMEVL_continue // calculate the stack if expression ended // FALLTROUGH @@ -133,48 +133,24 @@ FRMEVL_fetch_operator: // there is an operator waiting to be served jsr fetch_operator - bcs FRMEVL_calculate // branch if operator not recognized + bcs FRMEVL_continue // if operator not recognized, calculate what we have + // on stack and quit - // We have a two-argument operator - check if there is enough stack space - // XXX this can probably be checked later + // XXX check the priorities - possibly execute the current stack first + // FALLTROUGH + +FRMEVL_push_value_operator: + + // Ccheck if there is enough stack space tsx cpx #$40 // XXX is this a safe threshold? bcc_16 do_FORMULA_TOO_COMPLEX_error - // XXX check the priorities - either push to stack, or execute it immediately - - bcs FRMEVL_push_value_operator // branch always - -FRMEVL_calculate: // this is the exit point for the operators - - // Now, we have to calculate all the operations; at this point we - // should have a value in FAC1 and (possibly) operator on the top of the stack - - pla - beq FRMEVL_done // branch if sentinel - - // Priority does not matter at this point - just jump to the operator - - // FALLTROUGH - -FRMEVL_done: - - rts - -FRMEVL_push_value_operator: - // Move the operator ID in .Y tay - // Push the return address - - lda #>(FRMEVL_calculate - 1) - pha - lda #<(FRMEVL_calculate - 1) - pha - // Push the value from FAC1 ldx VALTYP @@ -199,6 +175,8 @@ FRMEVL_push_string: txa pha + // FALLTROUGH + FRMEVL_push_operator_address: // Push the operator address to stack, in a form @@ -219,3 +197,12 @@ FRMEVL_push_operator_address: // Continue jmp FRMEVL_loop + + +FRMEVL_continue: // this is the exit point for the operators + + // Now, we have to calculate all the operations; at this point we + // should have a value in FAC1 and (possibly) operator on the top of the stack + + pla // priority does not matter here, get rid of it + rts // this either jumps to operator, or quits FRMEVL diff --git a/c64/basic/operators/oper_add.s b/c64/basic/operators/oper_add.s index 5593ffab..f4d03945 100644 --- a/c64/basic/operators/oper_add.s +++ b/c64/basic/operators/oper_add.s @@ -39,4 +39,4 @@ oper_add_strings: // XXX merge strings here - rts + jmp FRMEVL_continue From ea235af9978d3660d35f6ce98261eed01eb92a53 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 7 Jun 2020 15:54:30 +0200 Subject: [PATCH 045/103] some cleanup and documentation update --- c64/basic/engine/ad9e.frmevl.s | 39 ++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/c64/basic/engine/ad9e.frmevl.s b/c64/basic/engine/ad9e.frmevl.s index fd7f4475..9a0ea9bf 100644 --- a/c64/basic/engine/ad9e.frmevl.s +++ b/c64/basic/engine/ad9e.frmevl.s @@ -74,10 +74,12 @@ FRMEVL_loop: jmp do_SYNTAX_error -FRMEVL_handle_bracket: +// +// This subroutine handle brackets - it just calls FRMEVL recursively +// and consumes the closing bracket afterwards +// - // Brackets are easy to handle - just call FRMEVL recursively - // and consume the closing bracket afterwards +FRMEVL_handle_bracket: jsr FRMEVL jsr fetch_character @@ -86,11 +88,19 @@ FRMEVL_handle_bracket: jmp do_SYNTAX_error +// +// This subroutine fetches the floating point value from the 'outside world' +// + FRMEVL_fetch_float: // XXX implement this - jmp do_SYNTAX_error + jmp do_NOT_IMPLEMENTED_error + +// +// This subroutine fetches the string value from the 'outside world' +// FRMEVL_fetch_string: @@ -120,6 +130,18 @@ FRMEVL_fetch_string: jmp do_STRING_TOO_LONG_error + +// +// This subroutine handles the situation after fetching the value from 'outside world': +// - either there is nothing sane remaining there; if so, this value is or final result +// - or there is an operator following the value; in such case we have much more work to do; +// we push the current value and the operator to the stack and we proceed to fetch the next +// value (which is mandatory) +// small catch: if the priority of the new operator is not higher than priority of the last +// operator on the stack (sentinel is considered as the lowest priority operator) we first +// calculate what currently is present on the stack - this enforces proper operator precedence +// + FRMEVL_got_value: jsr end_of_statement_check @@ -142,7 +164,7 @@ FRMEVL_fetch_operator: FRMEVL_push_value_operator: - // Ccheck if there is enough stack space + // Check if there is enough stack space tsx cpx #$40 // XXX is this a safe threshold? bcc_16 do_FORMULA_TOO_COMPLEX_error @@ -198,8 +220,13 @@ FRMEVL_push_operator_address: jmp FRMEVL_loop +// +// This subroutine serves two purposes: +// - it is an exit point for the concrete operator implementations +// - it causes calculation of everything which is stored on the stack +// -FRMEVL_continue: // this is the exit point for the operators +FRMEVL_continue: // Now, we have to calculate all the operations; at this point we // should have a value in FAC1 and (possibly) operator on the top of the stack From 345f966ef3afef641d7da97f3fc493e9f37029db Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 7 Jun 2020 16:32:45 +0200 Subject: [PATCH 046/103] added support for unary operators --- STATUS.md | 2 +- c64/basic/engine/ad9e.frmevl.s | 82 +++++++++++++++++++++++++++------- 2 files changed, 68 insertions(+), 16 deletions(-) diff --git a/STATUS.md b/STATUS.md index 1bf8b632..8f757777 100644 --- a/STATUS.md +++ b/STATUS.md @@ -283,7 +283,7 @@ Not all of them - only these we want to have implemented. | `$A68E` | `RUNC` | DONE | | | `$A7AE` | `NEWSTT` | PARTIAL | redirected to RUN command | | `$AB1E` | `STROUT` | DONE | | -| `$AD9E` | `FRMEVL` | NOT DONE | | +| `$AD9E` | `FRMEVL` | PARTIAL | | | `$BDCD` | `LINPRT` | DONE | temporary implementation | | `$E3BF` | `INIT` | NOT DONE | | | `$E422` | `INITMSG` | DONE | | diff --git a/c64/basic/engine/ad9e.frmevl.s b/c64/basic/engine/ad9e.frmevl.s index 9a0ea9bf..2110432c 100644 --- a/c64/basic/engine/ad9e.frmevl.s +++ b/c64/basic/engine/ad9e.frmevl.s @@ -43,37 +43,81 @@ FRMEVL: FRMEVL_loop: - // Check if end of statement + // At this point there are 4 valid possibilities: + // - a string, a float, pi, or a variable (in short: a value to fetch) + // - a token (whichj means function to execute) + // - an unary operator + // - an opening bracket + + // Check if end of statement, fetch the character jsr end_of_statement_check bcs_16 do_SYNTAX_error - - // There are 4 basic possibilities: a string, a float, an opening bracket, or a token - jsr fetch_character + + // Check for a string or opening bracket + cmp #$22 // check for opening quote beq FRMEVL_fetch_string cmp #$28 // check for opening bracket beq FRMEVL_handle_bracket - cmp #$7F // check for a token - bcc FRMEVL_fetch_float - // Search for a value or unary operator, starting from the most probable - // XXX check all other operators + // Check for unary operators cmp #$AB // check for unary minus - beq_16 do_NOT_IMPLEMENTED_error // XXX + beq_16 FRMEVL_unary_minus cmp #$A8 // check for NOT - beq_16 do_NOT_IMPLEMENTED_error // XXX + beq_16 FRMEVL_unary_not + + // Check for the PI + cmp #$FF // check for PI - beq_16 do_NOT_IMPLEMENTED_error // XXX - cmp #$AA // check for unary plus (ignore this one) - beq FRMEVL_loop + beq_16 FRMEVL_fetch_PI // XXX + + // If not a PI and not an unary operator, than everything above + // $7F has to be a function + + cmp #$80 // check for a token + bcc FRMEVL_execute_function + + // There are 2 possibilities left - a floating point value or a variable + + + // XXX implement this part + // Nothing recognized jmp do_SYNTAX_error +// +// This subroutine handles the situation when we have to execute a BASIC function +// in place when parser normally expects a value +// + +FRMEVL_execute_function: + + // XXX implement this + + jmp do_NOT_IMPLEMENTED_error + +// +// These two subroutines handles the situation when we got an unary operator +// in place when parser normally expects a value +// + +FRMEVL_unary_not: + + ldy #$0D // our code for unary NOT + skip_2_bytes_trash_nvz + + // FALLTROUGH + +FRMEVL_unary_minus: + + ldy #$0E // our code for unary NOT + jmp FRMEVL_push_operator_address + // // This subroutine handle brackets - it just calls FRMEVL recursively // and consumes the closing bracket afterwards @@ -88,6 +132,16 @@ FRMEVL_handle_bracket: jmp do_SYNTAX_error +// +// This subroutine handles the situation when our value to fetch is PI +// + +FRMEVL_fetch_PI: + + // XXX implement this + + jmp do_NOT_IMPLEMENTED_error + // // This subroutine fetches the floating point value from the 'outside world' // @@ -204,8 +258,6 @@ FRMEVL_push_operator_address: // Push the operator address to stack, in a form // suitable for RTS - // XXX add support for other operators, use .Y - lda operator_jumptable_hi, y pha lda operator_jumptable_lo, y From e6ff6738d80075c849028af284e74839483c0801 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 7 Jun 2020 17:06:14 +0200 Subject: [PATCH 047/103] small expression evaluator improvements --- c64/basic/engine/ad9e.frmevl.s | 38 +++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/c64/basic/engine/ad9e.frmevl.s b/c64/basic/engine/ad9e.frmevl.s index 2110432c..8856ae65 100644 --- a/c64/basic/engine/ad9e.frmevl.s +++ b/c64/basic/engine/ad9e.frmevl.s @@ -212,21 +212,32 @@ FRMEVL_fetch_operator: bcs FRMEVL_continue // if operator not recognized, calculate what we have // on stack and quit - // XXX check the priorities - possibly execute the current stack first + // Move the new operator ID to .Y + tay + + // Compare the priority of the last operator with the new one + + pla + pha + + cmp operator_priorities, y + bcs !+ + + // Here the priority is not higher - so calculate what we already have on stack + // and restore the sentinel + + // XXX implement this + // XXX main problem: we need to go back here at the end; it seems we can use OPPTR (2 bytes) for this purpose + + // jmp FRMEVL_continue + // lda #$00 + // pha +!: // FALLTROUGH FRMEVL_push_value_operator: - // Check if there is enough stack space - tsx - cpx #$40 // XXX is this a safe threshold? - bcc_16 do_FORMULA_TOO_COMPLEX_error - - // Move the operator ID in .Y - - tay - // Push the value from FAC1 ldx VALTYP @@ -255,6 +266,13 @@ FRMEVL_push_string: FRMEVL_push_operator_address: + // Check if there is enough stack space; this could not have been done earlier, + // as this is the place where unary operator support calls + + tsx + cpx #$40 // XXX is this a safe threshold? + bcc_16 do_FORMULA_TOO_COMPLEX_error + // Push the operator address to stack, in a form // suitable for RTS From 558882ae8547874f7bae5ec5d072574fef55156e Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 7 Jun 2020 18:10:50 +0200 Subject: [PATCH 048/103] expression evaluator now supports opperator precedence --- c64/aliases/,aliases_ram_lowmem.s | 2 +- c64/basic/engine/ad9e.frmevl.s | 53 +++++++++++++++++++++---------- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/c64/aliases/,aliases_ram_lowmem.s b/c64/aliases/,aliases_ram_lowmem.s index acb718d5..2e316747 100644 --- a/c64/aliases/,aliases_ram_lowmem.s +++ b/c64/aliases/,aliases_ram_lowmem.s @@ -49,7 +49,7 @@ .label VARNAM = $45 // $45-$46 -- NOT IMPLEMENTED -- .label VARPNT = $47 // $47-$48 -- NOT IMPLEMENTED -- .label FORPNT = $49 // $49-$4A -- NOT IMPLEMENTED -- - .label OPPTR = $4B // $4B-$4C -- NOT IMPLEMENTED -- + .label OPPTR = $4B // $4B-$4C helper variable for expression computation, [!] our usage details are different .label OPMASK = $4D // -- NOT IMPLEMENTED -- .label DEFPNT = $4E // $4E-$4F -- NOT IMPLEMENTED -- .label DSCPNT = $50 // $50-$52 -- NOT IMPLEMENTED -- diff --git a/c64/basic/engine/ad9e.frmevl.s b/c64/basic/engine/ad9e.frmevl.s index 8856ae65..54bd7624 100644 --- a/c64/basic/engine/ad9e.frmevl.s +++ b/c64/basic/engine/ad9e.frmevl.s @@ -193,13 +193,13 @@ FRMEVL_fetch_string: // value (which is mandatory) // small catch: if the priority of the new operator is not higher than priority of the last // operator on the stack (sentinel is considered as the lowest priority operator) we first -// calculate what currently is present on the stack - this enforces proper operator precedence +// compute what currently is present on the stack - this enforces proper operator precedence // FRMEVL_got_value: jsr end_of_statement_check - bcs FRMEVL_continue // calculate the stack if expression ended + bcs FRMEVL_compute_all // compute the stack if expression ended // FALLTROUGH @@ -209,7 +209,7 @@ FRMEVL_fetch_operator: // there is an operator waiting to be served jsr fetch_operator - bcs FRMEVL_continue // if operator not recognized, calculate what we have + bcs FRMEVL_compute_all // if operator not recognized, compute what we have // on stack and quit // Move the new operator ID to .Y @@ -222,18 +222,25 @@ FRMEVL_fetch_operator: pha cmp operator_priorities, y - bcs !+ + bcc FRMEVL_push_value_operator - // Here the priority is not higher - so calculate what we already have on stack - // and restore the sentinel + // Here the priority is not higher - so compute what we already have on stack + // but do not finish proccessing - // XXX implement this - // XXX main problem: we need to go back here at the end; it seems we can use OPPTR (2 bytes) for this purpose - - // jmp FRMEVL_continue - // lda #$00 - // pha + sty OPPTR+1 // store .Y, we want to preserve it + lda #$FF // mark that we want to return here + sta OPPTR+0 !: + jmp FRMEVL_compute_partial + +FRMEVL_compute_partial_return: + + pla + pha + bne !- + + ldy OPPTR+1 + // FALLTROUGH FRMEVL_push_value_operator: @@ -291,15 +298,29 @@ FRMEVL_push_operator_address: jmp FRMEVL_loop // -// This subroutine serves two purposes: +// This part serves two purposes: // - it is an exit point for the concrete operator implementations -// - it causes calculation of everything which is stored on the stack +// - it causes computation of everything which is stored on the stack // +FRMEVL_compute_all: + + lda #$00 + sta OPPTR+0 + + // FALLTROUGH + FRMEVL_continue: - // Now, we have to calculate all the operations; at this point we - // should have a value in FAC1 and (possibly) operator on the top of the stack + lda OPPTR+0 + bne FRMEVL_compute_partial_return + + // FALLTROUGH + +FRMEVL_compute_partial: + + // Now, we have to compute operation; at this point we should have a value + // in FAC1 and (most likely) operator on a stack pla // priority does not matter here, get rid of it rts // this either jumps to operator, or quits FRMEVL From 82a52d6a0cbf69ffdfd71d30c3cde4f72117af87 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 7 Jun 2020 23:05:26 +0200 Subject: [PATCH 049/103] beginning of dummy string memory management --- c64/aliases/,aliases_ram_lowmem.s | 6 +- c64/basic/basic_do_new.s | 6 +- c64/basic/engine/ad9e.frmevl.s | 22 ++---- c64/basic/engine/alloc_temp_string.s | 81 ++++++++++++++++++++++ c64/basic/engine/execute_line_statements.s | 8 +++ c64/basic/operators/oper_add.s | 42 +++++++++-- 6 files changed, 139 insertions(+), 26 deletions(-) create mode 100644 c64/basic/engine/alloc_temp_string.s diff --git a/c64/aliases/,aliases_ram_lowmem.s b/c64/aliases/,aliases_ram_lowmem.s index 2e316747..72bd6d0b 100644 --- a/c64/aliases/,aliases_ram_lowmem.s +++ b/c64/aliases/,aliases_ram_lowmem.s @@ -28,9 +28,9 @@ .label TANSGN = $12 // -- NOT IMPLEMENTED -- .label CHANNL = $13 // -- NOT IMPLEMENTED -- .label LINNUM = $14 // $14-$15 BASIC line number, [!] also used by DOS Wedge - .label TEMPPT = $16 // -- NOT IMPLEMENTED -- - .label LASTPT = $17 // $17-$18 -- NOT IMPLEMENTED -- - .label TEMPST = $19 // $19-$21 -- NOT IMPLEMENTED -- + .label TEMPPT = $16 // pointer to the first available slot in the temporary string descriptor stack + .label LASTPT = $17 // $17-$18 pointer to the last used slot in the temporary string descriptor + .label TEMPST = $19 // $19-$21 temporary string stack descriptors .label INDEX = $22 // $22-$25 temporary variables, [!] our usage might be different .label RESHO = $26 // $26-$2A -- NOT IMPLEMENTED -- .label TXTTAB = $2B // $2B-$2C start of BASIC code diff --git a/c64/basic/basic_do_new.s b/c64/basic/basic_do_new.s index c50d10b1..aae36217 100644 --- a/c64/basic/basic_do_new.s +++ b/c64/basic/basic_do_new.s @@ -73,11 +73,14 @@ basic_do_clr: sta MEMSIZ+0 sta FRETOP+0 - // FALL THROUGH + // FALLTHROUGH basic_do_clr: + // XXX shouldnt FRETOP go here? + // Clear variables, arrays and strings + lda VARTAB+0 sta ARYTAB+0 sta STREND+0 @@ -87,4 +90,5 @@ basic_do_clr: rts + #endif // ROM layout diff --git a/c64/basic/engine/ad9e.frmevl.s b/c64/basic/engine/ad9e.frmevl.s index 54bd7624..a2bd1fdf 100644 --- a/c64/basic/engine/ad9e.frmevl.s +++ b/c64/basic/engine/ad9e.frmevl.s @@ -11,7 +11,6 @@ // // Output: // - VALTYP - $00 = floating number, $FF = string -// - INTFLG (XXX float/integer, probably) // - for float: FAC1 // - for string: __FAC1 + 0 = length, __FAC1 + 1 = pointer to string // @@ -20,20 +19,11 @@ // in a correct order // -// XXX finish the implementation +// XXX finish the implementation: invoking functions, fetcching PI, fetching float, fetching variables FRMEVL: - // XXX we neeed FRETOP for string concatenation - - // lda VARTAB+0 - // sta FRETOP+0 - // lda VARTAB+1 - // sta FRETOP+1 - - // XXX we also need TEMMPPT, LASTPT and TEMPST - // Push the sentinel to the stack lda #$00 @@ -72,7 +62,7 @@ FRMEVL_loop: // Check for the PI cmp #$FF // check for PI - beq_16 FRMEVL_fetch_PI // XXX + beq_16 FRMEVL_fetch_PI // If not a PI and not an unary operator, than everything above // $7F has to be a function @@ -256,16 +246,16 @@ FRMEVL_push_value_operator: FRMEVL_push_string: - // Push string - address, length, type + // Push string - length, address, type + + lda __FAC1+0 + pha lda __FAC1+1 pha lda __FAC1+2 pha - lda __FAC1+0 - pha - txa pha diff --git a/c64/basic/engine/alloc_temp_string.s b/c64/basic/engine/alloc_temp_string.s new file mode 100644 index 00000000..935c5ccd --- /dev/null +++ b/c64/basic/engine/alloc_temp_string.s @@ -0,0 +1,81 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Allocates area for a temporary string +// +// Input: +// - .A - string length +// + + +// XXX - this is a dummy implementation, until proper string handling is implemented +// XXX - addresses are probably wrong, debug it + + +alloc_temp_string: + + // Check if temporary descriptor stack has a free slot + + ldx LASTPT + cpx #$1F + bcs_16 do_FORMULA_TOO_COMPLEX_error + + // Prepare data in index registers + + tay // store length, we will need .A in a moment + + // Increment temporary descriptor stack pointers by 3 + + lda LASTPT + adc #$03 // Carry is already clear here + sta LASTPT + adc #$03 + sta TEMPPT + + // Fill in the new entry + + cmp #$1C + bne !+ + + // Fill in the address - first entry + + ldx TEMPPT + lda STREND+0 + sta $01, x // address - lo byte + lda STREND+1 + sta $02, x // address - hi byte + + jmp alloc_temp_string_space_check +!: + // Fill in the adress - use previous entry + + ldx LASTPT + lda $01, x // address - lo byte + ldx TEMPPT + sta $01, x + + ldx LASTPT + lda $02, x // address - hi byte + ldx TEMPPT + sta $02, x + inc $02, x + + // FALLTROUGH + +alloc_temp_string_space_check: + + // Fill in the length of the new string + + ldx TEMPPT + tya + sta $00, x // length + + // Check if we have enough space + + lda $02, x + cmp FRETOP+1 + beq_16 do_OUT_OF_MEMORY_error + + rts diff --git a/c64/basic/engine/execute_line_statements.s b/c64/basic/engine/execute_line_statements.s index b8a47eb6..5b0e39a3 100644 --- a/c64/basic/engine/execute_line_statements.s +++ b/c64/basic/engine/execute_line_statements.s @@ -32,6 +32,14 @@ execute_statements: cmp #$7F bcc_16 do_SYNTAX_error // branch if not a token XXX here we should handle variable assignments + // Initialize temporary string stack - just about any statement might need it + // XXX original C64 ROM initializes this during the startup too - not sure where to put this + + ldx #$16 + stx LASTPT + ldx #$19 + stx TEMPPT + #if !HAS_OPCODES_65C02 // Get the jump table entry for it, push it on the stack, and then RTS to start it. diff --git a/c64/basic/operators/oper_add.s b/c64/basic/operators/oper_add.s index f4d03945..2670de2e 100644 --- a/c64/basic/operators/oper_add.s +++ b/c64/basic/operators/oper_add.s @@ -25,11 +25,6 @@ oper_add_floats: oper_add_strings: - // Pull string length - - pla - sta __FAC2+0 - // Retrieve string address pla @@ -37,6 +32,41 @@ oper_add_strings: pla sta __FAC2+1 - // XXX merge strings here + // Pull string length + + pla + sta __FAC2+0 + beq oper_add_strings_end // if string 2 is empty, we have nothing to do + + // If string 1 is empty, just copy the metadata + + lda __FAC1+0 + bne !+ + + lda __FAC2+0 + sta __FAC1+0 + lda __FAC2+1 + sta __FAC1+1 + lda __FAC2+2 + sta __FAC1+2 + + jmp FRMEVL_continue +!: + // Allocate memory for concatenated string + + clc + adc __FAC2+0 + bcs_16 do_STRING_TOO_LONG_error + + jsr alloc_temp_string + +.break + + + + // XXX finish the implementation + + +oper_add_strings_end: jmp FRMEVL_continue From 3a885a2d1496d17b1d699407233c225d309c6829 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 8 Jun 2020 17:18:29 +0200 Subject: [PATCH 050/103] removed some test code --- c64/basic/engine/alloc_temp_string.s | 61 ++-------------------------- 1 file changed, 3 insertions(+), 58 deletions(-) diff --git a/c64/basic/engine/alloc_temp_string.s b/c64/basic/engine/alloc_temp_string.s index 935c5ccd..1701c78d 100644 --- a/c64/basic/engine/alloc_temp_string.s +++ b/c64/basic/engine/alloc_temp_string.s @@ -10,8 +10,7 @@ // -// XXX - this is a dummy implementation, until proper string handling is implemented -// XXX - addresses are probably wrong, debug it +// XXX - finish the implementation once string memory handling is done alloc_temp_string: @@ -22,60 +21,6 @@ alloc_temp_string: cpx #$1F bcs_16 do_FORMULA_TOO_COMPLEX_error - // Prepare data in index registers + // XXX - tay // store length, we will need .A in a moment - - // Increment temporary descriptor stack pointers by 3 - - lda LASTPT - adc #$03 // Carry is already clear here - sta LASTPT - adc #$03 - sta TEMPPT - - // Fill in the new entry - - cmp #$1C - bne !+ - - // Fill in the address - first entry - - ldx TEMPPT - lda STREND+0 - sta $01, x // address - lo byte - lda STREND+1 - sta $02, x // address - hi byte - - jmp alloc_temp_string_space_check -!: - // Fill in the adress - use previous entry - - ldx LASTPT - lda $01, x // address - lo byte - ldx TEMPPT - sta $01, x - - ldx LASTPT - lda $02, x // address - hi byte - ldx TEMPPT - sta $02, x - inc $02, x - - // FALLTROUGH - -alloc_temp_string_space_check: - - // Fill in the length of the new string - - ldx TEMPPT - tya - sta $00, x // length - - // Check if we have enough space - - lda $02, x - cmp FRETOP+1 - beq_16 do_OUT_OF_MEMORY_error - - rts + jmp do_NOT_IMPLEMENTED_error From 5a2f847cb6a72a6440ec8aa612c72b7958840c39 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 8 Jun 2020 17:36:25 +0200 Subject: [PATCH 051/103] shortened BASIC commands jumptable handling --- c64/basic/commands/command_jumptable.s | 90 ++++------------------ c64/basic/engine/execute_line_statements.s | 20 +++++ 2 files changed, 34 insertions(+), 76 deletions(-) diff --git a/c64/basic/commands/command_jumptable.s b/c64/basic/commands/command_jumptable.s index f15a5a84..dd64cb47 100644 --- a/c64/basic/commands/command_jumptable.s +++ b/c64/basic/commands/command_jumptable.s @@ -50,7 +50,7 @@ cmd_sys, cmd_open, - // $A0-$AF + // $A0-$A9 cmd_close, cmd_get, @@ -62,19 +62,18 @@ cmd_then, cmd_not, cmd_step, - cmd_plus, - cmd_minus, - cmd_mult, - cmd_div, - cmd_exponent, - cmd_and, - // $B0-$BF + // $CB, but remapped to $A9 + + cmd_go +) + +/* + XXX we need a separate function dispatch table for the following ones: + + + // $B4-$BF - cmd_or, - cmd_greater, - cmd_equal, - cmd_less, cmd_sgn, cmd_int, cmd_abs, @@ -88,7 +87,7 @@ cmd_cos, cmd_sin, - // $C0-$CF + // $C0-$CA cmd_tan, cmd_atn, @@ -100,70 +99,9 @@ cmd_chr, cmd_left, cmd_right, - cmd_mid, - cmd_go, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, + cmd_mid +*/ - // $D0-$DF - - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - - // $E0-$EF - - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - - // $F0-$FF - - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented, - cmd_unimplemented -) diff --git a/c64/basic/engine/execute_line_statements.s b/c64/basic/engine/execute_line_statements.s index 5b0e39a3..8d70b130 100644 --- a/c64/basic/engine/execute_line_statements.s +++ b/c64/basic/engine/execute_line_statements.s @@ -32,6 +32,11 @@ execute_statements: cmp #$7F bcc_16 do_SYNTAX_error // branch if not a token XXX here we should handle variable assignments + cmp #$A9 + bcs execute_statements_extended + +execute_statements_run_token: + // Initialize temporary string stack - just about any statement might need it // XXX original C64 ROM initializes this during the startup too - not sure where to put this @@ -63,6 +68,21 @@ execute_statements: #endif +execute_statements_extended: + + cmp #$CB + bne !+ + + // 'GO' command has a strande token, after functions + + lda #$A9 + bne execute_statements_run_token +!: + // XXX here is the place for possible extended BASIC command set + + jmp do_SYNTAX_error + + execute_statements_end_of_line: // First check, if we are in direct mode - if so, From 0c8c0d6ad4c008cf5f087763c20a3ac958a580ce Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 8 Jun 2020 18:26:38 +0200 Subject: [PATCH 052/103] separated commands from functions --- Makefile | 5 +- .../cmd__jumptable.s} | 59 ++----- c64/basic/basic_commands/cmd__unimplemented.s | 65 ++++++++ .../{commands => basic_commands}/cmd_clr.s | 0 .../{commands => basic_commands}/cmd_list.s | 0 .../cmd_load_verify.s | 0 .../{commands => basic_commands}/cmd_new.s | 0 .../{commands => basic_commands}/cmd_print.s | 0 .../{commands => basic_commands}/cmd_rem.s | 0 .../cmd_run_goto.s} | 0 .../{commands => basic_commands}/cmd_save.s | 0 .../cmd_stop_end.s} | 0 .../{commands => basic_commands}/cmd_sys.s | 0 c64/basic/basic_functions/fun__jumptable.s | 72 ++++++++ .../basic_functions/fun__unimplemented.s | 61 +++++++ .../oper__jumptable.s} | 0 .../{operators => basic_operators}/oper_add.s | 0 .../{operators => basic_operators}/oper_and.s | 0 .../oper_cmp_eq.s | 0 .../oper_cmp_gt.s | 0 .../oper_cmp_gteq.s | 0 .../oper_cmp_lt.s | 0 .../oper_cmp_lteq.s | 0 .../oper_cmp_neq.s | 0 .../{operators => basic_operators}/oper_div.s | 0 .../{operators => basic_operators}/oper_mul.s | 0 .../{operators => basic_operators}/oper_or.s | 0 .../{operators => basic_operators}/oper_pow.s | 0 .../{operators => basic_operators}/oper_sub.s | 0 .../oper_unary_minus.s | 0 .../oper_unary_not.s | 0 c64/basic/commands/cmd_unimplemented.s | 154 ------------------ c64/basic/engine/ad9e.frmevl.s | 2 +- c64/basic/engine/execute_line_statements.s | 6 +- 34 files changed, 215 insertions(+), 209 deletions(-) rename c64/basic/{commands/command_jumptable.s => basic_commands/cmd__jumptable.s} (65%) create mode 100644 c64/basic/basic_commands/cmd__unimplemented.s rename c64/basic/{commands => basic_commands}/cmd_clr.s (100%) rename c64/basic/{commands => basic_commands}/cmd_list.s (100%) rename c64/basic/{commands => basic_commands}/cmd_load_verify.s (100%) rename c64/basic/{commands => basic_commands}/cmd_new.s (100%) rename c64/basic/{commands => basic_commands}/cmd_print.s (100%) rename c64/basic/{commands => basic_commands}/cmd_rem.s (100%) rename c64/basic/{commands/cmd_run.s => basic_commands/cmd_run_goto.s} (100%) rename c64/basic/{commands => basic_commands}/cmd_save.s (100%) rename c64/basic/{commands/cmd_break.s => basic_commands/cmd_stop_end.s} (100%) rename c64/basic/{commands => basic_commands}/cmd_sys.s (100%) create mode 100644 c64/basic/basic_functions/fun__jumptable.s create mode 100644 c64/basic/basic_functions/fun__unimplemented.s rename c64/basic/{operators/operators_jumptable.s => basic_operators/oper__jumptable.s} (100%) rename c64/basic/{operators => basic_operators}/oper_add.s (100%) rename c64/basic/{operators => basic_operators}/oper_and.s (100%) rename c64/basic/{operators => basic_operators}/oper_cmp_eq.s (100%) rename c64/basic/{operators => basic_operators}/oper_cmp_gt.s (100%) rename c64/basic/{operators => basic_operators}/oper_cmp_gteq.s (100%) rename c64/basic/{operators => basic_operators}/oper_cmp_lt.s (100%) rename c64/basic/{operators => basic_operators}/oper_cmp_lteq.s (100%) rename c64/basic/{operators => basic_operators}/oper_cmp_neq.s (100%) rename c64/basic/{operators => basic_operators}/oper_div.s (100%) rename c64/basic/{operators => basic_operators}/oper_mul.s (100%) rename c64/basic/{operators => basic_operators}/oper_or.s (100%) rename c64/basic/{operators => basic_operators}/oper_pow.s (100%) rename c64/basic/{operators => basic_operators}/oper_sub.s (100%) rename c64/basic/{operators => basic_operators}/oper_unary_minus.s (100%) rename c64/basic/{operators => basic_operators}/oper_unary_not.s (100%) delete mode 100644 c64/basic/commands/cmd_unimplemented.s diff --git a/Makefile b/Makefile index 3aa682b4..7f0b7ccb 100644 --- a/Makefile +++ b/Makefile @@ -13,15 +13,16 @@ SRCDIR_BASIC = $(SRCDIR_COMMON) \ c64/basic/,stubs \ c64/basic/,stubs_math \ c64/basic/assets \ + c64/basic/basic_commands \ + c64/basic/basic_operators \ + c64/basic/basic_functions \ c64/basic/board_m65 \ c64/basic/board_x16 \ - c64/basic/commands \ c64/basic/engine \ c64/basic/init \ c64/basic/math \ c64/basic/math_consts \ c64/basic/math_mov \ - c64/basic/operators \ c64/basic/print \ c64/basic/rom_revision \ c64/basic/wedge diff --git a/c64/basic/commands/command_jumptable.s b/c64/basic/basic_commands/cmd__jumptable.s similarity index 65% rename from c64/basic/commands/command_jumptable.s rename to c64/basic/basic_commands/cmd__jumptable.s index dd64cb47..1fa25c49 100644 --- a/c64/basic/commands/command_jumptable.s +++ b/c64/basic/basic_commands/cmd__jumptable.s @@ -3,13 +3,10 @@ // #LAYOUT# * * #IGNORE // -// Jumptable for all known BASIC commands and functions +// Jumptable for all known BASIC commands // -// XXX use separate jumptables for commands and functions - - .const command_list = List().add( // $80 - $8F @@ -50,60 +47,24 @@ cmd_sys, cmd_open, - // $A0-$A9 + // $A0-$A6 cmd_close, cmd_get, cmd_new, - cmd_tab, - cmd_to, - cmd_fn, - cmd_spc, - cmd_then, - cmd_not, - cmd_step, + cmd_tab, // XXX this token probably does not belong here + do_SYNTAX_error, // 'TO' is not a standalone command + do_SYNTAX_error, // 'FN' is not a standalone command + cmd_spc, // XXX this token probably does not belong here + + // 'THEN' ($A7) and 'STEP' ($A9) are not standalone commands + // 'NOT' ($A8) is an operator, not a command - // $CB, but remapped to $A9 + // $CB, but remapped to $A7 cmd_go ) -/* - XXX we need a separate function dispatch table for the following ones: - - - // $B4-$BF - - cmd_sgn, - cmd_int, - cmd_abs, - cmd_usr, - cmd_fre, - cmd_pos, - cmd_sqr, - cmd_rnd, - cmd_log, - cmd_exp, - cmd_cos, - cmd_sin, - - // $C0-$CA - - cmd_tan, - cmd_atn, - cmd_peek, - cmd_len, - cmd_str, - cmd_val, - cmd_asc, - cmd_chr, - cmd_left, - cmd_right, - cmd_mid -*/ - - - #if !HAS_OPCODES_65C02 diff --git a/c64/basic/basic_commands/cmd__unimplemented.s b/c64/basic/basic_commands/cmd__unimplemented.s new file mode 100644 index 00000000..4e67d479 --- /dev/null +++ b/c64/basic/basic_commands/cmd__unimplemented.s @@ -0,0 +1,65 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Default handler for all not-yet-implemented commands +// +// Note: NOPs are here just to make debugging easier (no duplicated labels)! +// + + +cmd_for: + nop +cmd_next: + nop +cmd_data: + nop +cmd_inputhash: + nop +cmd_input: + nop +cmd_dim: + nop +cmd_read: + nop +cmd_let: + nop +cmd_if: + nop +cmd_restore: + nop +cmd_gosub: + nop +cmd_return: + nop +cmd_on: + nop +cmd_wait: + nop +cmd_def: + nop +cmd_poke: + nop +cmd_printhash: + nop +cmd_cont: + nop +cmd_cmd: + nop +cmd_open: + nop +cmd_close: + nop +cmd_get: + nop +cmd_tab: + nop +cmd_spc: + nop +cmd_go: + nop + + // Unimplemented tokens + + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/commands/cmd_clr.s b/c64/basic/basic_commands/cmd_clr.s similarity index 100% rename from c64/basic/commands/cmd_clr.s rename to c64/basic/basic_commands/cmd_clr.s diff --git a/c64/basic/commands/cmd_list.s b/c64/basic/basic_commands/cmd_list.s similarity index 100% rename from c64/basic/commands/cmd_list.s rename to c64/basic/basic_commands/cmd_list.s diff --git a/c64/basic/commands/cmd_load_verify.s b/c64/basic/basic_commands/cmd_load_verify.s similarity index 100% rename from c64/basic/commands/cmd_load_verify.s rename to c64/basic/basic_commands/cmd_load_verify.s diff --git a/c64/basic/commands/cmd_new.s b/c64/basic/basic_commands/cmd_new.s similarity index 100% rename from c64/basic/commands/cmd_new.s rename to c64/basic/basic_commands/cmd_new.s diff --git a/c64/basic/commands/cmd_print.s b/c64/basic/basic_commands/cmd_print.s similarity index 100% rename from c64/basic/commands/cmd_print.s rename to c64/basic/basic_commands/cmd_print.s diff --git a/c64/basic/commands/cmd_rem.s b/c64/basic/basic_commands/cmd_rem.s similarity index 100% rename from c64/basic/commands/cmd_rem.s rename to c64/basic/basic_commands/cmd_rem.s diff --git a/c64/basic/commands/cmd_run.s b/c64/basic/basic_commands/cmd_run_goto.s similarity index 100% rename from c64/basic/commands/cmd_run.s rename to c64/basic/basic_commands/cmd_run_goto.s diff --git a/c64/basic/commands/cmd_save.s b/c64/basic/basic_commands/cmd_save.s similarity index 100% rename from c64/basic/commands/cmd_save.s rename to c64/basic/basic_commands/cmd_save.s diff --git a/c64/basic/commands/cmd_break.s b/c64/basic/basic_commands/cmd_stop_end.s similarity index 100% rename from c64/basic/commands/cmd_break.s rename to c64/basic/basic_commands/cmd_stop_end.s diff --git a/c64/basic/commands/cmd_sys.s b/c64/basic/basic_commands/cmd_sys.s similarity index 100% rename from c64/basic/commands/cmd_sys.s rename to c64/basic/basic_commands/cmd_sys.s diff --git a/c64/basic/basic_functions/fun__jumptable.s b/c64/basic/basic_functions/fun__jumptable.s new file mode 100644 index 00000000..0d53bcdc --- /dev/null +++ b/c64/basic/basic_functions/fun__jumptable.s @@ -0,0 +1,72 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Jumptable for all known BASIC functions +// + + +.const function_list = List().add( + + // $B4-$BF + + fun_sgn, + fun_int, + fun_abs, + fun_usr, + fun_fre, + fun_pos, + fun_sqr, + fun_rnd, + fun_log, + fun_exp, + fun_cos, + fun_sin, + + // $C0-$CA + + fun_tan, + fun_atn, + fun_peek, + fun_len, + fun_str, + fun_val, + fun_asc, + fun_chr, + fun_left, + fun_right, + fun_mid +) + + +#if !HAS_OPCODES_65C02 + + +function_jumptable_lo: + + put_jumptable_lo(function_list) + + +function_jumptable_hi: + + put_jumptable_hi(function_list) + + +#else // HAS_OPCODES_65C02 + + +__before_function_jumptable: + +.if (mod(*, $2) == 1) { brk } // align code so that vector never crosses page boundary + +function_jumptable: + + put_jumptable(function_list) + + // Make sure routine size is always the same - build system limitation + +.if (__before_function_jumptable == function_jumptable) { brk } + + +#endif diff --git a/c64/basic/basic_functions/fun__unimplemented.s b/c64/basic/basic_functions/fun__unimplemented.s new file mode 100644 index 00000000..8954996d --- /dev/null +++ b/c64/basic/basic_functions/fun__unimplemented.s @@ -0,0 +1,61 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Default handler for all not-yet-implemented functions +// +// Note: NOPs are here just to make debugging easier (no duplicated labels)! +// + + +fun_sgn: + nop +fun_int: + nop +fun_abs: + nop +fun_usr: + nop +fun_fre: + nop +fun_pos: + nop +fun_sqr: + nop +fun_rnd: + nop +fun_log: + nop +fun_exp: + nop +fun_cos: + nop +fun_sin: + nop +fun_tan: + nop +fun_atn: + nop +fun_peek: + nop +fun_len: + nop +fun_str: + nop +fun_val: + nop +fun_asc: + nop +fun_chr: + nop +fun_left: + nop +fun_right: + nop +fun_mid: + nop + + // Unimplemented tokens + + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/operators/operators_jumptable.s b/c64/basic/basic_operators/oper__jumptable.s similarity index 100% rename from c64/basic/operators/operators_jumptable.s rename to c64/basic/basic_operators/oper__jumptable.s diff --git a/c64/basic/operators/oper_add.s b/c64/basic/basic_operators/oper_add.s similarity index 100% rename from c64/basic/operators/oper_add.s rename to c64/basic/basic_operators/oper_add.s diff --git a/c64/basic/operators/oper_and.s b/c64/basic/basic_operators/oper_and.s similarity index 100% rename from c64/basic/operators/oper_and.s rename to c64/basic/basic_operators/oper_and.s diff --git a/c64/basic/operators/oper_cmp_eq.s b/c64/basic/basic_operators/oper_cmp_eq.s similarity index 100% rename from c64/basic/operators/oper_cmp_eq.s rename to c64/basic/basic_operators/oper_cmp_eq.s diff --git a/c64/basic/operators/oper_cmp_gt.s b/c64/basic/basic_operators/oper_cmp_gt.s similarity index 100% rename from c64/basic/operators/oper_cmp_gt.s rename to c64/basic/basic_operators/oper_cmp_gt.s diff --git a/c64/basic/operators/oper_cmp_gteq.s b/c64/basic/basic_operators/oper_cmp_gteq.s similarity index 100% rename from c64/basic/operators/oper_cmp_gteq.s rename to c64/basic/basic_operators/oper_cmp_gteq.s diff --git a/c64/basic/operators/oper_cmp_lt.s b/c64/basic/basic_operators/oper_cmp_lt.s similarity index 100% rename from c64/basic/operators/oper_cmp_lt.s rename to c64/basic/basic_operators/oper_cmp_lt.s diff --git a/c64/basic/operators/oper_cmp_lteq.s b/c64/basic/basic_operators/oper_cmp_lteq.s similarity index 100% rename from c64/basic/operators/oper_cmp_lteq.s rename to c64/basic/basic_operators/oper_cmp_lteq.s diff --git a/c64/basic/operators/oper_cmp_neq.s b/c64/basic/basic_operators/oper_cmp_neq.s similarity index 100% rename from c64/basic/operators/oper_cmp_neq.s rename to c64/basic/basic_operators/oper_cmp_neq.s diff --git a/c64/basic/operators/oper_div.s b/c64/basic/basic_operators/oper_div.s similarity index 100% rename from c64/basic/operators/oper_div.s rename to c64/basic/basic_operators/oper_div.s diff --git a/c64/basic/operators/oper_mul.s b/c64/basic/basic_operators/oper_mul.s similarity index 100% rename from c64/basic/operators/oper_mul.s rename to c64/basic/basic_operators/oper_mul.s diff --git a/c64/basic/operators/oper_or.s b/c64/basic/basic_operators/oper_or.s similarity index 100% rename from c64/basic/operators/oper_or.s rename to c64/basic/basic_operators/oper_or.s diff --git a/c64/basic/operators/oper_pow.s b/c64/basic/basic_operators/oper_pow.s similarity index 100% rename from c64/basic/operators/oper_pow.s rename to c64/basic/basic_operators/oper_pow.s diff --git a/c64/basic/operators/oper_sub.s b/c64/basic/basic_operators/oper_sub.s similarity index 100% rename from c64/basic/operators/oper_sub.s rename to c64/basic/basic_operators/oper_sub.s diff --git a/c64/basic/operators/oper_unary_minus.s b/c64/basic/basic_operators/oper_unary_minus.s similarity index 100% rename from c64/basic/operators/oper_unary_minus.s rename to c64/basic/basic_operators/oper_unary_minus.s diff --git a/c64/basic/operators/oper_unary_not.s b/c64/basic/basic_operators/oper_unary_not.s similarity index 100% rename from c64/basic/operators/oper_unary_not.s rename to c64/basic/basic_operators/oper_unary_not.s diff --git a/c64/basic/commands/cmd_unimplemented.s b/c64/basic/commands/cmd_unimplemented.s deleted file mode 100644 index 1280d692..00000000 --- a/c64/basic/commands/cmd_unimplemented.s +++ /dev/null @@ -1,154 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - -// -// Default handler for all not-yet-implemented commands -// -// Note: NOPs are here just to make debugging easier! -// - -cmd_for: - nop -cmd_next: - nop -cmd_data: - nop -cmd_inputhash: - nop -cmd_input: - nop -cmd_dim: - nop -cmd_read: - nop -cmd_let: - nop -cmd_if: - nop -cmd_restore: - nop -cmd_gosub: - nop -cmd_return: - nop - - // $90-$9F - -cmd_on: - nop -cmd_wait: - nop -cmd_def: - nop -cmd_poke: - nop -cmd_printhash: - nop -cmd_cont: - nop -cmd_cmd: - nop -cmd_open: - nop - - // $A0-$AF - -cmd_close: - nop -cmd_get: - nop -cmd_tab: - nop -cmd_to: - nop -cmd_fn: - nop -cmd_spc: - nop -cmd_then: - nop -cmd_not: - nop -cmd_step: - nop -cmd_plus: - nop -cmd_minus: - nop -cmd_mult: - nop -cmd_div: - nop -cmd_exponent: - nop -cmd_and: - nop - - // $B0-$BF - -cmd_or: - nop -cmd_greater: - nop -cmd_equal: - nop -cmd_less: - nop -cmd_sgn: - nop -cmd_int: - nop -cmd_abs: - nop -cmd_usr: - nop -cmd_fre: - nop -cmd_pos: - nop -cmd_sqr: - nop -cmd_rnd: - nop -cmd_log: - nop -cmd_exp: - nop -cmd_cos: - nop -cmd_sin: - nop - - // $C0-$CF - -cmd_tan: - nop -cmd_atn: - nop -cmd_peek: - nop -cmd_len: - nop -cmd_str: - nop -cmd_val: - nop -cmd_asc: - nop -cmd_chr: - nop -cmd_left: - nop -cmd_right: - nop -cmd_mid: - nop -cmd_go: - nop - - // Undefined tokens - -cmd_unimplemented: - - jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/engine/ad9e.frmevl.s b/c64/basic/engine/ad9e.frmevl.s index a2bd1fdf..1c7e51af 100644 --- a/c64/basic/engine/ad9e.frmevl.s +++ b/c64/basic/engine/ad9e.frmevl.s @@ -87,7 +87,7 @@ FRMEVL_loop: FRMEVL_execute_function: - // XXX implement this + // XXX implement this - use function_jumptable* jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/engine/execute_line_statements.s b/c64/basic/engine/execute_line_statements.s index 8d70b130..df512e35 100644 --- a/c64/basic/engine/execute_line_statements.s +++ b/c64/basic/engine/execute_line_statements.s @@ -32,7 +32,7 @@ execute_statements: cmp #$7F bcc_16 do_SYNTAX_error // branch if not a token XXX here we should handle variable assignments - cmp #$A9 + cmp #$A6 bcs execute_statements_extended execute_statements_run_token: @@ -73,9 +73,9 @@ execute_statements_extended: cmp #$CB bne !+ - // 'GO' command has a strande token, after functions + // 'GO' command has a strange token, after function tokens - lda #$A9 + lda #$A7 bne execute_statements_run_token !: // XXX here is the place for possible extended BASIC command set From 4fe2e27c9e5fdc30248f6e423bef392b2e5d0aca Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 8 Jun 2020 18:53:11 +0200 Subject: [PATCH 053/103] fixed regression in error handling --- c64/basic/engine/do_error.s | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/c64/basic/engine/do_error.s b/c64/basic/engine/do_error.s index 86edb545..6947ca0b 100644 --- a/c64/basic/engine/do_error.s +++ b/c64/basic/engine/do_error.s @@ -47,7 +47,7 @@ do_MEMORY_CORRUPT_error: bpl do_basic_error // branch always do_kernal_error: // .A = KERNAL error code, also almost matches BASIC error codes - + // Convert to BASIC error code tax @@ -142,12 +142,12 @@ do_TO_MANY_FILES_error: do_basic_error: // error code in .X // "?" + phx_trash_a - pha jsr print_return lda #$3F jsr JCHROUT - plx_trash_a + pla // Error message text + " ERROR" From eadced28b9ab9e2ac63a893cc81d17e262ed7fe1 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 8 Jun 2020 19:04:09 +0200 Subject: [PATCH 054/103] small size optimization in BASIC code --- c64/basic/engine/execute_line_statements.s | 27 +++++++++------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/c64/basic/engine/execute_line_statements.s b/c64/basic/engine/execute_line_statements.s index df512e35..374db0e5 100644 --- a/c64/basic/engine/execute_line_statements.s +++ b/c64/basic/engine/execute_line_statements.s @@ -29,14 +29,6 @@ execute_statements: // Not end of the line - it seems we actually have something to execute - cmp #$7F - bcc_16 do_SYNTAX_error // branch if not a token XXX here we should handle variable assignments - - cmp #$A6 - bcs execute_statements_extended - -execute_statements_run_token: - // Initialize temporary string stack - just about any statement might need it // XXX original C64 ROM initializes this during the startup too - not sure where to put this @@ -45,6 +37,14 @@ execute_statements_run_token: ldx #$19 stx TEMPPT + // Check if token is valid for execution + + cmp #$7F + bcc_16 do_SYNTAX_error // branch if not a token XXX here we should handle variable assignments + + cmp #$A6 + bcs execute_statements_extended + #if !HAS_OPCODES_65C02 // Get the jump table entry for it, push it on the stack, and then RTS to start it. @@ -70,16 +70,11 @@ execute_statements_run_token: execute_statements_extended: - cmp #$CB - bne !+ - - // 'GO' command has a strange token, after function tokens - - lda #$A7 - bne execute_statements_run_token -!: // XXX here is the place for possible extended BASIC command set + cmp #$CB + beq_16 cmd_go // 'GO' command has a strange token, it is placed after function tokens + jmp do_SYNTAX_error From e56fbb18ea5595830eabbb9f5a90c75f216bab2a Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 8 Jun 2020 19:14:48 +0200 Subject: [PATCH 055/103] fixed support for strings without closing quotes --- c64/basic/engine/ad9e.frmevl.s | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/c64/basic/engine/ad9e.frmevl.s b/c64/basic/engine/ad9e.frmevl.s index 1c7e51af..71b1ccb7 100644 --- a/c64/basic/engine/ad9e.frmevl.s +++ b/c64/basic/engine/ad9e.frmevl.s @@ -168,11 +168,19 @@ FRMEVL_fetch_string: jsr fetch_character cmp #$22 beq FRMEVL_got_value + cmp #$00 + beq !+ inc __FAC1 + 0 bne !- jmp do_STRING_TOO_LONG_error +!: + // No closing quote, but end of the data + + jsr unconsume_character + + // FALLTROUGH // From 51e45e99830d376d3500c6e8321b4ebd667835dc Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 8 Jun 2020 19:26:09 +0200 Subject: [PATCH 056/103] updated binaries --- bin/basic_generic.rom | Bin 8192 -> 8192 bytes bin/basic_ultimate64.rom | Bin 8192 -> 8192 bytes bin/kernal_generic.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 6 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/basic_generic.rom b/bin/basic_generic.rom index 906796474fb0b9639cb96e6d3ff3001157544d34..60c817dfb7fcea19063e9ed94c7cee133835a30d 100644 GIT binary patch delta 3224 zcmZuzeQ;A%7Jo^aCjCrOpiMuyfV9+>3J5e7Qmd;@l-pg_9hX%ced%XfKgQkJ54Vh_ z&Tvbu?vl=1#=3yMefFljYTKk8rcImB&g=?#73D2dgcUWEmMwL39|}6GGi1*V>@I(B z=e>8&J@4F)^SkH#?rpDWuL-0ic^7YAuq$LVCMTQqx}-!g86JP&_=yu&uWvdY`gL=| zR}aMeb90gLiSWdQ$=TV-FvoGcIVCkMJtNa%wPh_?x-2`#o|~6nP*~J^`@-?m{eFwk zne<-vsfefxI#nGnCIy`erzJ<#@9|FI5o1y1lVJy~oGccSl zJi>JAd^O5Ffvwa;%rZwz@V3c%vJ2G@(l%o9n<8L?RKtS$U55$18b)7+0tVDLK~3+Q zH3M=)@E-c#K2SSJwHzl^_<$dKY|4EU2V)HJCe?V3`hT?LRzr0k9yDYqkA@dgaIIi&al zsr?ag)D?Mg)Ws_wfTyuO(EF) zN;=6V`8?U&RqE{*<7g=0Ipk6Hs(LaLRj1^a(aCsJ9m8XbLQz_-kZ*e3czH5#k`LNW z>%21OLjRieG0@qTtkkNNHCl=CE3G-Wp(? zO0~7n9rW->@s5mz4!6Ipqt3spqyEO2nXtvCi*EHY#59sGz=VPO(Uow(dC2Q=on6)I zv+TwYZ`-hY(Bo3C^ve@Tz`Lr~h5s@DF}ICw zQ;&Oi^l^|j7#odl&43$1)B-F1p4O42w4N-p^NARR3?(gEHfUQx`wVR$&(cOB9LTh7 zg>gJ+aZoZHuG_a`+IkISctnH5*$>zKX2-s|g-+{t)YJGB@lcPdxAW-w;6*oeTQB2! z;nR#Y!hz&_^?aZ3S@No4zK_iYQ}W=i0lzcG^9+M>Ed|2;Dmd@p?L03GWEQNyBXCf! z>zuZJ>%qr{Iy*a4r@X!|JYtFB^(}KrN%jb*`~B9yLGGr_S3|XU*DS<<=TLA{sYS79 zDN}KEh)2#KdvQfD+T#jtN*M6W!rqeE-{Zo0!EW1jf!gxRlnT|tFx9|yz{-Nx4g&@o zhhfVsA{T6fXfc7@gjy$sip(7Iz#v$lfkB}*bA|W%AgJ+|LFg%&_qnI7Kadwd25Lk9 zjH9fuY!NMJJT3!6Fv4QA!^Q;ct_>@9KxG{PaeK!TKEjG!P)nMT@sYhtOiA8T5jF`sei9^klW8OU zXfTHNk8(Uqyt`O9ZqdqE9=Bvj2qo_mlmnPtE-N?9V9s{rUCe{g}+1-$1AOZ;7ym7 zv;S58dl+vfekO<^@xgqbEC2xV-C`dqdROAaRFpn1=ig}QZnSnJTJmG!Br`E2l&G0X zxyf+$q|c*k-{E(@jR0LGxtp#fcain9f~+GOpfePH_bRdy?u9E!qu?(n z@iMZD={0uvGRDFQ2|ACGR8c3Hz*qdcIY`^4NynvrU#5}@iD}ZzN{W_k=N*ZIWmq#o zCd(%EYdKY2WUdcuX-ZH_W7-t;jGU&<$myy|oi1AKqGrdu$=+gwZK!K2%UkXo&iC*)3+9g+yq2!Na)ofFdDGwhzZU2 zQL|!&RlxON-w|KlM>d`67ixD}{IRPxOC_)O)Edu`y;Q8tpCNz1M`A2Ya}t!fj==@jiBY&rOu%I# WY!^nBZ^^nDGpY%KhTRez{C@zOy}oh) delta 3024 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 diff --git a/bin/basic_ultimate64.rom b/bin/basic_ultimate64.rom index 57b76a751621d318b6f05f829a95df31d3135c22..3ac5c270cad595433cee53f354739d7e4d857b40 100644 GIT binary patch delta 3050 zcmZ`*eNat5Y4dX0zM}4@`XEILJqoncZ5R+V*XwR=3s?6&LA@`>5KE>x|iRBi;3n z_D%BcdFP&U?mZv(ckYhr9o5SEgheH#i^>*1w&d}p%gUY0D=JsGs#aF7TK&YpPd}XK z&;GSf=8I*HB%}190EY%*=!28W4CL;|x7%etxGFG(BC+;jsfZ?{FJdT{HkUM&(q!F; z4@hX&5L!afxrkIT0gO8m-cHSK)H~@d@EfruDsT@TkO=TSE{zug2|X^A(`SrmKj7@> z$X#!X7vTN9LU2CX-z)Dx{#cMhpT(4WYO0<#whl~Z zM-Os_3A{@@lsM1VJ4sFYDajP#3~IGz#QTq^FTwE15GwCxyfS~ax?EX7O~ed-n&96k z8^|_P7p9HGB$*;0gEZrW_IAH=;NC@lN`q4va2RCC5kwct7o2 z`Sb{bfKAc=e@#;YDCH9eDIkU9QNdoHPxAeS>kdKuAb0+jBIgaBG}7W59N8w&wlX9B z@;GWZsUrQZTA|;8P&tAb&6&Zh<_y)R7;%17m6YVJNTAOhd9%+gsAs^_u@2xv3V_^B z>2gv@E657u9-^+qsyGkwIwclca}5V1G2678pAtJwC};BL9`HgCLuvCCzt(xsz_*;X z-tuBwXG=><^03eUjW^&>ef~M_V1hlu@qcRWJjhMUly{2%Ny{-*b&6S*7sXTNGc#{{ zd^Mb>@m8$#eyVsd$lH;#G~J$4NtvB8qo6+^`Ms}x*1;Ljih;% z&r5dtI(oSaOTE4o4k(i6?0Ou z#mhNMe0qj@SvRRGwM=Ug)J;d9j*(Fy)JOd#P=O}30W+I$cS*?3|? zZ$_zEwfb2(qnq9S>`!gHCc*6CbRKGQA7{9k&fm21cujXWo!OmuH=S4C(+p%ZWaaIz z+W6gx@mbL~KhsciSll~5-*CHI9G;(DJ`6FXLcIjkfe*i6tT}a}*&{VJ z*Gk)(>mJxlgJLyZ_h?hh9r-FOsH{fr0maqn^SUptzvj0zVK_N8*c0};wY%+DN-g84 z$4zV9w9eh?9vG`ujMyIS|HCzRe;xeSUvuNXgrHh#XpMH(E1+8ux+$?f(W4vj!YH-C zj(?!FWHzlMbL>L=v_V;s&3XoKw*Yr5-9%oY^+Y_7W^;iZFPaPoO~-2YY&dPb3pD%! z#vo@uR{O?=J+%`p*6*peek1WxuV%0d=zjRRhkC42ctKRWll;fA#)%Q;D>npnp7~o<4K-lTT&oGwmOrcbz{sdhVk3#rZFfU3lO8%Eh<-`PHT0 zeVvzg`J3Y%)6d`_BgWvneXt#2B20WwjB}Qw$EcVddQyh6jc&?^z&U`~)K)#DD zgV5O7g#{wVqLved-ebfc$q!nO93c51>xj1=n(rLvI9i1^33RzpfuY?+IEyN2NS`D1VeVl|Wk z(Sr+y--uBZ?n@A3*ARZ^Dudf!1)oO8uHfOT4_(ASt}qIBF}X-8X)i?=*!>IKfUG}= z8oq7lMamq@1!a5G2ZDgI`V88j8DyT_Py~Rj02kbVM+ey_ z+r67@zRF8nYz}^aQ$@0w6q8cfNJ;|S-nOEVwjw9m7aQB58|6STM9fJZhnSU10>fDf7g7~!%hemCzo zP$_G23YSiuR4z;-dfXgD4xGtnTW!4faYVBLL>fo5@8p?eHf(c_W`wYcIrc}MJRrpm zFI&2d!{Z&`8Z9C&T1=`0PEboV3u_rVAUmvV!8IoU;-5VMTZ6OS(+JJb1at%1a#Ac! z%QT0=Ab~<*ac$Zov+sw2jgwA*X3)IHbJ}{3ye|GZL1{w?qAhprZ=I!Uo+w?+am>*5 zMz~jO6VT2u3obe^B&}_O4C5MBbx;wR1i$5EBlm#kW_ntx{Tk5(*O`0NW$udSN8eqG_xl~al~ zluej6y=2Cw3d?-vag#RY_|2%c*Tn`b3M;tc0+tY?CiE%y`L#i5X?*sa4FlzP&d{_L zTs~BaTD|T({_qI_brN|uazxz>dOzxa7@D9O2Ua-Z-B0r8yN@uMVScZ4G=7r(R0M0) zx0|%Bj3!j6aJ=@j&}JBZGl;JBP~1#MWoWK{KGuplnGv<{)yW!h7rN4g>qKpnwg+gC z!VN3;8nkHd0J;(MbEu{ZYtQOb4wZHCBL0R4MvGV>N5y%3oA2@E^xxc)VFafs?P;NY zN<*HD!B%IUn%9SSIP-9=l7M#<+nq3dg?8I%x6KJu^*gau00DSf`3Ni4;nERC+$9+e zl^SQKw8}6A2B*m^Woq}cqf)aLNx#g^vNHnKDw=WuPNNg`aC~&EIm9R{v0lj-#@Z08 za&oj(e$VWAvBAQu<}r@AexT`>86XxsI-u&S*9jq` zf2v2X=#!wukc!Tu%hpLi%$@0e^G;bwB-aW ziHU{z^vYHNTh)hns}d(#)jPO$(NDx$baN0}(N}|bD|FIG;-sf;4w~^!^l}S&vD={u z7vP$4@Ro7#OXJ|`F<7ch%GWzP)m36X-hu2r(#|CFGxnaEVzGE%O_5mSNC+1yROWVA zq=Vu2vIxPYaqF<@!2fls4=^ls7$_LP*Z&$NS|!ByJPVV@(> z%`^mu8#(RdHrYBq^B zY*RF50jaHFE4CVM@tcBDB&G1VP?=)DhEP<6MUZCTcY1;9=U#{&gNq5&g^nv)fNRk` zUu-(laXvK99|GehQ#OS|M_YjhdZ{R9a=O|IgnXG7WVv+*to_D^;!Z*ObxKKb)xIj3 zam9mMH5$LPxh96}j`S+G#@wS}e=*y4M8h`r8}Hco%U&r(H?efN?+6gaFi~$KZAoYB zj!)cN56gy<9LbLuwtOV%2+Q&bK53=}qT)@tm9N*nR3BcO^#S~C0;fyIsEj`QqRXxl6Rlp^HG(GSY z03Y=LDyWSrW=>tW4!mubfa}Im#I6xY5dxk^RRre3bH%6dJaImf3AV&n#BeSKjY0hD*0ZznPD8P^Fk zu>;3fzNI}!Ju1@&@Z|H)I3IRhkLACHg5DEmxpOwezgX|IufVMDJA8674e8?h7 zKg%*|mIS57EL2G|IXqGzdD8gSgYn=6;o$fegM5*nVR%b7|6A$?uIJoKP}?BCp$VD2 zcuRauyj7){TY5Dm%?@S*l5ZO&-0N-X9MJhSZk@ol4Su@@5G2V2cvWa*R)86NkbvCl z_={aM5m~C}Nh@rkg)WXQ>&&>s$d=<`u>=>1#kf!`f=d^IP6`~U;gT#RC0wi|g^QHO zwXJB3m9k5Jm^3H&$6v`_^&nBt2{j@QVxnpjbbhK^xf$Ou|p8$|Zgj?DK= ztkMmuZ>F;F!a2lfMpM~QBg=o@BYmLH(!emPpQyQdTGA#LXvEXfjO2-lZ=F5}2^roN zPSY&Ol)G&1tg^)m%VyEXmuSJIVub*awATwggI@0zus=Sarn(Vz-2hrPiv7@y1&j1* WLXOmyJ2#bTThW5LX$35&oc{swZsAw} diff --git a/bin/kernal_generic.rom b/bin/kernal_generic.rom index 1b49889fe850832dd8eb58ebd37f72980c1978c7..2832244e184841b1acafa67063c18f796ee83d4f 100644 GIT binary patch delta 4100 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 Av;Y7A diff --git a/bin/kernal_ultimate64.rom b/bin/kernal_ultimate64.rom index b0d12b364f7eaa373496c56bcc807390c07454d5..cc5536964f79a57a6c96e751a8bf86db5d567c4a 100644 GIT binary patch delta 3964 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 F{{oVLcQXJ0 delta 4012 zcmb_feN&6Qj=tk<%3x7GG+-m+TS>}(&~iOnsr z#8kk3x=Ho=$)?%qBDqa_qju!+H_R(HW6SQcW#^+>wZBxMM0<{CXY<+H zM1sA8T`DYO7qN?lTsDtg!Vm<3vJblniNak??otPZKkdhdnt=SDpY8C55?h-{yi1U1 zNJR;UMU&lx+EkGIvPiN!M3r4(Cl0*~d|VgZ^PoF>(Vb_d-76e1U58#)7P*mn* zHhhQLRpe5w6kh$E#_A&(Rb6Z$NOzvJwMD0OoAL7R&^Mn5NeYFxI)y}c6s>nqxa4ss z+XmZlv_m9*#Dq7Y&M9_w!nH|BM6If1LSIdhY6-FnH(g{v1{~#yiacXGJmIu@Ng4$) zBGK4pXW$*$y{<6f;<52x&Emo_X~3CutMtqF*BMObAgK}rKkgjm2@ zU3zP>NWcc3C||{sy?ZSS4pLpeAEiYT2LC$8TAAhmYgL%B=x@|NW-&RzfW+{HKf&#L52 z{V`I^0pV-?IVGY7XLxG*Vin2QzECM_Pv?dsvTwaNz`n~kw~!KrcZ@i+sLm^BB` zy+c6RIpR16zC3x&aSEmS9jAe$^Eti{8MXlte#htNQ5Cgvt0On04Ed1n8i59G#4#|eH~`@^1h30*fG6m%AY4xIaKbWhMR zj_e8|bnD)R>GB~|FeLeb(u|(qMvb@pwxLx?nzBw^KyZRaL053?R6j1ig6e{3zlvm4 z&}Gqz5p5X&o-V~8xFiZ~9l)>3yKe=HSrgD-$Dntlq3SV_upr6Iz(}*@^V9N5;LHie zXvNV(_EbKT5fQvbjD?1O5kGgCSF4C#riJLE$F(+ZoZ+W+(-RDOasa=6JyxaQk6}M9 zbC$O;D8+Z^lp8Tb6m3SCdHItQ7j3H)ZJC0^1S zX-mAsWkhF1i=`3?dyc~n?l;jd#h@TOwjp5b$KVMUqLua!A;Vv=Kfz$_OW< zc;PE476hDRzXB@&Se(>65O##kV=Q1BG;hR&U%QVZ)_IFU+q0n#VBSB4TjL&*U%TCOuT=(kDs1H^ldVAOCc0Bfv$wmY3`}m1to9z ziVmQqS8&7x+@reaKv6T8^;yr&iRLA?iDPd$#;|PyJr{O>5KM#CK-tmq4*P7Y!I?|=$3++AQ@ER6C>daI_h)K=(OU9KH4N1DzaXc zE}5Bp<}Ymd>lIruQ9wNStNT_E`2LM|ttATP5d@{5W&#^IpCR3h6scvex)J@9{=vX= zyf7WKOOb^Oa9 z^s&-O+2gr<+2a|8FXS2VbCbzSxIfV8Bm`*{ZQUk&Tp1Dt8tW=ML-!-uQ$b%7dX%2d z9x;PGBYlY%dkCRZBJ-J+mq;xvZkq&;Ff)Wu3&%EIoATYKhVkb^SWt_@k+a5I2wn!t z&HA<()p)s`@#|(d0uC>GHmrMLubYCi+1IDee#Bjj&n`LT)tE<2R3g0>o_&u79*Svd z$1?#prG)jejbv-X;-P^6hE~h7b=m;G9r!OCQl>cEGVmh~d-1Xn?LbrDhsa6_7!i*1 zfpABr23z5XjOOeKvrR(Nx`XUNrtzGj7ZY&?_hkZ#ls#o2o&v zi`+U%&p(L(SBNSkU7{!WNa$rrVYD1K&f(-+=Jt7-iw;ya?m?>*$Y{JQbSe^fwL4ZS zKwUxbY;=ONCL>)6cPKf%B;Z$Ky6F(=9)=bCz_s?sKy&-3U#SDiCF!bQqa#EW5`#!E z9iN}f&qFs+MVYD;XsAW-9PiDtVUCw^)7D5gqd+W~8Sx0a3;oXT$m3o1i1IxE%x+SW zE2PoJJ>8NIR=7e!<0GD{xf9`8R6l^QkE`4URlvYTvT2Md~EFb z$9XydJrWX;?Uc4cp)EH6q=Ym1mowQju)yUcr`-*Ha**B6?z6vv&iEY#sMQCF&N{QL zA6b_+?h`tojJPBm)!OoXuxL#NY=51StM{wysj94=t#E4Xf?T&He)d)_U!}6%usJ(JqLfZCoz;RONwo{Xmr S*n4?`SyRAzzq|4Lz`p^vI%PZn diff --git a/bin/mega65.rom b/bin/mega65.rom index 9db5831430c4dffab969e7dec698e0d9e6bcde6c..9c3bd27bcba297833d9d9931119f951152dd515a 100644 GIT binary patch delta 7890 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 delta 6587 zcmcgQdt4J&x-%0(0;og;jrcl(74TJj7Ohs>s-@erTifkc2_R!zEq3YMM}K$M(pqrK zP}VIpc&zo&M;bHHp$ko9TPHjOMJeHGI~JE#Dl0`nuvG_wglDqf3GUs!uYd1A&f`1Z zcg}ad_e^fCJ~vlySvPKZ`b%juQWk8c8LFEgAE( zOy&qw62OZ_pQcMpAySMyjDXUthZUm~to)EfcO{3nEaG5`#w{Bc!{S}H%Mk`g6evCQ z)yfY>USfqKQjTy8ZA^8?w{-$RE} z-JEi>KegXxas%Cro&8x_AukzDb42wL09NMv6=+Yz^r$&EQU? z6J6@YWw7Tez!yI}_mLV$cjg?^(EVFg9RMAZ&Ed4u{g++5>10o8Y|gQ*s4>-{M;~rQ z*VEuQ*@vsP(ph)9qu0VXPq?+7BG%2SdbdWo2m*2e3VJ2OaSr`86_~o7R{kp%o%S{D zWa&b8dO6SHo(!>EI4hnI>Ui<2a7L^XPV?w#6MDmh_LpbnQH$>JwNcC~ziF!kJ%M!>iLwAf!fvS7ZxAS&0#jpr55VhJgw( z0d-xg18$T%04Ra;t{?F`c&)VFtuo%C(zgahT15lA6?2I+tVKo{bC60s&5GCQ;8!TP4}9RGK4P=A+HH{ z46RAgrueoxQl_RKP5E7llRavTM88W(5+CT8Um_-TEI_Z=tuc5iDckihr&N=kT~X|_ zMEB~9rTP?!pqK2@+ZGe5-(uw~v(dN?30qR>Oba50*)J?LW3vdDAt%}VYS!!!ll_vC z;P$Jr?i};%l4O&VE-aT)g%x`fa!M?I#FOi<=9TZvcC&aW&CMuJiDAmrE>Q=%)JXmX zlCKdRNULTzXmMMbP48mZknlqc+o=bshTU7pOB$;HZHc%^wflKHH`LdABaTEu;f;!mtW7hZw@(g z>L+lqMHP$4A8ZvfEMcw>jTg+BTWB*2(y64do2KMLrOx8>3WFr=GRzN*T_*&a>u0cZR2GHHxSr7scsZ zOC`A@PK!0QiMn%oRfAX;7DUi>Hc0z5=+_7jNq%7!ZgCc~QRLCKD3W52+Y+VXedXv* z51MiV2IBmrZdS+^7j!eiYdjETqRV!x?z89K-P~vxgfaYEG*-s=*>nHC`Q7Kb3Jm>X z=Ju^ZrkJU4;61nOo!i81h910?M4yTWIYg7_W6yFIs>pATE$24a%cWz>xcEEm;x;tW zF7Bkw-0oaqu0t=zbu;EKg*Y*;$udElD{Mn|+KIL#jVrDo&zG2Bt0#*M5#=*K$>nl* z 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 delta 6587 zcmcgQdt4J&x-%0(0;og;jrcl(74TJj7Ohs>s-@erTifkc2_R!zEq3YMM}K$M(pqrK zP}VIpc&zo&M;bHHp$ko9TPHjOMJeHGI~JE#Dl0`nuvG_wglDqf3GUs!uYd1A&f`1Z zcg}ad_e^fCJ~vlySvPKZ`b%juQWk8c8LFEgAE( zOy&qw62OZ_pQcMpAySMyjDXUthZUm~to)EfcO{3nEaG5`#w{Bc!{S}H%Mk`g6evCQ z)yfY>USfqKQjTy8ZA^8?w{-$RE} z-JEi>KegXxas%Cro&8x_AukzDb42wL09NMv6=+Yz^r$&EQU? z6J6@YWw7Tez!yI}_mLV$cjg?^(EVFg9RMAZ&Ed4u{g++5>10o8Y|gQ*s4>-{M;~rQ z*VEuQ*@vsP(ph)9qu0VXPq?+7BG%2SdbdWo2m*2e3VJ2OaSr`86_~o7R{kp%o%S{D zWa&b8dO6SHo(!>EI4hnI>Ui<2a7L^XPV?w#6MDmh_LpbnQH$>JwNcC~ziF!kJ%M!>iLwAf!fvS7ZxAS&0#jpr55VhJgw( z0d-xg18$T%04Ra;t{?F`c&)VFtuo%C(zgahT15lA6?2I+tVKo{bC60s&5GCQ;8!TP4}9RGK4P=A+HH{ z46RAgrueoxQl_RKP5E7llRavTM88W(5+CT8Um_-TEI_Z=tuc5iDckihr&N=kT~X|_ zMEB~9rTP?!pqK2@+ZGe5-(uw~v(dN?30qR>Oba50*)J?LW3vdDAt%}VYS!!!ll_vC z;P$Jr?i};%l4O&VE-aT)g%x`fa!M?I#FOi<=9TZvcC&aW&CMuJiDAmrE>Q=%)JXmX zlCKdRNULTzXmMMbP48mZknlqc+o=bshTU7pOB$;HZHc%^wflKHH`LdABaTEu;f;!mtW7hZw@(g z>L+lqMHP$4A8ZvfEMcw>jTg+BTWB*2(y64do2KMLrOx8>3WFr=GRzN*T_*&a>u0cZR2GHHxSr7scsZ zOC`A@PK!0QiMn%oRfAX;7DUi>Hc0z5=+_7jNq%7!ZgCc~QRLCKD3W52+Y+VXedXv* z51MiV2IBmrZdS+^7j!eiYdjETqRV!x?z89K-P~vxgfaYEG*-s=*>nHC`Q7Kb3Jm>X z=Ju^ZrkJU4;61nOo!i81h910?M4yTWIYg7_W6yFIs>pATE$24a%cWz>xcEEm;x;tW zF7Bkw-0oaqu0t=zbu;EKg*Y*;$udElD{Mn|+KIL#jVrDo&zG2Bt0#*M5#=*K$>nl* z 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 Date: Sun, 21 Jun 2020 18:16:38 +0200 Subject: [PATCH 057/103] new text compression and tokeniser - faster, about 100 bytes saved --- Makefile | 33 +- c64/,,config_custom.s | 6 +- .../{packed_keywords.s => packed_as_1n.s} | 5 +- .../assets/{packed_chars.s => packed_as_3n.s} | 5 +- .../{packed_tokens.s => packed_str_errors.s} | 5 +- c64/basic/assets/packed_str_keywords_V2.s | 9 + .../{packed_words.s => packed_str_misc.s} | 5 +- c64/basic/basic_commands/cmd_stop_end.s | 8 +- c64/basic/basic_main_loop.s | 4 +- .../board_m65/4000.mega65_vectable_basic_1.s | 20 +- c64/basic/engine/do_error.s | 10 +- c64/basic/init/basic_warm_start_internal.s | 4 +- c64/basic/init/initmsg_bytes_free.s | 4 +- c64/basic/pack_word.s | 260 ----- c64/basic/print/list_single_line.s | 14 +- c64/basic/print/print_packed_message.s | 244 ----- c64/basic/print/print_packed_string.s | 182 ++++ c64/basic/tokenise_line.s | 306 ------ c64/basic/tokenizer/tk_pack.s | 228 ++++ c64/basic/tokenizer/tk_search.s | 93 ++ c64/basic/tokenizer/tk_shorten.s | 112 ++ c64/basic/tokenizer/tokenise_line.s | 176 ++++ tools/generate_strings.cc | 987 ++++++++++++++++++ tools/{ => outdated}/compress_text.c | 0 24 files changed, 1848 insertions(+), 872 deletions(-) rename c64/basic/assets/{packed_keywords.s => packed_as_1n.s} (75%) rename c64/basic/assets/{packed_chars.s => packed_as_3n.s} (74%) rename c64/basic/assets/{packed_tokens.s => packed_str_errors.s} (72%) create mode 100644 c64/basic/assets/packed_str_keywords_V2.s rename c64/basic/assets/{packed_words.s => packed_str_misc.s} (74%) delete mode 100644 c64/basic/pack_word.s delete mode 100644 c64/basic/print/print_packed_message.s create mode 100644 c64/basic/print/print_packed_string.s delete mode 100644 c64/basic/tokenise_line.s create mode 100644 c64/basic/tokenizer/tk_pack.s create mode 100644 c64/basic/tokenizer/tk_search.s create mode 100644 c64/basic/tokenizer/tk_shorten.s create mode 100644 c64/basic/tokenizer/tokenise_line.s create mode 100644 tools/generate_strings.cc rename tools/{ => outdated}/compress_text.c (100%) diff --git a/Makefile b/Makefile index 7f0b7ccb..d65bbff7 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ SRCDIR_BASIC = $(SRCDIR_COMMON) \ c64/basic/math_mov \ c64/basic/print \ c64/basic/rom_revision \ + c64/basic/tokenizer \ c64/basic/wedge SRCDIR_KERNAL = $(SRCDIR_COMMON) \ @@ -54,7 +55,7 @@ SRC_TOOLS = $(wildcard tools/*.c,tools/*.cc) # Generated files -GEN_BASIC = build/,generated/packed_messages.s build/,generated/float_constants.s +GEN_BASIC = build/,generated/packed_strings.s build/,generated/float_constants.s GEN_KERNAL = # List of build directories @@ -68,12 +69,12 @@ DIR_X16 = build/target_cx16 # List of config files -CFG_CUS = c64/,,config_custom.s -CFG_GEN = c64/,,config_generic.s -CFG_TST = c64/,,config_testing.s -CFG_M65 = c64/,,config_mega65.s -CFG_U64 = c64/,,config_ultimate64.s -CFG_X16 = c64/,,config_cx16.s +CFG_CUS = c64/,,config_custom.s +CFG_GEN = c64/,,config_generic.s +CFG_TST = c64/,,config_testing.s +CFG_M65 = c64/,,config_mega65.s +CFG_U64 = c64/,,config_ultimate64.s +CFG_X16 = c64/,,config_cx16.s # Dependencies - helper variables @@ -83,8 +84,8 @@ DEP_KERNAL = $(SRC_KERNAL) $(SRCDIR_KERNAL) $(GEN_KERNAL) # List of tools TOOL_COLLECT_DATA = build/tools/collect_data -TOOL_COMPRESS_TEXT = build/tools/compress_text TOOL_GENERATE_CONSTANTS = build/tools/generate_constants +TOOL_GENERATE_STRINGS = build/tools/generate_strings TOOL_PATCH_CHARGEN = build/tools/patch_chargen TOOL_PNGPREPARE = build/tools/pngprepare TOOL_BUILD_SEGMENT = build/tools/build_segment @@ -166,19 +167,15 @@ updatebin: $(TOOL_PNGPREPARE): tools/pngprepare.c @mkdir -p build/tools - $(CC) -O2 -Wall -I/usr/local/include -L/usr/local/lib -o $@ $< -lpng - -$(TOOL_COMPRESS_TEXT): tools/compress_text.c - @mkdir -p build/tools - $(CC) -O2 -Wall -I/usr/local/include -L/usr/local/lib -o $@ $< -lm + $(CC) -O2 -g -Wall -I/usr/local/include -L/usr/local/lib -o $@ $< -lpng build/tools/%: tools/%.c @mkdir -p build/tools - $(CC) -O2 -Wall -o $@ $< + $(CC) -O2 -g -Wall -o $@ $< build/tools/%: tools/%.cc tools/common.h @mkdir -p build/tools - $(CXX) -O2 -Wall -o $@ $< + $(CXX) -O2 -g -Wall -o $@ $< # Rules - CHARGEN @@ -258,9 +255,9 @@ build/symbols_ultimate64.vs: $(DIR_U64)/BASIC_combined.vs $(DIR_U64)/KER # Rules - BASIC and KERNAL intermediate files -build/,generated/packed_messages.s: $(TOOL_COMPRESS_TEXT) +build/,generated/packed_strings.s: $(TOOL_GENERATE_STRINGS) @mkdir -p build/,generated - $(TOOL_COMPRESS_TEXT) > build/,generated/packed_messages.s + $(TOOL_GENERATE_STRINGS) -o build/,generated/packed_strings.s build/,generated/float_constants.s: $(TOOL_GENERATE_CONSTANTS) @mkdir -p build/,generated @@ -441,7 +438,7 @@ test_ultimate64: build/kernal_ultimate64.rom build/basic_ultimate64.rom build/sy 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) $(TARGET_M65_x_PXL) - ../xemu/build/bin/xmega65.native -dmarev 2 -forcerom -loadrom $(TARGET_M65_x_PXL) + ../xemu/build/bin/xmega65.native -dmarev 2 -besure -fontrefresh -forcerom -loadrom $(TARGET_M65_x_PXL) test_cx16: $(TARGET_X16_x) ../x16-emulator/x16emu -rom $(TARGET_X16_x) diff --git a/c64/,,config_custom.s b/c64/,,config_custom.s index 84c60ab8..e023c716 100644 --- a/c64/,,config_custom.s +++ b/c64/,,config_custom.s @@ -46,8 +46,8 @@ // I/O devices #define CONFIG_IEC -// #define CONFIG_IEC_DOLPHINDOS -// #define CONFIG_IEC_DOLPHINDOS_FAST +#define CONFIG_IEC_DOLPHINDOS +#define CONFIG_IEC_DOLPHINDOS_FAST #define CONFIG_IEC_JIFFYDOS // #define CONFIG_IEC_JIFFYDOS_BLANK // #define CONFIG_IEC_BURST_CIA1 // please keep disabled for now @@ -124,7 +124,7 @@ #define CONFIG_PANIC_SCREEN #define CONFIG_DOS_WEDGE #define CONFIG_TAPE_WEDGE -#define CONFIG_TAPE_HEAD_ALIGN +// #define CONFIG_TAPE_HEAD_ALIGN #define CONFIG_BCD_SAFE_INTERRUPTS diff --git a/c64/basic/assets/packed_keywords.s b/c64/basic/assets/packed_as_1n.s similarity index 75% rename from c64/basic/assets/packed_keywords.s rename to c64/basic/assets/packed_as_1n.s index 82229cde..ba42d331 100644 --- a/c64/basic/assets/packed_keywords.s +++ b/c64/basic/assets/packed_as_1n.s @@ -3,6 +3,7 @@ // #LAYOUT# X16 BASIC_0 #TAKE // #LAYOUT# * * #IGNORE -packed_keywords: - put_packed_keywords() +packed_as_1n: + + put_packed_as_1n() diff --git a/c64/basic/assets/packed_chars.s b/c64/basic/assets/packed_as_3n.s similarity index 74% rename from c64/basic/assets/packed_chars.s rename to c64/basic/assets/packed_as_3n.s index 985ca369..27e7f9e3 100644 --- a/c64/basic/assets/packed_chars.s +++ b/c64/basic/assets/packed_as_3n.s @@ -3,6 +3,7 @@ // #LAYOUT# X16 BASIC_0 #TAKE // #LAYOUT# * * #IGNORE -packed_message_chars: - put_packed_chars() +packed_as_3n: + + put_packed_as_3n() diff --git a/c64/basic/assets/packed_tokens.s b/c64/basic/assets/packed_str_errors.s similarity index 72% rename from c64/basic/assets/packed_tokens.s rename to c64/basic/assets/packed_str_errors.s index 0a2709a2..4582fb54 100644 --- a/c64/basic/assets/packed_tokens.s +++ b/c64/basic/assets/packed_str_errors.s @@ -3,6 +3,7 @@ // #LAYOUT# X16 BASIC_0 #TAKE // #LAYOUT# * * #IGNORE -packed_message_tokens: - put_packed_tokens() +packed_str_errors: + + put_freq_packed_errors() diff --git a/c64/basic/assets/packed_str_keywords_V2.s b/c64/basic/assets/packed_str_keywords_V2.s new file mode 100644 index 00000000..5247b32e --- /dev/null +++ b/c64/basic/assets/packed_str_keywords_V2.s @@ -0,0 +1,9 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +packed_str_keywords_V2: + + put_freq_packed_keywords_V2() diff --git a/c64/basic/assets/packed_words.s b/c64/basic/assets/packed_str_misc.s similarity index 74% rename from c64/basic/assets/packed_words.s rename to c64/basic/assets/packed_str_misc.s index 515892e6..bceadcdf 100644 --- a/c64/basic/assets/packed_words.s +++ b/c64/basic/assets/packed_str_misc.s @@ -3,6 +3,7 @@ // #LAYOUT# X16 BASIC_0 #TAKE // #LAYOUT# * * #IGNORE -packed_message_words: - put_packed_words() +packed_str_misc: + + put_freq_packed_misc() diff --git a/c64/basic/basic_commands/cmd_stop_end.s b/c64/basic/basic_commands/cmd_stop_end.s index ee1a5768..95fd5091 100644 --- a/c64/basic/basic_commands/cmd_stop_end.s +++ b/c64/basic/basic_commands/cmd_stop_end.s @@ -4,8 +4,8 @@ cmd_stop: - ldx #30 // "BREAK" - jsr print_packed_message + ldx #IDX__EV2_1E // "BREAK" + jsr print_packed_error // Are we in direct mode lda CURLIN+1 @@ -13,8 +13,8 @@ cmd_stop: beq !+ // Not direct mode - ldx #31 - jsr print_packed_message + ldx #IDX__STR_IN + jsr print_packed_misc_str lda CURLIN+1 ldx CURLIN+0 diff --git a/c64/basic/basic_main_loop.s b/c64/basic/basic_main_loop.s index fd4dede5..06179538 100644 --- a/c64/basic/basic_main_loop.s +++ b/c64/basic/basic_main_loop.s @@ -6,8 +6,8 @@ basic_main_loop: // Tell user we are ready - ldx #30 - jsr print_packed_message + ldx #IDX__STR_READY + jsr print_packed_misc_str // Enable Kernal messages lda #$80 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 e69e0332..25c233d0 100644 --- a/c64/basic/board_m65/4000.mega65_vectable_basic_1.s +++ b/c64/basic/board_m65/4000.mega65_vectable_basic_1.s @@ -11,13 +11,15 @@ // Label definitions - .label VB1__INITMSG = $4000 + 2 * 0 - .label VB1__LINKPRG = $4000 + 2 * 1 - .label VB1__tokenise_line = $4000 + 2 * 2 - .label VB1__list_single_line = $4000 + 2 * 3 - .label VB1__print_packed_message = $4000 + 2 * 4 - .label VB1__basic_do_clr = $4000 + 2 * 5 - .label VB1__basic_do_new = $4000 + 2 * 6 + .label VB1__INITMSG = $4000 + 2 * 0 + .label VB1__LINKPRG = $4000 + 2 * 1 + .label VB1__tokenise_line = $4000 + 2 * 2 + .label VB1__list_single_line = $4000 + 2 * 3 + .label VB1__print_packed_error = $4000 + 2 * 4 + .label VB1__print_packed_misc_str = $4000 + 2 * 5 + .label VB1__print_packed_keyword_V2 = $4000 + 2 * 6 + .label VB1__basic_do_clr = $4000 + 2 * 7 + .label VB1__basic_do_new = $4000 + 2 * 8 #else @@ -27,7 +29,9 @@ .word LINKPRG .word tokenise_line .word list_single_line - .word print_packed_message + .word print_packed_error + .word print_packed_misc_str + .word print_packed_keyword_V2 .word basic_do_clr .word basic_do_new diff --git a/c64/basic/engine/do_error.s b/c64/basic/engine/do_error.s index 6947ca0b..1d0c153e 100644 --- a/c64/basic/engine/do_error.s +++ b/c64/basic/engine/do_error.s @@ -151,10 +151,10 @@ do_basic_error: // error code in .X // Error message text + " ERROR" - jsr print_packed_message + jsr print_packed_error - ldx #33 - jsr print_packed_message + ldx #IDX__STR_ERROR + jsr print_packed_misc_str // Check if direct mode @@ -164,8 +164,8 @@ do_basic_error: // error code in .X // We were in a program, so show IN - ldx #31 - jsr print_packed_message + ldx #IDX__STR_IN + jsr print_packed_misc_str lda CURLIN+1 ldx CURLIN+0 diff --git a/c64/basic/init/basic_warm_start_internal.s b/c64/basic/init/basic_warm_start_internal.s index f9ad47c0..79257cd1 100644 --- a/c64/basic/init/basic_warm_start_internal.s +++ b/c64/basic/init/basic_warm_start_internal.s @@ -19,8 +19,8 @@ basic_warm_start_real: ora CMP0+1 beq !+ - ldx #32 - jsr print_packed_message + ldx #IDX__STR_BRK_AT + jsr print_packed_misc_str lda CMP0+1 jsr print_hex_byte diff --git a/c64/basic/init/initmsg_bytes_free.s b/c64/basic/init/initmsg_bytes_free.s index 0093c12a..b277340f 100644 --- a/c64/basic/init/initmsg_bytes_free.s +++ b/c64/basic/init/initmsg_bytes_free.s @@ -21,5 +21,5 @@ initmsg_bytes_free: jsr print_integer // Print rest of the start up message - ldx #34 - jmp print_packed_message + ldx #IDX__STR_BYTES + jmp print_packed_misc_str diff --git a/c64/basic/pack_word.s b/c64/basic/pack_word.s deleted file mode 100644 index d975ca38..00000000 --- a/c64/basic/pack_word.s +++ /dev/null @@ -1,260 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# M65 BASIC_1 #TAKE -// #LAYOUT# X16 BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - -// Pack a word using the simple compression scheme. -// This has to be the same implementation as in compress_text.c -// because we compress input lines of BASIC to do the tokenisation. -// This allows us to search through the compressed tokens directly -// using the compressed fragment of BASIC, and thus work out the -// token for a given piece of string. -// This also helps ensure that we have an implementation that is totally -// different to that of the original C64 BASIC, as well as likely -// saving a bit of space in the ROM, especially once we start implementing -// larger keyword vocabs for BASIC 7 or BASIC 10 compatibility, since the -// compression and decompression machinery is of fixed size. - -pack_word: - // Inputs: - // X = offset of string to pack. Address is $0200 + X - // __tokenise_work1 = number of bytes to pack - // __tokenise_work2 = packed length of string - - // Outputs: - // Output is written to $0100 (bottom of stack). - - // Memory modified: - // __tokenise_work4 = temporary storage - // __tokenise_work3 = flag for whether we have a nybl prepared or not. - // (This can also be checked on exit, to know whether the last byte - // is incomplete, which is important for searching for abbreviated - // key words.) - - - // Make sure we have a sane request - lda __tokenise_work1 - bne !+ - sec - rts -!: - // Initialise internal variables - lda #$00 - sta __tokenise_work2 - sta __tokenise_work3 - -pack_char_loop: - - // Get the next char - lda $0200,x - - // Work out what type of character we have, and thus - // how we need to pack it. - jsr get_packed_char_index - - cmp #$00 - bne not_exception_char - - // Char is an exception char. - // We need to either finish the previous byte with $xF, - // Or if there is no existing nybl, then we need to output - // either $FE or $FF, depending on whether this is the last - // byte or not - - lda __tokenise_work3 - bne have_nybl_before_exception_char - - // No nybl exists before the exception char, so prefix with $FE or $FF - // based on whether we are at the end of the input string or not - inx - lda __tokenise_work1 - cmp #$01 - beq at_end - lda #$FF - .byte $2C -at_end: - lda #$FE - dex - jsr write_unpacked_char - // Fall through - -output_exception_byte: - lda $0200,x - jsr write_unpacked_char - jmp consider_next_char - -have_nybl_before_exception_char: - // Or existing byte with #$0F, and clear nybl flag - ldy __tokenise_work2 - lda $0100,y - ora #$0f - sta $0100,y - inc __tokenise_work2 - - // FALL THROUGH - -write_literal_and_terminate_if_required: - - // Clear have nybl flag - lda #$00 - sta __tokenise_work3 - - lda $0200,x - jsr write_unpacked_char - - jmp end_string_if_required - -end_string_if_required: - // Check if X points to last char of string to be packed - inx - lda __tokenise_work1 - cmp #$01 - beq !+ - dex - jmp consider_next_char -!: - dex - // Fall through - -end_string: - // Write end of string sequence if required - lda #$00 - jsr write_unpacked_char - rts - -write_unpacked_char: - ldy __tokenise_work2 - sta $0100,y - iny - sty __tokenise_work2 - rts - -not_exception_char: - // It wasn't an exception char, so write the symbol out - cmp #$10 - bcs whole_byte_symbol - - // Nybl encoded value: Put in upper half or lower half of a byte? - ldy __tokenise_work3 - bne store_low_nybl - - // Store in high nybl -- so shift it into the hi nybl - asl - asl - asl - asl - ldy __tokenise_work2 - sta $0100,y - bne stored_nybl // Must be taken, as A cannot be $00 - -store_low_nybl: - // Low nybl gets added to high nybl already stored in the byte - ldy __tokenise_work2 - ora $0100,y - sta $0100,y - -stored_nybl: - // Now toggle the nybl flag - lda __tokenise_work3 - eor #$ff - sta __tokenise_work3 - // And advance the offset if we filled this byte up - bne consider_next_char // Taken if byte has a nybl free, i.e., don't advance pointer while half byte remains free - - // Count the filled up byte - inc __tokenise_work2 - - // Add termination byte if required - // (This re-writes the same byte again, which we don't care about) - jmp end_string_if_required - -whole_byte_symbol: - // It's a $Fx symbol. - // But if we have a nybl to flush, then we handle it like - // a full exception character - - ldy __tokenise_work3 - beq nothing_to_flush - - // Set low nybl to $F to mark next byte as literal - ldy __tokenise_work2 - lda $0100,y - ora #$0f - sta $0100,y - inc __tokenise_work2 - - jmp write_literal_and_terminate_if_required - -nothing_to_flush: - // Write the symbol as it is, or the literal - // if it has been passed to us via fall-through - jsr write_unpacked_char - - jmp end_string_if_required - -consider_next_char: - // Pack next char - inx - dec __tokenise_work1 - beq !+ - jmp pack_char_loop -!: - // Add 1 to length if nybl waiting to be flushed - // (but leave flag set so the caller knows if the - // bottom nybl might be different if the string were - // longer). - lda __tokenise_work3 - beq !+ - inc __tokenise_work2 - rts -!: - // Last byte was full, so we need at $00 on the end - // (unless a $FE token was written 2 bytes ago) - ldy __tokenise_work2 - iny - lda #$00 - sta $0100,y - inc __tokenise_work2 - - rts - -get_packed_char_index: - // Find char in A in the packed char list, and return - // $1 - $E, $F1 - $FD if the charactar is abbreviable, - // or else return $00 if the character has to be stored literally. - - // Y register and A are modified, as are processor flags. - - ldy #$00 -find_char_loop: - cmp packed_message_chars,y - bne not_a_match -enumerate: - // Is it a nybl abbreviable char? - cpy #14 - bcs not_nybl_char - // Yes, so add 1 and return it - iny - tya - rts - -not_nybl_char: - cpy #27 - bcs not_a_match - // It's a $Fx character. - // Since the lowest index is $E, and it should be encoded as $F1 - // we need to add $E3 - tya - clc - adc #$E3 - rts - -not_a_match: - iny - // Loop until we find it, or we discover it isn't - // a character with a special encoding - cpy #27 - bne find_char_loop - // Not a char that we can pack, so return 0 - lda #$00 - rts diff --git a/c64/basic/print/list_single_line.s b/c64/basic/print/list_single_line.s index 64e6b2b4..cf13147b 100644 --- a/c64/basic/print/list_single_line.s +++ b/c64/basic/print/list_single_line.s @@ -86,22 +86,16 @@ list_not_quote: pha phy_trash_a - // Get pointer to compressed keyword list - lda #packed_keywords - sta FRESPC+1 - - // Subtract $80 from token to get offset in word - // list + + // Subtract $80 from token to get offset in token list txa and #$7f tax // Now ask for it to be printed - ldy #$ff - jsr packed_word_search + jsr print_packed_keyword_V2 + // Restore registers ply_trash_a pla diff --git a/c64/basic/print/print_packed_message.s b/c64/basic/print/print_packed_message.s deleted file mode 100644 index 7a062e6a..00000000 --- a/c64/basic/print/print_packed_message.s +++ /dev/null @@ -1,244 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# M65 * #TAKE -// #LAYOUT# X16 BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - -// This routine prints messages that have been packed -// using the make_error_tables program. -// The general idea is to save space in the ROM. - -// The output of make_error_tables is written to packed_messages.s, and -// contains the following: -// -// packed_message_words - List of nybl packed words. -// packed_message_tokens - List of tokens that get joined to make messages -// packed_message_chars - List of characters in messages sorted by frequency. - - -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: - iny - cpx #$00 - beq found_message_in_token_stream - lda packed_message_tokens,y - cmp #$ff - bne !+ - dex -!: - cpy #$ff - bne packed_message_search - // Could not find message - sec - rts - -found_message_in_token_stream: // XXX size-optimize this - // Now print each word in the message - phy_trash_a - lda packed_message_tokens,y - cmp #$FF - beq found_message_in_token_stream_done - - jsr print_packed_word - ply_trash_a - iny - beq found_message_in_token_stream_done -!: - phy_trash_a - lda packed_message_tokens,y - cmp #$FF - beq found_message_in_token_stream_done - - pha - jsr print_space - pla - - jsr print_packed_word - ply_trash_a - iny - bne !- - -found_message_in_token_stream_done: - pla - rts - -print_packed_word: - // A = the word to print - tax - - // Setup pointer to packed words - lda #packed_message_words - sta FRESPC+1 - - // Find the word in the list - ldy #$ff -packed_word_search: - iny - cpx #$00 - beq found_packed_word - - // $x0 is an end of work marker - lda (FRESPC),y - and #$0f - cmp #$00 - bne !+ - dex -!: - // $FE $xx is an end of work marker - lda (FRESPC),y - cmp #$fe - bne !+ - dex - iny // skip next byte -!: - cmp #$ff - bne !+ - iny // skip next byte -!: - - // Advance to next page if required - cpy #$ff - bne packed_word_search - inc FRESPC+1 - jmp packed_word_search - -found_packed_word: - - // Get pointer to start of packed word - // Make sure we do not wrap on a page boundary - tya - clc - adc FRESPC+0 - sta FRESPC+0 - lda FRESPC+1 - adc #$00 - sta FRESPC+1 - -print_packed_string: - ldy #$ff - -next_packed_word_char: - // .Y = offset into packed word data - 1 - iny - - // Check for end of word - lda (FRESPC),y - cmp #$00 - beq end_of_packed_word - cmp #$fe - beq last_literal - cmp #$ff - beq next_is_literal_char - and #$f0 - beq end_of_packed_word - - // Check if it is an uncommon char - lda (FRESPC),y - and #$f0 - cmp #$f0 - beq is_uncommon_char - - // Is not an uncommon char, so get char of upper nybl - lda (FRESPC),y - - // Put high nybl into low bits of X - lsr - lsr - lsr - lsr - tax - - // X=1-14 = first 14 chars, so subtract one - lda packed_message_chars-1,x - jsr JCHROUT // preserves .Y - - // See if there is a char in the low nybl to print - lda (FRESPC),y - and #$0f - beq end_of_packed_word - cmp #$0f - beq no_lo_nybl_char - -has_lo_nybl_char: - // We need to print the low nybl char as well - tax - phy_trash_a - - // Skip lower nybls of $F or $0 in nybl packed - // bytes, as these do not encode characters - cpx #$f - beq !+ -has_nybl: - cpx #0 - beq !+ - - // X=1-14 = first 14 chars, so subtract one - lda packed_message_chars-1,x - jsr JCHROUT -!: - ply_trash_a - // FALLTHROUGH - -no_lo_nybl_char: - - // If current byte has $0F in low nybl, then the next - // byte is a whole byte. - lda (FRESPC),y - and #$0f - cmp #$0f - beq next_is_literal_char - -ready_for_next_char: - cpy #$ff - bne next_packed_word_char -end_of_packed_word: - // Hit end of packed data - rts - -last_literal: - jsr unpack_literal_char - rts - -next_is_literal_char: - jsr unpack_literal_char - jmp ready_for_next_char - -unpack_literal_char: - // Output the literal char, and ready for next char - iny - phy_trash_a - lda (FRESPC),y - jsr JCHROUT - pla - tay - rts - -is_uncommon_char: - // Lower nybl has offset into low-frequency part of the table - - lda (FRESPC),y - and #$0f - clc - adc #14 - - // We need to print the low nybl char as well - tax - phy_trash_a - - jmp has_nybl - - -#endif // ROM layout diff --git a/c64/basic/print/print_packed_string.s b/c64/basic/print/print_packed_string.s new file mode 100644 index 00000000..984a7d6b --- /dev/null +++ b/c64/basic/print/print_packed_string.s @@ -0,0 +1,182 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 * #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// This routine prints strings that have been packed using the 'generate_trings' tool. +// The general idea is to save space in the ROM. + + +#if (ROM_LAYOUT_M65 && SEGMENT_BASIC_0) + +print_packed_error: + + jsr map_BASIC_1 + jsr_ind VB1__print_packed_error + jmp map_NORMAL + +print_packed_misc_str: + + jsr map_BASIC_1 + jsr_ind VB1__print_packed_misc_str + jmp map_NORMAL + +print_packed_keyword_V2: + + jsr map_BASIC_1 + jsr_ind VB1__print_packed_keyword_V2 + jmp map_NORMAL + +#else + +print_packed_error: // .X - error string index + + lda #packed_str_errors + bne print_freq_packed_string // branch always + +print_packed_misc_str: // .X - misc string index + + lda #packed_str_misc + bne print_freq_packed_string // branch always + +print_packed_keyword_V2: // .X - token number + + lda #packed_str_keywords_V2 + + // FALLTROUGH + +print_freq_packed_string: // not to be used directly XXX rename to print_packed_string + + // First store the initial address of the packed strings list + + sta FRESPC+0 + sty FRESPC+1 + + // Now find the address of the string to print out + // The implementation assumes no packed string is longer than 255 bytes, including trailing zero +!: + cpx #$00 + beq print_freq_packed_string_found // branch if no need to advance anymore + dex + + ldy #$00 +!: + lda (FRESPC), y + iny + cmp #$00 + bne !- // branch if not the end of packed string + + clc // advance FREESPC pointer + tya + adc FRESPC+0 + sta FRESPC+0 + lda #$00 + adc FRESPC+1 + sta FRESPC+1 + + jmp !-- + +print_freq_packed_string_found: + + // At this point FRESPC contains a pointer to the string to display + // and we should start from the lower nibble + + ldy #$00 + + // FALLTROUGH + +print_freq_packed_string_nibble_lo: + + // Get the low nibble and check for the end of packed string + + lda (FRESPC), y + and #$0F + beq print_freq_packed_string_end + + // Not the end - check if this is a common character, encoded by a single nibble + + cmp #$0F + beq print_freq_packed_string_3n_split + + // Character is encoded by a single nibble - fetch it and display + + tax + lda packed_as_1n-1, x + jsr JCHROUT // preserves .Y + + // FALLTROUGH + +print_freq_packed_string_nibble_hi: + + // Get the high nibble and check for the end of packed string + + lda (FRESPC), y + and #$F0 + beq print_freq_packed_string_end + + // Not the end - check if this is a common character, encoded by a single nibble + + cmp #$F0 + beq print_freq_packed_string_3n_single + + // Character is encoded by a single nibble - fetch it and display + + lsr + lsr + lsr + lsr + + tax + lda packed_as_1n-1, x + jmp !+ // XXX should be bra on some CPUs + +print_freq_packed_string_3n_single: + + // Character is encoded using 3 nibbles (1st is a mark, already interpreted) + + iny + lda (FRESPC), y + tax + lda packed_as_3n-1, x +!: + jsr JCHROUT // preserves .Y + + // Advance to next nibble + + iny + bne print_freq_packed_string_nibble_lo // branch always + +print_freq_packed_string_3n_split: + + // Character is encoded using 3 nibbles (1st is a mark, already interpreted), + // but the 2 remaining nibbles are in two neighbour bytes; use a stack to combine them + + lda (FRESPC), y + and #$F0 + tsx + pha + + iny + lda (FRESPC), y + and #$0F + + clc + adc STACK, x + + txs // one cycle faster than PLA + + tax + lda packed_as_3n-1, x + jsr JCHROUT // preserves .Y + + jmp print_freq_packed_string_nibble_hi + +print_freq_packed_string_end: + + rts + + +#endif // ROM layout diff --git a/c64/basic/tokenise_line.s b/c64/basic/tokenise_line.s deleted file mode 100644 index 5e00a443..00000000 --- a/c64/basic/tokenise_line.s +++ /dev/null @@ -1,306 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# M65 * #TAKE -// #LAYOUT# X16 BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - -// Tokenise a line of BASIC -// Stored at $0200 -// Length in __tokenise_work1 - -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. - // This means we need separate start and end points to keep track of. - - // $0110 = offset into string - // $0111 = number of bytes to pack - // $0112 = offset into tokenised output - // $0113 = length of raw string - - lda #$00 - sta $0110 - sta $0112 - sta QTSW - - lda __tokenise_work1 - sta $0113 - -tokenise_char: - - // Check if we have reached end of the line? - lda $0110 - cmp $0113 - bne !+ - - // End of line reached - - // Finished tokenising line - // Update __tokenise_work1 and terminate with null - ldx $0112 - lda #$00 - sta $0200,x - stx __tokenise_work1 - - // Clear quote mode flag that is also used by KERNAL for screen display - lda #$00 - sta QTSW - rts -!: - // More to do - - // Maximum keyword length - lda #7 - sta $0111 - -tokenise_char_loop: - // Pack the word from the start (start = X, raw len = __tokenise_work1) - // Returns packed length in __tokenise_work2 and writes the packed - // word at $0100+ - - ldx $0110 - lda $0200,x - cmp #$22 - beq tk_quote - cmp #$DE - beq tk_pi - cmp #$3F - bne tk_not_special - - // FALLTROUGH - -tk_question_mark: - - lda #$99 - skip_2_bytes_trash_nvz - - // FALLTROUGH - -tk_pi: - - lda #$FF - ldx $0110 - sta $0200,x - - jmp tk_literal_char - -tk_quote: - - // Quote - lda QTSW - eor #$ff - sta QTSW - jmp tk_literal_char - -tk_not_special: - // Check for literal characters in various ranges - // (This just speeds the tokeniser up, by avoiding the packed token search - // for such characters). - - // SPACE and punctuation before +,- and * - cmp #$2a - bcc tk_literal_char - // Don't try to tokenise digits - cmp #$30 - bcc tk_might_be_keyword - cmp #$3a - bcs tk_might_be_keyword - jmp tk_literal_char - -tk_might_be_keyword: - // Don't tokenise in quote mode - lda QTSW - bne tk_literal_char - - // Pack string - ldx $0110 - lda $0111 - sta __tokenise_work1 - - // XXX - We should implement an optimisation where we - // trim the last symbol of successively, instead of re-packing the word - // again with one less char each time. - // XXX - We should limit the word length to the length of interesting chars - // that are available. - - jsr pack_word - lda __tokenise_work2 - cmp #$10 - bcc !+ - // Packed string too long - jmp do_STRING_TOO_LONG_error -!: - - // Search for it in keywords - jsr keyword_search - - // Did we find a keyword? - bcc found_token_in_line - - // Nope, so try shorter - dec $0111 - bne tokenise_char_loop - -tk_literal_char: - // Is not a token, so copy to output verbatim - ldx $0110 - ldy $0112 - lda $0200,x - sta $0200,y - inc $0112 - inc $0110 - - // Tokenise next char - jmp tokenise_char - -found_token_in_line: - - // Got a token, so write it out - ldx $0112 - sta $0200,x - inx - stx $0112 - - // If it is REM, then lock us in quote mode to the end of the line - cmp #$8f - bne not_rem - sta QTSW -not_rem: - - // Now skip over the length of the token - lda $0110 - clc - adc $0111 - sta $0110 - - // See if there is more of the line left to process - jmp tokenise_char - - - - - // Search for word in keyword list - // The packed form is canonical, so we can search for the keyword while - // it remains compressed. This also saves a little time. - // Algorithm is simply to find matching first bytes, and then look for - // the rest being a match. - -keyword_search: - // Search for the compressed keyword stored at $0100 in the list - // of compressed keywords - - // __tokenise_work1 = offset in line of input - // __tokenise_work2 = length of token we are matching - // __tokenise_work3 = offset in token list - // __tokenise_work5 = temporary work space - // X and Y registers used as temporary space. - // returns C=1 if no matching token, else C=0 and A=token - - lda #$00 - sta __tokenise_work1 - sta __tokenise_work3 -next_kw_offset: - // Advance offset in compressed keyword list, to see if a match - // BEGINS here - - // Get count of bytes to compare - lda __tokenise_work2 - sta __tokenise_work5 - - // Load current position - ldy __tokenise_work3 - ldx __tokenise_work1 - - // Advance offset in compressed token list, and stop at the end - inc __tokenise_work3 - lda __tokenise_work3 - cmp #packed_keyword_table_len - bne next_in_match - jmp done_searching_for_token -next_in_match: - lda $0100,x - cmp packed_keywords,y - bne next_kw_offset - // Advance to next chars in source and target - inx - iny - - dec __tokenise_work5 // Have we compared all bytes yet? - - bne next_in_match - - // Keyword matches! - - // Now make sure we started on a keyword boundary - // (we know we finished on one, because of the structure of the compressed - // keyword data). - // Offset 0 - // previous byte is $x0 - // two byte prior is $FE - - // Get offset of first byte of this token - ldx __tokenise_work3 - dex // pointer points one late, so rewind it - - // At start of list? - cpx #$00 - beq word_boundary - dex - // Previous byte is $x0 end token? - lda packed_keywords,x - and #$0f - beq word_boundary - dex - // Uber-previouss byte is $FE final literal token? - lda packed_keywords,x - cmp #$fe - beq word_boundary - - // Not a word boundary, so ignore - jmp next_kw_offset - -word_boundary: - // Found a token whose offset is in __tokenise_work3 - // Now trace back to the start of the compressed keyword list - // to work out what keyword number we are, so that we can return - // the token number. - - ldy #$80 - -token_count_loop: - lda packed_keywords,x - cmp #$fe - bne !+ - iny -!: - and #$0f - cmp #$00 - bne !+ - iny -!: - cpx #$00 - beq !+ - dex - jmp token_count_loop -!: - - tya - clc - rts - -done_searching_for_token: - // No token found - sec - lda #$00 - rts - -#endif // ROM layout diff --git a/c64/basic/tokenizer/tk_pack.s b/c64/basic/tokenizer/tk_pack.s new file mode 100644 index 00000000..bf4ee935 --- /dev/null +++ b/c64/basic/tokenizer/tk_pack.s @@ -0,0 +1,228 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Packs a keyword candidate using a simple compression scheme, +// same as in 'generate_strings.cc'. +// +// This allows us to search through the compressed tokens directly +// using the compressed fragment of BASIC, and thus work out the +// token for a given piece of string. +// +// This also helps ensure that we have an implementation that is totally +// different to that of the original C64 BASIC, as well as likely +// saving a bit of space in the ROM, especially once we start implementing +// larger keyword vocabs for extended BASIC, since the compression and +// decompression machinery is of fixed size. +// +// Input: +// - .X = offset of string to pack, address is BUF ($0200) + .X +// Output: +// - see labels in 'tk_pack' +// + + +tk_pack: + + // Reuse the CPU stack - addresses below $102 are used by 'tokenise_line.s' + + .label tk__len_unpacked = $103 // length of unpacked data; it could replace 'tk__nibble_flag', but at the cost of code size/performance + .label tk__shorten_bits = $104 // for quick shortening of packed candidate + .label tk__nibble_flag = $105 // $00 = start from new byte, $FF = start from high nibble + .label tk__byte_offset = $106 // offset of the current byte (to place new data) in tk__packed + + .label tk__packed = $107 // packed candidate, 13 bytes is enough for worst case - 8 byte keyword + + // Initialize variables + + lda #$00 + ldy #(tk__packed - tk__len_unpacked + 13) // XXX maybe do not clear that much, just put 0 at the end while compressing +!: + sta tk__len_unpacked, y + dey + bpl !- + + // FALLTROUGH + +tk_pack_loop: + + // Get the next character + + lda BUF, x + + // If character cannot be a part of a keyword - do not pack anything more + + cmp #$23 // '#' - first sane character for a keyword + bcc tk_pack_done // branch if below '#' + cmp #$7B // 'Z' + 1 + bcs tk_pack_done // branch if above 'Z' + + // Keywords should not contain digits, colons, or semicolons + + cmp #$30 + bcc !+ // branch if below '0' + cmp #$3C + bcc tk_pack_done // branch if below '<' +!: + // Try to find a nibble to encode the character + + ldy #$0E +!: + cmp packed_as_1n-1, y + beq tk_pack_1n + + dey + bne !- + + // Try to find a 3-nibble sequence to encode the character (1st nibble is always 0xF in this case) + + ldy #TK__PACKED_AS_3N +!: + cmp packed_as_3n-1, y + beq tk_pack_3n + + dey + bne !- + + // If it is not on the list, it cannot be a part of token - quit + + // FALLTROUGH + +tk_pack_done: + + rts + +tk_pack_1n: + + // .Y contains our nibble; check whether we should start a new encoded byte + + bit tk__nibble_flag + bpl tk_pack_1n_new_byte + + // Store in the high nibble of the current byte + + tya + + asl + asl + asl + asl + + ldy tk__byte_offset + ora tk__packed, y + sta tk__packed, y + + // Adjust remaining counters / flags + + inc tk__byte_offset + inc tk__nibble_flag // $FF -> $00 + + // FALLTROUGH + +tk_pack_1n_done: + + // Put the bit mark - to indicate 1-nibble encoding + + clc + ror tk__shorten_bits + + // FALLTROUGH + +tk_pack_loop_next: + + // Prepare for the next loop iteration - increment counters + + inx + inc tk__len_unpacked + + // Check length, if it is OK to pack one more byte; quit if not + + lda tk__len_unpacked + cmp #TK__MAX_KEYWORD_LEN + + bne tk_pack_loop + rts + +tk_pack_1n_new_byte: + + // Store in the low nibble of the next byte + + tya + ldy tk__byte_offset + sta tk__packed, y + + // Adjust remaining counters / flags + + dec tk__nibble_flag // $00 -> $FF + bmi tk_pack_1n_done + +tk_pack_3n: + + // .Y contains 2 nibbles to encode; check whether we should start a new encoded byte + + bit tk__nibble_flag + bpl tk_pack_3n_new_byte + + // Store 1st nibble (alwys 0xF) in the high nibble of the current byte + + phy_trash_a + + lda #$F0 + ldy tk__byte_offset + ora tk__packed, y + sta tk__packed, y + + // Store byte in the next byte + + iny + pla + sta tk__packed, y + + // Adjust remaining counters / flags + + iny + sty tk__byte_offset + inc tk__nibble_flag // $FF -> $00 + + // FALLTROUGH + +tk_pack_3n_done: + + // Put the bit mark - to indicate 3-nibble encoding + + sec + ror tk__shorten_bits + + bcc tk_pack_loop_next // branch always + +tk_pack_3n_new_byte: + + // First store everything in the current byte, we will set '0xF' mark later + + tya + ldy tk__byte_offset + sta tk__packed, y + + // Now store just the low nibble in the next byte + + iny + and #$0F + sta tk__packed, y + + // Go back for a moment and set the '0xF' mark in the low nibble + + dey + lda tk__packed, y + ora #$0F + sta tk__packed, y + iny + + // Adjust remaining counters / flags + + iny + sty tk__byte_offset + dec tk__nibble_flag // $00 -> $FF + + bmi tk_pack_3n_done // branch always diff --git a/c64/basic/tokenizer/tk_search.s b/c64/basic/tokenizer/tk_search.s new file mode 100644 index 00000000..fb847b24 --- /dev/null +++ b/c64/basic/tokenizer/tk_search.s @@ -0,0 +1,93 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Search for a token on the list pointed by FRESPC +// +// Input: +// - list address in FRESPC, has to be refreshed after routine call +// - uses same variables as 'tk_pack' +// Output: +// - Carry set = not found +// - .X = index of token found +// + + +tk_search: + + ldx #$00 // initial token index + + // FALLTROUGH + +tk_search_loop: + + // Check if end of the list + + ldy #$00 + lda (FRESPC), y + cmp #$FF + bne tk_search_compare + iny + lda (FRESPC), y + dey + cmp #$FF + bne tk_search_compare + + // End of the list + + sec + rts + +tk_search_compare: + + // Compare the packed candidate with the current keyword list entry + + lda (FRESPC), y + cmp tk__packed, y + bne tk_search_not_matching + + cmp #$00 + beq tk_search_found + + // For now everything matches, try the next byte + + iny + bne tk_search_compare // branch always + +tk_search_not_matching: + + inx // increment token index + + // We need to find the end of the keyword on the list + // and proceed one byte further + + cmp #$00 + beq tk_search_next +!: + iny + lda (FRESPC), y + bne !- + + // FALLTROUGH + +tk_search_next: + + // Update FRESPC - advance by .Y + + iny + tya + clc + adc FRESPC+0 + sta FRESPC+0 + lda FRESPC+1 + adc #$00 + sta FRESPC+1 + + bcc tk_search_loop // branch always + +tk_search_found: + + clc + rts diff --git a/c64/basic/tokenizer/tk_shorten.s b/c64/basic/tokenizer/tk_shorten.s new file mode 100644 index 00000000..9b14833f --- /dev/null +++ b/c64/basic/tokenizer/tk_shorten.s @@ -0,0 +1,112 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Shortens a keyword candidate previously packed by tk_pack by 1 character +// +// Input: +// - uses same variables as 'tk_pack' +// + + +tk_shorten: + + // First make sure we actually can shorten anything + + dec tk__len_unpacked + beq tk_shorten_end + + // Now check if the last character was encoded as 1 nibble or 3 nibbles + + asl tk__nibble_flag + bcs tk_shorten_3n + + // FALLTROUGH + +tk_shorten_1n: + + ldy tk__byte_offset // will be needed in both cases + + // Now we need to check which nibble to cut away + + bit tk__nibble_flag + bcs tk_shorten_1n_lo + + // FALLTROUGH + +tk_shorten_1n_hi: // tk__nibble_flag = $00, both nibbles free + + // Go back one byte and clear the high nibble only + + dey + sty tk__byte_offset + + lda tk__packed, y + and #$F0 + sta tk__packed, y + + // Adjust remaining counters / flags, and quit + + dec tk__nibble_flag // $00 -> $FF + + // FALLTROUGH + +tk_shorten_end: + + rts + +tk_shorten_1n_lo: // tk__nibble_flag = $FF, only the high nibble is free + + // Clear the whole byte, it will be faster + + lda #$00 + sta tk__packed, y + + // Adjust remaining counters / flags, and quit + + inc tk__nibble_flag // $FF -> $00 + rts + +tk_shorten_3n: + + ldy tk__byte_offset // will be needed in both cases + lda #$00 + + // Now we need to check which nibble to cut away + + bit tk__nibble_flag + bcs tk_shorten_3n_2bytes + + // FALLTROUGH + +tk_shorten_3n_byte_nibble: // tk__nibble_flag = $00, both nibbles free + + // Go back one byte, clear it, go back and clear the high nibble only + + dey + sta tk__packed, y + + // Reuse 'tk_shorten_1n_hi' + + sty tk__byte_offset +#if HAS_OPCODES_65C02 + bra tk_shorten_1n_hi +#else + jmp tk_shorten_1n_hi +#endif + +tk_shorten_3n_2bytes: // tk__nibble_flag = $FF, only the high nibble is free + + // Clear the byte, go back, clear one more byte + + sta tk__packed, y + dey + sta tk__packed, y + + // Adjust remaining counters / flags, and quit + + sty tk__byte_offset + inc tk__nibble_flag // $FF -> $00 + rts diff --git a/c64/basic/tokenizer/tokenise_line.s b/c64/basic/tokenizer/tokenise_line.s new file mode 100644 index 00000000..912e3832 --- /dev/null +++ b/c64/basic/tokenizer/tokenise_line.s @@ -0,0 +1,176 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 * #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Tokenise a line of BASIC stored at $0200 +// +// Input: +// - length in __tokenise_work1 +// + + +tokenise_line: + +#if (ROM_LAYOUT_M65 && SEGMENT_BASIC_0) + + jsr map_BASIC_1 + jsr_ind VB1__tokenise_line + jmp map_NORMAL + +#else + + // Reuse the CPU stack - addresses above $101 are used by 'tk_pack.s' + + .label tk__offset = $100 // offset into string + .label tk__length = $101 // length of the raw string XXX reuse __tokenise_work1? + + // Initialize variables + + lda #$00 + sta tk__offset + + ldx __tokenise_work1 + stx tk__length + + // Terminate input string with $00 + + // XXX do we need this? + sta BUF, x + + // FALLTROUGH + +tokenise_line_loop: + + // Check if we have reached end of the line + + lda tk__offset + cmp tk__length + beq tokenise_line_done + + // Check for some special characters + + ldx tk__offset + lda BUF, x + + cmp #$22 + beq tokenise_line_quote + + cmp #$DE + beq tokenise_line_pi + + cmp #$3F + beq tokenise_line_question_mark // shortcut for PRINT command + + // Try to tokenise + + jsr tk_pack +!: + lda tk__len_unpacked + beq tokenise_line_char // branch if attempt to tokenise failed + + lda #packed_str_keywords_V2 + sta FRESPC+1 + + jsr tk_search + bcc tokenise_line_keyword_V2 // branch if keyword identified + + // XXX add support for additional keyword lists here + + // Shorten packed keyword candidate and try again + + jsr tk_shorten + +#if HAS_OPCODES_65C02 + bra !- +#else + jmp !- +#endif + +tokenise_line_keyword_V2: + + // .X contains a token ID, starting from 0 + + txa + pha // store the token on the stack, we will need it for REM support + + // Store the token + + ldx tk__offset + clc + adc #$80 + sta BUF, x + + // Cut away unnecessary bytes + + inc tk__offset + ldx tk__offset + + dec tk__len_unpacked // keyword length, afterwards number of bytes to cut away + lda tk__len_unpacked + clc + adc tk__offset + tay +!: + lda BUF, y + sta BUF, x + beq !+ + + inx + iny + bne !- +!: + // Special handling for REM command - after this one nothing more should be tokenised + + pla + cmp #$0F // REM token index + bne tokenise_line_loop + + // FALLTROUGH + +tokenise_line_done: + + // Update line length and quit + + lda tk__length + sta __tokenise_work1 + + rts + +tokenise_line_quote: + + // For the quote, we advance without tokenizing, until the next quote is found + + inc tk__offset + ldx tk__offset + + lda BUF, x + beq tokenise_line_done + + cmp #$22 + beq tokenise_line_char + bne tokenise_line_quote // branch always + +tokenise_line_pi: + + lda #$FF // token for PI + skip_2_bytes_trash_nvz + + // FALLTROUGH + +tokenise_line_question_mark: + + lda #$99 // token for PRINT + sta BUF, x + + // FALLTROUGH + +tokenise_line_char: + + inc tk__offset + jmp tokenise_line_loop + +#endif // ROM layout diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc new file mode 100644 index 00000000..cc5f3586 --- /dev/null +++ b/tools/generate_strings.cc @@ -0,0 +1,987 @@ +// +// Utility to generate compressed messages and BASIC tokens +// + +// XXX parse the config file to select the string set (STD, M65, X16) and generate feature string +// XXX use DualStream class for logging +// XXX use dictionary compression by finding the set of non-overlapping strings that can be concatenated +// to produce full set of strings; some idea for the algorithm (not sure if proper one) is available here +// https://stackoverflow.com/questions/9195676/finding-the-smallest-number-of-substrings-to-represent-a-set-of-strings +// needs some investigation... + +#include "common.h" + +#include + +#include +#include +#include +#include +#include +#include + +// +// Command line settings +// + +std::string CMD_outFile = "out.s"; + +// +// Type definition for text/tokens to generate +// + +typedef struct StringEntry +{ + bool enabledSTD; // whether enabled for basic build + bool enabledM65; // whether enabled for Mega65 build + bool enabledX16; // whether enabled for Commander X16 build + std::string alias; // alias, for the assembler + std::string string; // string/token + uint8_t abbrevLen = 0; // length of token abbreviation +} StringEntry; + +enum class ListType +{ + KEYWORDS, + STRINGS_BASIC +}; + +typedef struct StringEntryList +{ + ListType type; + std::string name; + std::vector list; +} StringEntryList; + +typedef std::vector StringEncoded; +typedef std::vector StringEncodedList; + +// http://www.classic-games.com/commodore64/cbmtoken.html +// https://www.c64-wiki.com/wiki/BASIC_token + +// BASIC keywords - V2 dialect + +/* + The URLs here provide examples of other BASIC dialects that include the specified commands + or keywords. + All except VERIFY are known with certainty to be part of other BASIC dialects, and thus + cannot be subject to copyright infringement when implemented on a C64. + + The VERIFY Command however appears in other programming languages, and as a single word, + is the obvious complement to LOAD and SAVE when considering the following storage functions: + + 1. Load a file from storage into memory. + 2. Save a file from memory to storage. + 3. Verify that a file has been correctly written from memory to storage. + + Note that verify is the key verb in the behaviour of this function. Therefore it is the + obvious choice for the name for such a function, taking into account the convention of + LOAD and SAVE. Indeed, that this is so is highlighted by the fact that it was used in the + C64 ROM. Therefore there is no exercise of creativity here, and a reasonable person would + likely select this name independently. Also, single words cannot be copyright. + + Further, the list is a list of facts, and thus not copyrightable. + + We sourced the list from a public source, https://www.c64-wiki.com/wiki/BASIC, which has + been public on the internet for a long time, as have many other similar sources. + That website offers the page under the GFDL license, and we can therefore take the list + under those license terms if we wish, should the need arise. + + Note that in providing these justifications above, we do not in any way acknowledge that + without these conditions that the BASIC keyword list could be copyright, but provide this + information as a further layer of defence against any claims that it could somehow + infringe on the copyrights of the C64/C65/C128 etc ROMs. +*/ + +const StringEntryList GLOBAL_Keywords_V2 = { ListType::KEYWORDS, "keywords_V2", +{ + // STD M65 X16 + { true, true, true, "KV2_80", "END", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_81", "FOR", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_82", "NEXT", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_83", "DATA", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_84", "INPUT#", 2 }, // https://www.atariarchives.org/creativeatari/Using_Disks_With_Atari_Basic.php + { true, true, true, "KV2_85", "INPUT", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_86", "DIM", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_87", "READ", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_88", "LET", 2 }, // https://en.wikipedia.org/wiki/Atari_BASIC + { true, true, true, "KV2_89", "GOTO", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_8A", "RUN", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_8B", "IF", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_8C", "RESTORE", 3 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_8D", "GOSUB", 3 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_8E", "RETURN", 3 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_8F", "REM", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_90", "STOP", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_91", "ON", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_92", "WAIT", 2 }, // http://www.picaxe.com/BASIC-Commands/Time-Delays/wait/ + { true, true, true, "KV2_93", "LOAD", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_94", "SAVE", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_95", "VERIFY", 2 }, // https://en.wikipedia.org/wiki/Sinclair_BASIC + { true, true, true, "KV2_96", "DEF", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_97", "POKE", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_98", "PRINT#", 2 }, // https://www.atariarchives.org/creativeatari/Using_Disks_With_Atari_Basic.php + { true, true, true, "KV2_99", "PRINT", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_9A", "CONT", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_9B", "LIST", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_9C", "CLR", 2 }, // Apple I Replica Creation: Back to the Garage, p125 + { true, true, true, "KV2_9D", "CMD", 2 }, // https://en.wikipedia.org/wiki/List_of_DOS_commands + { true, true, true, "KV2_9E", "SYS", 2 }, // https://www.lifewire.com/dos-commands-4070427 + { true, true, true, "KV2_9F", "OPEN", 2 }, // https://www.atariarchives.org/creativeatari/Using_Disks_With_Atari_Basic.php + // STD M65 X16 + { true, true, true, "KV2_A0", "CLOSE", 3 }, // https://www.atariarchives.org/creativeatari/Using_Disks_With_Atari_Basic.php + { true, true, true, "KV2_A1", "GET", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_A2", "NEW", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_A3", "TAB(", 2 }, // http://www.antonis.de/qbebooks/gwbasman/tab.html + { true, true, true, "KV2_A4", "TO", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_A5", "FN", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_A6", "SPC(", 2 }, // http://www.antonis.de/qbebooks/gwbasman/spc.html + { true, true, true, "KV2_A7", "THEN", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_A8", "NOT", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_A9", "STEP", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_AA", "+", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_AB", "-", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_AC", "*", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_AD", "/", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_AE", "^", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_AF", "AND", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_B0", "OR", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_B1", ">", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_B2", "=", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_B3", "<", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_B4", "SGN", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_B5", "INT", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_B6", "ABS", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_B7", "USR", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_B8", "FRE", 2 }, // http://www.antonis.de/qbebooks/gwbasman/fre.html + { true, true, true, "KV2_B9", "POS", 0 }, // http://www.antonis.de/qbebooks/gwbasman/pos.html + { true, true, true, "KV2_BA", "SQR", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_BB", "RND", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_BC", "LOG", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_BD", "EXP", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_BE", "COS", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_BF", "SIN", 2 }, // https://www.landsnail.com/a2ref.htm + // STD M65 X16 + { true, true, true, "KV2_C0", "TAN", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_C1", "ATN", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_C2", "PEEK", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_C3", "LEN", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_C4", "STR$", 3 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_C5", "VAL", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_C6", "ASC", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_C7", "CHR$", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_C8", "LEFT$", 3 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_C9", "RIGHT$", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_CA", "MID$", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, "KV2_CB", "GO", 0 }, // https://en.wikipedia.org/wiki/Goto +} }; + +// extended BASIC keywords - reserved for generic (hardware independent) BASIC commands + +const StringEntryList GLOBAL_Keywords_CC = { ListType::KEYWORDS, "keywords_CC", +{ + // STD M65 X16 + { false, false, false, "KCC_01", "BLOAD", }, // http://www.antonis.de/qbebooks/gwbasman/bload.html + { false, false, false, "KCC_02", "BSAVE", }, // http://www.antonis.de/qbebooks/gwbasman/bload.html + { false, false, false, "KCC_03", "BVERIFY", }, +} }; + +// extended BASIC keywords - reserved for BASIC commands likely making sense on most C64-compatible machines + +const StringEntryList GLOBAL_Keywords_CD = { ListType::KEYWORDS, "keywords_CD", +{ + // STD M65 X16 + { false, false, false, "KCD_01", "SLOW", }, // https://en.wikipedia.org/wiki/Sinclair_BASIC - ZX81 variant + { false, false, false, "KCD_02", "FAST", }, // https://en.wikipedia.org/wiki/Sinclair_BASIC - ZX81 variant +} }; + +// extended BASIC keywords - reserved for board-specific BASIC commands + +const StringEntryList GLOBAL_Keywords_CE = { ListType::KEYWORDS, "keywords_CE", +{ + // STD M65 X16 + { false, false, false, "KCE_01", "TESTCMD", }, +} }; + +const StringEntryList GLOBAL_Keywords_CF = { ListType::KEYWORDS, "keywords_CF", +{ + // STD M65 X16 + { false, false, false, "KCF_01", "TESTCMD", }, +} }; + +// extended BASIC keywords - reserved for generic (hardware independent) BASIC functions + +const StringEntryList GLOBAL_Keywords_D0 = { ListType::KEYWORDS, "keywords_D0", +{ + // STD M65 X16 + { false, false, false, "KD0_01", "TESTFUN", }, +} }; + +// extended BASIC keywords - reserved for BASIC functions likely making sense on most C64-compatible machines + +const StringEntryList GLOBAL_Keywords_D1 = { ListType::KEYWORDS, "keywords_D1", +{ + // STD M65 X16 + { false, false, false, "KD1_01", "TESTFUN", }, +} }; + +// extended BASIC keywords - reserved for board-specific BASIC functions + +const StringEntryList GLOBAL_Keywords_D2 = { ListType::KEYWORDS, "keywords_D2", +{ + // STD M65 X16 + { false, false, false, "KD2_01", "TESTFUN", }, +} }; + +const StringEntryList GLOBAL_Keywords_D3 = { ListType::KEYWORDS, "keywords_D3", +{ + // STD M65 X16 + { false, false, false, "KD3_01", "TESTFUN", }, +} }; + + +// BASIC errors - all dialects + +/* + These error messages are generally so well known, that it seems silly to have to even point out that they are + so widely used and known, if not completely genericised. + The most of them are inherited from the MICROSOFT BASIC on which the C64's BASIC is based, so for those, there + cannot even be any claim to copyright over them in any exclusive way. + + However, copyright of such short phrases that express ideas in short form cannot be copyrighted: + https://fairuse.stanford.edu/2003/09/09/copyright_protection_for_short/ + */ + +const StringEntryList GLOBAL_Errors = { ListType::STRINGS_BASIC, "errors", +{ + // STD M65 X16 --- error strings compatible with CBM BASIC V2 + { true, true, true, "EV2_01", "TOO MANY FILES" }, + { true, true, true, "EV2_02", "FILE OPEN" }, + { true, true, true, "EV2_03", "FILE NOT OPEN" }, + { true, true, true, "EV2_04", "FILE NOT FOUND" }, + { true, true, true, "EV2_05", "DEVICE NOT PRESENT" }, + { true, true, true, "EV2_06", "NOT INPUT FILE" }, + { true, true, true, "EV2_07", "NOT OUTPUT FILE" }, + { true, true, true, "EV2_08", "MISSING FILENAME" }, + { true, true, true, "EV2_09", "ILLEGAL DEVICE NUMBER" }, + { true, true, true, "EV2_0A", "NEXT WITHOUT FOR" }, + { true, true, true, "EV2_0B", "SYNTAX" }, + { true, true, true, "EV2_0C", "RETURN WITHOUT GOSUB" }, + { true, true, true, "EV2_0D", "OUT OF DATA" }, + { true, true, true, "EV2_0E", "ILLEGAL QUANTITY" }, + { true, true, true, "EV2_0F", "OVERFLOW" }, + { true, true, true, "EV2_10", "OUT OF MEMORY" }, + { true, true, true, "EV2_11", "UNDEF\'D STATEMENT" }, + { true, true, true, "EV2_12", "BAD SUBSCRIPT" }, + { true, true, true, "EV2_13", "REDIM\'D ARRAY" }, + { true, true, true, "EV2_14", "DIVISION BY ZERO" }, + { true, true, true, "EV2_15", "ILLEGAL DIRECT" }, + { true, true, true, "EV2_16", "TYPE MISMATCH" }, + { true, true, true, "EV2_17", "STRING TOO LONG" }, + { true, true, true, "EV2_18", "FILE DATA" }, + { true, true, true, "EV2_19", "FORMULA TOO COMPLEX" }, + { true, true, true, "EV2_1A", "CAN\'T CONTINUE" }, + { true, true, true, "EV2_1B", "UNDEF\'D FUNCTION" }, + { true, true, true, "EV2_1C", "VERIFY" }, + { true, true, true, "EV2_1D", "LOAD" }, + { true, true, true, "EV2_1E", "BREAK" }, + // STD M65 X16 --- error strings compatible with CBM BASIC V7 + { false, false, false, "EV7_1F", "CAN'T RESUME" }, // not used for now + { false, false, false, "EV7_20", "LOOP NOT FOUND" }, // not used for now + { false, false, false, "EV7_21", "LOOP WITHOUT DO" }, // not used for now + { false, false, false, "EV7_22", "DIRECT MODE ONLY" }, // not used for now + { false, false, false, "EV7_23", "NO GRAPHICS AREA" }, // not used for now + { false, false, false, "EV7_24", "BAD DISK" }, // not used for now + { false, false, false, "EV7_25", "BEND NOT FOUND" }, // not used for now + { false, false, false, "EV7_26", "LINE NUMBER TOO LARGE" }, // not used for now + { false, false, false, "EV7_27", "UNRESOLVED REFERENCE" }, // not used for now + { true, true, true, "EV7_28", "NOT IMPLEMENTED" }, // this message actually differs rom CBM one + { false, false, false, "EV7_29", "FILE READ" }, // not used for now + // STD M65 X16 --- error strings specific to OpenROMs, not present in CBM BASIC dialects + { true, true, true, "EOR_2A", "MEMORY CORRUPT" }, +} }; + +// BASIC errors - miscelaneous strings + +const StringEntryList GLOBAL_MiscStrings = { ListType::STRINGS_BASIC, "misc", +{ + // STD M65 X16 --- misc strings as on CBM machines + { true, true, true, "STR_BYTES", " BASIC BYTES FREE" }, // https://github.com/stefanhaustein/expressionparser + { true, true, true, "STR_READY", "READY.\r" }, // https://www.ibm.com/support/knowledgecenter/zosbasics/com.ibm.zos.zconcepts/zconc_whatistsonative.htm https://github.com/stefanhaustein/expressionparser + { true, true, true, "STR_ERROR", " ERROR" }, // simply the word error that is attached to the other parts of messages https://fjkraan.home.xs4all.nl/comp/apple2faq/app2asoftfaq.html + { true, true, true, "STR_IN", " IN " }, + // STD M65 X16 --- misc strings specific to OpenROMs, not present in CBM ROMs + { true, true, true, "STR_BRK_AT", "BRK AT $" }, +} }; + + +/* NOTE: below are the BASIC V7/V10 keywords, see: + - https://sites.google.com/site/h2obsession/CBM/basic/tokens + - http://www.zimmers.net/anonftp/pub/cbm/programming/cbm-basic-tokens.txt + + "RGR" // $CC + "RCLR" // $CD + + "JOY" // $CF // https://www.qsl.net/hb9xch/computer/amstrad/locomotivebasic.html + "RDOT" // $D0 + "DEC" // $D1 // Amos Professional Manual, Command Index + "HEX$" // $D2 // http://www.antonis.de/qbebooks/gwbasman/hexs.html + "ERR$" // $D3 // Amos Professional Manual, Command Index + "INSTR" // $D4 // Amos Professional Manual, Command Index + "ELSE" // $D5 // Amos Professional Manual, Command Index + "RESUME" // $D6 // Amos Professional Manual, Command Index + "TRAP" // $D7 // Amos Professional Manual, Command Index + "TRON" // $D8 // https://www.qsl.net/hb9xch/computer/amstrad/locomotivebasic.html + "TROFF" // $D9 // https://www.qsl.net/hb9xch/computer/amstrad/locomotivebasic.html + "SOUND" // $DA // https://www.qsl.net/hb9xch/computer/amstrad/locomotivebasic.html + "VOL" // $DB + "AUTO" // $DC // http://www.antonis.de/qbebooks/gwbasman/auto.html + "PUDEF" // $DD + "GRAPHIC" // $DE + "PAINT" // $DF // Amos Professional Manual, Command Index + "CHAR" // $E0 // https://www.c64-wiki.com/wiki/Screen_Graphics_64 + "BOX" // $E1 // Amos Professional Manual, Command Index + "CIRCLE" // $E2 // https://en.wikipedia.org/wiki/Sinclair_BASIC + "PASTE" // $E3 // Amos Professional Manual, Command Index + "CUT" // $E4 + "LINE" // $E5 // https://en.wikipedia.org/wiki/Sinclair_BASIC + "LOCATE" // $E6 // https://www.qsl.net/hb9xch/computer/amstrad/locomotivebasic.html + "COLOR" // $E7 + "SCNCLR" // $E8 + "SCALE" // $E9 // https://www.c64-wiki.com/wiki/Super_Expander_64 + "HELP" // $EA // http://www.classic-games.com/commodore64/cbmtoken.html, Speech Basic 2.7 + "DO" // $EB // Amos Professional Manual, Command Index + "LOOP" // $EC // Amos Professional Manual, Command Index + "EXIT" // $ED // Amos Professional Manual, Command Index + "DIR" // $EE // Amos Professional Manual, Command Index + "DSAVE" // $EF // http://www.classic-games.com/commodore64/cbmtoken.html, AtBasic (@Basic) + "DLOAD" // $F0 // http://www.classic-games.com/commodore64/cbmtoken.html, AtBasic (@Basic) + "HEADER" // $F1 // http://www.classic-games.com/commodore64/cbmtoken.html, AtBasic (@Basic) + "SCRATCH" // $F2 // http://www.classic-games.com/commodore64/cbmtoken.html, AtBasic (@Basic) + "COLLECT" // $F3 + "COPY" // $F4 // https://en.wikipedia.org/wiki/Sinclair_BASIC + "RENAME" // $F5 // Amos Professional Manual, Command Index + "BACKUP" // $F6 // http://www.classic-games.com/commodore64/cbmtoken.html, AtBasic (@Basic) + "DELETE" // $F7 // http://www.classic-games.com/commodore64/cbmtoken.html, AtBasic (@Basic) + "RENUMBER" // $F8 // http://www.classic-games.com/commodore64/cbmtoken.html, AtBasic (@Basic) + "KEY" // $F9 // https://www.qsl.net/hb9xch/computer/amstrad/locomotivebasic.html + "MONITOR" // $FA // Amos Professional Manual, Command Index + "USING" // $FB // http://www.antonis.de/qbebooks/gwbasman/printusing.html + "UNTIL" // $FC // Amos Professional Manual, Command Index + "WHILE" // $FD // https://www.qsl.net/hb9xch/computer/amstrad/locomotivebasic.html + + "POT" // $CE $02 + "BUMP" // $CE $03 + "PEN" // $CE $04 // https://www.qsl.net/hb9xch/computer/amstrad/locomotivebasic.html + "RSPPOS" // $CE $05 // https://www.c64-wiki.com/wiki/Super_Expander_64 + "RSPRITE" // $CE $06 + "RSPCOLOR" // $CE $07 + "XOR" // $CE $08 + "RWINDOW" // $CE $09 + "POINTER" // $CE $0A + + "BANK" // $FE $02 // Amos Professional Manual, Command Index + "FILTER" // $FE $03 // https://www.c64-wiki.com/wiki/Super_Expander_64 + "PLAY" // $FE $04 // Amos Professional Manual, Command Index + "TEMPO" // $FE $05 // Amos Professional Manual, Command Index + "MOVSPR" // $FE $06 + "SPRITE" // $FE $07 // Amos Professional Manual, Command Index + "SPRCOLOR" // $FE $08 + "RREG" // $FE $09 + "ENVELOPE" // $FE $0A + "SLEEP" // $FE $0B + "CATALOG" // $FE $0C // http://www.classic-games.com/commodore64/cbmtoken.html, AtBasic (@Basic) + "DOPEN" // $FE $0D + "APPEND" // $FE $0E // Amos Professional Manual, Command Index + "DCLOSE" // $FE $0F + "BSAVE" // $FE $10 // http://www.antonis.de/qbebooks/gwbasman/bsave.html + "BLOAD" // $FE $11 // http://www.antonis.de/qbebooks/gwbasman/bload.html + "RECORD" // $FE $12 + "CONCAT" // $FE $13 + "DVERIFY" // $FE $14 // http://www.classic-games.com/commodore64/cbmtoken.html, AtBasic (@Basic) + "DCLEAR" // $FE $15 + "SPRSAV" // $FE $16 // https://www.c64-wiki.com/wiki/Super_Expander_64 + "COLLISION" // $FE $17 + "BEGIN" // $FE $18 + "BEND" // $FE $19 + "WINDOW" // $FE $1A // http://www.antonis.de/qbebooks/gwbasman/window.html + "BOOT" // $FE $1B + "WIDTH" // $FE $1C // http://www.antonis.de/qbebooks/gwbasman/width.html + "SPRDEF" // $FE $1D // https://www.c64-wiki.com/wiki/Super_Expander_64 + "QUIT" // $FE $1E // http://www.classic-games.com/commodore64/cbmtoken.html, Speech Basic 2.7 + + "STASH" // $FE $1F - v7 + "FETCH" // $FE $21 - v7 + "SWAP" // $FE $23 - v7 // http://www.antonis.de/qbebooks/gwbasman/swap.html + + "DMA" // $FE $17/$21/$23 - v10 + + "OFF" // $FE $24 // http://www.classic-games.com/commodore64/cbmtoken.html, Speech Basic 2.7 + "FAST" // $FE $25 // https://en.wikipedia.org/wiki/Sinclair_BASIC - ZX81 variant + "SLOW" // $FE $26 // https://en.wikipedia.org/wiki/Sinclair_BASIC - ZX81 variant + "TYPE" // $FE $27 + "BVERIFY" // $FE $28 + "DIRECTORY" // $FE $29 // http://www.classic-games.com/commodore64/cbmtoken.html, AtBasic (@Basic) + "ERASE" // $FE $2A // https://en.wikipedia.org/wiki/Sinclair_BASIC + "FIND" // $FE $2B // http://www.classic-games.com/commodore64/cbmtoken.html, AtBasic (@Basic) + "CHANGE" // $FE $2C + "SET" // $FE $2D + "SCREEN" // $FE $2E // http://www.antonis.de/qbebooks/gwbasman/screens.html + "POLYGON" // $FE $2F // Amos Professional Manual, Command Index + "ELLIPSE" // $FE $30 // Amos Professional Manual, Command Index + "VIEWPORT" // $FE $31 + "GCOPY" // $FE $32 + "PEN" // $FE $33 // Amos Professional Manual, Command Index + "PALETTE" // $FE $34 // Amos Professional Manual, Command Index + "DMODE" // $FE $35 + "DPAT" // $FE $36 + "PIC" // $FE $37 + "GENLOCK" // $FE $38 + "FOREGROUND" // $FE $39 + + "BACKGROUND" // $FE $3B + "BORDER" // $FE $3C // https://en.wikipedia.org/wiki/Sinclair_BASIC + "HIGHLIGHT" // $FE $3D +*/ + +// +// Work class definitions +// + +class DataSet +{ +public: + + void addStrings(const StringEntryList &stringList); + + const std::string &getOutput(); + +private: + + void process(); + + void calculateFrequencies(); + void encodeStrings(); + + void encodeByFreq(const std::string &plain, StringEncoded &encoded) const; + + void prepareOutput(); + + void putCharEncoding(std::ostringstream &stream, uint8_t idx, char character, bool is3n); + + virtual bool isRelevant(const StringEntry &entry) const = 0; + virtual std::string layoutName() const = 0; + + std::vector stringEntryLists; + std::vector stringEncodedLists; + + std::vector as1n; // list of bytes to be encoded as 1 nibble + std::vector as3n; // list of bytes to be encoded as 3 nibbles + + uint8_t tk__packed_as_3n = 0; + uint8_t tk__max_keyword_len = 0; + + size_t maxAliasLen = 0; + std::string outFileContent; +}; + +class DataSetSTD : public DataSet +{ + bool isRelevant(const StringEntry &entry) const { return entry.enabledSTD; } + std::string layoutName() const { return "STD"; } +}; + +class DataSetM65 : public DataSet +{ + bool isRelevant(const StringEntry &entry) const { return entry.enabledM65; } + std::string layoutName() const { return "M65"; } +}; + +class DataSetX16 : public DataSet +{ + bool isRelevant(const StringEntry &entry) const { return entry.enabledX16; } + std::string layoutName() const { return "X16"; } +}; + +// +// Work class implementation +// + +void DataSet::addStrings(const StringEntryList &stringList) +{ + // Import the new list of strings + + stringEntryLists.push_back(stringList); + + // Clear strings not relevant for the current configuration + + while (1) + { + if (isRelevant(stringEntryLists.back().list.back())) break; + + stringEntryLists.back().list.pop_back(); + if (stringEntryLists.back().list.empty()) + { + ERROR(std::string("no valid strings in layout '") + layoutName() + "', list'" + stringEntryLists.back().name + "'"); + } + } + + // Clear the output content - make sure it is not valid anymore + + outFileContent.clear(); +} + +void DataSet::process() +{ + std::cout << "Processing layout '" << layoutName() << "'" << std::endl; + + calculateFrequencies(); + encodeStrings(); + prepareOutput(); +} + +const std::string &DataSet::getOutput() +{ + if (outFileContent.empty()) + { + process(); + } + + return outFileContent; +} + +void DataSet::calculateFrequencies() +{ + as1n.clear(); + as3n.clear(); + + std::map freqMapGeneral; // general character frequency map + std::map freqMapKeywords; // frequency map for keywords + + // Calculate frequencies of characters in the strings + + for (const auto &stringEntryList : stringEntryLists) + { + for (const auto &stringEntry : stringEntryList.list) + { + if (!isRelevant(stringEntry)) continue; + + // Check for maximum allowed string length + if (stringEntry.string.length() > 255) ERROR("string cannot be longer than 255 characters"); + + // Check mor maximum keyword length + if (stringEntryList.type == ListType::KEYWORDS) + { + if (stringEntry.string.length() > 8) ERROR("keyword cannot be longer than 8 characters"); + tk__max_keyword_len = std::max(tk__max_keyword_len, (uint8_t) stringEntry.string.length()); + } + + // Update maximum alias length too + maxAliasLen = std::max(maxAliasLen, stringEntry.alias.length()); + + for (const auto &character : stringEntry.string) + { + if (character >= 0x80) + { + ERROR(std::string("character above 0x80 in string '") + stringEntry.string + "'"); + } + + freqMapGeneral[character]++; + if (stringEntryList.type == ListType::KEYWORDS) freqMapKeywords[character]++; + } + } + } + + // Sort characters by frequency + + std::vector freqVector1; + + for (auto iter = freqMapGeneral.begin(); iter != freqMapGeneral.end(); ++iter) + { + freqVector1.push_back(iter->first); + } + + std::sort(freqVector1.begin(), freqVector1.end(), [&freqMapGeneral](char e1, char e2) + { return freqMapGeneral[e2] < freqMapGeneral[e1]; }); + + // Check if minimal amount of characters needed, below 15 is not supported by the 6502 side code + + if (freqVector1.size() < 15) ERROR(std::string("not enough distinct characters in layout '") + layoutName() + "', at least 15 needed"); + + // Extract 14 most frequent characters to be encoded as 1 nibble + + for (uint8_t idx = 0; idx < 14; idx++) + { + as1n.push_back(freqVector1[idx]); + } + + // Now sort them by frequency in keywords, in descending order - this will speed up the tokenizer a little + + std::sort(as1n.begin(), as1n.end(), [&freqMapKeywords](char e1, char e2) { return freqMapKeywords[e2] > freqMapKeywords[e1]; }); + + // Extract characters to be encoded as 3 nibbles, which actually exist in keywords + + std::vector freqVector2; + + tk__packed_as_3n = 0; + for (uint8_t idx = 14; idx < freqVector1.size(); idx++) + { + const auto &character = freqVector1[idx]; + + if (freqMapKeywords[character] > 0) + { + as3n.push_back(character); + tk__packed_as_3n++; + } + else + { + freqVector2.push_back(character); + } + } + tk__packed_as_3n = std::max(tk__packed_as_3n, (uint8_t) 1); + + // Again, sort them by frequency in keywords, in descending order - this will speed up the tokenizer a little + + std::sort(as3n.begin(), as3n.end(), [&freqMapKeywords](char e1, char e2) { return freqMapKeywords[e2] > freqMapKeywords[e1]; }); + + // Finally extract the remaining characters to be encoded as 3 nibbles + + for (const auto &character : freqVector2) + { + as3n.push_back(character); + } +} + +void DataSet::encodeByFreq(const std::string &plain, StringEncoded &encoded) const +{ + bool fullByte = true; + + auto push1n = [&](uint8_t val) // push 1 nibble - encoded character or 0xF mark + { + if (fullByte) + { + encoded.push_back(val); + fullByte = false; + } + else + { + encoded.back() += val * 0x10; + fullByte = true; + } + }; + + auto push2n = [&](uint8_t val) // push the remaining nibbles for 3-niobble encoded characters + { + if (fullByte) + { + encoded.push_back(val); + } + else + { + // Encode byte in a way to be easily decoded by 6502 + encoded.back() += (val / 0x10) * 0x10; + encoded.push_back(val % 0x10); + } + }; + + // Encode every single character by frequency, put them in the output vector + + for (const char &character : plain) + { + auto iterEncoding1 = std::find(as1n.begin(), as1n.end(), character); + if (iterEncoding1 != as1n.end()) + { + push1n(std::distance(as1n.begin(), iterEncoding1) + 1); + } + else + { + push1n(0x0F); + + auto iterEncoding3 = std::find(as3n.begin(), as3n.end(), character); + if (iterEncoding3 == as3n.end()) + { + ERROR("internal error in 'encodeByFreq'"); + } + push2n(std::distance(as3n.begin(), iterEncoding3) + 1); + } + } + + // Make sure the last byte of encoded stream is 0 + + if (encoded.size() == 0 || encoded.back() != 0) encoded.push_back(0); +} + +void DataSet::encodeStrings() +{ + stringEncodedLists.clear(); + + // Encode every relevant string from every list - by character frequency + + for (const auto &stringEntryList : stringEntryLists) + { + stringEncodedLists.emplace_back(); + auto &stringEncodedList = stringEncodedLists.back(); + + for (const auto &stringEntry : stringEntryList.list) + { + stringEncodedList.emplace_back(); + auto &stringEncoded = stringEncodedList.back(); + + if (isRelevant(stringEntry)) + { + encodeByFreq(stringEntry.string, stringEncoded); + } + } + } +} + +void DataSet::putCharEncoding(std::ostringstream &stream, uint8_t idx, char character, bool is3n) +{ + stream << "\t.byte $" << std::uppercase << std::hex << + std::setfill('0') << std::setw(2) << +character << + " // " << std::setfill(is3n ? '0' : ' ') << std::setw(2) << +idx; + + std::string petscii; + + if (character == 0x20) + { + petscii = " = SPACE"; + } + else if (character == 0x27) + { + petscii = " = APOSTROPHE"; + } + else if (character == 0x0D) + { + petscii = " = RETURN"; + } + else if (character > ' ' && character < 'a') + { + petscii = std::string(" = '") + character + "'"; + } + + stream << petscii << std::endl; +} + +void DataSet::prepareOutput() +{ + // Convert our encoded strings to a KickAssembler source + + std::ostringstream stream; + stream << std::endl << "#if ROM_LAYOUT_" << layoutName() << std::endl; + + uint8_t idx; + + // Export all nibble-encoded characters + + stream << std::endl << ".macro put_packed_as_1n() // characters encoded as 1 nibble" << std::endl << "{" << std::endl; + + idx = 0; + for (const auto& encoding : as1n) + { + putCharEncoding(stream, ++idx, encoding, false); + } + + stream << "}" << std::endl; + + // Export all byte-encoded characters + + stream << std::endl << ".macro put_packed_as_3n() // characters encoded as 3 nibbles" << std::endl << "{" << std::endl; + + idx = 0; + for (const auto& encoding : as3n) + { + if (idx == tk__packed_as_3n) stream << std::endl << + "\t// Characters below are not used by any BASIC keyword" << std::endl << std::endl; + + putCharEncoding(stream, ++idx, encoding, true); + } + + stream << "}" << std::endl; + + // Export additional data for the tokenizer + + stream << std::endl << ".label TK__PACKED_AS_3N = $" << std::hex << +tk__packed_as_3n << + std::endl << ".label TK__MAX_KEYWORD_LEN = " << std::dec << +tk__max_keyword_len << std::endl; + + // Export frequency-encoded strings + + for (uint8_t idxList = 0; idxList < stringEntryLists.size(); idxList++) + { + const auto &stringEntryList = stringEntryLists[idxList]; + const auto &stringEncodedList = stringEncodedLists[idxList]; + + stream << std::endl; + for (uint8_t idxString = 0; idxString < stringEncodedList.size(); idxString++) + { + const auto &stringEntry = stringEntryList.list[idxString]; + const auto &stringEncoded = stringEncodedList[idxString]; + + if (!stringEncoded.empty()) + { + stream << ".label IDX__" << stringEntry.alias << std::string(maxAliasLen - stringEntry.alias.length(), ' ') << + " = $" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << +idxString << std::endl; + } + } + + stream << std::endl << ".macro put_freq_packed_" << stringEntryList.name << "()" << std::endl << "{" << std::endl; + + enum LastStr { NONE, SKIPPED, WRITTEN } lastStr = LastStr::NONE; + for (uint8_t idxString = 0; idxString < stringEncodedList.size(); idxString++) + { + const auto &stringEntry = stringEntryList.list[idxString]; + const auto &stringEncoded = stringEncodedList[idxString]; + + if (stringEncoded.empty()) + { + if (lastStr == LastStr::WRITTEN) stream << std::endl; + stream << "\t.byte $00 // skipped " << stringEntry.alias << std::endl; + lastStr = LastStr::SKIPPED; + } + else + { + if (lastStr != LastStr::NONE) stream << std::endl; + + stream << "\t// IDX__" << stringEntry.alias << std::endl; + stream << "\t.byte "; + + bool first = true; + for (const auto &charEncoded : stringEncoded) + { + if (first) + { + first = false; + } + else + { + stream << ", "; + } + + stream << "$" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << +charEncoded; + } + + stream << std::endl; + lastStr = LastStr::WRITTEN; + } + } + + // For the token list - pu the 'end of keywords' mark + + if (stringEntryList.type == ListType::KEYWORDS) + { + stream << std::endl << "\t// Marker - end of the keyword list" << std::endl; + stream << "\t.byte $FF, $FF" << std::endl; + } + + stream << "}" << std::endl; + } + + // Finalize the file stream + + stream << std::endl << "#endif // ROM_LAYOUT_" << layoutName() << std::endl; + outFileContent = stream.str(); +} + + +// +// Common helper functions +// + +void printUsage() +{ + std::cout << "\n" << + "usage: generate_strings [-o ]" << "\n\n"; +} + +void printBanner() +{ + printBannerLineTop(); + std::cout << "// Generating compressed messages and BASIC tokens" << "\n"; + printBannerLineBottom(); +} + +void parseCommandLine(int argc, char **argv) +{ + int opt; + + // Retrieve command line options + + while ((opt = getopt(argc, argv, "o:")) != -1) + { + switch(opt) + { + case 'o': CMD_outFile = optarg; break; + default: printUsage(); ERROR(); + } + } +} + +void writeStrings() +{ + DataSetSTD dataSetSTD; + DataSetM65 dataSetM65; + DataSetX16 dataSetX16; + + // Add input data to computation objects + + dataSetSTD.addStrings(GLOBAL_Keywords_V2); + dataSetSTD.addStrings(GLOBAL_Errors); + dataSetSTD.addStrings(GLOBAL_MiscStrings); + + dataSetM65.addStrings(GLOBAL_Keywords_V2); + dataSetM65.addStrings(GLOBAL_Errors); + dataSetM65.addStrings(GLOBAL_MiscStrings); + + dataSetX16.addStrings(GLOBAL_Keywords_V2); + dataSetX16.addStrings(GLOBAL_Errors); + dataSetX16.addStrings(GLOBAL_MiscStrings); + + // Retrieve the results + + std::string outputSTD = dataSetSTD.getOutput(); + std::string outputM65 = dataSetM65.getOutput(); + std::string outputX16 = dataSetX16.getOutput(); + + // Remove old file + + unlink(CMD_outFile.c_str()); + + // Open output file for writing + + std::ofstream outFile(CMD_outFile, std::fstream::out | std::fstream::trunc); + if (!outFile.good()) ERROR(std::string("can't open oputput file '") + CMD_outFile + "'"); + + // Write header + + outFile << "//\n// Generated file - do not edit\n//"; + + // Write packed strings + + outFile << std::endl << std::endl; + outFile << outputSTD; + outFile << std::endl << std::endl; + outFile << outputM65; + outFile << std::endl << std::endl; + outFile << outputX16; + outFile << std::endl << std::endl; + + // Close the file + + outFile.close(); + + std::cout << std::string("Compressed strings written to: ") + CMD_outFile + "\n\n"; +} + +// +// Main function +// + +int main(int argc, char **argv) +{ + printBanner(); + parseCommandLine(argc, argv); + + writeStrings(); + + return 0; +} diff --git a/tools/compress_text.c b/tools/outdated/compress_text.c similarity index 100% rename from tools/compress_text.c rename to tools/outdated/compress_text.c From ee6650112dc7938450a2290e314a0c8f32da1859 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 21 Jun 2020 18:57:38 +0200 Subject: [PATCH 058/103] display improvements, saved some bytes --- c64/basic/basic_commands/cmd_list.s | 3 --- c64/basic/basic_commands/cmd_load_verify.s | 18 +----------------- c64/basic/basic_commands/cmd_save.s | 2 +- c64/basic/engine/do_error.s | 6 ------ c64/basic/init/basic_warm_start_internal.s | 2 -- c64/basic/init/initmsg_real.s | 5 ++--- c64/basic/print/list_single_line.s | 7 ++++--- c64/basic/wedge/wedge_dos.s | 14 ++++++++------ c64/kernal/assets/kernal_messages.s | 2 -- tools/generate_strings.cc | 4 ++-- 10 files changed, 18 insertions(+), 45 deletions(-) diff --git a/c64/basic/basic_commands/cmd_list.s b/c64/basic/basic_commands/cmd_list.s index a1fcdb1d..93a1fdf3 100644 --- a/c64/basic/basic_commands/cmd_list.s +++ b/c64/basic/basic_commands/cmd_list.s @@ -11,9 +11,6 @@ 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 diff --git a/c64/basic/basic_commands/cmd_load_verify.s b/c64/basic/basic_commands/cmd_load_verify.s index 8730cc7e..e77a22e4 100644 --- a/c64/basic/basic_commands/cmd_load_verify.s +++ b/c64/basic/basic_commands/cmd_load_verify.s @@ -53,7 +53,7 @@ cmd_load_got_params: // input for tape wedge lda VERCKB // LOAD or VERIFY jsr JLOAD - jsr cmd_load_save_handle_result + bcs_16 do_kernal_error cmd_load_no_error: @@ -94,19 +94,3 @@ cmd_load_no_error: cmd_load_end: jmp basic_main_loop - - -// -// Handle result from Kernal - common for LOAD/VERIFY/SAVE -// - -cmd_load_save_handle_result: - - php - pha - jsr print_return - pla - plp - bcs_16 do_kernal_error - - rts diff --git a/c64/basic/basic_commands/cmd_save.s b/c64/basic/basic_commands/cmd_save.s index 1f06cf23..eae7c785 100644 --- a/c64/basic/basic_commands/cmd_save.s +++ b/c64/basic/basic_commands/cmd_save.s @@ -32,7 +32,7 @@ cmd_save: // Perform saving jsr JSAVE - jsr cmd_load_save_handle_result + bcs_16 do_kernal_error // The end diff --git a/c64/basic/engine/do_error.s b/c64/basic/engine/do_error.s index 1d0c153e..6458b90c 100644 --- a/c64/basic/engine/do_error.s +++ b/c64/basic/engine/do_error.s @@ -171,12 +171,6 @@ do_basic_error: // error code in .X ldx CURLIN+0 jsr print_integer !: - // New lines - - jsr print_return - lda #$00 - jsr JCHROUT - // Reset stack, and go back to main loop ldx #$FE diff --git a/c64/basic/init/basic_warm_start_internal.s b/c64/basic/init/basic_warm_start_internal.s index 79257cd1..75fc68c5 100644 --- a/c64/basic/init/basic_warm_start_internal.s +++ b/c64/basic/init/basic_warm_start_internal.s @@ -26,7 +26,5 @@ basic_warm_start_real: jsr print_hex_byte lda CMP0+0 jsr print_hex_byte - jsr print_return - !: jmp basic_main_loop diff --git a/c64/basic/init/initmsg_real.s b/c64/basic/init/initmsg_real.s index 332ef462..62e612d4 100644 --- a/c64/basic/init/initmsg_real.s +++ b/c64/basic/init/initmsg_real.s @@ -167,10 +167,9 @@ initmsg_real: ldx #$08 ldy #$00 jsr plot_set - jsr print_features - jmp print_return + jmp print_features #else - ldx #$08 + ldx #$07 ldy #$00 jmp plot_set #endif diff --git a/c64/basic/print/list_single_line.s b/c64/basic/print/list_single_line.s index cf13147b..454b9cbb 100644 --- a/c64/basic/print/list_single_line.s +++ b/c64/basic/print/list_single_line.s @@ -13,7 +13,8 @@ list_single_line: #else - // Print line number + // Print line number - in a new line + jsr print_return ldy #3 #if ROM_LAYOUT_M65 @@ -121,8 +122,8 @@ list_is_literal: bne list_print_loop list_end_of_line: - // Print end of line - jmp print_return + + rts #endif // ROM layout diff --git a/c64/basic/wedge/wedge_dos.s b/c64/basic/wedge/wedge_dos.s index a7a787d8..0e9b5d3d 100644 --- a/c64/basic/wedge/wedge_dos.s +++ b/c64/basic/wedge/wedge_dos.s @@ -70,7 +70,6 @@ wedge_dos_command: !: // Retrieve status, print it if not OK jsr JCLALL - jsr print_return jsr wedge_dos_status_get lda BUF+0 cmp #$30 // '0' @@ -97,11 +96,14 @@ wedge_dos_change_drive: jmp do_ILLEGAL_DEVICE_NUMBER_error !: sta FA - jsr print_return jmp basic_main_loop wedge_dos_status_get: + // New line - separate status from current display + + jsr print_return + // Here the flow is mostly the same as in the example from // https://codebase64.org/doku.php?id=base:reading_the_error_channel_of_a_disk_drive @@ -131,17 +133,20 @@ wedge_dos_status_get: jsr JCHRIN bcc wedge_dos_x1 jmp wedge_dos_basic_error // XXX try to optimize this + wedge_dos_x1: sta BUF, y iny jmp !- !: + // Strip ending RETURN + + dey rts wedge_dos_status: jsr wedge_dos_status_get - jsr print_return // FALLTROUGH wedge_dos_status_print: @@ -186,9 +191,6 @@ wedge_dos_directory: jsr JCHRIN bcs wedge_dos_basic_error - // Print new line - jsr print_return - wedge_dos_directory_line: // Load a single line, reuse BASIC input buffer diff --git a/c64/kernal/assets/kernal_messages.s b/c64/kernal/assets/kernal_messages.s index 3c876dc9..16cca4ce 100644 --- a/c64/kernal/assets/kernal_messages.s +++ b/c64/kernal/assets/kernal_messages.s @@ -97,12 +97,10 @@ __msg_kernaloksearching: __msg_kernalpal: .text "PAL" - .byte $0D .byte $80 + $0D // end of string mark + return __msg_kernalntsc: .text "NTSC" - .byte $0D .byte $80 + $0D // end of string mark + return #endif // CONFIG_SHOW_PAL_NTSC diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index cc5f3586..e0c9da64 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -307,11 +307,11 @@ const StringEntryList GLOBAL_MiscStrings = { ListType::STRINGS_BASIC, "misc", { // STD M65 X16 --- misc strings as on CBM machines { true, true, true, "STR_BYTES", " BASIC BYTES FREE" }, // https://github.com/stefanhaustein/expressionparser - { true, true, true, "STR_READY", "READY.\r" }, // https://www.ibm.com/support/knowledgecenter/zosbasics/com.ibm.zos.zconcepts/zconc_whatistsonative.htm https://github.com/stefanhaustein/expressionparser + { true, true, true, "STR_READY", "\rREADY.\r" }, // https://www.ibm.com/support/knowledgecenter/zosbasics/com.ibm.zos.zconcepts/zconc_whatistsonative.htm https://github.com/stefanhaustein/expressionparser { true, true, true, "STR_ERROR", " ERROR" }, // simply the word error that is attached to the other parts of messages https://fjkraan.home.xs4all.nl/comp/apple2faq/app2asoftfaq.html { true, true, true, "STR_IN", " IN " }, // STD M65 X16 --- misc strings specific to OpenROMs, not present in CBM ROMs - { true, true, true, "STR_BRK_AT", "BRK AT $" }, + { true, true, true, "STR_BRK_AT", "\rBRK AT $" }, } }; From 97131d8d556cbcfacaab76b89ba08ce251dea74f Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 21 Jun 2020 19:13:57 +0200 Subject: [PATCH 059/103] fixed some error messages, more size optimizations --- c64/,,config_custom.s | 4 ++-- c64/basic/engine/do_error.s | 11 +++++------ tools/generate_strings.cc | 1 + 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/c64/,,config_custom.s b/c64/,,config_custom.s index e023c716..1e03bdff 100644 --- a/c64/,,config_custom.s +++ b/c64/,,config_custom.s @@ -54,9 +54,9 @@ // #define CONFIG_IEC_BURST_CIA2 // please keep disabled for now // #define CONFIG_IEC_BURST_SOFT // please keep disabled for now -// #define CONFIG_TAPE_NORMAL +#define CONFIG_TAPE_NORMAL #define CONFIG_TAPE_TURBO -// #define CONFIG_TAPE_AUTODETECT +#define CONFIG_TAPE_AUTODETECT // #define CONFIG_TAPE_NO_KEY_SENSE // #define CONFIG_TAPE_NO_MOTOR_CONTROL // #define CONFIG_TAPE_NO_ERROR_CORRECTION diff --git a/c64/basic/engine/do_error.s b/c64/basic/engine/do_error.s index 6458b90c..47a893f2 100644 --- a/c64/basic/engine/do_error.s +++ b/c64/basic/engine/do_error.s @@ -38,12 +38,12 @@ do_NOT_IMPLEMENTED_error: - ldx #36 + ldx #IDX__EV7_28 bpl do_basic_error // branch always do_MEMORY_CORRUPT_error: - ldx #35 + ldx #IDX__EOR_2A bpl do_basic_error // branch always do_kernal_error: // .A = KERNAL error code, also almost matches BASIC error codes @@ -144,10 +144,9 @@ do_basic_error: // error code in .X // "?" phx_trash_a - jsr print_return - lda #$3F - jsr JCHROUT - pla + ldx #IDX__STR_RET_QM + jsr print_packed_misc_str + plx_trash_a // Error message text + " ERROR" diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index e0c9da64..f381b616 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -306,6 +306,7 @@ const StringEntryList GLOBAL_Errors = { ListType::STRINGS_BASIC, "errors", const StringEntryList GLOBAL_MiscStrings = { ListType::STRINGS_BASIC, "misc", { // STD M65 X16 --- misc strings as on CBM machines + { true, true, true, "STR_RET_QM", "\r?" }, { true, true, true, "STR_BYTES", " BASIC BYTES FREE" }, // https://github.com/stefanhaustein/expressionparser { true, true, true, "STR_READY", "\rREADY.\r" }, // https://www.ibm.com/support/knowledgecenter/zosbasics/com.ibm.zos.zconcepts/zconc_whatistsonative.htm https://github.com/stefanhaustein/expressionparser { true, true, true, "STR_ERROR", " ERROR" }, // simply the word error that is attached to the other parts of messages https://fjkraan.home.xs4all.nl/comp/apple2faq/app2asoftfaq.html From e74fd4140acca358a8d99cda77d984ce30c667fb Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 21 Jun 2020 19:58:11 +0200 Subject: [PATCH 060/103] preparation for a couple of new BASIC commands --- Makefile | 2 + c64/basic/basic_commands/cmd__jumptable.s | 2 +- .../basic_commands_CC/cmd__jumptable_CC.s | 49 +++++++++++++++++++ c64/basic/basic_commands_CC/cmd_bload.s | 8 +++ c64/basic/basic_commands_CC/cmd_bsave.s | 8 +++ c64/basic/basic_commands_CC/cmd_bverify.s | 8 +++ c64/basic/basic_commands_CC/cmd_merge.s | 8 +++ .../basic_commands_CD/cmd__jumptable_CD.s | 46 +++++++++++++++++ c64/basic/basic_commands_CD/cmd_fast.s | 8 +++ c64/basic/basic_commands_CD/cmd_slow.s | 8 +++ c64/basic/basic_functions/fun__jumptable.s | 2 +- c64/basic/engine/do_error.s | 47 ++++++++++++------ tools/generate_strings.cc | 23 ++++++--- 13 files changed, 195 insertions(+), 24 deletions(-) create mode 100644 c64/basic/basic_commands_CC/cmd__jumptable_CC.s create mode 100644 c64/basic/basic_commands_CC/cmd_bload.s create mode 100644 c64/basic/basic_commands_CC/cmd_bsave.s create mode 100644 c64/basic/basic_commands_CC/cmd_bverify.s create mode 100644 c64/basic/basic_commands_CC/cmd_merge.s create mode 100644 c64/basic/basic_commands_CD/cmd__jumptable_CD.s create mode 100644 c64/basic/basic_commands_CD/cmd_fast.s create mode 100644 c64/basic/basic_commands_CD/cmd_slow.s diff --git a/Makefile b/Makefile index d65bbff7..5ed42036 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,8 @@ SRCDIR_BASIC = $(SRCDIR_COMMON) \ c64/basic/,stubs_math \ c64/basic/assets \ c64/basic/basic_commands \ + c64/basic/basic_commands_CC \ + c64/basic/basic_commands_CD \ c64/basic/basic_operators \ c64/basic/basic_functions \ c64/basic/board_m65 \ diff --git a/c64/basic/basic_commands/cmd__jumptable.s b/c64/basic/basic_commands/cmd__jumptable.s index 1fa25c49..d5f8e1ff 100644 --- a/c64/basic/basic_commands/cmd__jumptable.s +++ b/c64/basic/basic_commands/cmd__jumptable.s @@ -3,7 +3,7 @@ // #LAYOUT# * * #IGNORE // -// Jumptable for all known BASIC commands +// Jumptable for BASIC V2 dialect commands // diff --git a/c64/basic/basic_commands_CC/cmd__jumptable_CC.s b/c64/basic/basic_commands_CC/cmd__jumptable_CC.s new file mode 100644 index 00000000..72168c3e --- /dev/null +++ b/c64/basic/basic_commands_CC/cmd__jumptable_CC.s @@ -0,0 +1,49 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Jumptable for BASIC commands with tokens prefixed by $CC +// + + +.const command_CC_list = List().add( + + cmd_merge, + + cmd_bload, + cmd_bsave, + cmd_bverify +) + + +#if !HAS_OPCODES_65C02 + + +command_CC_jumptable_lo: + + put_jumptable_lo(command_CC_list) + + +command_CC_jumptable_hi: + + put_jumptable_hi(command_CC_list) + + +#else // HAS_OPCODES_65C02 + + +__before_command_CC_jumptable: + +.if (mod(*, $2) == 1) { brk } // align code so that vector never crosses page boundary + +command_CC_jumptable: + + put_jumptable(command_CC_list) + + // Make sure routine size is always the same - build system limitation + +.if (__before_command_CC_jumptable == command_CC_jumptable) { brk } + + +#endif diff --git a/c64/basic/basic_commands_CC/cmd_bload.s b/c64/basic/basic_commands_CC/cmd_bload.s new file mode 100644 index 00000000..2feed6d0 --- /dev/null +++ b/c64/basic/basic_commands_CC/cmd_bload.s @@ -0,0 +1,8 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +cmd_bload: + + jmp do_NOT_IMPLEMENTED_error // XXX implement the command diff --git a/c64/basic/basic_commands_CC/cmd_bsave.s b/c64/basic/basic_commands_CC/cmd_bsave.s new file mode 100644 index 00000000..3849a57d --- /dev/null +++ b/c64/basic/basic_commands_CC/cmd_bsave.s @@ -0,0 +1,8 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +cmd_bsave: + + jmp do_NOT_IMPLEMENTED_error // XXX implement the command diff --git a/c64/basic/basic_commands_CC/cmd_bverify.s b/c64/basic/basic_commands_CC/cmd_bverify.s new file mode 100644 index 00000000..3fdfdf8a --- /dev/null +++ b/c64/basic/basic_commands_CC/cmd_bverify.s @@ -0,0 +1,8 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +cmd_bverify: + + jmp do_NOT_IMPLEMENTED_error // XXX implement the command diff --git a/c64/basic/basic_commands_CC/cmd_merge.s b/c64/basic/basic_commands_CC/cmd_merge.s new file mode 100644 index 00000000..f464369e --- /dev/null +++ b/c64/basic/basic_commands_CC/cmd_merge.s @@ -0,0 +1,8 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +cmd_merge: + + jmp do_NOT_IMPLEMENTED_error // XXX implement the command diff --git a/c64/basic/basic_commands_CD/cmd__jumptable_CD.s b/c64/basic/basic_commands_CD/cmd__jumptable_CD.s new file mode 100644 index 00000000..9cfa0c9a --- /dev/null +++ b/c64/basic/basic_commands_CD/cmd__jumptable_CD.s @@ -0,0 +1,46 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Jumptable for BASIC commands with tokens prefixed by $CD +// + + +.const command_CD_list = List().add( + + cmd_slow, + cmd_fast +) + + +#if !HAS_OPCODES_65C02 + + +command_CD_jumptable_lo: + + put_jumptable_lo(command_CD_list) + + +command_CD_jumptable_hi: + + put_jumptable_hi(command_CD_list) + + +#else // HAS_OPCODES_65C02 + + +__before_command_CD_jumptable: + +.if (mod(*, $2) == 1) { brk } // align code so that vector never crosses page boundary + +command_CD_jumptable: + + put_jumptable(command_CD_list) + + // Make sure routine size is always the same - build system limitation + +.if (__before_command_CD_jumptable == command_CD_jumptable) { brk } + + +#endif diff --git a/c64/basic/basic_commands_CD/cmd_fast.s b/c64/basic/basic_commands_CD/cmd_fast.s new file mode 100644 index 00000000..056fed10 --- /dev/null +++ b/c64/basic/basic_commands_CD/cmd_fast.s @@ -0,0 +1,8 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +cmd_fast: + + jmp do_NOT_IMPLEMENTED_error // XXX implement the command diff --git a/c64/basic/basic_commands_CD/cmd_slow.s b/c64/basic/basic_commands_CD/cmd_slow.s new file mode 100644 index 00000000..730fb203 --- /dev/null +++ b/c64/basic/basic_commands_CD/cmd_slow.s @@ -0,0 +1,8 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +cmd_slow: + + jmp do_NOT_IMPLEMENTED_error // XXX implement the command diff --git a/c64/basic/basic_functions/fun__jumptable.s b/c64/basic/basic_functions/fun__jumptable.s index 0d53bcdc..266ff347 100644 --- a/c64/basic/basic_functions/fun__jumptable.s +++ b/c64/basic/basic_functions/fun__jumptable.s @@ -3,7 +3,7 @@ // #LAYOUT# * * #IGNORE // -// Jumptable for all known BASIC functions +// Jumptable for BASIC V2 dialect functions // diff --git a/c64/basic/engine/do_error.s b/c64/basic/engine/do_error.s index 47a893f2..e86c82d6 100644 --- a/c64/basic/engine/do_error.s +++ b/c64/basic/engine/do_error.s @@ -33,18 +33,7 @@ // message that the $2C method would result in. -// XXX consider reworking the two errors below to reuse '$E6' mechanism - - -do_NOT_IMPLEMENTED_error: - - ldx #IDX__EV7_28 - bpl do_basic_error // branch always - -do_MEMORY_CORRUPT_error: - - ldx #IDX__EOR_2A - bpl do_basic_error // branch always + // Error messages reported by KERNAL do_kernal_error: // .A = KERNAL error code, also almost matches BASIC error codes @@ -52,9 +41,39 @@ do_kernal_error: // .A = KERNAL error code, also almost ma tax dex - bpl do_basic_error + bpl do_basic_error // branch always - // FALLTROUGN + // Error messages specific to OpenROMs BASIC dialect + +do_MEMORY_CORRUPT_error: + .byte $E6 + + // Error messages compatible with CBM BASIC V7 dialect + +do_FILE_READ_error: + .byte $E6 +do_NOT_IMPLEMENTED_error: + .byte $E6 +do_UNRESOLVED_REFERENCE_error: + .byte $E6 +do_LINE_NUMBER_TOO_LARGE_error: + .byte $E6 +do_BEND_NOT_FOUND_error: + .byte $E6 +do_BAD_DISK_error: + .byte $E6 +do_NO_GRAPHICS_AREA_error: + .byte $E6 +do_DIRECT_MODE_ONLY_error: + .byte $E6 +do_LOOP_WITHOUT_DO_error: + .byte $E6 +do_LOOP_NOT_FOUND_error: + .byte $E6 +do_CANT_RESUME_error: + .byte $E6 + + // Error messages compatible with CBM BASIC V2 dialect do_BREAK_error: .byte $E6 diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index f381b616..16124a4a 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -180,10 +180,11 @@ const StringEntryList GLOBAL_Keywords_V2 = { ListType::KEYWORDS, "keywords_V2", const StringEntryList GLOBAL_Keywords_CC = { ListType::KEYWORDS, "keywords_CC", { - // STD M65 X16 - { false, false, false, "KCC_01", "BLOAD", }, // http://www.antonis.de/qbebooks/gwbasman/bload.html - { false, false, false, "KCC_02", "BSAVE", }, // http://www.antonis.de/qbebooks/gwbasman/bload.html - { false, false, false, "KCC_03", "BVERIFY", }, + // STD M65 X16 + { true, true, true, "KCC_01", "MERGE", }, // OpenROMs specific, not present in CBM BASIC dialects + { true, true, true, "KCC_02", "BLOAD", }, // http://www.antonis.de/qbebooks/gwbasman/bload.html + { true, true, true, "KCC_03", "BSAVE", }, // http://www.antonis.de/qbebooks/gwbasman/bsave.html + { true, true, true, "KCC_04", "BVERIFY", }, } }; // extended BASIC keywords - reserved for BASIC commands likely making sense on most C64-compatible machines @@ -191,8 +192,8 @@ const StringEntryList GLOBAL_Keywords_CC = { ListType::KEYWORDS, "keywords_CC", const StringEntryList GLOBAL_Keywords_CD = { ListType::KEYWORDS, "keywords_CD", { // STD M65 X16 - { false, false, false, "KCD_01", "SLOW", }, // https://en.wikipedia.org/wiki/Sinclair_BASIC - ZX81 variant - { false, false, false, "KCD_02", "FAST", }, // https://en.wikipedia.org/wiki/Sinclair_BASIC - ZX81 variant + { true, true, true, "KCD_01", "SLOW", }, // https://en.wikipedia.org/wiki/Sinclair_BASIC - ZX81 variant + { true, true, true, "KCD_02", "FAST", }, // https://en.wikipedia.org/wiki/Sinclair_BASIC - ZX81 variant } }; // extended BASIC keywords - reserved for board-specific BASIC commands @@ -289,13 +290,13 @@ const StringEntryList GLOBAL_Errors = { ListType::STRINGS_BASIC, "errors", { false, false, false, "EV7_1F", "CAN'T RESUME" }, // not used for now { false, false, false, "EV7_20", "LOOP NOT FOUND" }, // not used for now { false, false, false, "EV7_21", "LOOP WITHOUT DO" }, // not used for now - { false, false, false, "EV7_22", "DIRECT MODE ONLY" }, // not used for now + { true, true, true, "EV7_22", "DIRECT MODE ONLY" }, { false, false, false, "EV7_23", "NO GRAPHICS AREA" }, // not used for now { false, false, false, "EV7_24", "BAD DISK" }, // not used for now { false, false, false, "EV7_25", "BEND NOT FOUND" }, // not used for now { false, false, false, "EV7_26", "LINE NUMBER TOO LARGE" }, // not used for now { false, false, false, "EV7_27", "UNRESOLVED REFERENCE" }, // not used for now - { true, true, true, "EV7_28", "NOT IMPLEMENTED" }, // this message actually differs rom CBM one + { true, true, true, "EV7_28", "NOT IMPLEMENTED" }, // this message actually differs from the CBM one { false, false, false, "EV7_29", "FILE READ" }, // not used for now // STD M65 X16 --- error strings specific to OpenROMs, not present in CBM BASIC dialects { true, true, true, "EOR_2A", "MEMORY CORRUPT" }, @@ -926,14 +927,20 @@ void writeStrings() // Add input data to computation objects dataSetSTD.addStrings(GLOBAL_Keywords_V2); + dataSetSTD.addStrings(GLOBAL_Keywords_CC); + dataSetSTD.addStrings(GLOBAL_Keywords_CD); dataSetSTD.addStrings(GLOBAL_Errors); dataSetSTD.addStrings(GLOBAL_MiscStrings); dataSetM65.addStrings(GLOBAL_Keywords_V2); + dataSetM65.addStrings(GLOBAL_Keywords_CC); + dataSetM65.addStrings(GLOBAL_Keywords_CD); dataSetM65.addStrings(GLOBAL_Errors); dataSetM65.addStrings(GLOBAL_MiscStrings); dataSetX16.addStrings(GLOBAL_Keywords_V2); + dataSetX16.addStrings(GLOBAL_Keywords_CC); + dataSetX16.addStrings(GLOBAL_Keywords_CD); dataSetX16.addStrings(GLOBAL_Errors); dataSetX16.addStrings(GLOBAL_MiscStrings); From 9846b69c718badb01442487d901e4c8060453ded Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 21 Jun 2020 21:53:49 +0200 Subject: [PATCH 061/103] more work on extended command set --- c64/aliases/,aliases_hardware.s | 13 ++- c64/basic/assets/packed_str_keywords_CC.s | 9 ++ c64/basic/assets/packed_str_keywords_CD.s | 9 ++ c64/basic/basic_commands_CD/cmd_fast.s | 34 +++++++- c64/basic/basic_commands_CD/cmd_slow.s | 39 ++++++++- .../board_m65/4000.mega65_vectable_basic_1.s | 6 +- c64/basic/engine/execute_line_statements.s | 85 ++++++++++++++++++- c64/basic/print/list_single_line.s | 75 ++++++++++++++++ c64/basic/print/print_packed_string.s | 18 ++-- c64/basic/tokenizer/tk_cut_away.s | 30 +++++++ c64/basic/tokenizer/tokenise_line.s | 76 +++++++++++++---- tools/generate_strings.cc | 10 ++- 12 files changed, 367 insertions(+), 37 deletions(-) create mode 100644 c64/basic/assets/packed_str_keywords_CC.s create mode 100644 c64/basic/assets/packed_str_keywords_CD.s create mode 100644 c64/basic/tokenizer/tk_cut_away.s diff --git a/c64/aliases/,aliases_hardware.s b/c64/aliases/,aliases_hardware.s index 74e8b6d3..f0096f81 100644 --- a/c64/aliases/,aliases_hardware.s +++ b/c64/aliases/,aliases_hardware.s @@ -187,10 +187,17 @@ #if CONFIG_MB_MEGA_65 - .const C65_EXTKEYS_PR = $D607 - .const C65_EXTKEYS_DDR = $D608 + .label C65_EXTKEYS_PR = $D607 + .label C65_EXTKEYS_DDR = $D608 - .const M65_BADL_SLI = $D710 + .label M65_BADL_SLI = $D710 + +#else + + // SuperCPU registers + + .label SCPU_SPEED_NORMAL = $D07A + .label SCPU_SPEED_TURBO = $D07B #endif diff --git a/c64/basic/assets/packed_str_keywords_CC.s b/c64/basic/assets/packed_str_keywords_CC.s new file mode 100644 index 00000000..4fe84295 --- /dev/null +++ b/c64/basic/assets/packed_str_keywords_CC.s @@ -0,0 +1,9 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +packed_str_keywords_CC: + + put_freq_packed_keywords_CC() diff --git a/c64/basic/assets/packed_str_keywords_CD.s b/c64/basic/assets/packed_str_keywords_CD.s new file mode 100644 index 00000000..8c9e51f3 --- /dev/null +++ b/c64/basic/assets/packed_str_keywords_CD.s @@ -0,0 +1,9 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +packed_str_keywords_CD: + + put_freq_packed_keywords_CD() diff --git a/c64/basic/basic_commands_CD/cmd_fast.s b/c64/basic/basic_commands_CD/cmd_fast.s index 056fed10..d447de59 100644 --- a/c64/basic/basic_commands_CD/cmd_fast.s +++ b/c64/basic/basic_commands_CD/cmd_fast.s @@ -5,4 +5,36 @@ cmd_fast: - jmp do_NOT_IMPLEMENTED_error // XXX implement the command +#if CONFIG_MB_MEGA_65 + + // Command implementation for Mega65 + + // XXX provide better implementation + + jmp execute_statements + +#elif CONFIG_MB_ULTIMATE_64 + + // Try to enable turbo in SuperCPU compatible way + sta SCPU_SPEED_TURBO + + jmp execute_statements + +#elif CONFIG_PLATFORM_COMMODORE_64 + + // Command implementation for generic C64 platform + + // Try to enable turbo mode in C128 compatible way + lda #$01 + sta VIC_CLKRATE + + // Try to enable turbo in SuperCPU compatible way + sta SCPU_SPEED_TURBO + + jmp execute_statements + +#else + + jmp do_NOT_IMPLEMENTED_error + +#endif diff --git a/c64/basic/basic_commands_CD/cmd_slow.s b/c64/basic/basic_commands_CD/cmd_slow.s index 730fb203..602dd740 100644 --- a/c64/basic/basic_commands_CD/cmd_slow.s +++ b/c64/basic/basic_commands_CD/cmd_slow.s @@ -5,4 +5,41 @@ cmd_slow: - jmp do_NOT_IMPLEMENTED_error // XXX implement the command + .break + +#if CONFIG_MB_MEGA_65 + + // Command implementation for Mega65 + + // XXX provide implementation + + jmp do_NOT_IMPLEMENTED_error + +#elif CONFIG_MB_ULTIMATE_64 + + // Command implementation for Ultimate 64 + + // Try to disable turbo in SuperCPU compatible way + sta SCPU_SPEED_NORMAL + + jmp execute_statements + +#elif CONFIG_PLATFORM_COMMODORE_64 + + // Command implementation for generic C64 platform + + // Try to disable turbo mode in C128 compatible way + + lda #$00 + sta VIC_CLKRATE + + // Try to disable turbo in SuperCPU compatible way + sta SCPU_SPEED_NORMAL + + jmp execute_statements + +#else + + jmp do_NOT_IMPLEMENTED_error + +#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 index 25c233d0..9239e233 100644 --- a/c64/basic/board_m65/4000.mega65_vectable_basic_1.s +++ b/c64/basic/board_m65/4000.mega65_vectable_basic_1.s @@ -17,9 +17,8 @@ .label VB1__list_single_line = $4000 + 2 * 3 .label VB1__print_packed_error = $4000 + 2 * 4 .label VB1__print_packed_misc_str = $4000 + 2 * 5 - .label VB1__print_packed_keyword_V2 = $4000 + 2 * 6 - .label VB1__basic_do_clr = $4000 + 2 * 7 - .label VB1__basic_do_new = $4000 + 2 * 8 + .label VB1__basic_do_clr = $4000 + 2 * 6 + .label VB1__basic_do_new = $4000 + 2 * 7 #else @@ -31,7 +30,6 @@ .word list_single_line .word print_packed_error .word print_packed_misc_str - .word print_packed_keyword_V2 .word basic_do_clr .word basic_do_new diff --git a/c64/basic/engine/execute_line_statements.s b/c64/basic/engine/execute_line_statements.s index 374db0e5..23b8a680 100644 --- a/c64/basic/engine/execute_line_statements.s +++ b/c64/basic/engine/execute_line_statements.s @@ -59,7 +59,7 @@ execute_statements: #else // HAS_OPCODES_65C02 - // Use jumptable to go to the token + // Use jumptable to go to the command routine asl tax @@ -70,14 +70,93 @@ execute_statements: execute_statements_extended: - // XXX here is the place for possible extended BASIC command set + // Support for extended BASIC commands + + cmp #$CC + beq execute_statements_CC + cmp #$CD + beq execute_statements_CD + + // 'GO' command has a strange token, it is placed after function tokens cmp #$CB - beq_16 cmd_go // 'GO' command has a strange token, it is placed after function tokens + beq_16 cmd_go jmp do_SYNTAX_error +execute_statements_CC: + + // Get the sub-token, check that it is valid + + jsr fetch_character + cmp #$00 + beq_16 do_SYNTAX_error + + cmp #(TK__MAXTOKEN_keywords_CC+1) + bcs_16 do_SYNTAX_error + + // Execute command + +#if !HAS_OPCODES_65C02 + + // Get the jump table entry for it, push it on the stack, and then RTS to start it. + + tax + lda command_CC_jumptable_hi - 1, x + pha + lda command_CC_jumptable_lo - 1, x + pha + + rts + +#else // HAS_OPCODES_65C02 + + // Use jumptable to go to the command routine + + asl + tax + jmp (command_CC_jumptable - 2, x) + +#endif + + +execute_statements_CD: + + // Get the sub-token, check that it is valid + + jsr fetch_character + cmp #$00 + beq_16 do_SYNTAX_error + + cmp #(TK__MAXTOKEN_keywords_CD+1) + bcs_16 do_SYNTAX_error + + // Execute command + +#if !HAS_OPCODES_65C02 + + // Get the jump table entry for it, push it on the stack, and then RTS to start it. + + tax + lda command_CD_jumptable_hi - 1, x + pha + lda command_CD_jumptable_lo - 1, x + pha + + rts + +#else // HAS_OPCODES_65C02 + + // Use jumptable to go to the command routine + + asl + tax + jmp (command_CD_jumptable - 2, x) + +#endif + + execute_statements_end_of_line: // First check, if we are in direct mode - if so, diff --git a/c64/basic/print/list_single_line.s b/c64/basic/print/list_single_line.s index 454b9cbb..7a3e5a35 100644 --- a/c64/basic/print/list_single_line.s +++ b/c64/basic/print/list_single_line.s @@ -82,11 +82,82 @@ list_not_quote: // Display a token +list_display_token_CC: + + cmp #$CC + bne list_display_token_CD + + // Fetch the sub-token + + iny +#if ROM_LAYOUT_M65 + jsr peek_via_OLDTXT +#elif CONFIG_MEMORY_MODEL_60K + ldx #packed_str_misc bne print_freq_packed_string // branch always +print_packed_keyword_CC: // .X - token number + + lda #packed_str_keywords_CC + bne print_freq_packed_string // branch always + +print_packed_keyword_CD: // .X - token number + + lda #packed_str_keywords_CD + bne print_freq_packed_string // branch always + print_packed_keyword_V2: // .X - token number lda #packed_str_keywords_V2 @@ -78,7 +80,23 @@ tokenise_line_loop: jsr tk_search bcc tokenise_line_keyword_V2 // branch if keyword identified - // XXX add support for additional keyword lists here + // Check for extended tokens + + lda #packed_str_keywords_CC + sta FRESPC+1 + + jsr tk_search + bcc tokenise_line_keyword_CC // branch if keyword identified + + lda #packed_str_keywords_CD + sta FRESPC+1 + + jsr tk_search + bcc tokenise_line_keyword_CD // branch if keyword identified // Shorten packed keyword candidate and try again @@ -106,28 +124,13 @@ tokenise_line_keyword_V2: // Cut away unnecessary bytes - inc tk__offset - ldx tk__offset + jsr tk_cut_away - dec tk__len_unpacked // keyword length, afterwards number of bytes to cut away - lda tk__len_unpacked - clc - adc tk__offset - tay -!: - lda BUF, y - sta BUF, x - beq !+ - - inx - iny - bne !- -!: // Special handling for REM command - after this one nothing more should be tokenised pla cmp #$0F // REM token index - bne tokenise_line_loop + jmp tokenise_line_loop // FALLTROUGH @@ -173,4 +176,41 @@ tokenise_line_char: inc tk__offset jmp tokenise_line_loop + +// Support for extended keyword lists + +tokenise_line_keyword_CC: + + // Store the token list index + + lda #$CC + skip_2_bytes_trash_nvz + + // FALLTROUGH + +tokenise_line_keyword_CD: + + // Store the token list index + + lda #$CD + + ldy tk__offset + sta BUF, y + + // Store the sub-token itself + + inx + txa + iny + sty tk__offset + sta BUF, y + + // Cut away unnecessary bytes + + inc tk__offset + dec tk__len_unpacked + + jsr tk_cut_away + jmp tokenise_line_loop + #endif // ROM layout diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index 16124a4a..552f4671 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -826,6 +826,14 @@ void DataSet::prepareOutput() } } + // For the token list - put the number of tokens available + + if (stringEntryList.type == ListType::KEYWORDS) + { + stream << std::endl << ".label TK__MAXTOKEN_" << stringEntryList.name << " = " << + std::dec << stringEncodedList.size() << std::endl; + } + stream << std::endl << ".macro put_freq_packed_" << stringEntryList.name << "()" << std::endl << "{" << std::endl; enum LastStr { NONE, SKIPPED, WRITTEN } lastStr = LastStr::NONE; @@ -867,7 +875,7 @@ void DataSet::prepareOutput() } } - // For the token list - pu the 'end of keywords' mark + // For the token list - put the 'end of keywords' mark if (stringEntryList.type == ListType::KEYWORDS) { From 92fd4552c4723c126e2cb6ff467b23e0ba2b0521 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 21 Jun 2020 22:06:46 +0200 Subject: [PATCH 062/103] fixed 2-byte tokens in tokenizer --- c64/basic/basic_commands_CD/cmd_slow.s | 2 -- c64/basic/tokenizer/tk_cut_away.s | 11 +++++++++-- c64/basic/tokenizer/tokenise_line.s | 7 ++----- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/c64/basic/basic_commands_CD/cmd_slow.s b/c64/basic/basic_commands_CD/cmd_slow.s index 602dd740..0a98f2c6 100644 --- a/c64/basic/basic_commands_CD/cmd_slow.s +++ b/c64/basic/basic_commands_CD/cmd_slow.s @@ -5,8 +5,6 @@ cmd_slow: - .break - #if CONFIG_MB_MEGA_65 // Command implementation for Mega65 diff --git a/c64/basic/tokenizer/tk_cut_away.s b/c64/basic/tokenizer/tk_cut_away.s index 941a322f..c88e3c6a 100644 --- a/c64/basic/tokenizer/tk_cut_away.s +++ b/c64/basic/tokenizer/tk_cut_away.s @@ -8,12 +8,19 @@ // -tk_cut_away: +tk_cut_away_2: // for two-bytes tokenized keywords + + dec tk__len_unpacked + + // FALLTROUGH + +tk_cut_away_1: // for single-byte tokenized keywords + + dec tk__len_unpacked // keyword length, afterwards number of bytes to cut away inc tk__offset ldy tk__offset - dec tk__len_unpacked // keyword length, afterwards number of bytes to cut away lda tk__len_unpacked clc adc tk__offset diff --git a/c64/basic/tokenizer/tokenise_line.s b/c64/basic/tokenizer/tokenise_line.s index 467c9c49..fc817293 100644 --- a/c64/basic/tokenizer/tokenise_line.s +++ b/c64/basic/tokenizer/tokenise_line.s @@ -124,7 +124,7 @@ tokenise_line_keyword_V2: // Cut away unnecessary bytes - jsr tk_cut_away + jsr tk_cut_away_1 // Special handling for REM command - after this one nothing more should be tokenised @@ -207,10 +207,7 @@ tokenise_line_keyword_CD: // Cut away unnecessary bytes - inc tk__offset - dec tk__len_unpacked - - jsr tk_cut_away + jsr tk_cut_away_2 jmp tokenise_line_loop #endif // ROM layout From 20ce3b5405f585497b3633899bb5061a28e634c5 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 21 Jun 2020 22:35:46 +0200 Subject: [PATCH 063/103] PAL/NTSC display moved back to BASIC, reuses string compression --- CONFIG.md | 8 +------- c64/,,config_cx16.s | 1 - c64/,,config_generic.s | 1 - c64/,,config_mega65.s | 1 - c64/,,config_testing.s | 1 - c64/,,config_ultimate64.s | 1 - c64/basic/,imports.s | 4 ---- c64/basic/init/initmsg_real.s | 18 +++--------------- c64/basic/print/print_pal_ntsc.s | 21 +++++++++++++++++++++ c64/kernal/assets/kernal_messages.s | 17 ----------------- c64/kernal/print/print_pal_ntsc.s | 20 -------------------- tools/generate_strings.cc | 2 ++ 12 files changed, 27 insertions(+), 68 deletions(-) create mode 100644 c64/basic/print/print_pal_ntsc.s delete mode 100644 c64/kernal/print/print_pal_ntsc.s diff --git a/CONFIG.md b/CONFIG.md index afeab009..b33a17ed 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -313,16 +313,10 @@ Richer banners need more BASIC segment, varies between brands. ### `CONFIG_SHOW_FEATURES` -If enabled, shows the most important compiled-in features on the startup screen. +If enabled, shows the most important compiled-in features on the startup screen. Also shows the video system (PAL/NTSC). It is recommended to keep it enabled for informational purposes. -### `CONFIG_BANNER_PAL_NTSC` - -If enabled, prints video system on startup banner. Eye candy only. - -Feature needs few bytes in BASIC and about 25 bytes in KERNAL segment. - ## Debug options Options in this section are for debug purposes only. If unsure - disable. diff --git a/c64/,,config_cx16.s b/c64/,,config_cx16.s index 0643ac68..b1ce579a 100644 --- a/c64/,,config_cx16.s +++ b/c64/,,config_cx16.s @@ -128,7 +128,6 @@ #define CONFIG_BANNER_FANCY // #define CONFIG_BANNER_BRAND // #define CONFIG_SHOW_FEATURES -// #define CONFIG_SHOW_PAL_NTSC // Debug options diff --git a/c64/,,config_generic.s b/c64/,,config_generic.s index 711d06b5..aea04a58 100644 --- a/c64/,,config_generic.s +++ b/c64/,,config_generic.s @@ -126,7 +126,6 @@ #define CONFIG_BANNER_FANCY // #define CONFIG_BANNER_BRAND #define CONFIG_SHOW_FEATURES -#define CONFIG_SHOW_PAL_NTSC // Debug options diff --git a/c64/,,config_mega65.s b/c64/,,config_mega65.s index 1d8e77e5..dafe48d5 100644 --- a/c64/,,config_mega65.s +++ b/c64/,,config_mega65.s @@ -126,7 +126,6 @@ // #define CONFIG_BANNER_FANCY #define CONFIG_BANNER_BRAND // #define CONFIG_SHOW_FEATURES -// #define CONFIG_SHOW_PAL_NTSC // Debug options diff --git a/c64/,,config_testing.s b/c64/,,config_testing.s index 1b50ed8b..c0785af2 100644 --- a/c64/,,config_testing.s +++ b/c64/,,config_testing.s @@ -126,7 +126,6 @@ // #define CONFIG_BANNER_FANCY // #define CONFIG_BANNER_BRAND #define CONFIG_SHOW_FEATURES -#define CONFIG_SHOW_PAL_NTSC // Debug options diff --git a/c64/,,config_ultimate64.s b/c64/,,config_ultimate64.s index 6fc5a03e..bb76f26a 100644 --- a/c64/,,config_ultimate64.s +++ b/c64/,,config_ultimate64.s @@ -126,7 +126,6 @@ #define CONFIG_BANNER_FANCY // #define CONFIG_BANNER_BRAND #define CONFIG_SHOW_FEATURES -#define CONFIG_SHOW_PAL_NTSC // Debug options diff --git a/c64/basic/,imports.s b/c64/basic/,imports.s index 20eaa980..3d0934dc 100644 --- a/c64/basic/,imports.s +++ b/c64/basic/,imports.s @@ -47,10 +47,6 @@ .label print_features = KERNAL().print_features #endif -#if CONFIG_SHOW_PAL_NTSC -.label print_pal_ntsc = KERNAL().print_pal_ntsc -#endif - #if CONFIG_TAPE_HEAD_ALIGN .label tape_head_align = KERNAL().tape_head_align #endif diff --git a/c64/basic/init/initmsg_real.s b/c64/basic/init/initmsg_real.s index 62e612d4..3438c8ad 100644 --- a/c64/basic/init/initmsg_real.s +++ b/c64/basic/init/initmsg_real.s @@ -17,7 +17,7 @@ initmsg_real: #endif - // Clear the screen first, some cartridges (like IEEE-488) leeave a mess on the screen + // Clear the screen first, some cartridges (like IEEE-488) are leaving a mess on the screen lda #147 jsr JCHROUT @@ -55,16 +55,10 @@ initmsg_real: ldx #$05 #endif ldy #$00 -#if CONFIG_SHOW_PAL_NTSC && CONFIG_SHOW_FEATURES +#if CONFIG_SHOW_FEATURES jsr plot_set jsr print_features jmp print_pal_ntsc -#elif CONFIG_SHOW_PAL_NTSC - jsr plot_set - jmp print_pal_ntsc -#elif CONFIG_SHOW_FEATURES - jsr plot_set - jmp print_features #else jmp plot_set #endif @@ -115,16 +109,10 @@ initmsg_real: ldx #$05 #endif ldy #$00 -#if CONFIG_SHOW_PAL_NTSC && CONFIG_SHOW_FEATURES +#if CONFIG_SHOW_FEATURES jsr plot_set jsr print_features jmp print_pal_ntsc -#elif CONFIG_SHOW_PAL_NTSC - jsr plot_set - jmp print_pal_ntsc -#elif CONFIG_SHOW_FEATURES - jsr plot_set - jmp print_features #else jmp plot_set #endif diff --git a/c64/basic/print/print_pal_ntsc.s b/c64/basic/print/print_pal_ntsc.s new file mode 100644 index 00000000..cfabc62e --- /dev/null +++ b/c64/basic/print/print_pal_ntsc.s @@ -0,0 +1,21 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Print video system on startup banner +// + +#if CONFIG_SHOW_FEATURES + +print_pal_ntsc: + + ldx #IDX__STR_NTSC + lda TVSFLG + beq !+ + ldx #IDX__STR_PAL +!: + jmp print_packed_misc_str + +#endif // CONFIG_SHOW_FEATURES diff --git a/c64/kernal/assets/kernal_messages.s b/c64/kernal/assets/kernal_messages.s index 16cca4ce..a5d712bf 100644 --- a/c64/kernal/assets/kernal_messages.s +++ b/c64/kernal/assets/kernal_messages.s @@ -26,11 +26,6 @@ #endif #endif -#if CONFIG_SHOW_PAL_NTSC -.label __MSG_KERNAL_PAL = __msg_kernalpal - __msg_kernal_first -.label __MSG_KERNAL_NTSC = __msg_kernalntsc - __msg_kernal_first -#endif - #if CONFIG_PANIC_SCREEN .label __MSG_KERNAL_PANIC = __msg_kernalpanic - __msg_kernal_first .label __MSG_KERNAL_PANIC_ROM_MISMATCH = __msg_kernalpanic_rom_mismatch - __msg_kernal_first @@ -93,18 +88,6 @@ __msg_kernaloksearching: #endif -#if CONFIG_SHOW_PAL_NTSC - -__msg_kernalpal: - .text "PAL" - .byte $80 + $0D // end of string mark + return - -__msg_kernalntsc: - .text "NTSC" - .byte $80 + $0D // end of string mark + return - -#endif // CONFIG_SHOW_PAL_NTSC - #if CONFIG_PANIC_SCREEN __msg_kernalpanic: diff --git a/c64/kernal/print/print_pal_ntsc.s b/c64/kernal/print/print_pal_ntsc.s deleted file mode 100644 index d005a63f..00000000 --- a/c64/kernal/print/print_pal_ntsc.s +++ /dev/null @@ -1,20 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# * KERNAL_0 #TAKE -// #LAYOUT# * * #IGNORE - -// -// Print video system on startup banner -// - -#if CONFIG_SHOW_PAL_NTSC - -print_pal_ntsc: - - ldx #__MSG_KERNAL_NTSC - lda TVSFLG - beq !+ - ldx #__MSG_KERNAL_PAL -!: - jmp print_kernal_message - -#endif // CONFIG_SHOW_PAL_NTSC diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index 552f4671..720c4ceb 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -313,6 +313,8 @@ const StringEntryList GLOBAL_MiscStrings = { ListType::STRINGS_BASIC, "misc", { true, true, true, "STR_ERROR", " ERROR" }, // simply the word error that is attached to the other parts of messages https://fjkraan.home.xs4all.nl/comp/apple2faq/app2asoftfaq.html { true, true, true, "STR_IN", " IN " }, // STD M65 X16 --- misc strings specific to OpenROMs, not present in CBM ROMs + { true, true, true, "STR_PAL", "PAL\r" }, + { true, true, true, "STR_NTSC", "NTSC\r" }, { true, true, true, "STR_BRK_AT", "\rBRK AT $" }, } }; From 86f56d77f9f9c2a2abac4c27c44bedab9a8c3fb5 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 21 Jun 2020 22:57:33 +0200 Subject: [PATCH 064/103] fixed a bug preventing proper tokenizing of some keywords --- c64/basic/tokenizer/tk_pack.s | 1 - 1 file changed, 1 deletion(-) diff --git a/c64/basic/tokenizer/tk_pack.s b/c64/basic/tokenizer/tk_pack.s index bf4ee935..5c9143dd 100644 --- a/c64/basic/tokenizer/tk_pack.s +++ b/c64/basic/tokenizer/tk_pack.s @@ -221,7 +221,6 @@ tk_pack_3n_new_byte: // Adjust remaining counters / flags - iny sty tk__byte_offset dec tk__nibble_flag // $00 -> $FF From 4ac36931b02351d8f5eebe68ca8be8def9314022 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 21 Jun 2020 23:05:23 +0200 Subject: [PATCH 065/103] updated binaries --- Makefile | 1 + bin/basic_generic.rom | Bin 8192 -> 8192 bytes bin/basic_ultimate64.rom | Bin 8192 -> 8192 bytes bin/kernal_generic.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 7 files changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 5ed42036..c4ec4e0c 100644 --- a/Makefile +++ b/Makefile @@ -372,6 +372,7 @@ build/symbols_hybrid.vs: $(DIR_GEN)/KERNAL_combined.vs # Rules - platform 'Mega65' specific $(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 + rm -f $(TARGET_M65_x) $(TARGET_M65_x_PXL) 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 diff --git a/bin/basic_generic.rom b/bin/basic_generic.rom index 60c817dfb7fcea19063e9ed94c7cee133835a30d..825da11fb7ddd3ea7a6313386f3ad78acc4addea 100644 GIT binary patch delta 3861 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 Z6QfBh)h3ND++dz{Em;e`r8YlS?!Sm4o~-}? diff --git a/bin/basic_ultimate64.rom b/bin/basic_ultimate64.rom index 3ac5c270cad595433cee53f354739d7e4d857b40..e7fa7bb7d0ebc58ccffcc058a4bc9b1ccee36520 100644 GIT binary patch delta 3736 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 Y2c-Q@1KSe6Oh4%{Q4KDW6L}8(U#0GHEC2ui diff --git a/bin/kernal_generic.rom b/bin/kernal_generic.rom index 2832244e184841b1acafa67063c18f796ee83d4f..b8ec999da4830541ee286c9e1159f9431ea52be2 100644 GIT binary patch delta 2992 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 fe;K_$i-s$QVS50E` delta 2957 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 delta 2872 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 diff --git a/bin/mega65_pxlfont.rom b/bin/mega65_pxlfont.rom index 6d47bae8cb7657b11c4eb719e3c2caa825a97cb9..ac549a038e79346158b129fb6226dea2655daab7 100644 GIT binary patch delta 3991 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 From 5cdd71b3fc062b9188ab8fdbff2748dc38bbe521 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 21 Jun 2020 23:26:31 +0200 Subject: [PATCH 066/103] some error message improvements --- c64/basic/engine/do_error.s | 2 ++ c64/basic/engine/execute_line_statements.s | 20 +++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/c64/basic/engine/do_error.s b/c64/basic/engine/do_error.s index e86c82d6..e916f016 100644 --- a/c64/basic/engine/do_error.s +++ b/c64/basic/engine/do_error.s @@ -40,6 +40,8 @@ do_kernal_error: // .A = KERNAL error code, also almost ma // Convert to BASIC error code tax + beq do_BREAK_error // XXX is 0 really a proper error code? + dex bpl do_basic_error // branch always diff --git a/c64/basic/engine/execute_line_statements.s b/c64/basic/engine/execute_line_statements.s index 23b8a680..6b85037b 100644 --- a/c64/basic/engine/execute_line_statements.s +++ b/c64/basic/engine/execute_line_statements.s @@ -40,7 +40,7 @@ execute_statements: // Check if token is valid for execution cmp #$7F - bcc_16 do_SYNTAX_error // branch if not a token XXX here we should handle variable assignments + bcc_16 execute_statements_var_assign // not a token - try variable assign cmp #$A6 bcs execute_statements_extended @@ -224,3 +224,21 @@ execute_line: sta CURLIN+1 jmp execute_statements + + +execute_statements_var_assign: + + // XXX here we should handle variable assignments, probably in a separate file + + // Prevent wedges from being executed within a program + +#if CONFIG_TAPE_WEDGE + cmp #$40 + beq_16 do_DIRECT_MODE_ONLY_error +#endif +#if CONFIG_DOS_WEDGE + cmp #$5F + beq_16 do_DIRECT_MODE_ONLY_error +#endif + + jmp do_SYNTAX_error From 7c1c7849f530094a7db3c313a0ff4640e582d30d Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 21 Jun 2020 23:36:01 +0200 Subject: [PATCH 067/103] FAST and SLOW commands for the Mega65 are now implemented too --- c64/basic/basic_commands_CD/cmd_fast.s | 3 ++- c64/basic/basic_commands_CD/cmd_slow.s | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/c64/basic/basic_commands_CD/cmd_fast.s b/c64/basic/basic_commands_CD/cmd_fast.s index d447de59..913ca187 100644 --- a/c64/basic/basic_commands_CD/cmd_fast.s +++ b/c64/basic/basic_commands_CD/cmd_fast.s @@ -9,7 +9,8 @@ cmd_fast: // Command implementation for Mega65 - // XXX provide better implementation + lda #$41 + sta CPU_D6510 jmp execute_statements diff --git a/c64/basic/basic_commands_CD/cmd_slow.s b/c64/basic/basic_commands_CD/cmd_slow.s index 0a98f2c6..cae5e5d6 100644 --- a/c64/basic/basic_commands_CD/cmd_slow.s +++ b/c64/basic/basic_commands_CD/cmd_slow.s @@ -9,9 +9,10 @@ cmd_slow: // Command implementation for Mega65 - // XXX provide implementation + lda #$40 + sta CPU_D6510 - jmp do_NOT_IMPLEMENTED_error + jmp execute_statements #elif CONFIG_MB_ULTIMATE_64 From 6639ac5609c20a5d3e0e183b6ac4a4f87a7d9c89 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 21 Jun 2020 23:44:26 +0200 Subject: [PATCH 068/103] saved few bytes in BASIC segment --- c64/basic/basic_commands_CD/cmd_fast.s | 41 ----------- c64/basic/basic_commands_CD/cmd_fast_slow.s | 78 +++++++++++++++++++++ c64/basic/basic_commands_CD/cmd_slow.s | 44 ------------ 3 files changed, 78 insertions(+), 85 deletions(-) delete mode 100644 c64/basic/basic_commands_CD/cmd_fast.s create mode 100644 c64/basic/basic_commands_CD/cmd_fast_slow.s delete mode 100644 c64/basic/basic_commands_CD/cmd_slow.s diff --git a/c64/basic/basic_commands_CD/cmd_fast.s b/c64/basic/basic_commands_CD/cmd_fast.s deleted file mode 100644 index 913ca187..00000000 --- a/c64/basic/basic_commands_CD/cmd_fast.s +++ /dev/null @@ -1,41 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - - -cmd_fast: - -#if CONFIG_MB_MEGA_65 - - // Command implementation for Mega65 - - lda #$41 - sta CPU_D6510 - - jmp execute_statements - -#elif CONFIG_MB_ULTIMATE_64 - - // Try to enable turbo in SuperCPU compatible way - sta SCPU_SPEED_TURBO - - jmp execute_statements - -#elif CONFIG_PLATFORM_COMMODORE_64 - - // Command implementation for generic C64 platform - - // Try to enable turbo mode in C128 compatible way - lda #$01 - sta VIC_CLKRATE - - // Try to enable turbo in SuperCPU compatible way - sta SCPU_SPEED_TURBO - - jmp execute_statements - -#else - - jmp do_NOT_IMPLEMENTED_error - -#endif diff --git a/c64/basic/basic_commands_CD/cmd_fast_slow.s b/c64/basic/basic_commands_CD/cmd_fast_slow.s new file mode 100644 index 00000000..79fcb6ae --- /dev/null +++ b/c64/basic/basic_commands_CD/cmd_fast_slow.s @@ -0,0 +1,78 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +#if CONFIG_MB_MEGA_65 + + // Command implementation for Mega65 + + // XXX - I think there are some bit-set instructions in 65CE02... + +cmd_slow: + + lda #$40 + skip_2_bytes_trash_nvz + + // FALLTROUGH + +cmd_fast: + + lda #$41 + sta CPU_D6510 + + jmp execute_statements + +#elif CONFIG_MB_ULTIMATE_64 + + // Command implementation for Ultimate 64 - SuperCPU compatible way should be enough + +cmd_slow: + + sta SCPU_SPEED_NORMAL + jmp execute_statements + +cmd_fast: + + sta SCPU_SPEED_TURBO + jmp execute_statements + +#elif CONFIG_PLATFORM_COMMODORE_64 + + // Command implementation for generic C64 platform + +cmd_slow: + + // Try to disable turbo in SuperCPU compatible way + sta SCPU_SPEED_NORMAL + + // Try to disable turbo mode in C128 compatible way + + lda #$00 + beq !+ // branch always + +cmd_fast: + + // Try to enable turbo in SuperCPU compatible way + sta SCPU_SPEED_TURBO + + // Try to enable turbo mode in C128 compatible way + lda #$01 +!: + sta VIC_CLKRATE + + jmp execute_statements + +#else + +cmd_slow: + + nop // to prevent double label + + // FALLTROUGH + +cmd_fast: + + jmp do_NOT_IMPLEMENTED_error + +#endif diff --git a/c64/basic/basic_commands_CD/cmd_slow.s b/c64/basic/basic_commands_CD/cmd_slow.s deleted file mode 100644 index cae5e5d6..00000000 --- a/c64/basic/basic_commands_CD/cmd_slow.s +++ /dev/null @@ -1,44 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - - -cmd_slow: - -#if CONFIG_MB_MEGA_65 - - // Command implementation for Mega65 - - lda #$40 - sta CPU_D6510 - - jmp execute_statements - -#elif CONFIG_MB_ULTIMATE_64 - - // Command implementation for Ultimate 64 - - // Try to disable turbo in SuperCPU compatible way - sta SCPU_SPEED_NORMAL - - jmp execute_statements - -#elif CONFIG_PLATFORM_COMMODORE_64 - - // Command implementation for generic C64 platform - - // Try to disable turbo mode in C128 compatible way - - lda #$00 - sta VIC_CLKRATE - - // Try to disable turbo in SuperCPU compatible way - sta SCPU_SPEED_NORMAL - - jmp execute_statements - -#else - - jmp do_NOT_IMPLEMENTED_error - -#endif From c3335393c21edaf13b584181177826988550c075 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 22 Jun 2020 15:33:48 +0200 Subject: [PATCH 069/103] implemented MERGE command --- c64/basic/basic_commands/cmd_load_verify.s | 3 ++ c64/basic/basic_commands_CC/cmd_bload.s | 8 ---- .../basic_commands_CC/cmd_bload_bverify.s | 41 +++++++++++++++++ c64/basic/basic_commands_CC/cmd_bverify.s | 8 ---- c64/basic/basic_commands_CC/cmd_merge.s | 44 ++++++++++++++++++- c64/basic/engine/fetch_device_secondary.s | 33 +++++++------- 6 files changed, 105 insertions(+), 32 deletions(-) delete mode 100644 c64/basic/basic_commands_CC/cmd_bload.s create mode 100644 c64/basic/basic_commands_CC/cmd_bload_bverify.s delete mode 100644 c64/basic/basic_commands_CC/cmd_bverify.s diff --git a/c64/basic/basic_commands/cmd_load_verify.s b/c64/basic/basic_commands/cmd_load_verify.s index e77a22e4..45e1520c 100644 --- a/c64/basic/basic_commands/cmd_load_verify.s +++ b/c64/basic/basic_commands/cmd_load_verify.s @@ -50,6 +50,9 @@ cmd_load_got_params: // input for tape wedge ldy TXTTAB+1 ldx TXTTAB+0 + +cmd_load_loadmerge: // entry point for 'cmd_merge' + lda VERCKB // LOAD or VERIFY jsr JLOAD diff --git a/c64/basic/basic_commands_CC/cmd_bload.s b/c64/basic/basic_commands_CC/cmd_bload.s deleted file mode 100644 index 2feed6d0..00000000 --- a/c64/basic/basic_commands_CC/cmd_bload.s +++ /dev/null @@ -1,8 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - - -cmd_bload: - - jmp do_NOT_IMPLEMENTED_error // XXX implement the command diff --git a/c64/basic/basic_commands_CC/cmd_bload_bverify.s b/c64/basic/basic_commands_CC/cmd_bload_bverify.s new file mode 100644 index 00000000..aaab38d0 --- /dev/null +++ b/c64/basic/basic_commands_CC/cmd_bload_bverify.s @@ -0,0 +1,41 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +cmd_bverify: + + // LOAD and VERIFY are very similar, from BASIC perspective there is almost no difference; + // just different parameter passed to Kernal and different error message in case of failure + + lda #$01 // mark operation as VERIFY + skip_2_bytes_trash_nvz + +cmd_bload: + + lda #$00 // mark operation as LOAD + sta VERCKB + + // Set default device and secondary address; channel is not important now + + jsr select_device + ldy #$00 // secondary address 0 - it has to be loaded precisely where we want + jsr JSETFLS + + // Fetch the file name + + jsr fetch_filename + bcc !+ + + // No filename supplied - this should only be allowed for tape (device number below 8) + + lda FA + and #%11111000 + bne_16 do_MISSING_FILENAME_error + + lda #$00 + sta FNLEN +!: + // XXX finish the implementation + + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/basic_commands_CC/cmd_bverify.s b/c64/basic/basic_commands_CC/cmd_bverify.s deleted file mode 100644 index 3fdfdf8a..00000000 --- a/c64/basic/basic_commands_CC/cmd_bverify.s +++ /dev/null @@ -1,8 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - - -cmd_bverify: - - jmp do_NOT_IMPLEMENTED_error // XXX implement the command diff --git a/c64/basic/basic_commands_CC/cmd_merge.s b/c64/basic/basic_commands_CC/cmd_merge.s index f464369e..42410adb 100644 --- a/c64/basic/basic_commands_CC/cmd_merge.s +++ b/c64/basic/basic_commands_CC/cmd_merge.s @@ -5,4 +5,46 @@ cmd_merge: - jmp do_NOT_IMPLEMENTED_error // XXX implement the command + lda #$00 // mark operation as LOAD + sta VERCKB + + // Set default device and secondary address; channel is not important now + + jsr select_device + ldy #$00 // secondary address 0 - it has to be loaded precisely where we want + jsr JSETFLS + + // Fetch the file name + + jsr fetch_filename + bcc !+ + + // No filename supplied - this should only be allowed for tape (device number below 8) + + lda FA + and #%11111000 + bne_16 do_MISSING_FILENAME_error + + lda #$00 + sta FNLEN +!: + // Fetch device number + + jsr fetch_device_secondary_uint8 + bcs !+ + + sta FA +!: + // Perform loading - just for a different address + + sec + lda VARTAB+0 + sbc #$02 + sta VARTAB+0 + tax + bcs !+ + dec VARTAB+1 +!: + ldy VARTAB+1 + + jmp cmd_load_loadmerge // XXX check variable handling (VARTAB) after failure to load diff --git a/c64/basic/engine/fetch_device_secondary.s b/c64/basic/engine/fetch_device_secondary.s index 8094d303..3fb96a95 100644 --- a/c64/basic/engine/fetch_device_secondary.s +++ b/c64/basic/engine/fetch_device_secondary.s @@ -11,15 +11,9 @@ fetch_device_secondary: // Fetch the device number - jsr injest_comma - bcs fetch_secondary + jsr fetch_device_secondary_uint8 + bcs fetch_device_secondary_done - jsr injest_spaces - jsr basic_parse_line_number - lda LINNUM+1 - bne_16 do_ILLEGAL_QUANTITY_error - - lda LINNUM+0 sta FA // FALLTROUGH @@ -28,15 +22,9 @@ fetch_secondary: // Fetch secondary address - jsr injest_comma + jsr fetch_device_secondary_uint8 bcs fetch_device_secondary_done - jsr injest_spaces - jsr basic_parse_line_number - lda LINNUM+1 - bne_16 do_ILLEGAL_QUANTITY_error - - lda LINNUM+0 sta SA // FALLTROUGH @@ -44,3 +32,18 @@ fetch_secondary: fetch_device_secondary_done: rts + + +fetch_device_secondary_uint8: // also called by 'cmd_merge' + + jsr injest_comma + bcs !+ + + jsr injest_spaces + jsr basic_parse_line_number + lda LINNUM+1 + bne_16 do_ILLEGAL_QUANTITY_error + lda LINNUM+0 + clc +!: + rts From 37b32759dc618c053a2a0b8f7a44ee1c93d92730 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 22 Jun 2020 17:07:15 +0200 Subject: [PATCH 070/103] feature set string is now compressed too --- Makefile | 100 +++++--- c64/,,config_custom.s | 3 +- c64/aliases/,aliases_config.s | 91 +------ c64/aliases/,aliases_ram_lowmem.s | 2 +- c64/basic/,imports.s | 4 - c64/basic/init/initmsg_real.s | 6 +- .../{print_pal_ntsc.s => print_features.s} | 9 +- c64/kernal/assets/kernal_messages.s | 11 - c64/kernal/iec/iec_cmd_open.s | 2 +- c64/kernal/iec/load_iec.s | 2 +- c64/kernal/iec/save_iec.s | 2 +- ...soft_advertise.s => burst_m65_advertise.s} | 2 +- c64/kernal/print/print_features.s | 17 -- tools/generate_strings.cc | 239 +++++++++++++++--- 14 files changed, 294 insertions(+), 196 deletions(-) rename c64/basic/print/{print_pal_ntsc.s => print_features.s} (65%) rename c64/kernal/iec_fast/{burst_soft_advertise.s => burst_m65_advertise.s} (93%) delete mode 100644 c64/kernal/print/print_features.s diff --git a/Makefile b/Makefile index c4ec4e0c..300eafd0 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,7 @@ SRC_TOOLS = $(wildcard tools/*.c,tools/*.cc) # Generated files -GEN_BASIC = build/,generated/packed_strings.s build/,generated/float_constants.s +GEN_BASIC = build/,generated/float_constants.s GEN_KERNAL = # List of build directories @@ -78,10 +78,19 @@ CFG_M65 = c64/,,config_mega65.s CFG_U64 = c64/,,config_ultimate64.s CFG_X16 = c64/,,config_cx16.s +# List of files with generated strings + +GEN_STR_CUS = $(DIR_CUS)/,generated/packed_strings.s +GEN_STR_GEN = $(DIR_GEN)/,generated/packed_strings.s +GEN_STR_TST = $(DIR_TST)/,generated/packed_strings.s +GEN_STR_M65 = $(DIR_M65)/,generated/packed_strings.s +GEN_STR_U64 = $(DIR_U64)/,generated/packed_strings.s +GEN_STR_X16 = $(DIR_X16)/,generated/packed_strings.s + # Dependencies - helper variables -DEP_BASIC = $(SRC_BASIC) $(SRCDIR_BASIC) $(GEN_BASIC) -DEP_KERNAL = $(SRC_KERNAL) $(SRCDIR_KERNAL) $(GEN_KERNAL) +DEP_BASIC = $(SRC_BASIC) $(SRCDIR_BASIC) $(GEN_BASIC) +DEP_KERNAL = $(SRC_KERNAL) $(SRCDIR_KERNAL) $(GEN_KERNAL) # List of tools @@ -196,42 +205,42 @@ build/chargen_pxlfont.patched: $(TOOL_PATCH_CHARGEN) build/chargen_pxlfont.rom # Dependencies - BASIC and KERNAL $(DIR_CUS)/OUTB_x.BIN $(DIR_CUS)/BASIC_combined.vs: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_BASIC) $(CFG_CUS) $(DIR_CUS)/KERNAL_combined.sym + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_BASIC) $(CFG_CUS) $(GEN_STR_CUS) $(DIR_CUS)/KERNAL_combined.sym $(DIR_GEN)/OUTB_x.BIN $(DIR_GEN)/BASIC_combined.vs: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_BASIC) $(CFG_GEN) $(DIR_GEN)/KERNAL_combined.sym + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_BASIC) $(CFG_GEN) $(GEN_STR_GEN) $(DIR_GEN)/KERNAL_combined.sym $(DIR_TST)/OUTB_x.BIN $(DIR_TST)/BASIC_combined.vs: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_BASIC) $(CFG_TST) $(DIR_TST)/KERNAL_combined.sym + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_BASIC) $(CFG_TST) $(GEN_STR_TST) $(DIR_TST)/KERNAL_combined.sym $(DIR_U64)/OUTB_x.BIN $(DIR_U64)/BASIC_combined.vs: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_BASIC) $(CFG_U64) $(DIR_U64)/KERNAL_combined.sym + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_BASIC) $(CFG_U64) $(GEN_STR_U64) $(DIR_U64)/KERNAL_combined.sym $(DIR_CUS)/OUTK_x.BIN $(DIR_CUS)/KERNAL_combined.vs $(DIR_CUS)/KERNAL_combined.sym: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_KERNAL) $(CFG_CUS) + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_KERNAL) $(CFG_CUS) $(GEN_STR_CUS) $(DIR_GEN)/OUTK_x.BIN $(DIR_GEN)/KERNAL_combined.vs $(DIR_GEN)/KERNAL_combined.sym: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_KERNAL) $(CFG_GEN) + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_KERNAL) $(CFG_GEN) $(GEN_STR_GEN) $(DIR_TST)/OUTK_x.BIN $(DIR_TST)/KERNAL_combined.vs $(DIR_TST)/KERNAL_combined.sym: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_KERNAL) $(CFG_TST) + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_KERNAL) $(CFG_TST) $(GEN_STR_TST) $(DIR_U64)/OUTK_x.BIN $(DIR_U64)/KERNAL_combined.vs $(DIR_U64)/KERNAL_combined.sym: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_KERNAL) $(CFG_U64) + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_KERNAL) $(CFG_U64) $(GEN_STR_U64) $(DIR_M65)/OUTB_0.BIN $(DIR_M65)/BASIC_0_combined.vs $(DIR_M65)/BASIC_0_combined.sym: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_BASIC) $(CFG_M65) $(DIR_M65)/KERNAL_0_combined.sym + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_BASIC) $(CFG_M65) $(GEN_STR_M65) $(DIR_M65)/KERNAL_0_combined.sym $(DIR_M65)/OUTK_0.BIN $(DIR_M65)/KERNAL_0_combined.vs $(DIR_M65)/KERNAL_0_combined.sym: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_KERNAL) $(CFG_M65) + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_KERNAL) $(CFG_M65) $(GEN_STR_M65) $(DIR_X16)/OUTB_0.BIN $(DIR_X16)/BASIC_0_combined.vs $(DIR_X16)/BASIC_0_combined.sym: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_BASIC) $(CFG_X16) $(DIR_X16)/KERNAL_0_combined.sym + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_BASIC) $(CFG_X16) $(GEN_STR_X16) $(DIR_X16)/KERNAL_0_combined.sym $(DIR_X16)/OUTK_0.BIN $(DIR_X16)/KERNAL_0_combined.vs $(DIR_X16)/KERNAL_0_combined.sym: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_KERNAL) $(CFG_X16) + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_KERNAL) $(CFG_X16) $(GEN_STR_X16) $(DIR_M65)/basic.seg_1 $(DIR_M65)/BASIC_1_combined.vs $(DIR_M65)/BASIC_1_combined.sym: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_BASIC) $(CFG_M65) $(DIR_M65)/KERNAL_0_combined.sym $(DIR_M65)/BASIC_0_combined.sym + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_BASIC) $(CFG_M65) $(GEN_STR_M65) $(DIR_M65)/KERNAL_0_combined.sym $(DIR_M65)/BASIC_0_combined.sym $(DIR_M65)/kernal.seg_1 $(DIR_M65)/KERNAL_1_combined.vs $(DIR_M65)/KERNAL_1_combined.sym: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_KERNAL) $(CFG_M65) $(DIR_M65)/KERNAL_0_combined.sym + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_KERNAL) $(CFG_M65) $(GEN_STR_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_X16)/KERNAL_0_combined.sym $(DIR_X16)/BASIC_0_combined.sym + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_BASIC) $(CFG_X16) $(GEN_STR_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 + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(DEP_KERNAL) $(CFG_X16) $(GEN_STR_X16) $(DIR_X16)/KERNAL_0_combined.sym $(DIR_CUS)/OUTx_x.BIN: $(DIR_CUS)/OUTB_x.BIN $(DIR_CUS)/OUTK_x.BIN $(DIR_GEN)/OUTx_x.BIN: $(DIR_GEN)/OUTB_x.BIN $(DIR_GEN)/OUTK_x.BIN @@ -257,69 +266,96 @@ build/symbols_ultimate64.vs: $(DIR_U64)/BASIC_combined.vs $(DIR_U64)/KER # Rules - BASIC and KERNAL intermediate files -build/,generated/packed_strings.s: $(TOOL_GENERATE_STRINGS) - @mkdir -p build/,generated - $(TOOL_GENERATE_STRINGS) -o build/,generated/packed_strings.s +$(GEN_STR_CUS): $(TOOL_GENERATE_STRINGS) $(CFG_CUS) + @mkdir -p $(DIR_CUS)/,generated + $(TOOL_GENERATE_STRINGS) -o $@ -c $(CFG_CUS) + +$(GEN_STR_GEN): $(TOOL_GENERATE_STRINGS) $(CFG_GEN) + @mkdir -p $(DIR_GEN)/,generated + $(TOOL_GENERATE_STRINGS) -o $@ -c $(CFG_GEN) + +$(GEN_STR_TST): $(TOOL_GENERATE_STRINGS) $(CFG_TST) + @mkdir -p $(DIR_TST)/,generated + $(TOOL_GENERATE_STRINGS) -o $@ -c $(CFG_TST) + +$(GEN_STR_M65): $(TOOL_GENERATE_STRINGS) $(CFG_M65) + @mkdir -p $(DIR_M65)/,generated + $(TOOL_GENERATE_STRINGS) -o $@ -c $(CFG_M65) + +$(GEN_STR_U64): $(TOOL_GENERATE_STRINGS) $(CFG_U64) + @mkdir -p $(DIR_U64)/,generated + $(TOOL_GENERATE_STRINGS) -o $@ -c $(CFG_U64) + +$(GEN_STR_X16): $(TOOL_GENERATE_STRINGS) $(CFG_X16) + @mkdir -p $(DIR_X16)/,generated + $(TOOL_GENERATE_STRINGS) -o $@ -c $(CFG_X16) build/,generated/float_constants.s: $(TOOL_GENERATE_CONSTANTS) @mkdir -p build/,generated $(TOOL_GENERATE_CONSTANTS) -o build/,generated/float_constants.s +GEN_STR_custom = $(GEN_STR_CUS) +GEN_STR_generic = $(GEN_STR_GEN) +GEN_STR_testing = $(GEN_STR_TST) +GEN_STR_mega65 = $(GEN_STR_M65) +GEN_STR_ultimate64 = $(GEN_STR_U64) +GEN_STR_cx16 = $(GEN_STR_X16) + .PRECIOUS: build/target_%/OUTB_x.BIN build/target_%/BASIC_combined.vs build/target_%/OUTB_x.BIN build/target_%/BASIC_combined.vs: @mkdir -p build/target_$* @rm -f $@* build/target_$*/BASIC* - @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r STD -s BASIC -i BASIC-$* -o OUTB_x.BIN -d build/target_$* -l a000 -h e4d2 c64/,,config_$*.s $(SRCDIR_BASIC) $(GEN_BASIC) + @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r STD -s BASIC -i BASIC-$* -o OUTB_x.BIN -d build/target_$* -l a000 -h e4d2 c64/,,config_$*.s $(SRCDIR_BASIC) $(GEN_BASIC) $(GEN_STR_$*) .PRECIOUS: build/target_%/OUTK_x.BIN build/target_%/KERNAL_combined.vs build/target_%/KERNAL_combined.sym build/target_%/OUTK_x.BIN build/target_%/KERNAL_combined.vs build/target_%/KERNAL_combined.sym: @mkdir -p build/target_$* @rm -f $@* build/target_$*/KERNAL* - @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r STD -s KERNAL -i KERNAL-$* -o OUTK_x.BIN -d build/target_$* -l e4d3 -h ffff c64/,,config_$*.s $(SRCDIR_KERNAL) $(GEN_KERNAL) + @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r STD -s KERNAL -i KERNAL-$* -o OUTK_x.BIN -d build/target_$* -l e4d3 -h ffff c64/,,config_$*.s $(SRCDIR_KERNAL) $(GEN_KERNAL) $(GEN_STR_$*) # Rules - BASIC and KERNAL intermediate files, for Mega65 $(DIR_M65)/OUTB_0.BIN $(DIR_M65)/BASIC_0_combined.vs $(DIR_M65)/BASIC_0_combined.sym: @mkdir -p $(DIR_M65) @rm -f $@* $(DIR_M65)/BASIC_0* - @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r M65 -s BASIC_0 -i BASIC_0-mega65 -o OUTB_0.BIN -d $(DIR_M65) -l a000 -h e4d2 $(CFG_M65) $(SRCDIR_BASIC) $(GEN_BASIC) + @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r M65 -s BASIC_0 -i BASIC_0-mega65 -o OUTB_0.BIN -d $(DIR_M65) -l a000 -h e4d2 $(CFG_M65) $(GEN_STR_M65) $(SRCDIR_BASIC) $(GEN_BASIC) $(DIR_M65)/OUTK_0.BIN $(DIR_M65)/KERNAL_0_combined.vs $(DIR_M65)/KERNAL_0_combined.sym: @mkdir -p $(DIR_M65) @rm -f $@* $(DIR_M65)/KERNAL_0* - @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r M65 -s KERNAL_0 -i KERNAL_0-mega65 -o OUTK_0.BIN -d $(DIR_M65) -l e4d3 -h ffff $(CFG_M65) $(SRCDIR_KERNAL) $(GEN_KERNAL) + @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r M65 -s KERNAL_0 -i KERNAL_0-mega65 -o OUTK_0.BIN -d $(DIR_M65) -l e4d3 -h ffff $(CFG_M65) $(GEN_STR_M65) $(SRCDIR_KERNAL) $(GEN_KERNAL) $(DIR_M65)/basic.seg_1 $(DIR_M65)/BASIC_1_combined.vs $(DIR_M65)/BASIC_1_combined.sym: @mkdir -p $(DIR_M65) @rm -f $@* $(DIR_M65)/basic.seg_1 $(DIR_M65)/BASIC_1* - @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r M65 -s BASIC_1 -i BASIC_1-mega65 -o basic.seg_1 -d $(DIR_M65) -l 4000 -h 5fff $(CFG_M65) $(SRCDIR_BASIC) $(GEN_BASIC) + @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r M65 -s BASIC_1 -i BASIC_1-mega65 -o basic.seg_1 -d $(DIR_M65) -l 4000 -h 5fff $(CFG_M65) $(GEN_STR_M65) $(SRCDIR_BASIC) $(GEN_BASIC) $(DIR_M65)/kernal.seg_1 $(DIR_M65)/KERNAL_1_combined.vs $(DIR_M65)/KERNAL_1_combined.sym: @mkdir -p $(DIR_M65) @rm -f $@* $(DIR_M65)/kernal.seg_1 $(DIR_M65)/KERNAL_1* - @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r M65 -s KERNAL_1 -i KERNAL_1-mega65 -o kernal.seg_1 -d $(DIR_M65) -l 4000 -h 5fff $(CFG_M65) $(SRCDIR_KERNAL) $(GEN_KERNAL) + @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r M65 -s KERNAL_1 -i KERNAL_1-mega65 -o kernal.seg_1 -d $(DIR_M65) -l 4000 -h 5fff $(CFG_M65) $(GEN_STR_M65) $(SRCDIR_KERNAL) $(GEN_KERNAL) # Rules - BASIC and KERNAL intermediate files, for Commander X16 $(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-x16 -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) $(GEN_STR_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-x16 -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) $(GEN_STR_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-x16 -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) $(GEN_STR_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-x16 -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) $(GEN_STR_X16) $(SRCDIR_KERNAL) $(GEN_KERNAL) # Rules - BASIC and KERNAL diff --git a/c64/,,config_custom.s b/c64/,,config_custom.s index 1e03bdff..b2b827c4 100644 --- a/c64/,,config_custom.s +++ b/c64/,,config_custom.s @@ -52,7 +52,7 @@ // #define CONFIG_IEC_JIFFYDOS_BLANK // #define CONFIG_IEC_BURST_CIA1 // please keep disabled for now // #define CONFIG_IEC_BURST_CIA2 // please keep disabled for now -// #define CONFIG_IEC_BURST_SOFT // please keep disabled for now +// #define CONFIG_IEC_BURST_MEGA_65 // please keep disabled for now #define CONFIG_TAPE_NORMAL #define CONFIG_TAPE_TURBO @@ -135,7 +135,6 @@ #define CONFIG_BANNER_FANCY // #define CONFIG_BANNER_BRAND #define CONFIG_SHOW_FEATURES -#define CONFIG_SHOW_PAL_NTSC // Debug options diff --git a/c64/aliases/,aliases_config.s b/c64/aliases/,aliases_config.s index 0a652064..3e14bbaa 100644 --- a/c64/aliases/,aliases_config.s +++ b/c64/aliases/,aliases_config.s @@ -148,12 +148,12 @@ .error "CONFIG_IEC_DOLPHINDOS_FAST requires CONFIG_IEC_DOLPHINDOS" #endif -#if (CONFIG_IEC_BURST_CIA1 || CONFIG_IEC_BURST_CIA1 || CONFIG_IEC_BURST_SOFT) && !CONFIG_IEC +#if (CONFIG_IEC_BURST_CIA1 || CONFIG_IEC_BURST_CIA1 || CONFIG_IEC_BURST_MEGA_65) && !CONFIG_IEC .error "CONFIG_IEC_BURST_* requires CONFIG_IEC" #endif -#if CONFIG_IEC_BURST_SOFT && !CONFIG_MB_MEGA_65 - .error "CONFIG_IEC_BURST_SOFT requires CONFIG_MB_MEGA_65" +#if CONFIG_IEC_BURST_MEGA_65 && !CONFIG_MB_MEGA_65 + .error "CONFIG_IEC_BURST_MEGA_65 requires CONFIG_MB_MEGA_65" #endif .var selected_iec_burst = 0; @@ -164,7 +164,7 @@ #if CONFIG_IEC_BURST_CIA2 .eval selected_iec_burst++ #endif -#if CONFIG_IEC_BURST_SOFT +#if CONFIG_IEC_BURST_MEGA_65 .eval selected_iec_burst++ #endif @@ -358,86 +358,3 @@ .const CONFIG_COLOR_TXT = $01 #endif - - -// Function for printing out build features - -.var feature_new_line = false - -.function ADD_FEATURE(current_features, new_feature) -{ - .var features_str = current_features - - .if (!feature_new_line && features_str.size() > 0) - { - .eval features_str = features_str + ", " - } - - .if (feature_new_line) - { - .eval feature_new_line = false - .eval features_str = features_str + @"\r" - } - - .return features_str + new_feature -} - -.function BUILD_FEATURES_STR() -{ - .var features_str = "" - -#if CONFIG_TAPE_NORMAL && !CONFIG_TAPE_TURBO - .eval features_str = ADD_FEATURE(features_str, "TAPE LOAD NORMAL") -#endif -#if !CONFIG_TAPE_NORMAL && CONFIG_TAPE_TURBO - .eval features_str = ADD_FEATURE(features_str, "TAPE LOAD TURBO") -#endif -#if CONFIG_TAPE_NORMAL && CONFIG_TAPE_TURBO - .eval features_str = ADD_FEATURE(features_str, "TAPE LOAD NORMAL TURBO") -#endif - - .eval feature_new_line = true - -#if CONFIG_IEC - .var iec_features_str = "IEC" -#if CONFIG_IEC_BURST_CIA1 - .eval iec_features_str = iec_features_str + " BURST1" -#endif -#if CONFIG_IEC_BURST_CIA2 - .eval iec_features_str = iec_features_str + " BURST2" -#endif -#if CONFIG_IEC_BURST_SOFT - .eval iec_features_str = iec_features_str + " BURST" -#endif -#if CONFIG_IEC_DOLPHINDOS - .eval iec_features_str = iec_features_str + " DOLPHIN" -#endif -#if CONFIG_IEC_JIFFYDOS - .eval iec_features_str = iec_features_str + " JIFFY" -#endif -#if !CONFIG_IEC_BURST_CIA1 && !CONFIG_IEC_BURST_CIA2 && !CONFIG_IEC_BURST_SOFT && !CONFIG_IEC_DOLPHINDOS && !CONFIG_IEC_JIFFYDOS - .eval iec_features_str = iec_features_str + " NORMAL" -#endif - .eval features_str = ADD_FEATURE(features_str, iec_features_str) -#endif - - .eval feature_new_line = true - -#if CONFIG_RS232_UP2400 - .eval features_str = ADD_FEATURE(features_str, "UP2400") -#endif - -#if CONFIG_RS232_UP2400 - .eval features_str = ADD_FEATURE(features_str, "UP9600") -#endif - -#if CONFIG_KEYBOARD_C128 - .eval features_str = ADD_FEATURE(features_str, "KBD 128") -#endif - -#if CONFIG_KEYBOARD_C65 - .eval features_str = ADD_FEATURE(features_str, "KBD 65") -#endif - - .return features_str -} diff --git a/c64/aliases/,aliases_ram_lowmem.s b/c64/aliases/,aliases_ram_lowmem.s index 72bd6d0b..3e206102 100644 --- a/c64/aliases/,aliases_ram_lowmem.s +++ b/c64/aliases/,aliases_ram_lowmem.s @@ -103,7 +103,7 @@ .label PTR1 = $9E // for tape support, counter of errorneous bytes .label PTR2 = $9F // for tape support, counter for errorneous bytes correction .label TIME = $A0 // $A0-$A2 jiffy clock -#if !CONFIG_IEC_JIFFYDOS && !CONFIG_IEC_DOLPHINDOS && !CONFIG_IEC_BURST_CIA1 && !CONFIG_IEC_BURST_CIA2 && !CONFIG_IEC_BURST_SOFT +#if !CONFIG_IEC_JIFFYDOS && !CONFIG_IEC_DOLPHINDOS && !CONFIG_IEC_BURST_CIA1 && !CONFIG_IEC_BURST_CIA2 && !CONFIG_IEC_BURST_MEGA_65 .label TSFCNT = $A3 // temporary variable for tape and IEC, [!] our usage differs #else .label IECPROTO = $A3 // -- WIP -- [!] 0 = normal, 1 = JiffyDOS, >= $80 for unknown diff --git a/c64/basic/,imports.s b/c64/basic/,imports.s index 3d0934dc..8b3c1e45 100644 --- a/c64/basic/,imports.s +++ b/c64/basic/,imports.s @@ -43,10 +43,6 @@ .label print_return = KERNAL().print_return .label print_space = KERNAL().print_space -#if CONFIG_SHOW_FEATURES -.label print_features = KERNAL().print_features -#endif - #if CONFIG_TAPE_HEAD_ALIGN .label tape_head_align = KERNAL().tape_head_align #endif diff --git a/c64/basic/init/initmsg_real.s b/c64/basic/init/initmsg_real.s index 3438c8ad..98df977a 100644 --- a/c64/basic/init/initmsg_real.s +++ b/c64/basic/init/initmsg_real.s @@ -57,8 +57,7 @@ initmsg_real: ldy #$00 #if CONFIG_SHOW_FEATURES jsr plot_set - jsr print_features - jmp print_pal_ntsc + jmp print_features #else jmp plot_set #endif @@ -111,8 +110,7 @@ initmsg_real: ldy #$00 #if CONFIG_SHOW_FEATURES jsr plot_set - jsr print_features - jmp print_pal_ntsc + jmp print_features #else jmp plot_set #endif diff --git a/c64/basic/print/print_pal_ntsc.s b/c64/basic/print/print_features.s similarity index 65% rename from c64/basic/print/print_pal_ntsc.s rename to c64/basic/print/print_features.s index cfabc62e..47de7cda 100644 --- a/c64/basic/print/print_pal_ntsc.s +++ b/c64/basic/print/print_features.s @@ -4,11 +4,18 @@ // #LAYOUT# * * #IGNORE // -// Print video system on startup banner +// Print configured features and current video system on startup banner // #if CONFIG_SHOW_FEATURES +print_features: + + ldx #IDX__STR_FEATURES + jsr print_packed_misc_str + + // FALLTROUGH + print_pal_ntsc: ldx #IDX__STR_NTSC diff --git a/c64/kernal/assets/kernal_messages.s b/c64/kernal/assets/kernal_messages.s index a5d712bf..16129aa8 100644 --- a/c64/kernal/assets/kernal_messages.s +++ b/c64/kernal/assets/kernal_messages.s @@ -31,9 +31,6 @@ .label __MSG_KERNAL_PANIC_ROM_MISMATCH = __msg_kernalpanic_rom_mismatch - __msg_kernal_first #endif -#if CONFIG_SHOW_FEATURES -.label __MSG_KERNAL_FEATURES = __msg_kernalfeatures - __msg_kernal_first -#endif __msg_kernal_first: @@ -99,11 +96,3 @@ __msg_kernalpanic_rom_mismatch: .byte $80 + $48 // end of string mark + 'H' #endif // CONFIG_PANIC_SCREEN - -#if CONFIG_SHOW_FEATURES - -__msg_kernalfeatures: - .text BUILD_FEATURES_STR() - .byte $80 + $0D // end of string mark + return - -#endif // CONFIG_SHOW_FEATURES diff --git a/c64/kernal/iec/iec_cmd_open.s b/c64/kernal/iec/iec_cmd_open.s index 6d1bba33..a4a0e2df 100644 --- a/c64/kernal/iec/iec_cmd_open.s +++ b/c64/kernal/iec/iec_cmd_open.s @@ -20,7 +20,7 @@ iec_cmd_open: // similar to TKSA, but without turnaround !: ora #$F0 -#if CONFIG_IEC_BURST_CIA1 || CONFIG_IEC_BURST_CIA2 || CONFIG_IEC_BURST_SOFT +#if CONFIG_IEC_BURST_CIA1 || CONFIG_IEC_BURST_CIA2 || CONFIG_IEC_BURST_MEGA_65 pha jsr burst_advertise pla diff --git a/c64/kernal/iec/load_iec.s b/c64/kernal/iec/load_iec.s index 578e9f97..fdd75f85 100644 --- a/c64/kernal/iec/load_iec.s +++ b/c64/kernal/iec/load_iec.s @@ -60,7 +60,7 @@ load_iec: jsr TALK bcs load_iec_error -#if CONFIG_IEC_BURST_CIA1 || CONFIG_IEC_BURST_CIA2 || CONFIG_IEC_BURST_SOFT +#if CONFIG_IEC_BURST_CIA1 || CONFIG_IEC_BURST_CIA2 || CONFIG_IEC_BURST_MEGA_65 jsr burst_advertise #endif diff --git a/c64/kernal/iec/save_iec.s b/c64/kernal/iec/save_iec.s index 83dff28b..324653c6 100644 --- a/c64/kernal/iec/save_iec.s +++ b/c64/kernal/iec/save_iec.s @@ -42,7 +42,7 @@ save_iec: jsr LISTEN bcs save_iec_dev_not_found -#if CONFIG_IEC_BURST_CIA1 || CONFIG_IEC_BURST_CIA2 || CONFIG_IEC_BURST_SOFT +#if CONFIG_IEC_BURST_CIA1 || CONFIG_IEC_BURST_CIA2 || CONFIG_IEC_BURST_MEGA_65 jsr burst_advertise #endif diff --git a/c64/kernal/iec_fast/burst_soft_advertise.s b/c64/kernal/iec_fast/burst_m65_advertise.s similarity index 93% rename from c64/kernal/iec_fast/burst_soft_advertise.s rename to c64/kernal/iec_fast/burst_m65_advertise.s index 7e9e9dcf..d0b91b84 100644 --- a/c64/kernal/iec_fast/burst_soft_advertise.s +++ b/c64/kernal/iec_fast/burst_m65_advertise.s @@ -7,7 +7,7 @@ // -#if CONFIG_IEC_BURST_SOFT +#if CONFIG_IEC_BURST_MEGA_65 burst_advertise: diff --git a/c64/kernal/print/print_features.s b/c64/kernal/print/print_features.s deleted file mode 100644 index c4b4c0ae..00000000 --- a/c64/kernal/print/print_features.s +++ /dev/null @@ -1,17 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# * KERNAL_0 #TAKE -// #LAYOUT# * * #IGNORE - -// -// Print configured features on startup banner -// - -#if CONFIG_SHOW_FEATURES - -print_features: - - ldx #__MSG_KERNAL_FEATURES -!: - jmp print_kernal_message - -#endif // CONFIG_SHOW_FEATURES diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index 720c4ceb..8245f3ab 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -2,7 +2,7 @@ // Utility to generate compressed messages and BASIC tokens // -// XXX parse the config file to select the string set (STD, M65, X16) and generate feature string +// XXX print somewhere configuration file used to generate strings // XXX use DualStream class for logging // XXX use dictionary compression by finding the set of non-overlapping strings that can be concatenated // to produce full set of strings; some idea for the algorithm (not sure if proper one) is available here @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ // std::string CMD_outFile = "out.s"; +std::string CMD_cnfFile = ""; // // Type definition for text/tokens to generate @@ -313,9 +315,8 @@ const StringEntryList GLOBAL_MiscStrings = { ListType::STRINGS_BASIC, "misc", { true, true, true, "STR_ERROR", " ERROR" }, // simply the word error that is attached to the other parts of messages https://fjkraan.home.xs4all.nl/comp/apple2faq/app2asoftfaq.html { true, true, true, "STR_IN", " IN " }, // STD M65 X16 --- misc strings specific to OpenROMs, not present in CBM ROMs - { true, true, true, "STR_PAL", "PAL\r" }, - { true, true, true, "STR_NTSC", "NTSC\r" }, { true, true, true, "STR_BRK_AT", "\rBRK AT $" }, + // Note: depending on configuration, additional strings will be added here } }; @@ -448,6 +449,8 @@ const StringEntryList GLOBAL_MiscStrings = { ListType::STRINGS_BASIC, "misc", "HIGHLIGHT" // $FE $3D */ +std::map GLOBAL_ConfigOptions; + // // Work class definitions // @@ -464,6 +467,7 @@ private: void process(); + void generateConfigDepStrings(); void calculateFrequencies(); void encodeStrings(); @@ -539,6 +543,7 @@ void DataSet::process() { std::cout << "Processing layout '" << layoutName() << "'" << std::endl; + generateConfigDepStrings(); calculateFrequencies(); encodeStrings(); prepareOutput(); @@ -554,6 +559,101 @@ const std::string &DataSet::getOutput() return outFileContent; } +void DataSet::generateConfigDepStrings() +{ + // Generate string to show the build features + + std::string featureStr; + + // Tape support features + + if (GLOBAL_ConfigOptions["CONFIG_TAPE_NORMAL"] && GLOBAL_ConfigOptions["CONFIG_TAPE_TURBO"]) + { + featureStr = "TAPE LOAD NORMAL TURBO\r"; + } + else if (GLOBAL_ConfigOptions["CONFIG_TAPE_NORMAL"]) + { + featureStr = "TAPE LOAD NORMAL\r"; + } + else if (GLOBAL_ConfigOptions["CONFIG_TAPE_TURBO"]) + { + featureStr = "TAPE LOAD TURBO\r"; + } + + // IEC support features + + if (GLOBAL_ConfigOptions["CONFIG_IEC"]) + { + featureStr += "IEC"; + + bool extendedIEC = false; + + if (GLOBAL_ConfigOptions["CONFIG_IEC_BURST_CIA1"]) + { + featureStr += " BURST1"; + extendedIEC = true; + } + if (GLOBAL_ConfigOptions["CONFIG_IEC_BURST_CIA2"]) + { + featureStr += " BURST2"; + extendedIEC = true; + } + if (GLOBAL_ConfigOptions["CONFIG_IEC_BURST_MEGA65"]) + { + featureStr += " BURST"; + extendedIEC = true; + } + + if (GLOBAL_ConfigOptions["CONFIG_IEC_DOLPHINDOS"]) + { + featureStr += " DOLPHIN"; + extendedIEC = true; + } + + if (GLOBAL_ConfigOptions["CONFIG_IEC_JIFFYDOS"]) + { + featureStr += " JIFFY"; + extendedIEC = true; + } + + if (!extendedIEC) featureStr += " NORMAL"; + + featureStr += "\r"; + } + + // RS-232 support features + + if (GLOBAL_ConfigOptions["CONFIG_RS232_UP2400"]) featureStr += "UP2400\r"; + if (GLOBAL_ConfigOptions["CONFIG_RS232_UP9600"]) featureStr += "UP9600\r"; + + // Keyboard support features + + if (GLOBAL_ConfigOptions["CONFIG_KEYBOARD_C128"]) featureStr += "KBD 128\r"; + if (GLOBAL_ConfigOptions["CONFIG_KEYBOARD_C65"]) featureStr += "KBD 65\r"; + + // Add strings to appropriate list + + for (auto &stringEntryList : stringEntryLists) + { + if (stringEntryList.name != std::string("misc")) continue; + + // List found + + if (GLOBAL_ConfigOptions["CONFIG_SHOW_FEATURES"]) + { + StringEntry newEntry1 = { true, true, true, "STR_PAL", "PAL\r" }; + StringEntry newEntry2 = { true, true, true, "STR_NTSC", "NTSC\r" }; + StringEntry newEntry3 = { true, true, true, "STR_FEATURES", featureStr }; + + stringEntryList.list.push_back(newEntry1); + stringEntryList.list.push_back(newEntry2); + stringEntryList.list.push_back(newEntry3); + + break; + } + } +} + void DataSet::calculateFrequencies() { as1n.clear(); @@ -899,10 +999,59 @@ void DataSet::prepareOutput() // Common helper functions // +void parseConfigFile() +{ + GLOBAL_ConfigOptions.clear(); + + // Open the configuration file + + std::ifstream cnfFile; + cnfFile.open(CMD_cnfFile); + if (!cnfFile.good()) ERROR("unable to open config file"); + + // Parse the file + + size_t lineNum = 0; + while (!cnfFile.eof()) + { + lineNum++; + std::string workStr; + + // Read a single line, remove leading spaces and tabs + + std::getline(cnfFile, workStr); // XXX check for errors here + workStr = std::regex_replace(workStr, std::regex("^[ \t]+"), ""); + + // Skip lines which are not preprocessor definitions + + if (workStr.empty() || workStr[0] != '#') continue; + + // Make sure this is '#define ' + + if (!std::regex_match(workStr, std::regex("^#define[ \t].*"))) + { + ERROR(std::string("only '#define' preprocessor directives allowed in config files - line ") + std::to_string(lineNum)); + } + + // Get rid of the directive and trailing spaces/comments + + workStr = std::regex_replace(workStr, std::regex("^#define[ \t]+"), ""); + workStr = std::regex_replace(workStr, std::regex("[ \t]+.*"), ""); + + // Add definitin to config option map + + if (workStr.empty()) ERROR(std::string("error parsing config file - line ") + std::to_string(lineNum)); + + GLOBAL_ConfigOptions[workStr] = true; + } + + cnfFile.close(); +} + void printUsage() { std::cout << "\n" << - "usage: generate_strings [-o ]" << "\n\n"; + "usage: generate_strings [-o ] [-c ]" << "\n\n"; } void printBanner() @@ -918,11 +1067,12 @@ void parseCommandLine(int argc, char **argv) // Retrieve command line options - while ((opt = getopt(argc, argv, "o:")) != -1) + while ((opt = getopt(argc, argv, "o:c:")) != -1) { switch(opt) { case 'o': CMD_outFile = optarg; break; + case 'c': CMD_cnfFile = optarg; break; default: printUsage(); ERROR(); } } @@ -930,36 +1080,61 @@ void parseCommandLine(int argc, char **argv) void writeStrings() { - DataSetSTD dataSetSTD; - DataSetM65 dataSetM65; - DataSetX16 dataSetX16; + std::string outputString; + + if (GLOBAL_ConfigOptions["CONFIG_PLATFORM_COMMANDER_X16"]) + { + DataSetX16 dataSetX16; - // Add input data to computation objects + // Add input data to computation objects + + dataSetX16.addStrings(GLOBAL_Keywords_V2); + dataSetX16.addStrings(GLOBAL_Keywords_CC); + dataSetX16.addStrings(GLOBAL_Keywords_CD); + dataSetX16.addStrings(GLOBAL_Errors); + dataSetX16.addStrings(GLOBAL_MiscStrings); - dataSetSTD.addStrings(GLOBAL_Keywords_V2); - dataSetSTD.addStrings(GLOBAL_Keywords_CC); - dataSetSTD.addStrings(GLOBAL_Keywords_CD); - dataSetSTD.addStrings(GLOBAL_Errors); - dataSetSTD.addStrings(GLOBAL_MiscStrings); + // Retrieve the results + + outputString = dataSetX16.getOutput(); + } + else if (GLOBAL_ConfigOptions["CONFIG_PLATFORM_COMMODORE_64"] && GLOBAL_ConfigOptions["CONFIG_MB_MEGA_65"]) + { + DataSetM65 dataSetM65; - dataSetM65.addStrings(GLOBAL_Keywords_V2); - dataSetM65.addStrings(GLOBAL_Keywords_CC); - dataSetM65.addStrings(GLOBAL_Keywords_CD); - dataSetM65.addStrings(GLOBAL_Errors); - dataSetM65.addStrings(GLOBAL_MiscStrings); + // Add input data to computation objects - dataSetX16.addStrings(GLOBAL_Keywords_V2); - dataSetX16.addStrings(GLOBAL_Keywords_CC); - dataSetX16.addStrings(GLOBAL_Keywords_CD); - dataSetX16.addStrings(GLOBAL_Errors); - dataSetX16.addStrings(GLOBAL_MiscStrings); + dataSetM65.addStrings(GLOBAL_Keywords_V2); + dataSetM65.addStrings(GLOBAL_Keywords_CC); + dataSetM65.addStrings(GLOBAL_Keywords_CD); + dataSetM65.addStrings(GLOBAL_Errors); + dataSetM65.addStrings(GLOBAL_MiscStrings); + + // Retrieve the results + + outputString = dataSetM65.getOutput(); + } + else if (GLOBAL_ConfigOptions["CONFIG_PLATFORM_COMMODORE_64"]) + { + DataSetSTD dataSetSTD; - // Retrieve the results + // Add input data to computation objects - std::string outputSTD = dataSetSTD.getOutput(); - std::string outputM65 = dataSetM65.getOutput(); - std::string outputX16 = dataSetX16.getOutput(); + dataSetSTD.addStrings(GLOBAL_Keywords_V2); + dataSetSTD.addStrings(GLOBAL_Keywords_CC); + dataSetSTD.addStrings(GLOBAL_Keywords_CD); + dataSetSTD.addStrings(GLOBAL_Errors); + dataSetSTD.addStrings(GLOBAL_MiscStrings); + // Retrieve the results + + outputString = dataSetSTD.getOutput(); + } + else + { + ERROR("unable to determine string set"); + } + // Remove old file unlink(CMD_outFile.c_str()); @@ -976,11 +1151,7 @@ void writeStrings() // Write packed strings outFile << std::endl << std::endl; - outFile << outputSTD; - outFile << std::endl << std::endl; - outFile << outputM65; - outFile << std::endl << std::endl; - outFile << outputX16; + outFile << outputString; outFile << std::endl << std::endl; // Close the file @@ -999,6 +1170,8 @@ int main(int argc, char **argv) printBanner(); parseCommandLine(argc, argv); + parseConfigFile(); + writeStrings(); return 0; From 524d532433b76d8bb33725c79380cf07feb5b8eb Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 22 Jun 2020 18:45:24 +0200 Subject: [PATCH 071/103] small cleanup in BASIC --- c64/basic/basic_commands/cmd_load_verify.s | 12 +++------ c64/basic/basic_commands/cmd_save.s | 2 +- .../helper_load_fetch_filename.s} | 7 +++-- .../basic_commands/helper_load_init_param.s | 23 ++++++++++++++++ .../basic_commands_CC/cmd_bload_bverify.s | 10 ++----- c64/basic/basic_commands_CC/cmd_merge.s | 12 +++------ c64/basic/engine/fetch_device_secondary.s | 19 ++----------- c64/basic/engine/fetch_uint8.s | 27 +++++++++++++++++++ 8 files changed, 64 insertions(+), 48 deletions(-) rename c64/basic/{engine/fetch_file_name.s => basic_commands/helper_load_fetch_filename.s} (88%) create mode 100644 c64/basic/basic_commands/helper_load_init_param.s create mode 100644 c64/basic/engine/fetch_uint8.s diff --git a/c64/basic/basic_commands/cmd_load_verify.s b/c64/basic/basic_commands/cmd_load_verify.s index 45e1520c..3dba753d 100644 --- a/c64/basic/basic_commands/cmd_load_verify.s +++ b/c64/basic/basic_commands/cmd_load_verify.s @@ -14,18 +14,12 @@ cmd_verify: cmd_load: - lda #$00 // mark operation as LOAD - sta VERCKB - - // Set default device and secondary address; channel is not important now - - jsr select_device - ldy #$00 // secondary address - jsr JSETFLS + lda #$00 // mark operation as LOAD + jsr helper_load_init_params // Fetch the file name - jsr fetch_filename + jsr helper_load_fetch_filename bcs cmd_load_no_filename // Try to fetch device and secondary address diff --git a/c64/basic/basic_commands/cmd_save.s b/c64/basic/basic_commands/cmd_save.s index eae7c785..f4d4bf9f 100644 --- a/c64/basic/basic_commands/cmd_save.s +++ b/c64/basic/basic_commands/cmd_save.s @@ -13,7 +13,7 @@ cmd_save: // Fetch the file name - jsr fetch_filename + jsr helper_load_fetch_filename bcs_16 do_MISSING_FILENAME_error // Try to fetch device diff --git a/c64/basic/engine/fetch_file_name.s b/c64/basic/basic_commands/helper_load_fetch_filename.s similarity index 88% rename from c64/basic/engine/fetch_file_name.s rename to c64/basic/basic_commands/helper_load_fetch_filename.s index ece023d2..d93a4055 100644 --- a/c64/basic/engine/fetch_file_name.s +++ b/c64/basic/basic_commands/helper_load_fetch_filename.s @@ -7,12 +7,12 @@ // -fetch_filename: +helper_load_fetch_filename: // Check if end of statement jsr end_of_statement_check - bcs fetch_filename_done + bcs !+ // Call the expression parser, make sure it returned a string @@ -37,6 +37,5 @@ fetch_filename: // FALLTROUGH -fetch_filename_done: - +!: rts diff --git a/c64/basic/basic_commands/helper_load_init_param.s b/c64/basic/basic_commands/helper_load_init_param.s new file mode 100644 index 00000000..b9c29be2 --- /dev/null +++ b/c64/basic/basic_commands/helper_load_init_param.s @@ -0,0 +1,23 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Sets initial parameters for LOAD and simiar commands +// +// Input: +// - VERCKB content in .A +// + + +helper_load_init_params: + + // Set LOAD/VERIFY flag + + sta VERCKB + + // Set default device, set secondary address to 0 + + jsr select_device + ldy #$00 // secondary address + jmp JSETFLS diff --git a/c64/basic/basic_commands_CC/cmd_bload_bverify.s b/c64/basic/basic_commands_CC/cmd_bload_bverify.s index aaab38d0..8ec63ef5 100644 --- a/c64/basic/basic_commands_CC/cmd_bload_bverify.s +++ b/c64/basic/basic_commands_CC/cmd_bload_bverify.s @@ -14,17 +14,11 @@ cmd_bverify: cmd_bload: lda #$00 // mark operation as LOAD - sta VERCKB - - // Set default device and secondary address; channel is not important now - - jsr select_device - ldy #$00 // secondary address 0 - it has to be loaded precisely where we want - jsr JSETFLS + jsr helper_load_init_params // Fetch the file name - jsr fetch_filename + jsr helper_load_fetch_filename bcc !+ // No filename supplied - this should only be allowed for tape (device number below 8) diff --git a/c64/basic/basic_commands_CC/cmd_merge.s b/c64/basic/basic_commands_CC/cmd_merge.s index 42410adb..e7e5af3f 100644 --- a/c64/basic/basic_commands_CC/cmd_merge.s +++ b/c64/basic/basic_commands_CC/cmd_merge.s @@ -6,17 +6,11 @@ cmd_merge: lda #$00 // mark operation as LOAD - sta VERCKB - - // Set default device and secondary address; channel is not important now - - jsr select_device - ldy #$00 // secondary address 0 - it has to be loaded precisely where we want - jsr JSETFLS + jsr helper_load_init_params // Fetch the file name - jsr fetch_filename + jsr helper_load_fetch_filename bcc !+ // No filename supplied - this should only be allowed for tape (device number below 8) @@ -30,7 +24,7 @@ cmd_merge: !: // Fetch device number - jsr fetch_device_secondary_uint8 + jsr fetch_coma_uint8 bcs !+ sta FA diff --git a/c64/basic/engine/fetch_device_secondary.s b/c64/basic/engine/fetch_device_secondary.s index 3fb96a95..1f16e6e4 100644 --- a/c64/basic/engine/fetch_device_secondary.s +++ b/c64/basic/engine/fetch_device_secondary.s @@ -11,7 +11,7 @@ fetch_device_secondary: // Fetch the device number - jsr fetch_device_secondary_uint8 + jsr fetch_coma_uint8 bcs fetch_device_secondary_done sta FA @@ -22,7 +22,7 @@ fetch_secondary: // Fetch secondary address - jsr fetch_device_secondary_uint8 + jsr fetch_coma_uint8 bcs fetch_device_secondary_done sta SA @@ -32,18 +32,3 @@ fetch_secondary: fetch_device_secondary_done: rts - - -fetch_device_secondary_uint8: // also called by 'cmd_merge' - - jsr injest_comma - bcs !+ - - jsr injest_spaces - jsr basic_parse_line_number - lda LINNUM+1 - bne_16 do_ILLEGAL_QUANTITY_error - lda LINNUM+0 - clc -!: - rts diff --git a/c64/basic/engine/fetch_uint8.s b/c64/basic/engine/fetch_uint8.s new file mode 100644 index 00000000..30776d84 --- /dev/null +++ b/c64/basic/engine/fetch_uint8.s @@ -0,0 +1,27 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Fetches 8-bit unsigned integer +// + + +fetch_coma_uint8: + + jsr injest_comma + bcs !+ + + // FALLTROUGH + +fetch_uint8: + + jsr injest_spaces + jsr basic_parse_line_number + // XXX this should also detect errors + lda LINNUM+1 + bne_16 do_ILLEGAL_QUANTITY_error + lda LINNUM+0 + clc +!: + rts From e1d21e287fd68738ed8d37387e4e5066e2d5c81b Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 22 Jun 2020 21:25:23 +0200 Subject: [PATCH 072/103] more I/O work in BASIC --- c64/basic/basic_commands/cmd_load_verify.s | 21 +++----- c64/basic/basic_commands/cmd_save.s | 20 ++++--- .../basic_commands/helper_load_fetch_devnum.s | 20 +++++++ .../helper_load_fetch_secondary.s | 20 +++++++ .../basic_commands/helper_load_init_param.s | 4 ++ .../basic_commands/helper_load_setnam_any.s | 15 ++++++ c64/basic/basic_commands_CC/cmd_bsave.s | 51 +++++++++++++++++- c64/basic/basic_commands_CC/cmd_merge.s | 5 +- c64/basic/engine/fetch_uint8.s | 3 +- testsuite/testdisk.d64 | Bin 174848 -> 174848 bytes 10 files changed, 130 insertions(+), 29 deletions(-) create mode 100644 c64/basic/basic_commands/helper_load_fetch_devnum.s create mode 100644 c64/basic/basic_commands/helper_load_fetch_secondary.s create mode 100644 c64/basic/basic_commands/helper_load_setnam_any.s diff --git a/c64/basic/basic_commands/cmd_load_verify.s b/c64/basic/basic_commands/cmd_load_verify.s index 3dba753d..6e3c0541 100644 --- a/c64/basic/basic_commands/cmd_load_verify.s +++ b/c64/basic/basic_commands/cmd_load_verify.s @@ -16,26 +16,19 @@ cmd_load: lda #$00 // mark operation as LOAD jsr helper_load_init_params + jsr helper_load_setnam_any // if no file name found, use "*" // Fetch the file name jsr helper_load_fetch_filename - bcs cmd_load_no_filename + bcs !+ - // Try to fetch device and secondary address - - jsr fetch_device_secondary - jmp cmd_load_got_params - -cmd_load_no_filename: - - // If no file name is supplied, try to load first file from disc - - lda #$01 // name length - ldx #filename_any - jsr JSETNAM + // Try to fetch device number and secondary address + jsr helper_load_fetch_devnum + bcs !+ + jsr helper_load_fetch_secondary +!: // FALLTROUGH cmd_load_got_params: // input for tape wedge diff --git a/c64/basic/basic_commands/cmd_save.s b/c64/basic/basic_commands/cmd_save.s index f4d4bf9f..5ced4b27 100644 --- a/c64/basic/basic_commands/cmd_save.s +++ b/c64/basic/basic_commands/cmd_save.s @@ -5,22 +5,22 @@ cmd_save: - // Set default device and secondary address; channel is not important now + // Set default device and secondary address - jsr select_device - ldy #$00 - jsr JSETFLS + jsr helper_load_init_params_no_VERCKB // Fetch the file name jsr helper_load_fetch_filename bcs_16 do_MISSING_FILENAME_error - // Try to fetch device + // Try to fetch device number and secondary address - jsr fetch_device_secondary - - // Setup the start and end addresses + jsr helper_load_fetch_devnum + bcs !+ + jsr helper_load_fetch_secondary +!: + // Setup the start address lda #TXTTAB @@ -29,6 +29,10 @@ cmd_save: ldx VARTAB+0 ldy VARTAB+1 + // FALLTROUGH + +cmd_save_do: // entry point for BSAVE + // Perform saving jsr JSAVE diff --git a/c64/basic/basic_commands/helper_load_fetch_devnum.s b/c64/basic/basic_commands/helper_load_fetch_devnum.s new file mode 100644 index 00000000..5b6f66e4 --- /dev/null +++ b/c64/basic/basic_commands/helper_load_fetch_devnum.s @@ -0,0 +1,20 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +// +// Tries to fetch device number - sets Carry if failure +// + + +helper_load_fetch_devnum: + + // Fetch the device number + + jsr fetch_coma_uint8 + bcs !+ + + sta FA +!: + rts diff --git a/c64/basic/basic_commands/helper_load_fetch_secondary.s b/c64/basic/basic_commands/helper_load_fetch_secondary.s new file mode 100644 index 00000000..89212e12 --- /dev/null +++ b/c64/basic/basic_commands/helper_load_fetch_secondary.s @@ -0,0 +1,20 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +// +// Tries to fetch secondary address - sets Carry if failure +// + + +helper_load_fetch_secondary: + + // Fetch the device number + + jsr fetch_coma_uint8 + bcs !+ + + sta SA +!: + rts diff --git a/c64/basic/basic_commands/helper_load_init_param.s b/c64/basic/basic_commands/helper_load_init_param.s index b9c29be2..3e48bbdb 100644 --- a/c64/basic/basic_commands/helper_load_init_param.s +++ b/c64/basic/basic_commands/helper_load_init_param.s @@ -16,6 +16,10 @@ helper_load_init_params: sta VERCKB + // FALLTROUGH + +helper_load_init_params_no_VERCKB: + // Set default device, set secondary address to 0 jsr select_device diff --git a/c64/basic/basic_commands/helper_load_setnam_any.s b/c64/basic/basic_commands/helper_load_setnam_any.s new file mode 100644 index 00000000..b702ed98 --- /dev/null +++ b/c64/basic/basic_commands/helper_load_setnam_any.s @@ -0,0 +1,15 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Set '*' as file name +// + + +helper_load_setnam_any: + + lda #$01 // name length + ldx #filename_any + jmp JSETNAM diff --git a/c64/basic/basic_commands_CC/cmd_bsave.s b/c64/basic/basic_commands_CC/cmd_bsave.s index 3849a57d..11bbf0f1 100644 --- a/c64/basic/basic_commands_CC/cmd_bsave.s +++ b/c64/basic/basic_commands_CC/cmd_bsave.s @@ -5,4 +5,53 @@ cmd_bsave: - jmp do_NOT_IMPLEMENTED_error // XXX implement the command + // Set default device and secondary address + + jsr helper_load_init_params_no_VERCKB + + // Fetch the file name + + jsr helper_load_fetch_filename + bcs_16 do_MISSING_FILENAME_error + + // Fetch device number + + jsr injest_comma + bcs_16 do_SYNTAX_error + jsr helper_load_fetch_devnum + bcs_16 do_SYNTAX_error + + // Fetch memory area start address + + jsr injest_comma + bcs_16 do_SYNTAX_error + + jsr basic_parse_line_number // XXX detect errors here + + lda LINNUM+0 + pha + lda LINNUM+1 + pha + + // Fetch memory area end address + + jsr injest_comma + bcs_16 do_SYNTAX_error + + jsr basic_parse_line_number // XXX detect errors here + + // Setup start/end addresses + + ldx LINNUM+0 + ldy LINNUM+1 + + pla + sta LINNUM+1 + pla + sta LINNUM+0 + + lda #LINNUM + + // Perform SAVE - reuse regular command + + jmp cmd_save_do diff --git a/c64/basic/basic_commands_CC/cmd_merge.s b/c64/basic/basic_commands_CC/cmd_merge.s index e7e5af3f..375c61f9 100644 --- a/c64/basic/basic_commands_CC/cmd_merge.s +++ b/c64/basic/basic_commands_CC/cmd_merge.s @@ -24,11 +24,8 @@ cmd_merge: !: // Fetch device number - jsr fetch_coma_uint8 - bcs !+ + jsr helper_load_fetch_devnum - sta FA -!: // Perform loading - just for a different address sec diff --git a/c64/basic/engine/fetch_uint8.s b/c64/basic/engine/fetch_uint8.s index 30776d84..1637b056 100644 --- a/c64/basic/engine/fetch_uint8.s +++ b/c64/basic/engine/fetch_uint8.s @@ -17,8 +17,7 @@ fetch_coma_uint8: fetch_uint8: jsr injest_spaces - jsr basic_parse_line_number - // XXX this should also detect errors + jsr basic_parse_line_number // XXX detect errors here lda LINNUM+1 bne_16 do_ILLEGAL_QUANTITY_error lda LINNUM+0 diff --git a/testsuite/testdisk.d64 b/testsuite/testdisk.d64 index a455d2ee8fc3863fbc0022af6383ad7b1d85193c..5401b7138613bda840dcae3bc5d9772765475c78 100644 GIT binary patch delta 87 zcmZp;#?=5sTNoJwdH5MQxH-5OW-@GL2-(Q^nPXcNqYF2i;Gf_8f`6v_r80_5Pe^4v YB-VE2TpXq+7jAGLhQW+05vTS8xyypS{ei{&Q From 3c7b02ac0967c72d6bedc7e50e01ebc3ba0a5204 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 22 Jun 2020 21:28:20 +0200 Subject: [PATCH 073/103] remove obsolete file --- c64/basic/engine/fetch_device_secondary.s | 34 ----------------------- 1 file changed, 34 deletions(-) delete mode 100644 c64/basic/engine/fetch_device_secondary.s diff --git a/c64/basic/engine/fetch_device_secondary.s b/c64/basic/engine/fetch_device_secondary.s deleted file mode 100644 index 1f16e6e4..00000000 --- a/c64/basic/engine/fetch_device_secondary.s +++ /dev/null @@ -1,34 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - -// -// Fetches device number and secondary address - if they are present -// - - -fetch_device_secondary: - - // Fetch the device number - - jsr fetch_coma_uint8 - bcs fetch_device_secondary_done - - sta FA - - // FALLTROUGH - -fetch_secondary: - - // Fetch secondary address - - jsr fetch_coma_uint8 - bcs fetch_device_secondary_done - - sta SA - - // FALLTROUGH - -fetch_device_secondary_done: - - rts From e04def71cba2589d282978e0ecd3dd1c43f31292 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 22 Jun 2020 21:52:17 +0200 Subject: [PATCH 074/103] preparation for dictionary compresion --- tools/generate_strings.cc | 45 ++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index 8245f3ab..2fee7fc8 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -45,7 +45,8 @@ typedef struct StringEntry enum class ListType { KEYWORDS, - STRINGS_BASIC + STRINGS_BASIC, + DICTIONARY // for internal use only }; typedef struct StringEntryList @@ -55,8 +56,14 @@ typedef struct StringEntryList std::vector list; } StringEntryList; -typedef std::vector StringEncoded; -typedef std::vector StringEncodedList; +typedef std::vector StringFreqEncoded; +typedef std::vector StringDictEncoded; + +typedef struct StringEncodedList +{ + std::vector byFreq; + std::vector byDict; +} StringEncodedList; // http://www.classic-games.com/commodore64/cbmtoken.html // https://www.c64-wiki.com/wiki/BASIC_token @@ -471,7 +478,7 @@ private: void calculateFrequencies(); void encodeStrings(); - void encodeByFreq(const std::string &plain, StringEncoded &encoded) const; + void encodeByFreq(const std::string &plain, StringFreqEncoded &encoded) const; void prepareOutput(); @@ -756,7 +763,7 @@ void DataSet::calculateFrequencies() } } -void DataSet::encodeByFreq(const std::string &plain, StringEncoded &encoded) const +void DataSet::encodeByFreq(const std::string &plain, StringFreqEncoded &encoded) const { bool fullByte = true; @@ -828,8 +835,8 @@ void DataSet::encodeStrings() for (const auto &stringEntry : stringEntryList.list) { - stringEncodedList.emplace_back(); - auto &stringEncoded = stringEncodedList.back(); + stringEncodedList.byFreq.emplace_back(); + auto &stringEncoded = stringEncodedList.byFreq.back(); if (isRelevant(stringEntry)) { @@ -912,16 +919,16 @@ void DataSet::prepareOutput() for (uint8_t idxList = 0; idxList < stringEntryLists.size(); idxList++) { - const auto &stringEntryList = stringEntryLists[idxList]; - const auto &stringEncodedList = stringEncodedLists[idxList]; + const auto &stringEntryList = stringEntryLists[idxList]; + const auto &stringFreqEncodedList = stringEncodedLists[idxList].byFreq; stream << std::endl; - for (uint8_t idxString = 0; idxString < stringEncodedList.size(); idxString++) + for (uint8_t idxString = 0; idxString < stringFreqEncodedList.size(); idxString++) { - const auto &stringEntry = stringEntryList.list[idxString]; - const auto &stringEncoded = stringEncodedList[idxString]; + const auto &stringEntry = stringEntryList.list[idxString]; + const auto &stringFreqEncoded = stringFreqEncodedList[idxString]; - if (!stringEncoded.empty()) + if (!stringFreqEncoded.empty()) { stream << ".label IDX__" << stringEntry.alias << std::string(maxAliasLen - stringEntry.alias.length(), ' ') << " = $" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << +idxString << std::endl; @@ -933,18 +940,18 @@ void DataSet::prepareOutput() if (stringEntryList.type == ListType::KEYWORDS) { stream << std::endl << ".label TK__MAXTOKEN_" << stringEntryList.name << " = " << - std::dec << stringEncodedList.size() << std::endl; + std::dec << stringFreqEncodedList.size() << std::endl; } stream << std::endl << ".macro put_freq_packed_" << stringEntryList.name << "()" << std::endl << "{" << std::endl; enum LastStr { NONE, SKIPPED, WRITTEN } lastStr = LastStr::NONE; - for (uint8_t idxString = 0; idxString < stringEncodedList.size(); idxString++) + for (uint8_t idxString = 0; idxString < stringFreqEncodedList.size(); idxString++) { - const auto &stringEntry = stringEntryList.list[idxString]; - const auto &stringEncoded = stringEncodedList[idxString]; + const auto &stringEntry = stringEntryList.list[idxString]; + const auto &stringFreqEncoded = stringFreqEncodedList[idxString]; - if (stringEncoded.empty()) + if (stringFreqEncoded.empty()) { if (lastStr == LastStr::WRITTEN) stream << std::endl; stream << "\t.byte $00 // skipped " << stringEntry.alias << std::endl; @@ -958,7 +965,7 @@ void DataSet::prepareOutput() stream << "\t.byte "; bool first = true; - for (const auto &charEncoded : stringEncoded) + for (const auto &charEncoded : stringFreqEncoded) { if (first) { From c5513f09b4c87364c4ae7ce21fdff492252f4ad6 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 22 Jun 2020 21:56:05 +0200 Subject: [PATCH 075/103] fixed broken test disk --- c64/basic/basic_commands/cmd_save.s | 2 +- testsuite/testdisk.d64 | Bin 174848 -> 174848 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/c64/basic/basic_commands/cmd_save.s b/c64/basic/basic_commands/cmd_save.s index 5ced4b27..115ecb7c 100644 --- a/c64/basic/basic_commands/cmd_save.s +++ b/c64/basic/basic_commands/cmd_save.s @@ -39,5 +39,5 @@ cmd_save_do: // entry point for BSAVE bcs_16 do_kernal_error // The end - +.break jmp execute_statements diff --git a/testsuite/testdisk.d64 b/testsuite/testdisk.d64 index 5401b7138613bda840dcae3bc5d9772765475c78..a455d2ee8fc3863fbc0022af6383ad7b1d85193c 100644 GIT binary patch delta 44 zcmZp;#?=5sTNoJwH!}a{*cQd;!p$c1?>E2TpXq+7jAGLhQW+05vTS8xyypS{ei{&Q delta 87 zcmZp;#?=5sTNoJwdH5MQxH-5OW-@GL2-(Q^nPXcNqYF2i;Gf_8f`6v_r80_5Pe^4v YB-V Date: Mon, 22 Jun 2020 22:34:41 +0200 Subject: [PATCH 076/103] bugfix in the expression parser operator support --- c64/basic/basic_commands/cmd_load_verify.s | 1 - c64/basic/basic_commands/cmd_save.s | 2 +- c64/basic/basic_commands_CC/cmd_bsave.s | 2 -- c64/basic/engine/fetch_operator.s | 2 ++ 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/c64/basic/basic_commands/cmd_load_verify.s b/c64/basic/basic_commands/cmd_load_verify.s index 6e3c0541..a9d719cb 100644 --- a/c64/basic/basic_commands/cmd_load_verify.s +++ b/c64/basic/basic_commands/cmd_load_verify.s @@ -41,7 +41,6 @@ cmd_load_got_params: // input for tape wedge cmd_load_loadmerge: // entry point for 'cmd_merge' lda VERCKB // LOAD or VERIFY - jsr JLOAD bcs_16 do_kernal_error diff --git a/c64/basic/basic_commands/cmd_save.s b/c64/basic/basic_commands/cmd_save.s index 115ecb7c..5ced4b27 100644 --- a/c64/basic/basic_commands/cmd_save.s +++ b/c64/basic/basic_commands/cmd_save.s @@ -39,5 +39,5 @@ cmd_save_do: // entry point for BSAVE bcs_16 do_kernal_error // The end -.break + jmp execute_statements diff --git a/c64/basic/basic_commands_CC/cmd_bsave.s b/c64/basic/basic_commands_CC/cmd_bsave.s index 11bbf0f1..886501a0 100644 --- a/c64/basic/basic_commands_CC/cmd_bsave.s +++ b/c64/basic/basic_commands_CC/cmd_bsave.s @@ -16,8 +16,6 @@ cmd_bsave: // Fetch device number - jsr injest_comma - bcs_16 do_SYNTAX_error jsr helper_load_fetch_devnum bcs_16 do_SYNTAX_error diff --git a/c64/basic/engine/fetch_operator.s b/c64/basic/engine/fetch_operator.s index 3c87cf45..26a260f6 100644 --- a/c64/basic/engine/fetch_operator.s +++ b/c64/basic/engine/fetch_operator.s @@ -41,6 +41,8 @@ fetch_operator_success: fetch_operator_failed: + jsr unconsume_character + sec rts From 16e84dd5629d62610b3a8238ef482bd155d16bfa Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 22 Jun 2020 22:41:38 +0200 Subject: [PATCH 077/103] updated binaries --- Makefile | 32 ++++++++++++++------------------ bin/basic_generic.rom | Bin 8192 -> 8192 bytes bin/basic_ultimate64.rom | Bin 8192 -> 8192 bytes bin/kernal_generic.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 7 files changed, 14 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 300eafd0..1be7f610 100644 --- a/Makefile +++ b/Makefile @@ -407,41 +407,39 @@ build/symbols_hybrid.vs: $(DIR_GEN)/KERNAL_combined.vs # Rules - platform 'Mega65' specific -$(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 - rm -f $(TARGET_M65_x) $(TARGET_M65_x_PXL) - 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 +build/padding_08_KB: + dd if=/dev/zero bs=8192 count=1 of=build/padding_08_KB +build/padding_64_KB: + dd if=/dev/zero bs=8192 count=8 of=build/padding_64_KB + +$(TARGET_M65_x) $(TARGET_M65_x_PXL): build/padding_08_KB build/padding_64_KB $(SEG_LIST_M65) build/chargen_openroms.rom build/chargen_openroms.patched build/chargen_pxlfont.rom build/chargen_pxlfont.patched @echo - cat build/m65_padding_08_KB > $(TARGET_M65_x) - cat build/m65_padding_08_KB >> $(TARGET_M65_x) + cat build/padding_08_KB > $(TARGET_M65_x) + cat build/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 build/padding_08_KB >> $(TARGET_M65_x) cat $(DIR_M65)/basic.seg_0 >> $(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) + cat build/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 build/padding_08_KB > $(TARGET_M65_x_PXL) + cat build/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 build/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_* + cat build/padding_64_KB >> $(TARGET_M65_x_PXL) @echo # Rules - platform 'Commander X16' specific $(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) @@ -449,8 +447,6 @@ $(TARGET_X16_x): $(SEG_LIST_X16) build/chargen_openroms.rom 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 diff --git a/bin/basic_generic.rom b/bin/basic_generic.rom index 825da11fb7ddd3ea7a6313386f3ad78acc4addea..5d1d0d42107834b96986dbc88a8a94c5658c660e 100644 GIT binary patch delta 3478 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 Zlgicnd-j@a?NClN4FGj5nN4i$zX5p=%6tF- delta 3304 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 Q)7_zaH^R+n2UE}g8{flP>i_@% delta 2962 zcmZuz4Rln+6`tMA{$!KQ+a;T16Oz1#U&H56=qGis4ecUZ4k4Ya>U%GY$XsjalMivh3%o9D}%nC4+ed_@}8EVoY1B# z@2V#5n*G4nS0k8!q`6t|LOm~n@UtNN9m}ei5hNWq|w7ykbClT-J(QiRg4&f23k6Tgspt& z9p?g4Wh*ANw)|<{*18bBzEw2oUaVB&TDq8$7)m$j=l^CmICPgQGn1!YA6?+1wu)h^ zXOr0%!owsp_d0UI;$2$b@~YLa6aLRx4Cl=To_o1NMnaKLEX)u}gqgf&Ly=I_Y&=)Y z;|brJKO-8RFBmR3FPl}P1&b+{ES(ye-tCE#D%}%8CmS*B&5_Ky!r#Wom z-jakU7=TZX%IGQuB7@&fstTf`D>XOnh|g6S{HG-CRb=erGUc5-Y$Bqab5eW2(D&n? zs$aq;GLoV}9!KL~63KTx;N2?)<6x?K`8QI-{;gb3d?JKAIL6OYzjm2!Qd0!K_64o2 z{*h3NBQ4aAkF?ND@F63q`IV6t4}BDG4B@dsa9t7IaMk#stH$fE8b6pAlbh{DM(Y6C zXkX(O3m~}vA6GcK?tt3fijh!rhGGxf6{}`bQnhSInnXUnp;@s!C|lL@vRxh3GxQBD zO^Ik}IyF^2C8wz$$myy|3e)m3D}rG)Th0u2s!sV|!B14Xe3-PS6|Y*`3Yj^tgwbjg zMk@*R+#-R;fS_sf6-`UK1)5Iee%IO;nHTCA?*Mk6dP0|o`hZlzcp8ym_XLM~rj?Jl z&KMv`e0ZG%LGP7_?3j*w^(zr{lm;`nMQ!-?gSxdP+H7DaZwoo^V6zTMU^y%cFT!U+ zVef%D-|4a_nUYa-Q$*_GqP{LK{L7*~?zaaaM$74P^}RY?m(Kx>)GHF z*9$QZuZNWE$S7gHHAcUNr!TaTV4mC9(oNpXy9PJX`0wY>n~#(-m7xq=FSwPUp5f}+ zJv{z#J2`8fX ze&{)N0M!h!f;%bwxr-gLqkk|Tk7fLg+4p|Aj4nIRe&s-;v)@Tl#;b8<)(YKMa52$@=KjH?ETo#O}zN#U5s*ji71^JLbtc z@JkkLVe7XlV{X>Tj_gjV+A_+1h`x578*_EA+rQ3c81zxYm8?I%TBWdNIN$BCCAs8U zb;&uFEzkULmn--B=54^AD6bGmFXW$BSWqW;d0sR^MU=PU z=D3KU9E2|`4lSd9B_trA##z@C&&g40)!vq@dhuDPnz$zpC=Wn)f@Dv^Gob!72v*4o z^#W?N=~MOJO;$Y8i8pkIO?X{DwH~u+COo-?+&?MX*ht9}llDzEBPIng7Q~nkV?%vr zBqPRv7%O6ohvsC~rc52_gwoX(mcdhl^ee1L}i)t1-ir1Ch%#Ke+WA4uJYzUTm zqj{Bx2GK;oxVw{qJHqsuY2*HcJicWx?ZdHc?yUxw=$pyNpGBWKqgQPSec9t**xNuS5Bh_9vU;^@)+AFgbASOY|?9(W+{$ zy6TQ_Kq@Y*Gv!-Jq_nlNFu57Qy{n{00ji##Na?X zKGUs#1MLt&J^+Pu2ZlqzR<*&Xe34_iaja9v5QwNA%{L_gG!u7BPU4vy6pBE$IDu!h zsAAYJ6orj%7t>;ALa0daI^p3uVRN0ZNh<`$FqC8#xYGfAmdCjJ+Q5T| z?8(2jSdI&o{YF^VE9p-aE-?a!bqMyL0iLwcI0O*!M6zwS>WiR}rwUd(M9V?Rs2N2w zyh{=JxL~1vdDz0K&>dP*m}kfk diff --git a/bin/kernal_generic.rom b/bin/kernal_generic.rom index b8ec999da4830541ee286c9e1159f9431ea52be2..9b1b8b9fa24121512ce0d9a91675f91b6ba48f72 100644 GIT binary patch delta 4253 zcmY*c4OCNCw!SwZ3IDnL8dS(p6bK3hYCGuEDYUhw_Gs1CvG&c<>p0WNOm(g2^Vw(H zRl)VRG{X{_^im79wK3+Rmllk4X3;oOsg9QLs$RuMp~4&NKoF9U8$clZFd#Sqk)Oyata5cm>e#5h+uLx zG=WxKauR|Z*Z$}%waf9>efYIHeEDk&abdlnYJ*0mp$pBIUMOj3{4_;-Y?jL3_%(5; z-|UKp_M7fUeZKBD#DMmY*7Z&I-eGqS@k#2p8L5Z*q1PR_lfN;R&>sBTx7wsb{l~TU ziH-eQCUJp#G)~(eNqE$~{@Cx;pWVsli5aSADux)&X@i zws+?!B9PGdY#~!2Snom;< z+7sHn{c1S5d{&dHJ<;>+j|&&3&nCa?B((p0dyFEgUnR7*Ds?mgAL(d++^#g|I3-IOTDk2UcG(~P!WD&%s8WK2%IU3NX! zmW!ztwojH9e`~-ZhqH|r*4G=**f|uKV3*4aO0IJF&3`&?2(fT!y}m}@j-1krG_25- z)T3LR;he$wz93`nwh49oQE<~X;S^1y3uo;z#z9*W9NRBA%a>aSZm)T{xV()!U|!C>E-1MJx)L*x`=#a$sri!`xXS*W+e>4j zk6jt|*yfvZQd}CVAnnV(P?D>mr;Nvyq(epO#99@3Q$d3MU@!s$VBiUfCDI5pz=dD$ zhrv&T#KD>)lefPz_0o3oxedS0Ey&AzvY;UM`Db(U31Y!?6;^d$v=DucyQ}CD!)oxG z?wa1WL?NQ3R@ArrS=7_*)IY51-X9(a%Bpf1ZkleVMsX7xp;(b{*kh98Uwa(8WDzuK zc1Z+Vq{sC{Bgi`e zH;1_l^(#zUzegvebKr_ggJ^xg9>JM(MS`5O(FOw!4AA(utV6jXveMf?_L>_DQ3X4w z%v1-wb~#QOrfKf%hR>PL*;JK*+B3p6VrZ@)XuiRF*bi0ts!AVhRH4IeWfqqT#mXiyk|nR?jQ z|FIy)IEZ%yEA$A7hI&h8L%Ga6#v}7>BQ;J}Kn#T+L74$-uz~2!rc~|1WESr5W?`on zeK(0d3!>p5N9rgs0x3OkVXLU(S|vF>_~`I6MF_n%WQs@40qE_E(WL-SR3bq`!$?{Q zN6qY;k(*e^1n`Uf)zvFE3iBdNIBL+6V$Gth!78GMhKs2gsm+_At妔ys!_FlshnXZxl>CQ(pE)_ytLOlEXdo1hqSH6n5XLAB@?C~h0uT>lEEu|Fu?Em zj&$i8QsiQoVZTOhz#He$(_<)K3W7>s1j1X`*P>r6X_{`(2oW-2tRY@-=9;3R^Tr7} zl~ZXSr}bR5pmJ4f49thL1|67nRpW7wq26$g`$Eq(>bV9zcV0p-JtmAOvcM!dJX5$<6}5%4oq2^Jv6tr;vZn z9`*OLg372nDm;+PWNQ|a06Rj4;2Z!Sp%Gfe{%@@Q3BZEWqlyJJfI^Rr0tt}iBn3JC z<)~wy3?K&hAK}>8utczj)FrY64?C{jw)m0fh#^hF{d*k}lm_E72Q`L}xR3fFEp zpLi}aZFXDQ2NUydx5wjlPr~P+duD{4PcC53P#Foe0i)o*-Xgd)5ME%pv*--lLuJcw zDO(h$T`rj$|Iv@H3}P;LB&5_2J$iI`6!fP1M?LEDu*c$_NihY`CqBD}`92h)+)1Y# z-tqD@%4d7x^47$8C1ZrmRUo~jjy)cDpQv7Npj|$vTns&QpNy#m3u`3*#wNBXUZejR z`=SN*WdlEBKZ&0lm6+KDYbUwEHBgdULIb_Wo+W89B>y_r60c2{oNR_Z(hw(rmQv@W z2dJ28OYqTShS4>aPgqm({b)TvaLC6%A7?mQWt>oM!!<5^!AqcIFStN0FK13laU+Hm zqPJ!ZG(65$BT_~%;kB>e>1DoF0>3n7t7(md2OslsU)AoCaTja%$v8*t0a;sF4djE6 zYy%@2`YD-;hvVJzl)qIY zjsnnA!xFsjU;3Z2Q6GCMapjXalF?#ZxNQ)kPzpT$X~36;N?B!<4A7@iW|2GYyDNzv z$ACMB>=7bhDP@QaBxV-R4SQf>12-W)WeHkUE$bwUQdGYfubFbL`%vgha+8h8d|T+EM9Y9y-h(X2S7j)|m80Zb-7Z z8A-Bix2OQaH%+6R-n!1ec2n`FU_wHAX+@5b#_@S}S#pLFJvV^QPqUkoQF_1)pj1)! z5#mLF0nZ$FT@)JrOXiFbiqP03S~HI(SyM71cd{3fQ%gvn7~M`yp>{v4;B6Bv8ee^j z(kGsVnFqo{&P;{zK?qcypm_v|&t-u!>9nA5S#kUbciOpFnB=U^mjpi;+{&C5hqz8r zcD)mX;X0if$ST7Rz#iwPQG%y66KrmtYb)!Z`hYZ26I|!hV(0ZvK9lJXZt|Cz571j9 z_B?B=C9M1-$aYXJ3>$^7 zVW$@DCik#AH5tXu5qlB3?*-T~Exp)>Opn){;;urveZc))YRgZ-qA3}&9CS*wXb=xh zac3caUxhKGUHk?6wdQehEjy|yC}zbaIl-S-hyEblO>DiY*)}aw5ovMRvL7kEkA0TA}#Xe4Fb619VlO zfICzc*g8PrtyzK!oW<2?>uB8yu?BFxe*mrWV!!{0Np}5A2(loI0JS)qPF>%^g$AO& zu3CC=m#2#8H7KepiQY|{bb0L6#hFP?FHnFZTs4-@)OA52o`~OMZ^kcPx_bt1m;`Cc zI>2db3I{ssZ5>9md**rvIBQtKvXyC~B~$WYp#%A6&<~Xg9xi0rdqy zeeN5^CS`5z%0dr^KtXo(Ct{(%5@Fws@z7@eeke!WUXoby)pS-!JIcTjPz8t>;f6ls z0Tdssl=lMkk-aE5g>TJ53u)P^5>(t7h|UcooNW_hvn#>)`0A|WK7hW!ljLrv?!6kS z&!}+7=y_7+1>`!?WeuK0>pX&dKT&GUs!A3R`*3N7EY-)Rrk0WCS!?Pq6aUX=jjM|7 zu^y|6>A|5a{~gWxQ-4FQW4EN`=;3f?76hv5e@)Xm_QCztxeB`s5Vpaurb#@x{>Q-o1D3?yJpcdz delta 4230 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 j>@UyZ%I9+GFXkGQy#GPX_Khc;EBCnk48m diff --git a/bin/kernal_ultimate64.rom b/bin/kernal_ultimate64.rom index 67d825a52288f4c7f63e111accc101eb42c028c9..99bcc4f27481f615da2780b86c3a054756b67188 100644 GIT binary patch delta 3978 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 EU*l45+5i9m delta 3922 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 HX6XL_S}abM diff --git a/bin/mega65.rom b/bin/mega65.rom index 62b930f2aed955f10852556624c9d27cc88cc0f1..7590e052c4b6dad671439bebdc299e5950f6f987 100644 GIT binary patch delta 2419 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 gv?j(6YQ5|RJQ&N!__pela5;2hG&VRIW7n Date: Tue, 23 Jun 2020 06:45:06 +0200 Subject: [PATCH 078/103] more work towards dictionary text compression --- c64/,,config_custom.s | 2 +- tools/generate_strings.cc | 177 ++++++++++++++++++++++++++++++++------ 2 files changed, 153 insertions(+), 26 deletions(-) diff --git a/c64/,,config_custom.s b/c64/,,config_custom.s index b2b827c4..e43a3a58 100644 --- a/c64/,,config_custom.s +++ b/c64/,,config_custom.s @@ -126,7 +126,7 @@ #define CONFIG_TAPE_WEDGE // #define CONFIG_TAPE_HEAD_ALIGN #define CONFIG_BCD_SAFE_INTERRUPTS - +// #define CONFIG_COMPRESSION_LVL_2 // work-in-progress // Eye candy diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index 2fee7fc8..24316cc1 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -4,10 +4,6 @@ // XXX print somewhere configuration file used to generate strings // XXX use DualStream class for logging -// XXX use dictionary compression by finding the set of non-overlapping strings that can be concatenated -// to produce full set of strings; some idea for the algorithm (not sure if proper one) is available here -// https://stackoverflow.com/questions/9195676/finding-the-smallest-number-of-substrings-to-represent-a-set-of-strings -// needs some investigation... #include "common.h" @@ -56,8 +52,8 @@ typedef struct StringEntryList std::vector list; } StringEntryList; -typedef std::vector StringFreqEncoded; -typedef std::vector StringDictEncoded; +typedef std::vector StringFreqEncoded; +typedef std::vector StringDictEncoded; typedef struct StringEncodedList { @@ -462,6 +458,22 @@ std::map GLOBAL_ConfigOptions; // Work class definitions // +class DictEncoder +{ +public: + + void addString(const std::string &inString, StringDictEncoded *outPtr); + + void process(StringEntryList &outDictionary); + +private: + + bool optimizeSplit(); + + std::vector encodings; + std::vector dictionary; +}; + class DataSet { public: @@ -475,8 +487,10 @@ private: void process(); void generateConfigDepStrings(); + void validateLists(); void calculateFrequencies(); - void encodeStrings(); + void encodeStringsDict(); + void encodeStringsFreq(); void encodeByFreq(const std::string &plain, StringFreqEncoded &encoded) const; @@ -484,6 +498,8 @@ private: void putCharEncoding(std::ostringstream &stream, uint8_t idx, char character, bool is3n); + bool isCompressionLvl2(const StringEntryList &list) const; + virtual bool isRelevant(const StringEntry &entry) const = 0; virtual std::string layoutName() const = 0; @@ -496,7 +512,7 @@ private: uint8_t tk__packed_as_3n = 0; uint8_t tk__max_keyword_len = 0; - size_t maxAliasLen = 0; + size_t maxAliasLen = 0; std::string outFileContent; }; @@ -522,11 +538,70 @@ class DataSetX16 : public DataSet // Work class implementation // +void DictEncoder::addString(const std::string &inString, StringDictEncoded *outPtr) +{ + // Store the pointer to encoding + + encodings.push_back(outPtr); + + // Check if string is already present in the dictionary + + auto pos = std::find(dictionary.begin(), dictionary.end(), inString); + + // Create initial encoding + + if (pos != dictionary.end()) + { + encodings.back()->push_back(pos - dictionary.begin()); + } + else + { + if (dictionary.size() > 255) + { + ERROR("max 255 strings for dictionary compression"); + } + + dictionary.push_back(inString); + encodings.back()->push_back(dictionary.size() - 1); + } +} + +bool DictEncoder::optimizeSplit() +{ + // XXX + + return false; +} + +void DictEncoder::process(StringEntryList &outDictionary) +{ + // Optimize as long as it brings any improvement + + while (optimizeSplit()) ; + + // Export the dictionary to external format + + outDictionary.type = ListType::DICTIONARY; + outDictionary.name = "DICTIONARY"; + + for (const auto &dictionaryStr : dictionary) + { + StringEntry newEntry = { true, true, true, "", dictionaryStr }; + outDictionary.list.push_back(newEntry); + } +} + +bool DataSet::isCompressionLvl2(const StringEntryList &list) const +{ + return (GLOBAL_ConfigOptions["CONFIG_COMPRESSION_LVL_2"] && list.type == ListType::STRINGS_BASIC); +} + void DataSet::addStrings(const StringEntryList &stringList) { // Import the new list of strings stringEntryLists.push_back(stringList); + stringEncodedLists.emplace_back(); // Clear strings not relevant for the current configuration @@ -551,8 +626,10 @@ void DataSet::process() std::cout << "Processing layout '" << layoutName() << "'" << std::endl; generateConfigDepStrings(); + validateLists(); + encodeStringsDict(); calculateFrequencies(); - encodeStrings(); + encodeStringsFreq(); prepareOutput(); } @@ -661,22 +738,12 @@ void DataSet::generateConfigDepStrings() } } -void DataSet::calculateFrequencies() +void DataSet::validateLists() { - as1n.clear(); - as3n.clear(); - - std::map freqMapGeneral; // general character frequency map - std::map freqMapKeywords; // frequency map for keywords - - // Calculate frequencies of characters in the strings - for (const auto &stringEntryList : stringEntryLists) { for (const auto &stringEntry : stringEntryList.list) { - if (!isRelevant(stringEntry)) continue; - // Check for maximum allowed string length if (stringEntry.string.length() > 255) ERROR("string cannot be longer than 255 characters"); @@ -696,7 +763,62 @@ void DataSet::calculateFrequencies() { ERROR(std::string("character above 0x80 in string '") + stringEntry.string + "'"); } - + } + } + } +} + +void DataSet::encodeStringsDict() +{ + DictEncoder dictEncoder; + + // Add strings for dictionary compresssion + + for (uint8_t idx = 0; idx < stringEntryLists.size(); idx++) + { + const auto &stringEntryList = stringEntryLists[idx]; + auto &stringEncodedList = stringEncodedLists[idx]; + + // Skip lists not to be encoded using the dictionary + if (!isCompressionLvl2(stringEntryList)) continue; + + stringEncodedList.byDict.resize(stringEntryList.list.size()); + for (uint8_t idxEntry = 0; idxEntry < stringEntryList.list.size(); idxEntry++) + { + dictEncoder.addString(stringEntryList.list[idxEntry].string, + &stringEncodedList.byDict[idxEntry]); + } + } + + // Perform the compression + + stringEntryLists.emplace_back(); + stringEncodedLists.emplace_back(); + + dictEncoder.process(stringEntryLists.back()); +} + +void DataSet::calculateFrequencies() +{ + as1n.clear(); + as3n.clear(); + + std::map freqMapGeneral; // general character frequency map + std::map freqMapKeywords; // frequency map for keywords + + // Calculate frequencies of characters in the strings + + for (const auto &stringEntryList : stringEntryLists) + { + // Skip lists encoded by the dictionary + if (isCompressionLvl2(stringEntryList)) continue; + + for (const auto &stringEntry : stringEntryList.list) + { + if (!isRelevant(stringEntry)) continue; + + for (const auto &character : stringEntry.string) + { freqMapGeneral[character]++; if (stringEntryList.type == ListType::KEYWORDS) freqMapKeywords[character]++; } @@ -822,16 +944,21 @@ void DataSet::encodeByFreq(const std::string &plain, StringFreqEncoded &encoded) if (encoded.size() == 0 || encoded.back() != 0) encoded.push_back(0); } -void DataSet::encodeStrings() +void DataSet::encodeStringsFreq() { stringEncodedLists.clear(); // Encode every relevant string from every list - by character frequency - for (const auto &stringEntryList : stringEntryLists) + for (uint8_t idx = 0; idx < stringEntryLists.size(); idx++) { - stringEncodedLists.emplace_back(); - auto &stringEncodedList = stringEncodedLists.back(); + const auto &stringEntryList = stringEntryLists[idx]; + auto &stringEncodedList = stringEncodedLists[idx]; + + // Skip lists encoded by the dictionary + if (isCompressionLvl2(stringEntryList)) continue; + + // Perform encoding of the list for (const auto &stringEntry : stringEntryList.list) { From d3fdc6cc59773ab5aef38e1a361b65d6a6205aa7 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Tue, 23 Jun 2020 17:28:46 +0200 Subject: [PATCH 079/103] more work towards dictionary encoding --- tools/generate_strings.cc | 317 +++++++++++++++++++++++++++++++++----- 1 file changed, 278 insertions(+), 39 deletions(-) diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index 24316cc1..9a97792f 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -2,9 +2,6 @@ // Utility to generate compressed messages and BASIC tokens // -// XXX print somewhere configuration file used to generate strings -// XXX use DualStream class for logging - #include "common.h" #include @@ -52,14 +49,8 @@ typedef struct StringEntryList std::vector list; } StringEntryList; -typedef std::vector StringFreqEncoded; -typedef std::vector StringDictEncoded; - -typedef struct StringEncodedList -{ - std::vector byFreq; - std::vector byDict; -} StringEncodedList; +typedef std::vector StringEncoded; +typedef std::vector StringEncodedList; // http://www.classic-games.com/commodore64/cbmtoken.html // https://www.c64-wiki.com/wiki/BASIC_token @@ -462,16 +453,21 @@ class DictEncoder { public: - void addString(const std::string &inString, StringDictEncoded *outPtr); + void addString(const std::string &inString, StringEncoded *outPtr); void process(StringEntryList &outDictionary); private: bool optimizeSplit(); + bool optimizeJoin(); + void optimizeOrder(); - std::vector encodings; - std::vector dictionary; + void extractWords(std::vector &candidateList); + int32_t evaluateCandidate(std::string &candidate); + + std::vector encodings; + std::vector dictionary; }; class DataSet @@ -492,7 +488,7 @@ private: void encodeStringsDict(); void encodeStringsFreq(); - void encodeByFreq(const std::string &plain, StringFreqEncoded &encoded) const; + void encodeByFreq(const std::string &plain, StringEncoded &encoded) const; void prepareOutput(); @@ -538,7 +534,7 @@ class DataSetX16 : public DataSet // Work class implementation // -void DictEncoder::addString(const std::string &inString, StringDictEncoded *outPtr) +void DictEncoder::addString(const std::string &inString, StringEncoded *outPtr) { // Store the pointer to encoding @@ -566,18 +562,244 @@ void DictEncoder::addString(const std::string &inString, StringDictEncoded *outP } } + +void DictEncoder::extractWords(std::vector &candidateList) +{ + for (const auto &dictionaryEntry : dictionary) + { + // Split the dictionary entry into words + + std::istringstream entryStream(dictionaryEntry); + while (entryStream) + { + // XXX probably not the best way + std::string word_1; + entryStream >> word_1; + + // Create possible variants with spaces + + std::string word_2 = " " + word_1; + std::string word_3 = word_1 + " "; + std::string word_4 = word_2 + " "; + + // If necessary, add the word to candidate list + + auto addToList = [&dictionaryEntry, &candidateList](std::string &word) + { + // Before dding, make sure the word variant exists in the string, + // is not already on the list, and is long enough it makes sense to try + + if (word.size() < 1) return; + if (dictionaryEntry.find(word) == std::string::npos) return; + if (std::find(candidateList.begin(), candidateList.end(), word) == candidateList.end()) return; + + candidateList.push_back(word); + }; + + addToList(word_1); + addToList(word_2); + addToList(word_3); + addToList(word_4); + } + } +} + +int32_t DictEncoder::evaluateCandidate(std::string &candidate) +{ + // Build the score - find how much bytes can be spared by extracting this particular candidate + // Limited size of the dictionary is taken into consideration + + int32_t score = -(candidate.size() + 1); + uint32_t targetSize = dictionary.size() + 1; + + // First check for situation when the candidate equals the currently existing dictionary entry + + for (const auto &dictionaryEntry : dictionary) + { + if (dictionaryEntry == candidate) + { + // Candidate equals the string + + score += candidate.size() + 1; + targetSize--; + continue; + } + } + + // Now check the remaining cases + + for (const auto &dictionaryEntry : dictionary) + { + if (dictionaryEntry == candidate) continue; // already handled + + // Find all the occurences of the candidate in the current string + + std::vector occurences; + for (auto iter = dictionaryEntry.begin(); iter < (dictionaryEntry.end() - candidate.size() + 1); iter++) + { + if (candidate != std::string(iter, iter + candidate.size())) continue; + + occurences.push_back(iter - dictionaryEntry.begin()); + iter += candidate.size() - 1; // to make sure we have no occurence overlapping + } + + if (occurences.empty()) continue; + + // Now summarize what we are going to gain when doing replacement + + if (occurences[0] != 0) + { + // For the substring before the first occurence we need to create a separate entry + // in the dictionary - unless it is already there, it brings some additional cost + + // XXX, targetSize + } + + for (auto iter = occurences.begin(); iter < occurences.end(); iter++) + { + // With a replacement, we should gain some bytes + score += candidate.size() - 1; + + // If the occurence ends with the last byte of dictionary string - nothing more to do + if (*iter + candidate.size() == dictionaryEntry.size()) break; + + // If next occurence starts immediately after this one - next iteration + if (iter + 1 != occurences.end() && (*(iter + 1) - *iter) == (uint8_t) candidate.size()) continue; + + // For the substring between this occurence and the next one (or the end of the string) + // we need to create a separate entry in the dictionary - unless it is already there, + // it brings some additional cost + + // XXX, targetSize + } + + // We crossed the maximum number of strings, do not consider this candidate + // XXX improve the behaviour, maybe only some substrings can be replaced + + if (targetSize > 255) return -1; + } + + return score; +} + bool DictEncoder::optimizeSplit() { + if (dictionary.size() >= 255) return false; // up to 255 entries in the dictionary are possible + + // First select words, which can potentially be extracted to new substrings + + std::vector candidateList; + extractWords(candidateList); + + // XXX find a couple of largest common substrings and add them as candidates too + + // Now find the best word to be extracted + + auto bestCandidate = candidateList.end(); + int32_t bestCandidateScore = 0; + + for (auto iter = candidateList.begin(); iter < candidateList.end(); iter++) + { + int32_t candidateScore = evaluateCandidate(*iter); + if (candidateScore > bestCandidateScore) + { + bestCandidate = iter; + bestCandidateScore = bestCandidateScore; + } + } + + if (bestCandidateScore < 1) return false; + + // Perform the extraction + // XXX return false; } +bool DictEncoder::optimizeJoin() +{ + // Try to optimize by joining two substrings + + // XXX + + return false; +} + +void DictEncoder::optimizeOrder() +{ + // Try to optimize order of strings in the dictionary for fastest display + // - put the shorter substrings first + // - for strings with roughly the same length put more frequently used first + + typedef struct Entry + { + uint32_t penalty; + std::string word; + } Entry; + + // Create copy of the dictionary with optimization info + + std::vector optimizedOrder; + for (auto iter = dictionary.begin(); iter < dictionary.end(); iter++) + { + const auto &dictionaryStr = *iter; + + uint8_t sizePenalty = dictionaryStr.size() / 3; + uint16_t freqPenalty = 65535; + + // Calculate penalty for low occurence frequency + + for (auto &encoding : encodings) + { + for (auto &byte : *encoding) + { + if (byte == (iter - dictionary.begin())) freqPenalty--; + } + } + + // Create new entry + + Entry newEntry; + newEntry.word = dictionaryStr; + newEntry.penalty = sizePenalty * 65536 + freqPenalty; + + optimizedOrder.push_back(newEntry); + } + + // Determine ordering - sort from smallest penalty to largest + + std::sort(optimizedOrder.begin(), optimizedOrder.end(), + [](const Entry &e1, const Entry &e2) { return e1.penalty < e2.penalty; }); + + // Create helper table for reordering + + std::vector reorderTable; + + for (uint8_t idx1 = 0; idx1 < dictionary.size(); idx1++) + { + uint8_t idx2 = 0; + while (dictionary[idx1] != optimizedOrder[idx2].word) idx2++; + + reorderTable.push_back(idx2); + } + + // Perform the reordering + + for (auto &encoding : encodings) + { + for (auto &byte : *encoding) byte = reorderTable[byte]; + } + + for (uint8_t idx = 0; idx < dictionary.size(); idx++) dictionary[idx] = optimizedOrder[idx].word; +} + void DictEncoder::process(StringEntryList &outDictionary) { // Optimize as long as it brings any improvement - while (optimizeSplit()) ; + while (optimizeSplit() || optimizeJoin()) ; + optimizeOrder(); // Export the dictionary to external format @@ -589,6 +811,14 @@ void DictEncoder::process(StringEntryList &outDictionary) StringEntry newEntry = { true, true, true, "", dictionaryStr }; outDictionary.list.push_back(newEntry); } + + // Adapt the encoding to external format (0 = end of string) + + for (auto &encoding : encodings) + { + for (auto &byte : *encoding) byte++; + encoding->push_back(0); + } } bool DataSet::isCompressionLvl2(const StringEntryList &list) const @@ -623,7 +853,7 @@ void DataSet::addStrings(const StringEntryList &stringList) void DataSet::process() { - std::cout << "Processing layout '" << layoutName() << "'" << std::endl; + std::cout << "Processing file '" << CMD_cnfFile << "', layout '" << layoutName() << "'" << std::endl; generateConfigDepStrings(); validateLists(); @@ -782,11 +1012,11 @@ void DataSet::encodeStringsDict() // Skip lists not to be encoded using the dictionary if (!isCompressionLvl2(stringEntryList)) continue; - stringEncodedList.byDict.resize(stringEntryList.list.size()); + stringEncodedList.resize(stringEntryList.list.size()); for (uint8_t idxEntry = 0; idxEntry < stringEntryList.list.size(); idxEntry++) { dictEncoder.addString(stringEntryList.list[idxEntry].string, - &stringEncodedList.byDict[idxEntry]); + &stringEncodedList[idxEntry]); } } @@ -885,7 +1115,7 @@ void DataSet::calculateFrequencies() } } -void DataSet::encodeByFreq(const std::string &plain, StringFreqEncoded &encoded) const +void DataSet::encodeByFreq(const std::string &plain, StringEncoded &encoded) const { bool fullByte = true; @@ -958,12 +1188,12 @@ void DataSet::encodeStringsFreq() // Skip lists encoded by the dictionary if (isCompressionLvl2(stringEntryList)) continue; - // Perform encoding of the list + // Perform frequency encoding of the list for (const auto &stringEntry : stringEntryList.list) { - stringEncodedList.byFreq.emplace_back(); - auto &stringEncoded = stringEncodedList.byFreq.back(); + stringEncodedList.emplace_back(); + auto &stringEncoded = stringEncodedList.back(); if (isRelevant(stringEntry)) { @@ -1042,20 +1272,20 @@ void DataSet::prepareOutput() stream << std::endl << ".label TK__PACKED_AS_3N = $" << std::hex << +tk__packed_as_3n << std::endl << ".label TK__MAX_KEYWORD_LEN = " << std::dec << +tk__max_keyword_len << std::endl; - // Export frequency-encoded strings + // Export encoded strings for (uint8_t idxList = 0; idxList < stringEntryLists.size(); idxList++) { - const auto &stringEntryList = stringEntryLists[idxList]; - const auto &stringFreqEncodedList = stringEncodedLists[idxList].byFreq; + const auto &stringEntryList = stringEntryLists[idxList]; + const auto &stringEncodedList = stringEncodedLists[idxList]; stream << std::endl; - for (uint8_t idxString = 0; idxString < stringFreqEncodedList.size(); idxString++) + for (uint8_t idxString = 0; idxString < stringEncodedList.size(); idxString++) { - const auto &stringEntry = stringEntryList.list[idxString]; - const auto &stringFreqEncoded = stringFreqEncodedList[idxString]; + const auto &stringEntry = stringEntryList.list[idxString]; + const auto &stringEncoded = stringEncodedList[idxString]; - if (!stringFreqEncoded.empty()) + if (!stringEncoded.empty()) { stream << ".label IDX__" << stringEntry.alias << std::string(maxAliasLen - stringEntry.alias.length(), ' ') << " = $" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << +idxString << std::endl; @@ -1067,18 +1297,27 @@ void DataSet::prepareOutput() if (stringEntryList.type == ListType::KEYWORDS) { stream << std::endl << ".label TK__MAXTOKEN_" << stringEntryList.name << " = " << - std::dec << stringFreqEncodedList.size() << std::endl; + std::dec << stringEncodedList.size() << std::endl; } - stream << std::endl << ".macro put_freq_packed_" << stringEntryList.name << "()" << std::endl << "{" << std::endl; + if (isCompressionLvl2(stringEntryList)) + { + stream << std::endl << ".macro put_dict_packed_"; + } + else + { + stream << std::endl << ".macro put_freq_packed_"; + } + + stream << stringEntryList.name << "()" << std::endl << "{" << std::endl; enum LastStr { NONE, SKIPPED, WRITTEN } lastStr = LastStr::NONE; - for (uint8_t idxString = 0; idxString < stringFreqEncodedList.size(); idxString++) + for (uint8_t idxString = 0; idxString < stringEncodedList.size(); idxString++) { - const auto &stringEntry = stringEntryList.list[idxString]; - const auto &stringFreqEncoded = stringFreqEncodedList[idxString]; + const auto &stringEntry = stringEntryList.list[idxString]; + const auto &stringEncoded = stringEncodedList[idxString]; - if (stringFreqEncoded.empty()) + if (stringEncoded.empty()) { if (lastStr == LastStr::WRITTEN) stream << std::endl; stream << "\t.byte $00 // skipped " << stringEntry.alias << std::endl; @@ -1092,7 +1331,7 @@ void DataSet::prepareOutput() stream << "\t.byte "; bool first = true; - for (const auto &charEncoded : stringFreqEncoded) + for (const auto &charEncoded : stringEncoded) { if (first) { @@ -1191,7 +1430,7 @@ void printUsage() void printBanner() { printBannerLineTop(); - std::cout << "// Generating compressed messages and BASIC tokens" << "\n"; + std::cout << "// Generating compressed messages and BASIC tokens\n"; printBannerLineBottom(); } From 3b4d1345db2369effca79b09097ff5607c02a9b4 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Tue, 23 Jun 2020 19:38:56 +0200 Subject: [PATCH 080/103] added code to display dictionary compressed strings --- Makefile | 6 +- ..._str_keywords_V2.s => packed_dictionary.s} | 8 ++- c64/basic/assets/packed_errors.s | 19 ++++++ ...cked_str_errors.s => packed_keywords_CC.s} | 4 +- ...str_keywords_CC.s => packed_keywords_CD.s} | 4 +- ...str_keywords_CD.s => packed_keywords_V2.s} | 4 +- c64/basic/assets/packed_misc.s | 19 ++++++ c64/basic/assets/packed_str_misc.s | 9 --- c64/basic/print/print_packed_dict_string.s | 67 +++++++++++++++++++ ...ed_string.s => print_packed_freq_string.s} | 55 +++++---------- c64/basic/print/print_packed_search.s | 40 +++++++++++ c64/basic/tokenizer/tokenise_line.s | 12 ++-- tools/generate_strings.cc | 33 +++++---- 13 files changed, 202 insertions(+), 78 deletions(-) rename c64/basic/assets/{packed_str_keywords_V2.s => packed_dictionary.s} (58%) create mode 100644 c64/basic/assets/packed_errors.s rename c64/basic/assets/{packed_str_errors.s => packed_keywords_CC.s} (69%) rename c64/basic/assets/{packed_str_keywords_CC.s => packed_keywords_CD.s} (69%) rename c64/basic/assets/{packed_str_keywords_CD.s => packed_keywords_V2.s} (69%) create mode 100644 c64/basic/assets/packed_misc.s delete mode 100644 c64/basic/assets/packed_str_misc.s create mode 100644 c64/basic/print/print_packed_dict_string.s rename c64/basic/print/{print_packed_string.s => print_packed_freq_string.s} (77%) create mode 100644 c64/basic/print/print_packed_search.s diff --git a/Makefile b/Makefile index 1be7f610..5917680b 100644 --- a/Makefile +++ b/Makefile @@ -178,15 +178,15 @@ updatebin: $(TOOL_PNGPREPARE): tools/pngprepare.c @mkdir -p build/tools - $(CC) -O2 -g -Wall -I/usr/local/include -L/usr/local/lib -o $@ $< -lpng + $(CC) -O2 -Wall -I/usr/local/include -L/usr/local/lib -o $@ $< -lpng build/tools/%: tools/%.c @mkdir -p build/tools - $(CC) -O2 -g -Wall -o $@ $< + $(CC) -O2 -Wall -o $@ $< build/tools/%: tools/%.cc tools/common.h @mkdir -p build/tools - $(CXX) -O2 -g -Wall -o $@ $< + $(CXX) -O0 -g -Wall -o $@ $< # Rules - CHARGEN diff --git a/c64/basic/assets/packed_str_keywords_V2.s b/c64/basic/assets/packed_dictionary.s similarity index 58% rename from c64/basic/assets/packed_str_keywords_V2.s rename to c64/basic/assets/packed_dictionary.s index 5247b32e..b7f9c640 100644 --- a/c64/basic/assets/packed_str_keywords_V2.s +++ b/c64/basic/assets/packed_dictionary.s @@ -4,6 +4,10 @@ // #LAYOUT# * * #IGNORE -packed_str_keywords_V2: +#if CONFIG_COMPRESSION_LVL_2 - put_freq_packed_keywords_V2() +packed_dictionary: + + put_packed_freq_DICTIONARY() + +#endif diff --git a/c64/basic/assets/packed_errors.s b/c64/basic/assets/packed_errors.s new file mode 100644 index 00000000..d71177b0 --- /dev/null +++ b/c64/basic/assets/packed_errors.s @@ -0,0 +1,19 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +#if CONFIG_COMPRESSION_LVL_2 + +packed_dict_errors: + + put_packed_dict_errors() + +#else + +packed_freq_errors: + + put_packed_freq_errors() + +#endif diff --git a/c64/basic/assets/packed_str_errors.s b/c64/basic/assets/packed_keywords_CC.s similarity index 69% rename from c64/basic/assets/packed_str_errors.s rename to c64/basic/assets/packed_keywords_CC.s index 4582fb54..8cbf9bed 100644 --- a/c64/basic/assets/packed_str_errors.s +++ b/c64/basic/assets/packed_keywords_CC.s @@ -4,6 +4,6 @@ // #LAYOUT# * * #IGNORE -packed_str_errors: +packed_freq_keywords_CC: - put_freq_packed_errors() + put_packed_freq_keywords_CC() diff --git a/c64/basic/assets/packed_str_keywords_CC.s b/c64/basic/assets/packed_keywords_CD.s similarity index 69% rename from c64/basic/assets/packed_str_keywords_CC.s rename to c64/basic/assets/packed_keywords_CD.s index 4fe84295..c474d947 100644 --- a/c64/basic/assets/packed_str_keywords_CC.s +++ b/c64/basic/assets/packed_keywords_CD.s @@ -4,6 +4,6 @@ // #LAYOUT# * * #IGNORE -packed_str_keywords_CC: +packed_freq_keywords_CD: - put_freq_packed_keywords_CC() + put_packed_freq_keywords_CD() diff --git a/c64/basic/assets/packed_str_keywords_CD.s b/c64/basic/assets/packed_keywords_V2.s similarity index 69% rename from c64/basic/assets/packed_str_keywords_CD.s rename to c64/basic/assets/packed_keywords_V2.s index 8c9e51f3..b6cd2eab 100644 --- a/c64/basic/assets/packed_str_keywords_CD.s +++ b/c64/basic/assets/packed_keywords_V2.s @@ -4,6 +4,6 @@ // #LAYOUT# * * #IGNORE -packed_str_keywords_CD: +packed_freq_keywords_V2: - put_freq_packed_keywords_CD() + put_packed_freq_keywords_V2() diff --git a/c64/basic/assets/packed_misc.s b/c64/basic/assets/packed_misc.s new file mode 100644 index 00000000..3af051b7 --- /dev/null +++ b/c64/basic/assets/packed_misc.s @@ -0,0 +1,19 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +#if CONFIG_COMPRESSION_LVL_2 + +packed_dict_misc: + + put_packed_dict_misc() + +#else + +packed_freq_misc: + + put_packed_freq_misc() + +#endif diff --git a/c64/basic/assets/packed_str_misc.s b/c64/basic/assets/packed_str_misc.s deleted file mode 100644 index bceadcdf..00000000 --- a/c64/basic/assets/packed_str_misc.s +++ /dev/null @@ -1,9 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# M65 BASIC_1 #TAKE -// #LAYOUT# X16 BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - - -packed_str_misc: - - put_freq_packed_misc() diff --git a/c64/basic/print/print_packed_dict_string.s b/c64/basic/print/print_packed_dict_string.s new file mode 100644 index 00000000..4683b730 --- /dev/null +++ b/c64/basic/print/print_packed_dict_string.s @@ -0,0 +1,67 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +#if CONFIG_COMPRESSION_LVL_2 + +print_packed_error: // .X - error string index + + lda #packed_dict_errors + bne print_dict_packed_string // branch always + +print_packed_misc_str: // .X - misc string index + + lda #packed_dict_misc + + // FALLTROUGH + +print_dict_packed_string: + + // Search for the packed string on the list + + jsr print_packed_search + + ldy #$00 +!: + // At this point FRESPC contains a pointer to the string to display + // Fetch a byte-code + + lda (FRESPC), y + beq print_dict_packed_string_end // branch if everything displayed + tax + dex + + // Call 'print_freq_packed_string' - but preserve all the data needed to progress further + + phy_trash_a + lda FRESPC+0 + pha + lda FRESPC+1 + pha + + lda #packed_dictionary + + jsr print_freq_packed_string + + pla + sta FRESPC+1 + pla + sta FRESPC+0 + ply_trash_a + + // Next iteration + + iny + bne !- // branch always + +print_dict_packed_string_end: + + rts + + +#endif diff --git a/c64/basic/print/print_packed_string.s b/c64/basic/print/print_packed_freq_string.s similarity index 77% rename from c64/basic/print/print_packed_string.s rename to c64/basic/print/print_packed_freq_string.s index 84b6f3d7..a936a675 100644 --- a/c64/basic/print/print_packed_string.s +++ b/c64/basic/print/print_packed_freq_string.s @@ -23,69 +23,46 @@ print_packed_misc_str: #else +#if !CONFIG_COMPRESSION_LVL_2 + print_packed_error: // .X - error string index - lda #packed_str_errors + lda #packed_freq_errors bne print_freq_packed_string // branch always print_packed_misc_str: // .X - misc string index - lda #packed_str_misc + lda #packed_freq_misc bne print_freq_packed_string // branch always +#endif + print_packed_keyword_CC: // .X - token number - lda #packed_str_keywords_CC + lda #packed_freq_keywords_CC bne print_freq_packed_string // branch always print_packed_keyword_CD: // .X - token number - lda #packed_str_keywords_CD + lda #packed_freq_keywords_CD bne print_freq_packed_string // branch always print_packed_keyword_V2: // .X - token number - lda #packed_str_keywords_V2 + lda #packed_freq_keywords_V2 // FALLTROUGH print_freq_packed_string: // not to be used directly XXX rename to print_packed_string - // First store the initial address of the packed strings list + // Search for the packed string on the list - sta FRESPC+0 - sty FRESPC+1 - - // Now find the address of the string to print out - // The implementation assumes no packed string is longer than 255 bytes, including trailing zero -!: - cpx #$00 - beq print_freq_packed_string_found // branch if no need to advance anymore - dex - - ldy #$00 -!: - lda (FRESPC), y - iny - cmp #$00 - bne !- // branch if not the end of packed string - - clc // advance FREESPC pointer - tya - adc FRESPC+0 - sta FRESPC+0 - lda #$00 - adc FRESPC+1 - sta FRESPC+1 - - jmp !-- - -print_freq_packed_string_found: + jsr print_packed_search // At this point FRESPC contains a pointer to the string to display // and we should start from the lower nibble diff --git a/c64/basic/print/print_packed_search.s b/c64/basic/print/print_packed_search.s new file mode 100644 index 00000000..f536eb2e --- /dev/null +++ b/c64/basic/print/print_packed_search.s @@ -0,0 +1,40 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 BASIC_1 #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +print_packed_search: + + // First store the initial address of the packed strings list + + sta FRESPC+0 + sty FRESPC+1 + + // Now find the address of the string to print out + // The implementation assumes no packed string is longer than 255 bytes, including trailing zero +!: + cpx #$00 + beq print_packed_done // branch if no need to advance anymore + dex + + ldy #$00 +!: + lda (FRESPC), y + iny + cmp #$00 + bne !- // branch if not the end of packed string + + clc // advance FREESPC pointer + tya + adc FRESPC+0 + sta FRESPC+0 + lda #$00 + adc FRESPC+1 + sta FRESPC+1 + + jmp !-- + +print_packed_done: + + rts diff --git a/c64/basic/tokenizer/tokenise_line.s b/c64/basic/tokenizer/tokenise_line.s index fc817293..dc52f9de 100644 --- a/c64/basic/tokenizer/tokenise_line.s +++ b/c64/basic/tokenizer/tokenise_line.s @@ -72,9 +72,9 @@ tokenise_line_loop: // Check for BASIC V2 tokens - lda #packed_str_keywords_V2 + lda #>packed_freq_keywords_V2 sta FRESPC+1 jsr tk_search @@ -82,17 +82,17 @@ tokenise_line_loop: // Check for extended tokens - lda #packed_str_keywords_CC + lda #>packed_freq_keywords_CC sta FRESPC+1 jsr tk_search bcc tokenise_line_keyword_CC // branch if keyword identified - lda #packed_str_keywords_CD + lda #>packed_freq_keywords_CD sta FRESPC+1 jsr tk_search diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index 9a97792f..c8e547b1 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -1279,16 +1279,19 @@ void DataSet::prepareOutput() const auto &stringEntryList = stringEntryLists[idxList]; const auto &stringEncodedList = stringEncodedLists[idxList]; - stream << std::endl; - for (uint8_t idxString = 0; idxString < stringEncodedList.size(); idxString++) + if (stringEntryList.type != ListType::DICTIONARY) { - const auto &stringEntry = stringEntryList.list[idxString]; - const auto &stringEncoded = stringEncodedList[idxString]; - - if (!stringEncoded.empty()) + stream << std::endl; + for (uint8_t idxString = 0; idxString < stringEncodedList.size(); idxString++) { - stream << ".label IDX__" << stringEntry.alias << std::string(maxAliasLen - stringEntry.alias.length(), ' ') << - " = $" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << +idxString << std::endl; + const auto &stringEntry = stringEntryList.list[idxString]; + const auto &stringEncoded = stringEncodedList[idxString]; + + if (!stringEncoded.empty()) + { + stream << ".label IDX__" << stringEntry.alias << std::string(maxAliasLen - stringEntry.alias.length(), ' ') << + " = $" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << +idxString << std::endl; + } } } @@ -1302,11 +1305,11 @@ void DataSet::prepareOutput() if (isCompressionLvl2(stringEntryList)) { - stream << std::endl << ".macro put_dict_packed_"; + stream << std::endl << ".macro put_packed_dict_"; } else { - stream << std::endl << ".macro put_freq_packed_"; + stream << std::endl << ".macro put_packed_freq_"; } stream << stringEntryList.name << "()" << std::endl << "{" << std::endl; @@ -1314,20 +1317,24 @@ void DataSet::prepareOutput() enum LastStr { NONE, SKIPPED, WRITTEN } lastStr = LastStr::NONE; for (uint8_t idxString = 0; idxString < stringEncodedList.size(); idxString++) { - const auto &stringEntry = stringEntryList.list[idxString]; const auto &stringEncoded = stringEncodedList[idxString]; if (stringEncoded.empty()) { + if (stringEntryList.type == ListType::DICTIONARY) ERROR("internal error"); // should never happen + if (lastStr == LastStr::WRITTEN) stream << std::endl; - stream << "\t.byte $00 // skipped " << stringEntry.alias << std::endl; + stream << "\t.byte $00 // skipped " << stringEntryList.list[idxString].alias << std::endl; lastStr = LastStr::SKIPPED; } else { if (lastStr != LastStr::NONE) stream << std::endl; - stream << "\t// IDX__" << stringEntry.alias << std::endl; + if (stringEntryList.type != ListType::DICTIONARY) + { + stream << "\t// IDX__" << stringEntryList.list[idxString].alias << std::endl; + } stream << "\t.byte "; bool first = true; From 9e6dcd0b08ef8763b61696aacc18243b163f8b2d Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Tue, 23 Jun 2020 20:26:01 +0200 Subject: [PATCH 081/103] small code cleanup --- tools/generate_strings.cc | 203 ++++++++++++++++++++++---------------- 1 file changed, 118 insertions(+), 85 deletions(-) diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index c8e547b1..8da3790a 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -491,6 +491,13 @@ private: void encodeByFreq(const std::string &plain, StringEncoded &encoded) const; void prepareOutput(); + void prepareOutput_1n_3n(std::ostringstream &stream); + void prepareOutput_labels(std::ostringstream &stream, + const StringEntryList &stringEntryList, + const StringEncodedList &stringEncodedList); + void prepareOutput_packed(std::ostringstream &stream, + const StringEntryList &stringEntryList, + const StringEncodedList &stringEncodedList); void putCharEncoding(std::ostringstream &stream, uint8_t idx, char character, bool is3n); @@ -796,6 +803,7 @@ void DictEncoder::optimizeOrder() void DictEncoder::process(StringEntryList &outDictionary) { + if (dictionary.empty()) return; // Optimize as long as it brings any improvement while (optimizeSplit() || optimizeJoin()) ; @@ -1231,13 +1239,8 @@ void DataSet::putCharEncoding(std::ostringstream &stream, uint8_t idx, char char stream << petscii << std::endl; } -void DataSet::prepareOutput() +void DataSet::prepareOutput_1n_3n(std::ostringstream &stream) { - // Convert our encoded strings to a KickAssembler source - - std::ostringstream stream; - stream << std::endl << "#if ROM_LAYOUT_" << layoutName() << std::endl; - uint8_t idx; // Export all nibble-encoded characters @@ -1266,6 +1269,108 @@ void DataSet::prepareOutput() } stream << "}" << std::endl; +} + +void DataSet::prepareOutput_labels(std::ostringstream &stream, + const StringEntryList &stringEntryList, + const StringEncodedList &stringEncodedList) +{ + // For the dictionary we do not have any labels + if (stringEntryList.type == ListType::DICTIONARY) return; + + stream << std::endl; + for (uint8_t idxString = 0; idxString < stringEncodedList.size(); idxString++) + { + const auto &stringEntry = stringEntryList.list[idxString]; + const auto &stringEncoded = stringEncodedList[idxString]; + + if (!stringEncoded.empty()) + { + stream << ".label IDX__" << stringEntry.alias << std::string(maxAliasLen - stringEntry.alias.length(), ' ') << + " = $" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << +idxString << std::endl; + } + } +} + +void DataSet::prepareOutput_packed(std::ostringstream &stream, + const StringEntryList &stringEntryList, + const StringEncodedList &stringEncodedList) +{ + if (isCompressionLvl2(stringEntryList)) + { + stream << std::endl << ".macro put_packed_dict_"; + } + else + { + stream << std::endl << ".macro put_packed_freq_"; + } + + stream << stringEntryList.name << "()" << std::endl << "{" << std::endl; + + enum LastStr { NONE, SKIPPED, WRITTEN } lastStr = LastStr::NONE; + for (uint8_t idxString = 0; idxString < stringEncodedList.size(); idxString++) + { + const auto &stringEncoded = stringEncodedList[idxString]; + + if (stringEncoded.empty()) + { + if (stringEntryList.type == ListType::DICTIONARY) ERROR("internal error"); // should never happen + + if (lastStr == LastStr::WRITTEN) stream << std::endl; + stream << "\t.byte $00 // skipped " << stringEntryList.list[idxString].alias << std::endl; + lastStr = LastStr::SKIPPED; + } + else + { + if (lastStr != LastStr::NONE) stream << std::endl; + + if (stringEntryList.type != ListType::DICTIONARY) + { + stream << "\t// IDX__" << stringEntryList.list[idxString].alias << std::endl; + } + stream << "\t.byte "; + + bool first = true; + for (const auto &charEncoded : stringEncoded) + { + if (first) + { + first = false; + } + else + { + stream << ", "; + } + + stream << "$" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << +charEncoded; + } + + stream << std::endl; + lastStr = LastStr::WRITTEN; + } + } + + // For the token list - put the 'end of keywords' mark + + if (stringEntryList.type == ListType::KEYWORDS) + { + stream << std::endl << "\t// Marker - end of the keyword list" << std::endl; + stream << "\t.byte $FF, $FF" << std::endl; + } + + stream << "}" << std::endl; +} + +void DataSet::prepareOutput() +{ + // Convert our encoded strings to a KickAssembler source + + std::ostringstream stream; + stream << std::endl << "#if ROM_LAYOUT_" << layoutName() << std::endl; + + // Export 1-nibble and 3-nibble encoding data + + prepareOutput_1n_3n(stream); // Export additional data for the tokenizer @@ -1274,26 +1379,14 @@ void DataSet::prepareOutput() // Export encoded strings - for (uint8_t idxList = 0; idxList < stringEntryLists.size(); idxList++) + for (uint8_t idx = 0; idx < stringEntryLists.size(); idx++) { - const auto &stringEntryList = stringEntryLists[idxList]; - const auto &stringEncodedList = stringEncodedLists[idxList]; + const auto &stringEntryList = stringEntryLists[idx]; + const auto &stringEncodedList = stringEncodedLists[idx]; - if (stringEntryList.type != ListType::DICTIONARY) - { - stream << std::endl; - for (uint8_t idxString = 0; idxString < stringEncodedList.size(); idxString++) - { - const auto &stringEntry = stringEntryList.list[idxString]; - const auto &stringEncoded = stringEncodedList[idxString]; + // Export labels for the current list - if (!stringEncoded.empty()) - { - stream << ".label IDX__" << stringEntry.alias << std::string(maxAliasLen - stringEntry.alias.length(), ' ') << - " = $" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << +idxString << std::endl; - } - } - } + prepareOutput_labels(stream, stringEntryList, stringEncodedList); // For the token list - put the number of tokens available @@ -1303,69 +1396,9 @@ void DataSet::prepareOutput() std::dec << stringEncodedList.size() << std::endl; } - if (isCompressionLvl2(stringEntryList)) - { - stream << std::endl << ".macro put_packed_dict_"; - } - else - { - stream << std::endl << ".macro put_packed_freq_"; - } + // Export the packed data - stream << stringEntryList.name << "()" << std::endl << "{" << std::endl; - - enum LastStr { NONE, SKIPPED, WRITTEN } lastStr = LastStr::NONE; - for (uint8_t idxString = 0; idxString < stringEncodedList.size(); idxString++) - { - const auto &stringEncoded = stringEncodedList[idxString]; - - if (stringEncoded.empty()) - { - if (stringEntryList.type == ListType::DICTIONARY) ERROR("internal error"); // should never happen - - if (lastStr == LastStr::WRITTEN) stream << std::endl; - stream << "\t.byte $00 // skipped " << stringEntryList.list[idxString].alias << std::endl; - lastStr = LastStr::SKIPPED; - } - else - { - if (lastStr != LastStr::NONE) stream << std::endl; - - if (stringEntryList.type != ListType::DICTIONARY) - { - stream << "\t// IDX__" << stringEntryList.list[idxString].alias << std::endl; - } - stream << "\t.byte "; - - bool first = true; - for (const auto &charEncoded : stringEncoded) - { - if (first) - { - first = false; - } - else - { - stream << ", "; - } - - stream << "$" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << +charEncoded; - } - - stream << std::endl; - lastStr = LastStr::WRITTEN; - } - } - - // For the token list - put the 'end of keywords' mark - - if (stringEntryList.type == ListType::KEYWORDS) - { - stream << std::endl << "\t// Marker - end of the keyword list" << std::endl; - stream << "\t.byte $FF, $FF" << std::endl; - } - - stream << "}" << std::endl; + prepareOutput_packed(stream, stringEntryList, stringEncodedList); } // Finalize the file stream From 4e669bd9085a5aeb68e8b7624b61438317784e33 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Tue, 23 Jun 2020 20:42:32 +0200 Subject: [PATCH 082/103] small string generator fixes --- tools/generate_strings.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index 8da3790a..04ba249e 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -710,8 +710,8 @@ bool DictEncoder::optimizeSplit() int32_t candidateScore = evaluateCandidate(*iter); if (candidateScore > bestCandidateScore) { - bestCandidate = iter; - bestCandidateScore = bestCandidateScore; + bestCandidate = iter; + bestCandidateScore = candidateScore; } } @@ -997,7 +997,7 @@ void DataSet::validateLists() for (const auto &character : stringEntry.string) { - if (character >= 0x80) + if ((unsigned char) character >= 0x80) { ERROR(std::string("character above 0x80 in string '") + stringEntry.string + "'"); } From 3cd3f589545259ceb421e1bfa15a8ce925f20686 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Tue, 23 Jun 2020 21:20:42 +0200 Subject: [PATCH 083/103] fixed small bug preventing proper dictionary encoding --- tools/generate_strings.cc | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index 04ba249e..782ab2ff 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -867,7 +867,7 @@ void DataSet::process() validateLists(); encodeStringsDict(); calculateFrequencies(); - encodeStringsFreq(); + encodeStringsFreq(); prepareOutput(); } @@ -1015,7 +1015,7 @@ void DataSet::encodeStringsDict() for (uint8_t idx = 0; idx < stringEntryLists.size(); idx++) { const auto &stringEntryList = stringEntryLists[idx]; - auto &stringEncodedList = stringEncodedLists[idx]; + auto &stringEncodedList = stringEncodedLists[idx]; // Skip lists not to be encoded using the dictionary if (!isCompressionLvl2(stringEntryList)) continue; @@ -1030,10 +1030,13 @@ void DataSet::encodeStringsDict() // Perform the compression - stringEntryLists.emplace_back(); - stringEncodedLists.emplace_back(); + StringEntryList dictionary; + dictEncoder.process(dictionary); - dictEncoder.process(stringEntryLists.back()); + // Add new lists + + stringEntryLists.push_back(dictionary); + stringEncodedLists.emplace_back(); } void DataSet::calculateFrequencies() @@ -1184,8 +1187,6 @@ void DataSet::encodeByFreq(const std::string &plain, StringEncoded &encoded) con void DataSet::encodeStringsFreq() { - stringEncodedLists.clear(); - // Encode every relevant string from every list - by character frequency for (uint8_t idx = 0; idx < stringEntryLists.size(); idx++) @@ -1279,15 +1280,16 @@ void DataSet::prepareOutput_labels(std::ostringstream &stream, if (stringEntryList.type == ListType::DICTIONARY) return; stream << std::endl; - for (uint8_t idxString = 0; idxString < stringEncodedList.size(); idxString++) + for (uint8_t idx = 0; idx < stringEncodedList.size(); idx++) { - const auto &stringEntry = stringEntryList.list[idxString]; - const auto &stringEncoded = stringEncodedList[idxString]; + const auto &stringEntry = stringEntryList.list[idx]; + const auto &stringEncoded = stringEncodedList[idx]; if (!stringEncoded.empty()) { - stream << ".label IDX__" << stringEntry.alias << std::string(maxAliasLen - stringEntry.alias.length(), ' ') << - " = $" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << +idxString << std::endl; + stream << ".label IDX__" << stringEntry.alias << + std::string(maxAliasLen - stringEntry.alias.length(), ' ') << " = $" << + std::uppercase << std::hex << std::setfill('0') << std::setw(2) << +idx << std::endl; } } } From 74284d39b8b109f927848f6b6fdf934fd11a922a Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Tue, 23 Jun 2020 22:49:55 +0200 Subject: [PATCH 084/103] tested dictionary compression - not worth the effort, work stopped --- c64/,,config_custom.s | 5 ++- tools/generate_strings.cc | 71 ++++++++++++++++++++++++++++++++------- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/c64/,,config_custom.s b/c64/,,config_custom.s index e43a3a58..f2ec3464 100644 --- a/c64/,,config_custom.s +++ b/c64/,,config_custom.s @@ -126,7 +126,6 @@ #define CONFIG_TAPE_WEDGE // #define CONFIG_TAPE_HEAD_ALIGN #define CONFIG_BCD_SAFE_INTERRUPTS -// #define CONFIG_COMPRESSION_LVL_2 // work-in-progress // Eye candy @@ -141,3 +140,7 @@ // #define CONFIG_DBG_STUBS_BRK // #define CONFIG_DBG_PRINTF + +// Other + +#define CONFIG_COMPRESSION_LVL_2 // work on this option stopped - it would not give any improvement diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index 782ab2ff..6207451a 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -579,9 +579,10 @@ void DictEncoder::extractWords(std::vector &candidateList) std::istringstream entryStream(dictionaryEntry); while (entryStream) { - // XXX probably not the best way std::string word_1; entryStream >> word_1; + + if (word_1.empty()) continue; // Create possible variants with spaces @@ -598,8 +599,8 @@ void DictEncoder::extractWords(std::vector &candidateList) if (word.size() < 1) return; if (dictionaryEntry.find(word) == std::string::npos) return; - if (std::find(candidateList.begin(), candidateList.end(), word) == candidateList.end()) return; - + if (std::find(candidateList.begin(), candidateList.end(), word) != candidateList.end()) return; + candidateList.push_back(word); }; @@ -659,7 +660,19 @@ int32_t DictEncoder::evaluateCandidate(std::string &candidate) // For the substring before the first occurence we need to create a separate entry // in the dictionary - unless it is already there, it brings some additional cost - // XXX, targetSize + std::string otherStr = std::string(dictionaryEntry.begin(), dictionaryEntry.end() + occurences[0]); + + if (std::find(dictionary.begin(), dictionary.end(), otherStr) != dictionary.end()) + { + // This extra string is already in the dictionary - that gives extra saving + score += otherStr.size() - 1; + } + else + { + // This extra string is not in the dictionary, it has to be added + score -= 2; + targetSize++; + } } for (auto iter = occurences.begin(); iter < occurences.end(); iter++) @@ -676,12 +689,33 @@ int32_t DictEncoder::evaluateCandidate(std::string &candidate) // For the substring between this occurence and the next one (or the end of the string) // we need to create a separate entry in the dictionary - unless it is already there, // it brings some additional cost - - // XXX, targetSize + + std::string otherStr; + if (iter + 1 == occurences.end()) + { + otherStr = std::string(dictionaryEntry.begin() + *iter + candidate.size(), + dictionaryEntry.end()); + } + else + { + otherStr = std::string(dictionaryEntry.begin() + *iter + candidate.size(), + dictionaryEntry.begin() + *(iter + 1)); + } + + if (std::find(dictionary.begin(), dictionary.end(), otherStr) != dictionary.end()) + { + // This extra string is already in the dictionary - that gives extra saving + score += otherStr.size() - 1; + } + else + { + // This extra string is not in the dictionary, it has to be added + score -= 2; + targetSize++; + } } // We crossed the maximum number of strings, do not consider this candidate - // XXX improve the behaviour, maybe only some substrings can be replaced if (targetSize > 255) return -1; } @@ -697,8 +731,8 @@ bool DictEncoder::optimizeSplit() std::vector candidateList; extractWords(candidateList); - - // XXX find a couple of largest common substrings and add them as candidates too + + // XXX possible future improvement: find a couple of largest common substrings and add them as candidates too // Now find the best word to be extracted @@ -708,6 +742,9 @@ bool DictEncoder::optimizeSplit() for (auto iter = candidateList.begin(); iter < candidateList.end(); iter++) { int32_t candidateScore = evaluateCandidate(*iter); + + std::cout << "XXX candidate '" << *iter << "' score: " << candidateScore << std::endl; + if (candidateScore > bestCandidateScore) { bestCandidate = iter; @@ -717,10 +754,19 @@ bool DictEncoder::optimizeSplit() if (bestCandidateScore < 1) return false; - // Perform the extraction + // Extract the best candidate to a separate string + std::cout << "XXX best is '" << *bestCandidate << "' score: " << bestCandidateScore << std::endl; + // XXX + std::cout << std::endl << "NOTE: 'CONFIG_COMPRESSION_LVL_2' support is not finished - as of writing" << + std::endl << " this text, it would not give any space improvement, so I've decided" << + std::endl << " to stop working on it for now." << std::endl << + std::endl << " Please disable this option in your configuration file." << std::endl << std::endl; + + exit(1); + return false; } @@ -728,7 +774,7 @@ bool DictEncoder::optimizeJoin() { // Try to optimize by joining two substrings - // XXX + // XXX - possible future improvement return false; } @@ -1434,7 +1480,8 @@ void parseConfigFile() // Read a single line, remove leading spaces and tabs - std::getline(cnfFile, workStr); // XXX check for errors here + std::getline(cnfFile, workStr); + if (cnfFile.bad()) ERROR("error reading configuration file"); workStr = std::regex_replace(workStr, std::regex("^[ \t]+"), ""); // Skip lines which are not preprocessor definitions From fdf4b1cc1df329ff8cee249f38decdd5fea79df6 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 24 Jun 2020 15:54:30 +0200 Subject: [PATCH 085/103] maximum keyword length is not 16 bytes --- c64/,,config_custom.s | 2 +- c64/basic/tokenizer/tk_pack.s | 16 +++++++++------- c64/basic/tokenizer/tk_shorten.s | 3 ++- tools/generate_strings.cc | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/c64/,,config_custom.s b/c64/,,config_custom.s index f2ec3464..4465b483 100644 --- a/c64/,,config_custom.s +++ b/c64/,,config_custom.s @@ -143,4 +143,4 @@ // Other -#define CONFIG_COMPRESSION_LVL_2 // work on this option stopped - it would not give any improvement +// #define CONFIG_COMPRESSION_LVL_2 // work on this option stopped - it would not give any improvement diff --git a/c64/basic/tokenizer/tk_pack.s b/c64/basic/tokenizer/tk_pack.s index 5c9143dd..58e906e3 100644 --- a/c64/basic/tokenizer/tk_pack.s +++ b/c64/basic/tokenizer/tk_pack.s @@ -29,16 +29,16 @@ tk_pack: // Reuse the CPU stack - addresses below $102 are used by 'tokenise_line.s' .label tk__len_unpacked = $103 // length of unpacked data; it could replace 'tk__nibble_flag', but at the cost of code size/performance - .label tk__shorten_bits = $104 // for quick shortening of packed candidate - .label tk__nibble_flag = $105 // $00 = start from new byte, $FF = start from high nibble - .label tk__byte_offset = $106 // offset of the current byte (to place new data) in tk__packed + .label tk__shorten_bits = $104 // 2 bytes for quick shortening of packed candidate + .label tk__nibble_flag = $106 // $00 = start from new byte, $FF = start from high nibble + .label tk__byte_offset = $107 // offset of the current byte (to place new data) in tk__packed - .label tk__packed = $107 // packed candidate, 13 bytes is enough for worst case - 8 byte keyword + .label tk__packed = $108 // packed candidate, 13 bytes is enough for worst case - 8 byte keyword // Initialize variables lda #$00 - ldy #(tk__packed - tk__len_unpacked + 13) // XXX maybe do not clear that much, just put 0 at the end while compressing + ldy #(tk__packed - tk__len_unpacked + 14) // XXX maybe do not clear that much, just put 0 at the end while compressing !: sta tk__len_unpacked, y dey @@ -126,7 +126,8 @@ tk_pack_1n_done: // Put the bit mark - to indicate 1-nibble encoding clc - ror tk__shorten_bits + ror tk__shorten_bits+0 + ror tk__shorten_bits+1 // FALLTROUGH @@ -193,7 +194,8 @@ tk_pack_3n_done: // Put the bit mark - to indicate 3-nibble encoding sec - ror tk__shorten_bits + ror tk__shorten_bits+0 + ror tk__shorten_bits+1 bcc tk_pack_loop_next // branch always diff --git a/c64/basic/tokenizer/tk_shorten.s b/c64/basic/tokenizer/tk_shorten.s index 9b14833f..1d3fe0a1 100644 --- a/c64/basic/tokenizer/tk_shorten.s +++ b/c64/basic/tokenizer/tk_shorten.s @@ -20,7 +20,8 @@ tk_shorten: // Now check if the last character was encoded as 1 nibble or 3 nibbles - asl tk__nibble_flag + asl tk__shorten_bits+1 + rol tk__shorten_bits+0 bcs tk_shorten_3n // FALLTROUGH diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index 6207451a..fdbbcd26 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -1034,7 +1034,7 @@ void DataSet::validateLists() // Check mor maximum keyword length if (stringEntryList.type == ListType::KEYWORDS) { - if (stringEntry.string.length() > 8) ERROR("keyword cannot be longer than 8 characters"); + if (stringEntry.string.length() > 16) ERROR("keyword cannot be longer than 16 characters"); tk__max_keyword_len = std::max(tk__max_keyword_len, (uint8_t) stringEntry.string.length()); } From f2520eacb2ba72bcfaf424e4618f30f450c72acd Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 24 Jun 2020 16:11:39 +0200 Subject: [PATCH 086/103] fix for text packer initialization --- c64/basic/tokenizer/tk_pack.s | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/c64/basic/tokenizer/tk_pack.s b/c64/basic/tokenizer/tk_pack.s index 58e906e3..99c27e12 100644 --- a/c64/basic/tokenizer/tk_pack.s +++ b/c64/basic/tokenizer/tk_pack.s @@ -33,12 +33,12 @@ tk_pack: .label tk__nibble_flag = $106 // $00 = start from new byte, $FF = start from high nibble .label tk__byte_offset = $107 // offset of the current byte (to place new data) in tk__packed - .label tk__packed = $108 // packed candidate, 13 bytes is enough for worst case - 8 byte keyword + .label tk__packed = $108 // packed candidate, 25 bytes is enough for worst case - a 16 byte keyword // Initialize variables lda #$00 - ldy #(tk__packed - tk__len_unpacked + 14) // XXX maybe do not clear that much, just put 0 at the end while compressing + ldy #($04 + 25) // initialize 5 bytes of data + 25 bytes of space for packing !: sta tk__len_unpacked, y dey @@ -142,8 +142,8 @@ tk_pack_loop_next: lda tk__len_unpacked cmp #TK__MAX_KEYWORD_LEN - bne tk_pack_loop + rts tk_pack_1n_new_byte: From 4462a15061790f6551143707ff3bf998cf6de07d Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 24 Jun 2020 17:30:49 +0200 Subject: [PATCH 087/103] BLOAD/BVERIFY can now parse parameters and read data --- c64/basic/basic_commands/cmd_load_verify.s | 2 -- .../basic_commands_CC/cmd_bload_bverify.s | 29 +++++++++------ c64/basic/basic_commands_CC/cmd_bsave.s | 21 +++-------- c64/basic/basic_commands_CC/cmd_merge.s | 36 ++++++++++++------- .../helper_bload_fetch_address.s | 20 +++++++++++ .../helper_bload_fetch_filename.s | 26 ++++++++++++++ 6 files changed, 92 insertions(+), 42 deletions(-) create mode 100644 c64/basic/basic_commands_CC/helper_bload_fetch_address.s create mode 100644 c64/basic/basic_commands_CC/helper_bload_fetch_filename.s diff --git a/c64/basic/basic_commands/cmd_load_verify.s b/c64/basic/basic_commands/cmd_load_verify.s index a9d719cb..aab37558 100644 --- a/c64/basic/basic_commands/cmd_load_verify.s +++ b/c64/basic/basic_commands/cmd_load_verify.s @@ -38,8 +38,6 @@ cmd_load_got_params: // input for tape wedge ldy TXTTAB+1 ldx TXTTAB+0 -cmd_load_loadmerge: // entry point for 'cmd_merge' - lda VERCKB // LOAD or VERIFY jsr JLOAD bcs_16 do_kernal_error diff --git a/c64/basic/basic_commands_CC/cmd_bload_bverify.s b/c64/basic/basic_commands_CC/cmd_bload_bverify.s index 8ec63ef5..325257fd 100644 --- a/c64/basic/basic_commands_CC/cmd_bload_bverify.s +++ b/c64/basic/basic_commands_CC/cmd_bload_bverify.s @@ -18,18 +18,25 @@ cmd_bload: // Fetch the file name - jsr helper_load_fetch_filename - bcc !+ + jsr helper_bload_fetch_filename - // No filename supplied - this should only be allowed for tape (device number below 8) + // Fetch device number - lda FA - and #%11111000 - bne_16 do_MISSING_FILENAME_error + jsr fetch_coma_uint8 + bcs_16 do_SYNTAX_error - lda #$00 - sta FNLEN -!: - // XXX finish the implementation + sta FA - jmp do_NOT_IMPLEMENTED_error + // Fetch the start address + + jsr helper_bload_fetch_address + + // Perform loading + + lda VERCKB // LOAD or VERIFY + jsr JLOAD + bcs_16 do_kernal_error + + // That is it - continue execution + + jmp execute_line diff --git a/c64/basic/basic_commands_CC/cmd_bsave.s b/c64/basic/basic_commands_CC/cmd_bsave.s index 886501a0..1e2dbdf8 100644 --- a/c64/basic/basic_commands_CC/cmd_bsave.s +++ b/c64/basic/basic_commands_CC/cmd_bsave.s @@ -21,27 +21,14 @@ cmd_bsave: // Fetch memory area start address - jsr injest_comma - bcs_16 do_SYNTAX_error + jsr helper_bload_fetch_address - jsr basic_parse_line_number // XXX detect errors here - - lda LINNUM+0 - pha - lda LINNUM+1 - pha + phx_trash_a + phy_trash_a // Fetch memory area end address - jsr injest_comma - bcs_16 do_SYNTAX_error - - jsr basic_parse_line_number // XXX detect errors here - - // Setup start/end addresses - - ldx LINNUM+0 - ldy LINNUM+1 + jsr helper_bload_fetch_address pla sta LINNUM+1 diff --git a/c64/basic/basic_commands_CC/cmd_merge.s b/c64/basic/basic_commands_CC/cmd_merge.s index 375c61f9..6de6c68d 100644 --- a/c64/basic/basic_commands_CC/cmd_merge.s +++ b/c64/basic/basic_commands_CC/cmd_merge.s @@ -10,24 +10,16 @@ cmd_merge: // Fetch the file name - jsr helper_load_fetch_filename - bcc !+ + jsr helper_bload_fetch_filename - // No filename supplied - this should only be allowed for tape (device number below 8) - - lda FA - and #%11111000 - bne_16 do_MISSING_FILENAME_error - - lda #$00 - sta FNLEN -!: // Fetch device number jsr helper_load_fetch_devnum // Perform loading - just for a different address + // XXX sometimes works, sometimes does not - probably improper handling of VARTAB somewhere + sec lda VARTAB+0 sbc #$02 @@ -38,4 +30,24 @@ cmd_merge: !: ldy VARTAB+1 - jmp cmd_load_loadmerge // XXX check variable handling (VARTAB) after failure to load + lda VERCKB // LOAD or VERIFY + jsr JLOAD + bcs_16 do_kernal_error + +cmd_merge_no_error: + + // Store last loaded address + + stx VARTAB+0 + sty VARTAB+1 + + // Clear the variables + jsr basic_do_clr + + // Now relink the loaded program, line links supplied are almost certainly wrong + + jsr LINKPRG + + // Continue execution + + jmp execute_statements diff --git a/c64/basic/basic_commands_CC/helper_bload_fetch_address.s b/c64/basic/basic_commands_CC/helper_bload_fetch_address.s new file mode 100644 index 00000000..f5fca8f6 --- /dev/null +++ b/c64/basic/basic_commands_CC/helper_bload_fetch_address.s @@ -0,0 +1,20 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Fetches address for BLOAD/BVERIFY/BSAVE, reports error if not found +// + + +helper_bload_fetch_address: + + jsr injest_comma + bcs_16 do_SYNTAX_error + + jsr basic_parse_line_number // XXX detect errors here + + ldx LINNUM+0 + ldy LINNUM+1 + + rts diff --git a/c64/basic/basic_commands_CC/helper_bload_fetch_filename.s b/c64/basic/basic_commands_CC/helper_bload_fetch_filename.s new file mode 100644 index 00000000..13da848c --- /dev/null +++ b/c64/basic/basic_commands_CC/helper_bload_fetch_filename.s @@ -0,0 +1,26 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Fetches file name for BLOAD/BVERIFY/MERGE, reports error if not found +// + + +helper_bload_fetch_filename: + + // Fetch the file name + + jsr helper_load_fetch_filename + bcc !+ + + // No filename supplied - this should only be allowed for tape (device number below 8) + + lda FA + and #%11111000 + bne_16 do_MISSING_FILENAME_error + + lda #$00 + sta FNLEN +!: + rts From 0df838cfc9b6d42c5aeffaa7d4b586a90ed99c3c Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 24 Jun 2020 17:38:01 +0200 Subject: [PATCH 088/103] temporary workaround for syntax error after some commands --- c64/basic/basic_commands_CC/cmd_bload_bverify.s | 4 ++-- c64/basic/basic_commands_CC/cmd_merge.s | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/c64/basic/basic_commands_CC/cmd_bload_bverify.s b/c64/basic/basic_commands_CC/cmd_bload_bverify.s index 325257fd..a85891f5 100644 --- a/c64/basic/basic_commands_CC/cmd_bload_bverify.s +++ b/c64/basic/basic_commands_CC/cmd_bload_bverify.s @@ -37,6 +37,6 @@ cmd_bload: jsr JLOAD bcs_16 do_kernal_error - // That is it - continue execution + // XXX when number parsing is done, change to continue execution - jmp execute_line + jmp basic_main_loop diff --git a/c64/basic/basic_commands_CC/cmd_merge.s b/c64/basic/basic_commands_CC/cmd_merge.s index 6de6c68d..5734b68d 100644 --- a/c64/basic/basic_commands_CC/cmd_merge.s +++ b/c64/basic/basic_commands_CC/cmd_merge.s @@ -48,6 +48,6 @@ cmd_merge_no_error: jsr LINKPRG - // Continue execution + // XXX when number parsing is done, change to continue execution - jmp execute_statements + jmp basic_main_loop From 6a4fe4d1806314824e648d08ecfa1f953cab5f0e Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 24 Jun 2020 18:38:44 +0200 Subject: [PATCH 089/103] added memory models 46K and 50K to KERNAL --- c64/,,config_custom.s | 2 + c64/aliases/,aliases_config.s | 6 ++ c64/kernal/iec/iec_send_file_name.s | 2 + c64/kernal/iec/save_iec.s | 2 + c64/kernal/iostack/load_save_common.s | 9 ++- c64/kernal/memory/under_rom_routines.s | 91 ++++++++++++++++++++++++-- c64/kernal/rs232/close_rs232.s | 4 ++ c64/kernal/rs232/open_rs232.s | 3 + 8 files changed, 113 insertions(+), 6 deletions(-) diff --git a/c64/,,config_custom.s b/c64/,,config_custom.s index 4465b483..a6ab5010 100644 --- a/c64/,,config_custom.s +++ b/c64/,,config_custom.s @@ -40,6 +40,8 @@ // Memory model #define CONFIG_MEMORY_MODEL_38K +// #define CONFIG_MEMORY_MODEL_46K // please keep disabled for now +// #define CONFIG_MEMORY_MODEL_50K // please keep disabled for now // #define CONFIG_MEMORY_MODEL_60K diff --git a/c64/aliases/,aliases_config.s b/c64/aliases/,aliases_config.s index 3e14bbaa..42c8166b 100644 --- a/c64/aliases/,aliases_config.s +++ b/c64/aliases/,aliases_config.s @@ -121,6 +121,12 @@ #if CONFIG_MEMORY_MODEL_38K .eval selected++ #endif +#if CONFIG_MEMORY_MODEL_46K + .eval selected++ +#endif +#if CONFIG_MEMORY_MODEL_50K + .eval selected++ +#endif #if CONFIG_MEMORY_MODEL_60K .eval selected++ #endif diff --git a/c64/kernal/iec/iec_send_file_name.s b/c64/kernal/iec/iec_send_file_name.s index b250612a..8d61cb20 100644 --- a/c64/kernal/iec/iec_send_file_name.s +++ b/c64/kernal/iec/iec_send_file_name.s @@ -20,6 +20,8 @@ iec_send_file_name_loop: #if CONFIG_MEMORY_MODEL_60K ldx # Date: Wed, 24 Jun 2020 21:48:39 +0200 Subject: [PATCH 090/103] more work on new memory models --- c64/basic/a533.linkprg.s | 9 +- c64/basic/basic_commands/cmd_list.s | 3 + c64/basic/basic_commands/cmd_print.s | 4 + c64/basic/basic_delete_line.s | 4 + c64/basic/basic_do_new.s | 23 +++-- c64/basic/basic_find_line.s | 8 ++ c64/basic/basic_find_next_line.s | 4 + c64/basic/basic_follow_link_to_next_line.s | 4 + c64/basic/basic_insert_line.s | 6 +- c64/basic/basic_shift_mem_down.s | 11 ++- c64/basic/basic_shift_mem_up.s | 9 +- c64/basic/board_m65/mega65_imports.s | 3 - c64/basic/board_m65/mega65_proxies.s | 16 +--- c64/basic/e000.under_rom_routines_46k_50k.s | 72 ++++++++++++++++ c64/basic/engine/end_of_statement_check.s | 2 + c64/basic/engine/execute_line_statements.s | 4 + c64/basic/engine/fetch_character.s | 4 + c64/basic/peek_line_pointer_null_check.s | 6 ++ c64/basic/print/list_single_line.s | 23 +++-- ...om_routines.s => under_rom_routines_60k.s} | 10 +-- c64/kernal/iec/iec_send_file_name.s | 2 +- c64/kernal/iec/save_iec.s | 2 +- c64/kernal/iostack/load_save_common.s | 10 ++- .../memory/under_rom_routines_46k_50k.s | 85 +++++++++++++++++++ ...om_routines.s => under_rom_routines_60k.s} | 81 +----------------- c64/kernal/rs232/close_rs232.s | 4 - c64/kernal/rs232/open_rs232.s | 3 - 27 files changed, 279 insertions(+), 133 deletions(-) create mode 100644 c64/basic/e000.under_rom_routines_46k_50k.s rename c64/basic/{under_rom_routines.s => under_rom_routines_60k.s} (97%) create mode 100644 c64/kernal/memory/under_rom_routines_46k_50k.s rename c64/kernal/memory/{under_rom_routines.s => under_rom_routines_60k.s} (52%) diff --git a/c64/basic/a533.linkprg.s b/c64/basic/a533.linkprg.s index 57d6bdda..859faa8a 100644 --- a/c64/basic/a533.linkprg.s +++ b/c64/basic/a533.linkprg.s @@ -34,7 +34,10 @@ linkprg_loop: ldx #$F7FF +#elif CONFIG_MEMORY_MODEL_50K + lda #>$D000 +#elif CONFIG_MEMORY_MODEL_46K + lda #>$C000 #else // CONFIG_MEMORY_MODEL_38K lda #>$A000 #endif - .byte $2C + skip_2_bytes_trash_nvz !: -#if CONFIG_MEMORY_MODEL_60K - lda #>$F7FF -#else // CONFIG_MEMORY_MODEL_38K - lda #>$A000 -#endif + lda #>$8000 sta MEMSIZ+1 sta FRETOP+1 #if CONFIG_MEMORY_MODEL_60K - lda #<$F7FF -#else // CONFIG_MEMORY_MODEL_38K - lda #<$A000 + cpx #$80 + beq !+ + lda #$FF + skip_2_bytes_trash_nvz +!: + lda #<$00 +#else // CONFIG_MEMORY_MODEL_38K || CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K + lda #<$00 #endif sta MEMSIZ+0 sta FRETOP+0 diff --git a/c64/basic/basic_find_line.s b/c64/basic/basic_find_line.s index 45102507..be9a962e 100644 --- a/c64/basic/basic_find_line.s +++ b/c64/basic/basic_find_line.s @@ -22,6 +22,8 @@ basic_find_line_loop: #if CONFIG_MEMORY_MODEL_60K ldx # Date: Wed, 24 Jun 2020 22:14:58 +0200 Subject: [PATCH 091/103] memory models 46K and 50K work now, the 50K is now default, updated binaries --- CONFIG.md | 4 +++- STATUS.md | 6 +++--- bin/basic_generic.rom | Bin 8192 -> 8192 bytes bin/basic_ultimate64.rom | Bin 8192 -> 8192 bytes bin/kernal_generic.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_custom.s | 6 +++--- c64/,,config_cx16.s | 2 ++ c64/,,config_generic.s | 4 +++- c64/,,config_mega65.s | 4 +++- c64/,,config_testing.s | 2 ++ c64/,,config_ultimate64.s | 4 +++- c64/basic/e000.under_rom_routines_46k_50k.s | 2 +- 15 files changed, 23 insertions(+), 11 deletions(-) diff --git a/CONFIG.md b/CONFIG.md index b33a17ed..bd8182f2 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -105,12 +105,14 @@ Memory model the original machine uses - memory available for BASIC ends at `$9F ### `CONFIG_MEMORY_MODEL_46K` and `CONFIG_MEMORY_MODEL_50K` -Planned for the future - not available yet. +These models additionaly use RAM under BASIC, and the 50K additionally takes over `$C000`-`$CFFF` range. They should still be highly compatible (no additional RAM for helper routines is needed), and the performance penalty should be much lower than 60K model. ### `CONFIG_MEMORY_MODEL_60K` Uses RAM under BASIC, I/O and KERNAL, takes over `$C000`-`$CFFF` area requires special helper routines installed in `$2A7`-`$2FF` area (normally unused and free for the user). Gives the most free memory for BASIC programs, but it's the slowest (for example, forces disabling optimized LOAD loop for JiffyDOS) and the least compatible model. +It is currently not compatible with Mega65 extended ROMs. + Comparing to standard memory model, it needs about 180 bytes in BASIC segment and 80 bytes in KERNAL segment - at the moment of doing the test, these values are expected to change often. ## IEC devices diff --git a/STATUS.md b/STATUS.md index 8f757777..897686d2 100644 --- a/STATUS.md +++ b/STATUS.md @@ -22,7 +22,7 @@ Here are the features of the Open ROMs not found in the original ROMs from the 8 * command with just the file name tries to use the last device if it's number seems sane; otherwise uses 8 * command without parameters tries to load first file from drive chosen as above -* uses RAM under ROM and I/O: 61438 bytes free +* uses RAM under ROM and I/O: 51199 bytes free (up to `$CFFF`) by default, but 61438 is also possible * cold/warm start silences multiple SID chips * warm start due to BRK prints out the instruction address @@ -41,8 +41,8 @@ The following ROM features are currently missing: * most BASIC commands * BASIC variables -* BASIC expression parsing -* floating point routines +* BASIC expression handling +* most floating point routines * RS-232 support * NMI handling is incomplete diff --git a/bin/basic_generic.rom b/bin/basic_generic.rom index 5d1d0d42107834b96986dbc88a8a94c5658c660e..1451d2109896abc0e232a8aedd7b2fa0e2b278d3 100644 GIT binary patch delta 3555 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 diff --git a/bin/basic_ultimate64.rom b/bin/basic_ultimate64.rom index eaac04ce6e4618b72cd045e680bc9e87baff12b2..6bd95ad4889cefccf16b3e627399ee227c988e6a 100644 GIT binary patch delta 3493 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 delta 3407 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 diff --git a/bin/kernal_generic.rom b/bin/kernal_generic.rom index 9b1b8b9fa24121512ce0d9a91675f91b6ba48f72..523ca3dced08d1b07cb44f186e84ffc540d0c571 100644 GIT binary patch delta 4641 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 C&tV386mK0%WPe>A8uyn{Obf^>k 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 P*pC+f-t*(kzdQa9pW#~f diff --git a/bin/kernal_ultimate64.rom b/bin/kernal_ultimate64.rom index 99bcc4f27481f615da2780b86c3a054756b67188..764573327e2d1e8fa75d8a17c598c9ce1eaebee4 100644 GIT binary patch delta 4460 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 BLG}Ou delta 4451 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 L?Y{4)-*^5m3vpTX diff --git a/bin/mega65.rom b/bin/mega65.rom index 7590e052c4b6dad671439bebdc299e5950f6f987..851cfa1550ec2018d48ea5c05baaf092f66046a2 100644 GIT binary patch delta 5758 zcmYjV4O|mfwx5{*2_O&^G-|C^UBOgDUByyA>25#Joxb+9``%*2I%u`At9|zUw!4bD z#4Ur=j~05{KCrvnH0A~;Ei^RSV)!UnL5bDvv{+hgeVYa-V7FyLganXe&rP)3{NT>H z=YF5_|DSVbOeT%Vq;ZrOxbZ<;YAEC`+{6QhmuPMO=GAOHet+}4ne`#`pIaR5Xd>Ut zp!*F@g+;BQ&KoSMcltKRv1}_27Q798ty>;sUv%EsGL6#~ZTiKg?VI}z`whhg&nD-l zI(DNDKfO=)Gv}rpa&PYN@N(y)4^O2hs=juj*Z zgdaeF4iZDV#Fv2vdYP`k^R`SoNN<~;l&4A4%$sDb^jCAfoFEyXjFBo}uQ$Qsb=mq9 zj=F4nb3JYEkT1g+r6CVg`V`$EhCO+^ zg@4;1ptoAgDllVS85DLS_yE~kBu2avF|J~8&yy3$l?`F>iZqWe*lfEZ-|r49tKG%r z_qi|0NgZ_5y?KUv@P@dms>@2GdoJMO*Zo$!XdVK39oc5~gT?wIb_Zbl##Q>Uy) zyIR~x8FjBxhJhCwEz?S;TV|9_a~I9(!v_rK1N`^42`mAD4wHIcQk>-;4QQ0J@* zA7sc{-L4q1h|*3xVCGPgN4&3tmaF&@t2@`fJk`C`pOp&BMUKZXXi?8RE|(wlkwxNK zk}0kO7$$kz)0Cw#jx;&Bj8;;W7)QL!=>%BA!Q}|BSd!-i!$u}vSHrNt><0+G-aI4z zFOoR% z0E)MgB2jHqH$xvJtNP`UQZ;(agVqp-3KcXFb-PAUA=bqoA$b3Xnac$9LyIFBaZPk& zTIaN>BvmH}^jIO$xI~EeM8qQZ=YdlxYNNlFWpt((`whldLbDo?m zHlXiZBmsRMb{Z%1hlo(e{)5GB(u~6AZKM$W$wqe3B7MLlraLqwV}L3DyO=>TI?c%> zT`WY;+jL|v+HOa_?sD$ibh6_o@>4&NxBo=m7L}dr>`$pQRbJFKsx7#C{R5%lPhOv$ed&|mUD{#)Wp`6!LvwdiQ)5p{ zPfMN0Sz4=NwO~mNwInrZ0tn8xoRhdm%T1IW{9`WE?k!Iw4fR+q>pg!BP(sQrp*F8C&D@_Gw?(`T-w0vuf3@mYe~5d9pjfk>FMewCsPU z2PrF@hr+-KTdFlpz*!Ah*>s=$Md?Sx9`DW}iw8JyvE9L)&$4DkaXS_&U0jky8MmB( zF>yh|vba$fFscgUhPhn46@SoRm;)y+^#4bQ?DE@xpyw5LN@g(~Jf9IkI9}4I(uQUR@%xu))DliGD zSgPVrcB3gx=oKgbMHBWnJ)TA*qb@pIPA?4~(0>4zS5J?FmM)!u|Il2pQp(Mg?iU#V zj^NIcQ%DNra2N$2Z4{)Q*FJo4WwvL5n%)Njga6jDItk33sl-ES8wP+nZ?(jr3@Ke? z>x%NE43RYok;+<=FY?@G8n8|G%yF){3Om7vTT*d(i)L|TAK<3sJ0WEf6$HQ=;Icdn zrbbm>M;{SoaIogJfoPPjzYS%MGNF zuAhefT0@ei{<(`3iuGih*hsdEO*-N5hLmfT7ibZ=9neGFb>qejIA265m=j&^d#e~# znKodKah>&IxqEJ$u|27Cb{97E=rz92(QFU@L~R9|ijQ?C#HMt^&{sUVWH9z2!msY> zZ0>4i1nlcxhU==A?V)&PsC_hf*9>1t%;{fA$npz*)JGh#bxMjQ7FE1U>d@98aXT24{M^Cs?xDRBz?B~87At>2(OzP$U>D;0o@90f zKHoDh`-{P&%Ab@!PgG27SGFp)G3Qw2*vn&&jL%ncMi-2Jc5}~wLtWBY+J$!aT03oB z0y6jVPvhCW$CJ?J(Q*}kA{6i89~*Uk(3`-r2k_Z%^~DVe&kj-i!E#Yyi5~<3y)yww zKP7Dyttcz#Q1SbNkVFvwSy)3(xmh`8A-}`75F$Wud>?8bERRDU55g1q#?hyP7PYJ< zr{G5LV31fhidIJ)O1i}x`VeyqU61s+K6p|4RlX&hQo~%=YA(t_VDIq&UxN4b{ZDbr z;6K@~(06am4j=-|4n?MGOGs*{H$ljuV;@vMP0 z%N7MJIusr_-}SSr+ERXEG`^fq?4#l1iuk2?!P?cTQxah0(%5gi(8MVJNC1}&yfh2E zU$0C-jiViH^*Wi&0W;s#$LntJ&nV7iH;Q9Z&V6(_XDQ5bNsyAj>iGJgZVuYn%cuL3 z!YcR^#4{zX(guOaHHBNl;V=sLak8?ocs|P)_@b-xdjCGF+4dH(I%U92iH>IB&LiO@t#aWU8seiIWWEsBX@S(b~@pgaS*J;UnA3{&Y08|V!4 zBQu=jmkhxK<)L5Xf~}wtNOm+7pDS7^dHAfvAgu04hsDsF_>G}?li-z61FwuG`pSq~ zCT4PhA^g?Ee6D%umC#J%BLQG8`Yyot`S{NR40yv^+PArk7*P#$#OV&z7 zTjtutwV#ny{NYe5!$0b`R<@#Id$JW+;#GK$KSiu3Cd;K(zGYaTpmijT zyB}T@uyyqV=J`)YOWI1$?Ov)9F*zrmC2b`i!R`PmtiPIbtNj)Zy`kVE48I`^M32|% zzW|R3wl9@fxG=28*KW?967W~%^mf{==9@%?03uXe{dZVLFDz|`W7fB_tzKpl_H zh54>P5nAr&;ar#G$>b9`31+=4euCP^z@3)`JFI;aEG2m&MnP=~dPWf}Q!|k7<4**ai4hsRU|_6Bd4@Ui4vp40{=CL)1z_!2+t*WWryNiaI%{4@a7cme&|=RA+U4?gfndZgvR zkaOSdmZt}tdjkADLr61G8LvLw(YmmlGiQ`gXn;zIE34E8#YpW=Qd90EsW$w_(I*xV zHcuad8_+qsQDlz_cdCu1!8>BDsRw^Lx<>;EB#|Z%{Lt6}c0JxbHY;84zo;F8*hab( z?tB-lNxIxRS%q%&e@knygVqc`eCZl9Zhmppl4?$d4`P-A)SwuZ>3Q(+jDxx{4>G?I zvSh5q2rU-oB_#K2CoFOBydf*dKd7iWKMz32wspOKRXYWl#wAqoX+)3GZc+~H9nX$| zNH-lz<9D;UxMTbyEd)aV2{=Um4?Bdwm+;$ugd1*6nVU<)M1;e}6KOKvHIAx6j(_g^ zQe_FBq^bQh{{B`LHxR_LCk_?s{WUr{o|7Y(jof4M$g4_B4qDh}6d?Kn%RXn&{BV?I zKS(TPSs!JYH>&zdDvX-@Gjdk6>L6{AkD^ahAA&pGJEPHB_c{3VDJwAO8Cn1kzkzX+ zvVwrbh!XDK3qtAaY0QU~;KQLM#iA94pC4_vD*hY+CO-!gw+W=J{arbRoNKQY$X~Q+ z76vRD$({+2JtKFgt`Kb*x123I6c8~ oJ5$A93i9>e@(I1>uPu!5+5(T_z4gS6IySt%POJR*U!h(0FY27v`v3p{ delta 5710 zcmZ8l4_s7L_J8lqzziTVD(LwCf(4?8x`m4xrqveNZR@w~?~{&L4_j?CZQFj^uA%Ns z#Us|FhOQO%Z)eAOQ;&jXmMt9q?4W}2T-jb?q^2#xAYfa(afIQI%>2$BT({4@58Qk1 zz2}~H&pF?7&Yfqq>aAA2yV%4{Q%Q-bkb6-j{iavx==n{n*(2oBO=+`^gwg+OcDJDM z4R!{tGu5apIvQ@j!lENJflaY2dz1_pd<4AC%|BzSYp!gb&Kb6DT(WU$L80k_smt{D zjqh*tu#XyvX}9r~_c!K>KkZpuDdzTMq5pF^SlneQULoY1w=)%$o*Y$=cDTr!yB{Od zpI>6OciUNHaw#lt*FrBdYHX`AgbTf`6~?W3`Fc3c7S}>?&2|R(wzz~fW+4wR+b9tb zA~o3y5ZU11?5Su{k7TuPrlT0x0;B)6`zA(HVTArbK6*YwYtNGGq~rN)R!3rrGA(l^ z$FT0yk7L;^=nbU@Vp*?_%~TKR*nh;Zyu<+U0}#LpCOJ(>5YOBn5za_y_$!m^jIvISsH-iq#kNvDr6jh}ZTY5? zsLy1bEw}w>;s=v89#-~eS}M^sQ;}JIP2q$yt%@Z50rYQG{>)1s*&kD;ORRmPVgP!B z5-&XotyU_xZx(WjS9CJ!%#(J;lhZ0Q%80RIYmSg3F->~O<*(oltUV} z)G*q}aPk5hlJ~gh$jfY6`3_sMee$_qZ%`+fD#P~a=bAUDmX$#AU|7Q~74h(ZooDJ; zYV=rYcjMDqw(kcGTcu%To#N&zU>z30HOu^T(>#-;-rUk^hNV{U4Q$MXjkcB>?5&we zuu|&Pv2m23EL6fb5>rOD?YZ^7?VCWp`nXgMX4x#PKxa4F=1U*JV8g`V0qM#A4A!9( zll6=J`PB?-+-`l3;ZXMmvz&zI7m(9?7R;GnAf3vR+CFC3Lk!oqzx6?dcR6cG$h%X=0Y{jvjv@wwBl4J0;YI5OT7eKG0IuAs~;CT zng4qDmHt)!)&4vDdHyy2JN;|@>-=~5@Alv0|C#?@|9$>^|NZ{;{s;Wn|DgZp{)hYw zFP2Z+z1l+Gjnol&l{yHKw%#$lWQJpA$#mI5o@Zp2J0`wz?{KYrN}VLPsk7w22hY#K zyS#K06Z|k)j;T4E3>UI&-AkwW==|GKwpO)#57Q4kUGpc`<8(Jw}Md z^_}FRQOq-L*9z;4XdnxF?3^c0SlJ5AD$q?{8_Y?T9}g}|hL_#c6TM!O#;wHz0o3M| z7-Wkedp9*r0-D>2zVni2Ix{T5%p+|Bx>R5D-86KdyQXUz`oULoVH)s=$@yYRJ{`8v zp)1*$Viw>pSxUwq*UH&Sl9&Wh$Qc2&LJ~$UBabp%QbYiMc#7nY6dlmpkhd#3TxM&N zSGi@eP@P1#DH`;y3&$WAbY$V*QZ3)RfD?Z!f-r~vjlz?LG2t2hrY`>`csP!GGTP>& z=SyjyK21zE@;n*{c=GV;HPDye=m8276R4{C1_3aLvY^JRK!}TT`&pq#%<2bo^3rXL zU`FR$4&A3)-gxw+VFYOSvuhlT@zX8OJ^IF$zEZ=GXx{pmU>3~^=#0L1k!zmyWYz~; z6TuBn8Mh_~+gtUXJo4%Xv*Xuyx=+LD@f{)wbT8L{l|Ae~S<)=cEOgh4g{ZM!+)kVH zeyfn~){7bajO`ynhM3WApDd;eg~(lR6rVv)R3gs@Htuq|xb;W$uYN>7@gsW61YNVH z@>d%DKv&J@2>>%vS+#_N?p)Q}=>Wqtbu!>qcezjrK#8CsG(aX*7tDL4YVP1YcYl#{ z>Wkl=3RgDyJq>jYosA9kexJYIgHfQY9AC>77mvRT19Jbu^VS=+1yfcLRFlo!V4A*ML5#2ON^-T4ZVS zqT57(D+GnA!J|(6Z6iOcbFXio?+-qU&+2=@_oDA5-<{$eVzE!~mH1xv-Pg%vi8Q?=CO#9rQ7FpELzOc?4zG ziQAyGY{NT_K%_u8;aN={hN1J@)zxBQ@K;*Y&nxj)o2)b*bFkPV!luX+Ef282ouy z+#am_fhsI)lk7q|gm*?1u4HMwk#pCR`|BUGNUUR>J%Ae{u$nGp2n&TwVG(cKnl7XR zU^94}*MQI0gKGBmj{DJX8*rf8&NvG2nR=RoQlgoAnsr<(6l%pSLcREe&|u_oM+58- z;?Y~cjO!wF-^cn~; z&?vfNJZh3729Pr(ouaNquWAtM#eI#$=*lWL>?Bis56=5Z_Puv!F9)DblqBr&FzDrK z8i=T%jwgYxl-Ikp^XZUY5j}Z|1`HsUFVkSA6HRSEi~aZ=ANi|qbs`AJQsbbm4FW`K zuKTnIIp(6$PsCM_-zPb=)QYQIDGQGLd&&`^YQZ z@vEDUqjnrLaO=oPZxh1hZ?kjR{cc%X08Pwj0AE_>9vq-IfGW!#9!k?D2 zCtRh9>bv9R<9pQKtFF?X`m+bESwdLZ#zt{^(zBr`b zX^)^qqYho;0=0~}(70GlWG?_NXEsHYTkN`X3sfbp!nkj?`XNq(B0aDy>7?OIQv`k_ zMMbC!q_si|U&UU?OtNdv%?qj8Qo}IsO%Dl!-bEo{$eR}Wu(?J3MRAKXz3c!do@o0c z=QfjVeJT2{hOoWQ+crdA>a!ZxhUmSU@t$W6onu;?jLM*76$0oXGQ0nd<$TCtM3Mdz z9k-k_l;H7^I2%sr<)uV?I^yhTGP)DJ=NN+?_Ab-dAL8v9JSpvemF()D$-Nk=S$@S5 zQ*Ky7d;>;uabO1bY(E(qSU5R>#RUPd_8H+Uo*yPz>TJvRts&RND*GNfd|XVIbeldLq%q^CxmU` zA~W6}mi0EBthH(6`4GOyI%3mc5{~PH?T(m6jrAfoJVe~;jCgS0iz+w~T=k`z$Kl(^ z+Ca+f@RCEpK`lC_lD`b&yCb`8+=;^gj`Zs&Jd`gwGm|PCvjdb+^IZoiPCgzde+=9{ z&l`f%f;jOYt_}!apEv2nw`EQ6y96q#oO}~lVfjsHKjH#4_OSN}4hkvE>vXcFy_AlH zLq%pI4+@a*xX)sVM4$0-s{v`XEX#6QJ<2zs8xkIiN|;6^JRJ)X?u|-#8!x>I0^SVY zwH7cBi=eqJ9Jf|*QvBnU3B&MqcRIWb9V72tO|wV{JPSICwLv8TEr^J9C_Ci-L1NKU zBko@G{;<1iV(J^Ia3Xk4i$?{g5zXlpk4^OGNElMU@rgnAarj!G1Yl2@8r>*eif%*K z=&($M(l``ikShdUJ|t-#7T)G1v23X#y$KBu$~h}kL#cNo*K$PB;FrTq41Or+tZ0e{ zMT*1XkwY6fvF^|loajBYi)$^e0HI)koEW&a+|z^Sgvo*69QNl#3a(uApbGCeD6zs} z(OEV{DRE-oAYX~N-u{mqJ_O?-gQ=ufnODmlJnQ*PJOn& zBDbf#(%D{$;s#H&)6>NbX0I&^!=Xb#{7}R^LA($K>pu{OPSFLh{&`6EVEuM#{WCDN z=c>C+;wP-%j2_5+m~ksT7d_2CuES}B+Tw8V84eJd|QNra~#_dd0V?**k`55m8e0TQ8j*pMJGY7B%ig$k6x=2~@%r@pnh)~K+#VD&k@*glNQRA;T4 z0`7@Ml;{NyMJaF+E)IeY!FNVzSY?N5z6ilEjz_-?)HH|i&a2&aCFZgNr}c<`mS-s; z(IJy>hqF`IDF2?THNU&T|73s7QzUgHWx<><(vPdLr4^aO0)@@Z45m(iK!dN5jU$hc zFGqIip=u=1szL4@y_J2G>>Qn)K0kcYa23*`*r9SKI$*!pAsZD9y3%)r0mG4NT;QGl+fW_3nBd_v=3Y|e*!rWs0OjKd5o4(3&)^clt-vCv;pRFt5q zn)bhQ=-GZ($EW8EQ;~H{LgimZ=TXWviuGs4a-kyo{q<~a@(7tbzHc4W z2BQ+kDM7?uow$NjO;zM<+a&0|pQ2>yToU(Y413s zyk=f(ZuvyfipN{3dGS3%vV#HpL{SsxsgHiR`8rG&#vDl^Q8~v9YQ9WpXzqX?tvWSc z{Dj`*t1&dkD0P%l?-^vrGGN1+2+)m=)CsXhkGAnl|NmLnMiFAr`O2dNb3Cg0sMR~p4Wp5ReULgxn96B&JN){SMebg zUndQb1*!L_I~QtpF4FAG(%`@_uDy)od+Zk+4FAThhCtW#N3M9-$ekX8dh@^Bu>Ai4 Dhjhb? diff --git a/bin/mega65_pxlfont.rom b/bin/mega65_pxlfont.rom index e19eca4fcea6927605701d7b54068be89aa81a9f..8dd0ecf4627bf2ffc221989a3b1d3bc7c995194a 100644 GIT binary patch delta 5758 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 delta 5710 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 Dhjhb? diff --git a/c64/,,config_custom.s b/c64/,,config_custom.s index a6ab5010..54c8e7ae 100644 --- a/c64/,,config_custom.s +++ b/c64/,,config_custom.s @@ -39,9 +39,9 @@ // Memory model -#define CONFIG_MEMORY_MODEL_38K -// #define CONFIG_MEMORY_MODEL_46K // please keep disabled for now -// #define CONFIG_MEMORY_MODEL_50K // please keep disabled for now +// #define CONFIG_MEMORY_MODEL_38K +// #define CONFIG_MEMORY_MODEL_46K +#define CONFIG_MEMORY_MODEL_50K // #define CONFIG_MEMORY_MODEL_60K diff --git a/c64/,,config_cx16.s b/c64/,,config_cx16.s index b1ce579a..158500df 100644 --- a/c64/,,config_cx16.s +++ b/c64/,,config_cx16.s @@ -39,6 +39,8 @@ // Memory model #define CONFIG_MEMORY_MODEL_38K +// #define CONFIG_MEMORY_MODEL_46K +// #define CONFIG_MEMORY_MODEL_50K // #define CONFIG_MEMORY_MODEL_60K diff --git a/c64/,,config_generic.s b/c64/,,config_generic.s index aea04a58..209074e8 100644 --- a/c64/,,config_generic.s +++ b/c64/,,config_generic.s @@ -36,7 +36,9 @@ // Memory model -#define CONFIG_MEMORY_MODEL_38K +// #define CONFIG_MEMORY_MODEL_38K +// #define CONFIG_MEMORY_MODEL_46K +#define CONFIG_MEMORY_MODEL_50K // #define CONFIG_MEMORY_MODEL_60K diff --git a/c64/,,config_mega65.s b/c64/,,config_mega65.s index dafe48d5..bf90bfaa 100644 --- a/c64/,,config_mega65.s +++ b/c64/,,config_mega65.s @@ -36,7 +36,9 @@ // Memory model -#define CONFIG_MEMORY_MODEL_38K +// #define CONFIG_MEMORY_MODEL_38K +// #define CONFIG_MEMORY_MODEL_46K +#define CONFIG_MEMORY_MODEL_50K // #define CONFIG_MEMORY_MODEL_60K diff --git a/c64/,,config_testing.s b/c64/,,config_testing.s index c0785af2..9ec523c1 100644 --- a/c64/,,config_testing.s +++ b/c64/,,config_testing.s @@ -37,6 +37,8 @@ // Memory model // #define CONFIG_MEMORY_MODEL_38K +// #define CONFIG_MEMORY_MODEL_46K +// #define CONFIG_MEMORY_MODEL_50K #define CONFIG_MEMORY_MODEL_60K diff --git a/c64/,,config_ultimate64.s b/c64/,,config_ultimate64.s index bb76f26a..0f73f68b 100644 --- a/c64/,,config_ultimate64.s +++ b/c64/,,config_ultimate64.s @@ -36,7 +36,9 @@ // Memory model -#define CONFIG_MEMORY_MODEL_38K +// #define CONFIG_MEMORY_MODEL_38K +// #define CONFIG_MEMORY_MODEL_46K +#define CONFIG_MEMORY_MODEL_50K // #define CONFIG_MEMORY_MODEL_60K diff --git a/c64/basic/e000.under_rom_routines_46k_50k.s b/c64/basic/e000.under_rom_routines_46k_50k.s index 771b5dc2..6aef9262 100644 --- a/c64/basic/e000.under_rom_routines_46k_50k.s +++ b/c64/basic/e000.under_rom_routines_46k_50k.s @@ -43,7 +43,7 @@ peek_under_roms_via_OLDTXT: // Retrieve value from under ROMs - lda (TXTPTR), y + lda (OLDTXT), y #if HAS_OPCODES_65C02 bra peek_under_roms_finalize From bebffd052f58f05811416f37c45f45030e94dbcf Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 24 Jun 2020 22:59:39 +0200 Subject: [PATCH 092/103] removed some outdated remarks --- c64/basic/basic_shift_mem_down.s | 3 --- c64/basic/basic_shift_mem_up.s | 3 --- c64/basic/select_device.s | 2 +- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/c64/basic/basic_shift_mem_down.s b/c64/basic/basic_shift_mem_down.s index 30216b77..2653049f 100644 --- a/c64/basic/basic_shift_mem_down.s +++ b/c64/basic/basic_shift_mem_down.s @@ -3,9 +3,6 @@ // #LAYOUT# * * #IGNORE -// XXX review this code - for memory models below 60k this can probably be simplified - - basic_shift_mem_down_and_relink: // Shift memory down to basic_current_line_pointer // from X bytes further along. diff --git a/c64/basic/basic_shift_mem_up.s b/c64/basic/basic_shift_mem_up.s index d4cdad86..cfe7c0e7 100644 --- a/c64/basic/basic_shift_mem_up.s +++ b/c64/basic/basic_shift_mem_up.s @@ -3,9 +3,6 @@ // #LAYOUT# * * #IGNORE -// XXX review this code - for memory models below 60k this can probably be simplified - - basic_shift_mem_up_and_relink: // Shift memory up from OLDTXT // X bytes. diff --git a/c64/basic/select_device.s b/c64/basic/select_device.s index 40bb8d49..ba23425d 100644 --- a/c64/basic/select_device.s +++ b/c64/basic/select_device.s @@ -3,7 +3,7 @@ // #LAYOUT# * * #IGNORE -select_device: // XXX check usage, probably more can be put into this common section +select_device: // Take last device number, make sure it is a drive - 8 or above. Above 30, // although illegal for IEC we also consider a drive, as they exists From 07c36cdd4be5f19ec9f58ab1259f33189d0e6769 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 24 Jun 2020 23:08:58 +0200 Subject: [PATCH 093/103] fixed new lines for break key --- c64/basic/basic_commands/cmd_stop_end.s | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/c64/basic/basic_commands/cmd_stop_end.s b/c64/basic/basic_commands/cmd_stop_end.s index 95fd5091..51c4906e 100644 --- a/c64/basic/basic_commands/cmd_stop_end.s +++ b/c64/basic/basic_commands/cmd_stop_end.s @@ -4,13 +4,16 @@ cmd_stop: + + jsr print_return + ldx #IDX__EV2_1E // "BREAK" jsr print_packed_error // Are we in direct mode lda CURLIN+1 cmp #$FF - beq !+ + beq cmd_end // Not direct mode ldx #IDX__STR_IN @@ -20,8 +23,8 @@ cmd_stop: ldx CURLIN+0 jsr print_integer -!: - jsr print_return + // FALLTROUGH cmd_end: + jmp basic_main_loop From 473660be80451e1861561a9a59989978882b1d52 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 25 Jun 2020 17:32:42 +0200 Subject: [PATCH 094/103] made dictionary compression working - it stays optional, currently even worsens the situation --- tools/generate_strings.cc | 206 +++++++++++++++++++++++++++++++++++--- 1 file changed, 190 insertions(+), 16 deletions(-) diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index fdbbcd26..18ae5285 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -463,6 +463,8 @@ private: bool optimizeJoin(); void optimizeOrder(); + void cleanupDictionary(); + void extractWords(std::vector &candidateList); int32_t evaluateCandidate(std::string &candidate); @@ -561,7 +563,7 @@ void DictEncoder::addString(const std::string &inString, StringEncoded *outPtr) { if (dictionary.size() > 255) { - ERROR("max 255 strings for dictionary compression"); + ERROR("max 255 strings allowed for dictionary compression"); } dictionary.push_back(inString); @@ -679,7 +681,7 @@ int32_t DictEncoder::evaluateCandidate(std::string &candidate) { // With a replacement, we should gain some bytes score += candidate.size() - 1; - + // If the occurence ends with the last byte of dictionary string - nothing more to do if (*iter + candidate.size() == dictionaryEntry.size()) break; @@ -715,16 +717,54 @@ int32_t DictEncoder::evaluateCandidate(std::string &candidate) } } - // We crossed the maximum number of strings, do not consider this candidate + // We crossed the maximum number of strings (leave one free for the work buffer), + // do not consider this candidate - if (targetSize > 255) return -1; + if (targetSize > 254) return -1; } return score; } +void DictEncoder::cleanupDictionary() +{ + // Get rid of dictionary entries which are not needed anymore + + bool isClean = false; + + while (!isClean) + { + isClean = true; + + for (auto iter = dictionary.begin(); iter < dictionary.end(); iter++) + { + if (!iter->empty()) continue; + + // Found an empty string in the dictionary - remove it and adapt encoding + + isClean = false; + uint8_t obsoleteStrIdx = iter - dictionary.begin(); + + dictionary.erase(iter); + + for (auto &encoding : encodings) for (auto &byte : *encoding) + { + if (byte >= obsoleteStrIdx) byte--; + } + + break; + } + } +} + bool DictEncoder::optimizeSplit() { + // XXX - The code here is not the best one - redesign and algorithm improvements + // (like - consider optimizing as a game and apply alpha-beta scheme to select the best + // candidate, incorporate frequency encoding into candidate evaluation) could result in + // a slightly better compression. But currently we have very few strings, and the dictionary + // compression is disabled by default - so right now this is not worth the effort. + if (dictionary.size() >= 255) return false; // up to 255 entries in the dictionary are possible // First select words, which can potentially be extracted to new substrings @@ -743,8 +783,6 @@ bool DictEncoder::optimizeSplit() { int32_t candidateScore = evaluateCandidate(*iter); - std::cout << "XXX candidate '" << *iter << "' score: " << candidateScore << std::endl; - if (candidateScore > bestCandidateScore) { bestCandidate = iter; @@ -752,22 +790,157 @@ bool DictEncoder::optimizeSplit() } } + // Only allow for replacements that brings some size benefit + if (bestCandidateScore < 1) return false; // Extract the best candidate to a separate string - std::cout << "XXX best is '" << *bestCandidate << "' score: " << bestCandidateScore << std::endl; + // First add our selected candidate to the dictionary and replace all strings which are equal to it + + auto &selectedStr = *bestCandidate; + uint8_t selectedStrIdx = dictionary.size(); + + dictionary.push_back(selectedStr); - // XXX + for (auto iter = dictionary.begin(); iter < dictionary.end(); iter++) + { + uint8_t currentStrIdx = iter - dictionary.begin(); + + if (*iter != selectedStr || selectedStrIdx == currentStrIdx) continue; + + // Replace the current string with the new one + + for (auto &encoding : encodings) for (auto &byte : *encoding) + { + if (byte == currentStrIdx) byte = selectedStrIdx; + } + + // Mark obsolete dictionary entry as free for removal + + iter->clear(); + } - std::cout << std::endl << "NOTE: 'CONFIG_COMPRESSION_LVL_2' support is not finished - as of writing" << - std::endl << " this text, it would not give any space improvement, so I've decided" << - std::endl << " to stop working on it for now." << std::endl << - std::endl << " Please disable this option in your configuration file." << std::endl << std::endl; + cleanupDictionary(); - exit(1); + // Now handle normal cases, when the string needs to be split + // XXX - this is not time-effective, optimize this in the future - return false; + bool optimizeAgain = true; + bool nexIteration = true; + while (nexIteration) + { + nexIteration = false; + + for (auto iter = dictionary.begin(); iter < dictionary.end(); iter++) + { + auto ¤tStr = *iter; + uint8_t currentStrIdx = iter - dictionary.begin(); + auto selectedStrIter = std::find(dictionary.begin(), dictionary.end(), selectedStr); + selectedStrIdx = selectedStrIter - dictionary.begin(); + + if (currentStrIdx == selectedStrIdx) continue; + + // Check if the current string contains the selected string + + auto pos = currentStr.find(selectedStr); + if (pos == std::string::npos) continue; + + nexIteration = true; + optimizeAgain = true; + + // Prepare replacement sequence for 'selectedStrIdx' + + std::vector replacement; + + if (pos == 0) + { + // The current dictionary string starts with our selected substring + + replacement.push_back(selectedStrIdx); + currentStr = currentStr.substr(selectedStr.size(), currentStr.size() - selectedStr.size()); + + if (!currentStr.empty()) + { + // Check if the remaining string is present somewhere else in the dictionary; if so, reuse it + + uint8_t pos2 = currentStrIdx; + for (auto iter2 = dictionary.begin(); iter2 < dictionary.end(); iter2++) + { + if (iter2 == iter) continue; + if (currentStr == *iter2) + { + dictionary[pos2].clear(); + pos2 = iter2 - dictionary.begin(); + break; + } + } + + replacement.push_back(pos2); + } + } + else + { + // The current dictionary string does not start with our selected substring + + std::string newStr = currentStr.substr(0, pos); + currentStr = currentStr.substr(pos, currentStr.size() - pos); + + // Check if the newStr is present somewhere else in the dictionary; if so, reuse it + + bool found = false; + uint8_t pos2 = 0; + for (auto iter2 = dictionary.begin(); iter2 < dictionary.end(); iter2++) + { + if (*iter2 == newStr) + { + found = true; + pos2 = iter2 - dictionary.begin(); + + break; + } + } + + if (found) + { + replacement.push_back(pos2); + } + else + { + dictionary.push_back(newStr); + replacement.push_back(dictionary.size() - 1); + } + + replacement.push_back(currentStrIdx); + } + + // Now replace all the occurences of 'selectedStrIdx' with a 'replacement' vector + + for (auto &encoding : encodings) + { + for (uint8_t idx = 0; idx < encoding->size(); idx++) + { + if ((*encoding)[idx] != currentStrIdx) continue; + + // Perform replacement + + encoding->erase(encoding->begin() + idx); + + for (const auto replacementIdx : replacement) + { + encoding->insert(encoding->begin() + idx, replacementIdx); + idx++; + } + + idx--; + } + } + + cleanupDictionary(); + } + } + + return optimizeAgain; } bool DictEncoder::optimizeJoin() @@ -820,6 +993,7 @@ void DictEncoder::optimizeOrder() optimizedOrder.push_back(newEntry); } + // Determine ordering - sort from smallest penalty to largest std::sort(optimizedOrder.begin(), optimizedOrder.end(), @@ -839,9 +1013,9 @@ void DictEncoder::optimizeOrder() // Perform the reordering - for (auto &encoding : encodings) + for (auto &encoding : encodings) for (auto &byte : *encoding) { - for (auto &byte : *encoding) byte = reorderTable[byte]; + byte = reorderTable[byte]; } for (uint8_t idx = 0; idx < dictionary.size(); idx++) dictionary[idx] = optimizedOrder[idx].word; From 2d04b1b4cb182e00a08fe14cb8f1c013483d7bef Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 25 Jun 2020 17:59:35 +0200 Subject: [PATCH 095/103] added more debug output to string compressor --- tools/generate_strings.cc | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index 18ae5285..726b3594 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -1550,6 +1550,28 @@ void DataSet::prepareOutput_packed(std::ostringstream &stream, { stream << "\t// IDX__" << stringEntryList.list[idxString].alias << std::endl; } + + if (!isCompressionLvl2(stringEntryList)) + { + stream << "\t// '"; + for (auto &character : stringEntryList.list[idxString].string) + { + if (character >= 32 && character <= 132 && character != 39 && character != 34) + { + stream << character; + } + else if (character == 13) + { + stream << ""; + } + else + { + stream << "_"; + } + } + stream << "'" << std::endl; + } + stream << "\t.byte "; bool first = true; From e442fa366fc47e54401b5ac4aa1e17f88570ff26 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 25 Jun 2020 18:14:12 +0200 Subject: [PATCH 096/103] small comments updates --- c64/,,config_custom.s | 2 +- tools/generate_strings.cc | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/c64/,,config_custom.s b/c64/,,config_custom.s index 54c8e7ae..e37dd9c0 100644 --- a/c64/,,config_custom.s +++ b/c64/,,config_custom.s @@ -145,4 +145,4 @@ // Other -// #define CONFIG_COMPRESSION_LVL_2 // work on this option stopped - it would not give any improvement +// #define CONFIG_COMPRESSION_LVL_2 // work on this option stopped - for now it has no chance to improve anything diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index 726b3594..2fb08694 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -954,6 +954,8 @@ bool DictEncoder::optimizeJoin() void DictEncoder::optimizeOrder() { + // XXX - it would be better to do this after the dictionary is compressed + // Try to optimize order of strings in the dictionary for fastest display // - put the shorter substrings first // - for strings with roughly the same length put more frequently used first From cba3a8949fff7636adfd1eb60c3f954554f48619 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 25 Jun 2020 18:37:33 +0200 Subject: [PATCH 097/103] even more debug output added --- tools/generate_strings.cc | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index 2fb08694..790aaa8a 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -616,6 +616,8 @@ void DictEncoder::extractWords(std::vector &candidateList) int32_t DictEncoder::evaluateCandidate(std::string &candidate) { + // XXX it looks like this is not 100% right - debug the algorithm if dictionary compression is reintroduced + // Build the score - find how much bytes can be spared by extracting this particular candidate // Limited size of the dictionary is taken into consideration @@ -1548,31 +1550,34 @@ void DataSet::prepareOutput_packed(std::ostringstream &stream, { if (lastStr != LastStr::NONE) stream << std::endl; + // Output the label - as a comment + if (stringEntryList.type != ListType::DICTIONARY) { stream << "\t// IDX__" << stringEntryList.list[idxString].alias << std::endl; } - if (!isCompressionLvl2(stringEntryList)) + // Output the source string - as a comment + + stream << "\t// '"; + for (auto &character : stringEntryList.list[idxString].string) { - stream << "\t// '"; - for (auto &character : stringEntryList.list[idxString].string) + if (character >= 32 && character <= 132 && character != 39 && character != 34) { - if (character >= 32 && character <= 132 && character != 39 && character != 34) - { - stream << character; - } - else if (character == 13) - { - stream << ""; - } - else - { - stream << "_"; - } + stream << character; + } + else if (character == 13) + { + stream << ""; + } + else + { + stream << "_"; } - stream << "'" << std::endl; } + stream << "'" << std::endl; + + // Output the encoding stream << "\t.byte "; @@ -1630,6 +1635,8 @@ void DataSet::prepareOutput() const auto &stringEntryList = stringEntryLists[idx]; const auto &stringEncodedList = stringEncodedLists[idx]; + if (stringEncodedList.empty()) continue; + // Export labels for the current list prepareOutput_labels(stream, stringEntryList, stringEncodedList); From 585aa2beeb8c4df3d9f4eaf82bdf3c2957009405 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 25 Jun 2020 18:41:05 +0200 Subject: [PATCH 098/103] updated binaries --- Makefile | 2 +- bin/basic_generic.rom | Bin 8192 -> 8192 bytes bin/basic_ultimate64.rom | Bin 8192 -> 8192 bytes bin/kernal_generic.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 7 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5917680b..6b586abb 100644 --- a/Makefile +++ b/Makefile @@ -186,7 +186,7 @@ build/tools/%: tools/%.c build/tools/%: tools/%.cc tools/common.h @mkdir -p build/tools - $(CXX) -O0 -g -Wall -o $@ $< + $(CXX) -O2 -Wall -o $@ $< # Rules - CHARGEN diff --git a/bin/basic_generic.rom b/bin/basic_generic.rom index 1451d2109896abc0e232a8aedd7b2fa0e2b278d3..fa704fb4bbd494b79f2364f811d5b72ca44e6f6d 100644 GIT binary patch delta 45 zcmZp0XmHqYoLx%c+^a>h3b_xLTAlp=foBnmLNSoJ%u?a~ip>w%YsDE&C&$Y#1OVa4 B6lVYc delta 45 zcmZp0XmHqYoLy>>tU~U?rB)~Zf8bffqEHNEF0)j4ze3^MtIZGDYsDE&CdbP!1OVB1 B6lMSb diff --git a/bin/basic_ultimate64.rom b/bin/basic_ultimate64.rom index 6bd95ad4889cefccf16b3e627399ee227c988e6a..0e2d7647f564765e425ca9296f10a72ffde13d71 100644 GIT binary patch delta 45 zcmZp0XmHrDM?y;B#H&TJ3Qw0WwL1C#1J5EBh1WplGE0S74>w#~@C>2^Ad#=7I;J@wt**1Q R;}HP?HG{_Fx5nfFIvWOK8kGP5 delta 40 ycmV+@0N4M3fCzwq2(Vti0W`B;zdIz8o#Ph+AiD3fwBr#00W^cg#~@C>2^Ad#=7I;J@wt**1Q R;}HP?HG{_Fx5nfFIvWOK8kGP5 delta 40 ycmV+@0N4M3fCzwq2(Vti0W`B;zdIz8o#Ph+AiD3fwBr#00W^cg Date: Thu, 25 Jun 2020 19:32:13 +0200 Subject: [PATCH 099/103] documentation update --- CONFIG.md | 6 ++++++ README.md | 1 + STATUS.md | 1 + c64/,,config_custom.s | 2 +- c64/,,config_cx16.s | 4 ++++ c64/,,config_generic.s | 4 ++++ c64/,,config_mega65.s | 4 ++++ c64/,,config_testing.s | 4 ++++ c64/,,config_ultimate64.s | 4 ++++ doc/Extended-BASIC.md | 30 ++++++++++++++++++++++++++++++ 10 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 doc/Extended-BASIC.md diff --git a/CONFIG.md b/CONFIG.md index bd8182f2..968487c8 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -330,3 +330,9 @@ Replaces `RTS` stubbed routines implementation with one causing a break. ### `CONFIG_DBG_PRINTF` Makes `printf` routine available. + +## Other options + +### `CONFIG_COMPRESSION_LVL_2` + +Adds additional step in compressing BASIC interpreter strings - a dictionary compression. Not tested extensively - and for now it won't bring any improvement (it will even increase the code/data size) as we do not have enough strings yet to make this method useful. Do not use! diff --git a/README.md b/README.md index 4f8186b0..aa1af581 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ A project to create unencumbered open-source ROMs for use on selected retro comp * [implementation status](./STATUS.md) of various APIs and functionalities * [configuration options](./CONFIG.md) for those willing to compile their own, customized ROM set +* [BASIC extensions](doc/Extended-BASIC.md) * [development guide](./doc/Development.md) for those interested in OpenROMs technical aspects * [license](./LICENSE) information and list of major contributors * [credits](./CREDITS.md) to people whose work was of great help to us diff --git a/STATUS.md b/STATUS.md index 897686d2..384f08d8 100644 --- a/STATUS.md +++ b/STATUS.md @@ -10,6 +10,7 @@ Here are the features of the Open ROMs not found in the original ROMs from the 8 * JiffyDOS and DolphinDOS protocols support * DOS wedge (direct mode only) - `@`, `@`, `@$`, `@$`, `@` +* BASIC extensions, see the [documentation](doc/Extended-BASIC.md) * turbo tape load support (as device 7, or using `←L`), quite sophisticated: up to 250 blocks (can store bytes under I/O), automatically adjusts for tape speed differences * normal tape load error log is limited by free stack space only (no artificial limitation like in original ROMs) diff --git a/c64/,,config_custom.s b/c64/,,config_custom.s index e37dd9c0..ad83a50a 100644 --- a/c64/,,config_custom.s +++ b/c64/,,config_custom.s @@ -145,4 +145,4 @@ // Other -// #define CONFIG_COMPRESSION_LVL_2 // work on this option stopped - for now it has no chance to improve anything +// #define CONFIG_COMPRESSION_LVL_2 diff --git a/c64/,,config_cx16.s b/c64/,,config_cx16.s index 158500df..61056fb2 100644 --- a/c64/,,config_cx16.s +++ b/c64/,,config_cx16.s @@ -136,3 +136,7 @@ // #define CONFIG_DBG_STUBS_BRK // #define CONFIG_DBG_PRINTF + +// Other + +// #define CONFIG_COMPRESSION_LVL_2 diff --git a/c64/,,config_generic.s b/c64/,,config_generic.s index 209074e8..391de569 100644 --- a/c64/,,config_generic.s +++ b/c64/,,config_generic.s @@ -134,3 +134,7 @@ // #define CONFIG_DBG_STUBS_BRK // #define CONFIG_DBG_PRINTF + +// Other + +// #define CONFIG_COMPRESSION_LVL_2 diff --git a/c64/,,config_mega65.s b/c64/,,config_mega65.s index bf90bfaa..1c9cdbf5 100644 --- a/c64/,,config_mega65.s +++ b/c64/,,config_mega65.s @@ -134,3 +134,7 @@ // #define CONFIG_DBG_STUBS_BRK // #define CONFIG_DBG_PRINTF + +// Other + +// #define CONFIG_COMPRESSION_LVL_2 diff --git a/c64/,,config_testing.s b/c64/,,config_testing.s index 9ec523c1..b56027c3 100644 --- a/c64/,,config_testing.s +++ b/c64/,,config_testing.s @@ -134,3 +134,7 @@ // #define CONFIG_DBG_STUBS_BRK #define CONFIG_DBG_PRINTF + +// Other + +// #define CONFIG_COMPRESSION_LVL_2 diff --git a/c64/,,config_ultimate64.s b/c64/,,config_ultimate64.s index 0f73f68b..b463c918 100644 --- a/c64/,,config_ultimate64.s +++ b/c64/,,config_ultimate64.s @@ -134,3 +134,7 @@ // #define CONFIG_DBG_STUBS_BRK // #define CONFIG_DBG_PRINTF + +// Other + +// #define CONFIG_COMPRESSION_LVL_2 diff --git a/doc/Extended-BASIC.md b/doc/Extended-BASIC.md new file mode 100644 index 00000000..c5ebca1b --- /dev/null +++ b/doc/Extended-BASIC.md @@ -0,0 +1,30 @@ + +# Extended BASIC + +NOTE: Command syntax, behaviour details, and tokens are still subject to change! In the future most (if not all) extended commands will be available only on machines with extended ROM, like the Mega65. + +## Additional commands + +### `FAST` + +Tries to switch the machine to turbo mode - details differ depending on the configured machine / motherboard. + +### `SLOW` + +Tries to switch the machine back to 1 MHz operation mode. + +### `MERGE "file_name" [, device_number]` + +Appends the BASIC program from a storage medium to the one currently present in memory. NOTE: due to bug in BASIC editor (improper VARTAB handling) it currently works only with programs loaded from the storage medium, not the ones typed in! + +### `BLOAD "file_name", device_number, start_address` + +Loads a binary file starting from the given memory location. Does not clear variables, does not perform BASIC program relinking, etc. NOTE: for now syntax differs from the BASIC V3.5+ - this will be changed once the necessary BASIC infrastructure is implemented. + +### `BVERIFY "file_name", device_number, start_address` + +Verify operation for the binary data starting from a given addres. NOTE: for now syntax differs from the BASIC V3.5+ - this will be changed once the necessary BASIC infrastructure is implemented. + +### `BSAVE "file_name", device_number, start_address, end_address` + +Saves the binary data from the given memory area. NOTE: for now syntax differs from the BASIC V3.5+ - this will be changed once the necessary BASIC infrastructure is implemented. From a4d9679019f7d790c17e37989a30740e2e648f32 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Thu, 25 Jun 2020 21:23:07 +0200 Subject: [PATCH 100/103] fixed mising shift memory implementation for memory models 46K and 50K --- Makefile | 1 + bin/basic_generic.rom | Bin 8192 -> 8192 bytes bin/basic_ultimate64.rom | Bin 8192 -> 8192 bytes bin/kernal_generic.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/basic/e000.under_rom_routines_46k_50k.s | 72 --------- .../memory/e107.under_rom_routines_46k_50k.s | 148 ++++++++++++++++++ c64/basic/memory/shift_mem_down_38k.s | 30 ++++ c64/basic/memory/shift_mem_up_38k.s | 30 ++++ .../{ => memory}/under_rom_routines_60k.s | 42 ----- 12 files changed, 209 insertions(+), 114 deletions(-) delete mode 100644 c64/basic/e000.under_rom_routines_46k_50k.s create mode 100644 c64/basic/memory/e107.under_rom_routines_46k_50k.s create mode 100644 c64/basic/memory/shift_mem_down_38k.s create mode 100644 c64/basic/memory/shift_mem_up_38k.s rename c64/basic/{ => memory}/under_rom_routines_60k.s (69%) diff --git a/Makefile b/Makefile index 6b586abb..e3102ca5 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ SRCDIR_BASIC = $(SRCDIR_COMMON) \ c64/basic/math \ c64/basic/math_consts \ c64/basic/math_mov \ + c64/basic/memory \ c64/basic/print \ c64/basic/rom_revision \ c64/basic/tokenizer \ diff --git a/bin/basic_generic.rom b/bin/basic_generic.rom index fa704fb4bbd494b79f2364f811d5b72ca44e6f6d..68bc99f4a1ad29ddad7d895cabba1430589546e1 100644 GIT binary patch delta 2555 zcmZuz3vd(18D5=iOMXfwG8TSmc{o5Yt^);(6L|~?6A_MSLOXQ}xII6SUqBiX8so&c z%`tAKBr;n!Z4#$KW@XOQzH=$HElb!57<{f1j?{fkGmV8UN|Gt2Tgm{X$FvM@D4A@ zHKiMS`#=Nt_K_z|i*xVwK{x+T3Nt;%j`9ifU2(sFknr}?-+anDG&|%**bpQ;;_6NF zcFY?9yOQ3N?PQUmH0R-<8&P|^eVi7z+dY3W$^aGIg3p@ z`{?x)Wb1zYrrCBk9R+(N^jsFQ-L`z0)S7MM(2*PI=;ON!Z3cAo>ZYHhz4K+N;5g2sch zsz!6HqUYb2MIZPMe|R0j{$K%*3166B%8f>!30v?$L^I(_5!Y(A{4WtV&YPt+0XFfV zwu1NonEz4ansx&=k&xHt7T^qE5=lwgZn@#7uJAc93HEV7b4W6Q(QKmc^K+u(N#_&p6EL|}30JMI~rbIOC<2{iW}@b>!XTcy3fCQgSXHmH95&ot)=R;Wzg|Wbt;dx-z^Pf(!ldBcCPPIN*XQ zW#h8n$V0r(F=U5-zR$rQ?*;H~quaDeC-B0v$vwvhBBUY3%E7cFDa-9J?8MjmJcctB z9iGuLRuYa6su`fs6nivm7#jEl2(N3#0q}W ziw8#vB^25(?x&5RYEWtjRe@4{s1lUwLKRUZ1cfo^YB|8DYfuoF5AwqCDmI62VriyO zunIy?*fe1-CUb_R$Bc2rV$4`p7IgOD(x69=%Yw8B*qr2viHhEh*r<5!y~Q~9FJsoD z?Mf%7Ynw2C?&QC&w6(P*jJCKwak`hQEv__&C&n5;x|bxS6W!O@sgTFxv$=AG?20cl z(Dnj7|K=64H7AREqo3@_$;ls;nSlt59hKEs7pr;#4zDBdq}LI({r-?XIz&$Al=f++54|KDKY#E2mUGSL&W|0saL{L$q%j!+%MD9Oqhl?9ibr24onXZ41q8>Aj{;F4C|6E`Be;NLQHDhKIsl` z8io+Fiw-=`ygne4MVTAY&@^SFWRzrtoTnqH&fFYNSBZ9-Cl(7t$;@G?Ldz^@>55_+ zhwt#x3?7}~TZg^AX`{k*`yPmD&>L=y``b}^BfLdBwqnm$D;0`2(YGEH>!;J*h*Th?y4 z^l3lN_>3y>flvyN{@r@U3I>-RC(s+Ka3P3OU%eQr)FoOXodP^gNlW+x0q>Ny4Kl(O zp!gH&q?XF|R#A`R7mf*B8RTmM>IeVZS<5=v_-iX$dNT07p!1|teM95Ksd24SdIb{v zxYhxOAune?+hSDU;8CV}cC&L+yI4<)#fH}$)@r+0ON(ofSVvbEhHAw|nh&XPFKqRF?nHbA4{>fRHL*dBC>i2y)G1M55uqWa8yHUr)bwe9wY#%W!< zoz_Aa>%?NF{3k1U%hXR&Z98(-08Jp6{oM*D`UKoM%z}j9@w3(7UD9fM;&Hsx&mzTQ n^wsl8TIF4RA|L-{{`mxGic+N4P+9DDSTCh3kAXwd&3vq6Xy delta 2518 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 diff --git a/bin/kernal_generic.rom b/bin/kernal_generic.rom index 132e1f620fe8c3a473cfb6340219844a857854ad..18729a729054a5916325d00e9902073394648461 100644 GIT binary patch delta 802 zcmYLHZ%9*76n}4T#mq(~t2CQlHhr7qKLm62$I(s65clV@a>QISp|iy zh?1Zl)>WT@+p;iiHX$+>5if$iNZ_=$Fc1x-@RQxAL5IsZKhB@uJ@?!*P&ZK5KMD?p z*dQBV{cI^~XKgI&z@@4Wm0-Ktfr_zB^&%@~RZrN2EVu-f;$mdSR%F8##AZStlm(6h z>bL{fs;4KhLoEY_*eDI#(;Ud1kSP$}1>>(lUow^r<|jeoRhWTuQP>$LUWo>#+;oak z7`PC}ktzn>Uj^HVNTfgq@(W)5 z?_N@NGXBh-TeczE&dIgXGv&BkBuywe@}{(^9Fp%zGvW=plE&gR&Gz3)bJ+b(*lLM2 zW5J=iQ}$R*$`CeVcb;HCZtO$dxC8mH7j<9{^2!wQY<sD^8=MwF zBnxR30&){tRY-wYC1K0Qg2pD`APV6C3SvJBkbM8va%o1$tR&dGL zcPG16zb*Ra$;jUnH1kJm02&N*hv1Jyze(t?0FFdcUEEh6kMLXX+;)EAGe^;AW=b0 z1&GQTK>oOeG{0L$y6)240(O%Pv?jp&ak5))qd-U!yATD#)3+NRG!oN^j&&lFY=YmC uVxQiuGpEIe`jds9V?{rjU37!^uePs(TCFZZAC0XeMnojQbB6*C|EJhMqdPf2Il)`zJLDtzL}2g9oxgw zTEe75HfbGU+(I$2^7HaVV5b0AXYlRu2+L~|*po}K`1*uY^SG|djNcXLsuJgSW(9m6 zEU;Cn=?05Zi>DKh7`}B(z!kmVEOnJOeP;Rj38)w@$g^N4I&cuZNx(}oF$QawW z@-Nd6t!MecIDP`r=nBn?Y&3Z^+>-?RfH$&Dt^&t^FS1eAgLA+isgbqd8VE$Hh-uVOEfr2Vm! zY>+m^Cge(KIyNqsN%2^}ECv}f(=Xm<)`lOB31B5YXe9otHj~RrJkaPt#0zy6#X|yM zrtN|d*jFIsH1k-La?0>dsSKZ*_`pvS|75T$fJbs}QXWJ2)w7hwBv7Eu7x_aJs1-2; zo~U&QyiqH7h!wn~aj8lkF$qWwf&UbzL-c9Z)%{cvZqKER_(2b7sfA?;Xd+Lj&;8Wr zj7j*@z@{E9<}?Sx5>qQ7ygGyTWN8ibXUDOPK%xFGNbJoge+4G2|*hb+$Qj&naiEMy<(PKzn~B=%Aoqb zvuo_X;`rJ)e=Nz5cKiH+;PK{`6Rjstoj!B+T&S)6{DpAG#pM4(`1j)$byAgAZFg*R zaudCq=p-F)$&2kJRT@KHyj!w-)y^#U;lN>L_nsr>hWh#~4V%q-cbPXJ^vCeNHzjo| FegplSY$gBz diff --git a/bin/kernal_ultimate64.rom b/bin/kernal_ultimate64.rom index b228177770ea1c7aa0c2e50d274cb30285e7e397..0880452f31d436301289b3c319c3f6d79f238101 100644 GIT binary patch delta 734 zcma)3O=uHQ5Z+`HZHv(;DMY36NYhP1qZUD$Dwg6Y>Vkh)#ohcY*=$nkNdzGQ9Vk5| z<{~0e7ABe$OF}OmitWMHZcmGXB1Py@b`Jq@m4Xz(_%SE zvaiS$IEBk|F)qqQI4*%PGYcaaH8T*#h?$0AaoK(3KuXAlfsp~gUrJ%rdwUU)-k7|I!=!o|U(H=|%)xQK4xc+VoFa|GPS9C1YiMBbkJg0T-1FEMN)+ZeOzn?ma#5LKz*1C#v!W6Y=>#WvS8A35A_koC6 zn86HW=`1pICg}zPDf^=(2BnmgmNHUSnsM6ouYywniUOxYh8v=QqA6>nb(+#0McJW~ zu>eI>pn!Q$XhYuKvgDwYmlUZW6?;VA93ol;2PuLqFbpH`cMQ5~iaQ)$eqCYtl0oDZ z>K_>7@zPxKNs_u84CWxv2=HH4YD?~0m&xi*YmDr!Xy@%XY3z{auh8fB&oggDdw>iX z^Od|GWN~Zag2{cxrtr?mvSzGAcC3>X9iyADZnVi)T^|Ti9U=x;2 z8}S~(GSBGuOgz4=<>=2Q7O*k_o!wJ|NBeOVPLH z!!f^<#BGZh4YsdNV5F^hHx>4xsA-xz8;*Tc^v=3QXj=p{cyM)sm)102tD3s%Ly{~a zly}D(e*+4Aa!(+nu+8F%_p=TQfNV!DE7(6ca`n(xm0Z?gZ^{4&00RgBA|NLa3{C-I zk&_N5fCFJJzyg;DA{V)wAR-q=P9h2fH#kL*S$U4%#5vs2@$b`X%c8gEBho#I2SxQO zd{I6YDkSFd$!2BQ!#9g9!_z~m#V1IIge-bymYte40&1TTRQq*8J%wd|S+M+elUBt( zj$Jlxlj-vX3x{MKI2#3&<3a780i^b^W2Hod?8i_@EEBo=!o^FM!^2muj*O~f*R<=A d8{^TNw_@?7|DVKh;k;`%K>bDYuZ6Dde*nsSDrEow diff --git a/bin/mega65.rom b/bin/mega65.rom index f28ce902d8837539e4f380623dbd3bc3baf29e9b..f70851d7b6317a631fd434c80393b94e118c4f92 100644 GIT binary patch delta 2230 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 diff --git a/bin/mega65_pxlfont.rom b/bin/mega65_pxlfont.rom index d52ddce0891b3260a921a8f864f4c73f7b009298..91d86cbb65fc9c430c5173f7559e30d90e25765a 100644 GIT binary patch delta 2230 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 diff --git a/c64/basic/e000.under_rom_routines_46k_50k.s b/c64/basic/e000.under_rom_routines_46k_50k.s deleted file mode 100644 index 6aef9262..00000000 --- a/c64/basic/e000.under_rom_routines_46k_50k.s +++ /dev/null @@ -1,72 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - -// XXX extend build_segment tool to allow to specify placement range - - -#if CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K - - -peek_under_roms_via_TXTPTR: - - // Unmap BASIC lower ROM - - lda #$26 - sta CPU_R6510 - - // Retrieve value from under ROMs - - lda (TXTPTR), y - - // FALLTROUGH - -peek_under_roms_finalize: - - // Restore memory mapping - - pha - lda #$27 - sta CPU_R6510 - pla - - // Quit - - rts - -peek_under_roms_via_OLDTXT: - - // Unmap BASIC lower ROM - - lda #$26 - sta CPU_R6510 - - // Retrieve value from under ROMs - - lda (OLDTXT), y - -#if HAS_OPCODES_65C02 - bra peek_under_roms_finalize -#else - jmp peek_under_roms_finalize -#endif - -peek_under_roms_via_FAC1_PLUS_1: - - // Unmap BASIC lower ROM - - lda #$26 - sta CPU_R6510 - - // Retrieve value from under ROMs - - lda (__FAC1 + 1), y - -#if HAS_OPCODES_65C02 - bra peek_under_roms_finalize -#else - jmp peek_under_roms_finalize -#endif - - -#endif diff --git a/c64/basic/memory/e107.under_rom_routines_46k_50k.s b/c64/basic/memory/e107.under_rom_routines_46k_50k.s new file mode 100644 index 00000000..b46a03d1 --- /dev/null +++ b/c64/basic/memory/e107.under_rom_routines_46k_50k.s @@ -0,0 +1,148 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// XXX This can be any address - but definitely $E000 or above +// XXX TODO: extend build_segment tool to allow to specify placement range + + +#if CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K + + +peek_under_roms_via_TXTPTR: + + // Unmap BASIC lower ROM + + lda #$26 + sta CPU_R6510 + + // Retrieve value from under ROMs + + lda (TXTPTR), y + + // FALLTROUGH + +peek_under_roms_finalize: + + // Restore memory mapping + + pha + lda #$27 + sta CPU_R6510 + pla + + // Quit + + rts + +peek_under_roms_via_OLDTXT: + + // Unmap BASIC lower ROM + + lda #$26 + sta CPU_R6510 + + // Retrieve value from under ROMs + + lda (OLDTXT), y + +#if HAS_OPCODES_65C02 + bra peek_under_roms_finalize +#else + jmp peek_under_roms_finalize +#endif + +peek_under_roms_via_FAC1_PLUS_1: + + // Unmap BASIC lower ROM + + lda #$26 + sta CPU_R6510 + + // Retrieve value from under ROMs + + lda (__FAC1 + 1), y + +#if HAS_OPCODES_65C02 + bra peek_under_roms_finalize +#else + jmp peek_under_roms_finalize +#endif + + + +shift_mem_up: + + // Move __memmove_size bytes from __memmove_src to __memmove_dst, + // where __memmove_dst > __memmove_src + // This means we have to copy from the back end down. + // This routine assumes the pointers are already pointed + // to the end of the areas, and that Y is correctly initialised + // to allow the copy to begin. + + // Unmap BASIC lower ROM + + php + + lda #$26 + sta CPU_R6510 + + // Perform the copying +!: + lda (__memmove_src),y + sta (__memmove_dst),y + dey + bne !- + dec __memmove_src+1 + dec __memmove_dst+1 + dec __memmove_size+1 + bne !- + +#if HAS_OPCODES_65C02 + bra shift_mem_finalize +#else + jmp shift_mem_finalize +#endif + + +shift_mem_down: + + // Move __memmove_size bytes from __memmove_src to __memmove_dst, + // where __memmove_dst > __memmove_src + // This means we have to copy from the back end down. + // This routine assumes the pointers are already pointed + // to the end of the areas, and that Y is correctly initialised + // to allow the copy to begin. + + // Unmap BASIC lower ROM + + php + + lda #$26 + sta CPU_R6510 + + // Perform the copying +!: + lda (__memmove_src),y + sta (__memmove_dst),y + iny + bne !- + inc __memmove_src+1 + inc __memmove_dst+1 + dec __memmove_size+1 + bne !- + // FALLTROUGH + +shift_mem_finalize: + + // Restore memory mapping and quit + + lda #$27 + sta CPU_R6510 + + plp + + rts + + +#endif diff --git a/c64/basic/memory/shift_mem_down_38k.s b/c64/basic/memory/shift_mem_down_38k.s new file mode 100644 index 00000000..471ac56b --- /dev/null +++ b/c64/basic/memory/shift_mem_down_38k.s @@ -0,0 +1,30 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +#if CONFIG_MEMORY_MODEL_38K + +shift_mem_down: + + // Move __memmove_size bytes from __memmove_src to __memmove_dst, + // where __memmove_dst > __memmove_src + // This means we have to copy from the back end down. + // This routine assumes the pointers are already pointed + // to the end of the areas, and that Y is correctly initialised + // to allow the copy to begin. + + php +!: + lda (__memmove_src),y + sta (__memmove_dst),y + iny + bne !- + inc __memmove_src+1 + inc __memmove_dst+1 + dec __memmove_size+1 + bne !- + plp + rts + +#endif diff --git a/c64/basic/memory/shift_mem_up_38k.s b/c64/basic/memory/shift_mem_up_38k.s new file mode 100644 index 00000000..c8fab14b --- /dev/null +++ b/c64/basic/memory/shift_mem_up_38k.s @@ -0,0 +1,30 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +#if CONFIG_MEMORY_MODEL_38K + +shift_mem_up: + + // Move __memmove_size bytes from __memmove_src to __memmove_dst, + // where __memmove_dst > __memmove_src + // This means we have to copy from the back end down. + // This routine assumes the pointers are already pointed + // to the end of the areas, and that Y is correctly initialised + // to allow the copy to begin. + + php +!: + lda (__memmove_src),y + sta (__memmove_dst),y + dey + bne !- + dec __memmove_src+1 + dec __memmove_dst+1 + dec __memmove_size+1 + bne !- + plp + rts + +#endif diff --git a/c64/basic/under_rom_routines_60k.s b/c64/basic/memory/under_rom_routines_60k.s similarity index 69% rename from c64/basic/under_rom_routines_60k.s rename to c64/basic/memory/under_rom_routines_60k.s index e4458496..0a07dbc7 100644 --- a/c64/basic/under_rom_routines_60k.s +++ b/c64/basic/memory/under_rom_routines_60k.s @@ -113,46 +113,4 @@ smd1: __ram_routines_end: -#else // CONFIG_MEMORY_MODEL_60K - -shift_mem_up: - // Move __memmove_size bytes from __memmove_src to __memmove_dst, - // where __memmove_dst > __memmove_src - // This means we have to copy from the back end down. - // This routine assumes the pointers are already pointed - // to the end of the areas, and that Y is correctly initialised - // to allow the copy to begin. - php -smu1: - lda (__memmove_src),y - sta (__memmove_dst),y - dey - bne smu1 - dec __memmove_src+1 - dec __memmove_dst+1 - dec __memmove_size+1 - bne smu1 - plp - rts - -shift_mem_down: - // Move __memmove_size bytes from __memmove_src to __memmove_dst, - // where __memmove_dst > __memmove_src - // This means we have to copy from the back end down. - // This routine assumes the pointers are already pointed - // to the end of the areas, and that Y is correctly initialised - // to allow the copy to begin. - php -smd1: - lda (__memmove_src),y - sta (__memmove_dst),y - iny - bne smd1 - inc __memmove_src+1 - inc __memmove_dst+1 - dec __memmove_size+1 - bne smd1 - plp - rts - #endif From d4d32095d16a8929d157f00962ab705ed71fae4c Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Fri, 26 Jun 2020 19:13:47 +0200 Subject: [PATCH 101/103] build segment tool can now be instructed to always place routine above #E000 --- ...46k_50k.s => under_rom_routines_46k_50k.s} | 7 +- doc/Development.md | 3 + tools/build_segment.cc | 94 ++++++++++++++++++- 3 files changed, 96 insertions(+), 8 deletions(-) rename c64/basic/memory/{e107.under_rom_routines_46k_50k.s => under_rom_routines_46k_50k.s} (91%) diff --git a/c64/basic/memory/e107.under_rom_routines_46k_50k.s b/c64/basic/memory/under_rom_routines_46k_50k.s similarity index 91% rename from c64/basic/memory/e107.under_rom_routines_46k_50k.s rename to c64/basic/memory/under_rom_routines_46k_50k.s index b46a03d1..7ceb7a84 100644 --- a/c64/basic/memory/e107.under_rom_routines_46k_50k.s +++ b/c64/basic/memory/under_rom_routines_46k_50k.s @@ -1,9 +1,8 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# STD * #TAKE-HIGH +// #LAYOUT# * BASIC_0 #TAKE-HIGH // #LAYOUT# * * #IGNORE -// XXX This can be any address - but definitely $E000 or above -// XXX TODO: extend build_segment tool to allow to specify placement range +// This has to go $E000 or above - as the routines below bank out the main BASIC ROM! #if CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K diff --git a/doc/Development.md b/doc/Development.md index 95054f28..2a834a22 100644 --- a/doc/Development.md +++ b/doc/Development.md @@ -132,6 +132,7 @@ where: | `#IGNORE` | ignore the file completely | | `#TAKE` | compile the file normally | | `#TAKE-FLOAT` | compile the file, but force it to be floating | +| `#TAKE-HIGH` | as above, but always place routine at `$E000` or above | | `#TAKE-OFFSET` | shifts the fixed-location address by hex offset given as parameter | The first match counts, all the remaining ones are dropped. Examples: @@ -184,6 +185,8 @@ ROUTINE_NAME: #endif ``` +Last, but not least - the `#TAKE-HIGH` is intended to be used for BASIC routines, which should still be available after the main BASIC ROM is banked out. + ### CPU-specific optimizations TODO diff --git a/tools/build_segment.cc b/tools/build_segment.cc index 422819ef..d160f055 100644 --- a/tools/build_segment.cc +++ b/tools/build_segment.cc @@ -88,6 +88,7 @@ public: bool ignore; bool floating; + bool high; std::vector content; std::string label; @@ -109,6 +110,7 @@ public: void addToProblem(SourceFile *routine); void fillGap(DualStream &logOutput, int gapAddress, const std::list &routines); + void placeHighRoutines(DualStream &logOutput); void performObviousSteps(DualStream &logOutput); void removeUselessGaps(DualStream &logOutput); void sortFloatingRoutinesBySize(); @@ -416,9 +418,22 @@ void prepareBinningProblem() { std::string spacing; spacing.resize(GLOBAL_maxFileNameLen + 4 - sourceFile.fileName.length(), ' '); - std::string floating = sourceFile.floating ? "(floating) " : " "; + std::string floating_high; - logOutput << "file: " << floating << sourceFile.fileName << spacing << "size: " << std::to_string(sourceFile.codeLength) << "\n"; + if (sourceFile.high) + { + floating_high = "(floating, high) "; + } + else if (sourceFile.floating) + { + floating_high = "(floating) "; + } + else + { + floating_high = " "; + } + + logOutput << "file: " << floating_high << sourceFile.fileName << spacing << "size: " << std::to_string(sourceFile.codeLength) << "\n"; } // Create the binning problem @@ -569,6 +584,7 @@ SourceFile::SourceFile(const std::string &fileName, const std::string &dirName) dirName(dirName), ignore(false), floating(false), + high(false), startAddr(-1), codeLength(-1), testAddrStart(-1), @@ -686,12 +702,17 @@ bool SourceFile::preprocessLine(const std::string &line) if (iter->compare("#IGNORE") == 0) { - ignore = true; + ignore = true; } else if (iter->compare("#TAKE-FLOAT") == 0) { floating = true; } + else if (iter->compare("#TAKE-HIGH") == 0) + { + floating = true; + high = true; + } else if (iter->compare("#TAKE-OFFSET") == 0) { if (++iter == tokens.end()) ERROR("syntax error, missing parameter for '#TAKE-OFFSET'"); @@ -844,10 +865,71 @@ void BinningProblem::fillGap(DualStream &logOutput, int gapAddress, const std::l gaps.erase(gapAddress); } +void BinningProblem::placeHighRoutines(DualStream &logOutput) +{ + // Place routines which has to be stored in the high ROM area + // It is expected there will be very few of them, so no complicated algorithms here + + std::string spacing; + + while (!floatingRoutines.empty()) + { + // Try to find any high routine + + auto iterRoutine = floatingRoutines.begin(); + while (iterRoutine != floatingRoutines.end() && !(*iterRoutine)->high) iterRoutine++; + + if (iterRoutine == floatingRoutines.end()) break; + + // Now we need to find a space to put it - just take the largest gap available, + // which is located in the high ROM area + + int routineSize = (*iterRoutine)->codeLength; + int gapAddress = -1; + + for (auto &gap : gaps) + { + if (gap.second < routineSize || gap.first < 0xE000) continue; + + if (gap.second == routineSize) + { + gapAddress = gap.first; + break; + } + + if (gapAddress < 0 || gap.second > gaps[gapAddress]) + { + gapAddress = gap.first; + } + } + + if (gapAddress < 0) ERROR("no suitable space for a high routine"); + + // Place routine in the gap found + + gaps[gapAddress] -= routineSize; + + int targetAddr = gapAddress + gaps[gapAddress]; + fixedRoutines[targetAddr] = *iterRoutine; + statFree -= routineSize; + + logOutput << "reducing gap $" << std::hex << gapAddress << std::dec << + " to size " << gaps[gapAddress] << "\n"; + + spacing.resize(GLOBAL_maxFileNameLen + 4 - (*iterRoutine)->fileName.length(), ' '); + logOutput << " $" << std::hex << targetAddr << std::dec << ": " << + (*iterRoutine)->fileName << spacing << "size: " << + (*iterRoutine)->codeLength << "\n"; + + floatingRoutines.erase(iterRoutine); + if (gaps[gapAddress] == 0) gaps.erase(gapAddress); + } +} + void BinningProblem::performObviousSteps(DualStream &logOutput) { // Get the size of the biggest routine; if there is just one gap which - // can handle it - put the roputine exactly there + // can handle it - put the routine exactly there std::string spacing; @@ -954,6 +1036,10 @@ void Solver::run() problem.sortFloatingRoutinesBySize(); + // Place routines which should be stored in high-ROM + + problem.placeHighRoutines(logOutput); + // Run the solver until all is done while (!problem.gaps.empty() && !problem.floatingRoutines.empty()) From 76aaf298b867789d5f2ac92334372bdd7a4fe89a Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Fri, 26 Jun 2020 19:44:01 +0200 Subject: [PATCH 102/103] more sane directory name, updated binaries --- CONFIG.md | 10 +- Makefile | 100 +++++++++--------- STATUS.md | 2 +- bin/basic_generic.rom | Bin 8192 -> 8192 bytes bin/basic_ultimate64.rom | Bin 8192 -> 8192 bytes bin/kernal_generic.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 => src}/,,config_custom.s | 0 {c64 => src}/,,config_cx16.s | 0 {c64 => src}/,,config_generic.s | 0 {c64 => src}/,,config_mega65.s | 0 {c64 => src}/,,config_testing.s | 0 {c64 => src}/,,config_ultimate64.s | 0 {c64 => src}/aliases/,aliases_config.s | 0 {c64 => src}/aliases/,aliases_cpu.s | 0 {c64 => src}/aliases/,aliases_error_codes.s | 0 {c64 => src}/aliases/,aliases_hardware.s | 0 {c64 => src}/aliases/,aliases_hardware_cx16.s | 0 {c64 => src}/aliases/,aliases_petscii_codes.s | 0 {c64 => src}/aliases/,aliases_ram_lowmem.s | 0 {c64 => src}/aliases/,aliases_rom_basic.s | 0 {c64 => src}/aliases/,aliases_rom_cart.s | 0 {c64 => src}/aliases/,aliases_rom_kernal.s | 0 {c64 => src}/basic/,aliases.s | 0 {c64 => src}/basic/,imports.s | 0 {c64 => src}/basic/,stubs/a408.interop | 0 {c64 => src}/basic/,stubs/a408.reason.s | 0 {c64 => src}/basic/,stubs/a453.interop | 0 {c64 => src}/basic/,stubs/a453.unknown.s | 0 {c64 => src}/basic/,stubs/a483.main.s | 0 {c64 => src}/basic/,stubs/a57c.chrnch.s | 0 {c64 => src}/basic/,stubs/a57c.interop | 0 {c64 => src}/basic/,stubs/a644.interop | 0 {c64 => src}/basic/,stubs/a644.new.s | 0 {c64 => src}/basic/,stubs/a659.interop | 0 {c64 => src}/basic/,stubs/a659.setcharptr.s | 0 {c64 => src}/basic/,stubs/a71a.interop | 0 {c64 => src}/basic/,stubs/a71a.qplop.s | 0 {c64 => src}/basic/,stubs/a7e4.gone.s | 0 {c64 => src}/basic/,stubs/a7e4.interop | 0 {c64 => src}/basic/,stubs/ae86.eval.s | 0 {c64 => src}/basic/,stubs/ae86.interop | 0 {c64 => src}/basic/,stubs/basic_adray1.s | 0 {c64 => src}/basic/,stubs/basic_adray2.s | 0 {c64 => src}/basic/,stubs/e38b.error.s | 0 {c64 => src}/basic/,stubs/e38b.interop | 0 {c64 => src}/basic/,stubs/e3bf.init.s | 0 {c64 => src}/basic/,stubs/e3bf.interop | 0 {c64 => src}/basic/,stubs/e453.interop | 0 {c64 => src}/basic/,stubs/e453.rvect.s | 0 .../,stubs_math/a9c4.convert_FAC1_to_INT.s | 0 {c64 => src}/basic/,stubs_math/a9c4.interop | 0 {c64 => src}/basic/,stubs_math/aabc.interop | 0 .../basic/,stubs_math/aabc.print_FAC1.s | 0 .../basic/,stubs_math/af7b.compute_TI.s | 0 {c64 => src}/basic/,stubs_math/af7b.interop | 0 {c64 => src}/basic/,stubs_math/af7e.interop | 0 .../basic/,stubs_math/af7e.math_stub.s | 0 {c64 => src}/basic/,stubs_math/af87.interop | 0 .../basic/,stubs_math/af87.math_stub.s | 0 .../basic/,stubs_math/af9a.compute_ST.s | 0 {c64 => src}/basic/,stubs_math/af9a.interop | 0 {c64 => src}/basic/,stubs_math/b1aa.FACINX.s | 0 {c64 => src}/basic/,stubs_math/b1aa.interop | 0 .../,stubs_math/b1bf.convert_FAC1_to_s16.s | 0 {c64 => src}/basic/,stubs_math/b1bf.interop | 0 {c64 => src}/basic/,stubs_math/b391.GIVAYF.s | 0 {c64 => src}/basic/,stubs_math/b391.interop | 0 .../,stubs_math/b3a2.convert_Y_to_FAC1.s | 0 {c64 => src}/basic/,stubs_math/b3a2.interop | 0 .../,stubs_math/b794.convert_A_to_FAC1.s | 0 {c64 => src}/basic/,stubs_math/b794.interop | 0 {c64 => src}/basic/,stubs_math/b7b5.STRVAL.s | 0 {c64 => src}/basic/,stubs_math/b7b5.interop | 0 .../,stubs_math/b7f7.convert_FAC1_to_ADDR.s | 0 {c64 => src}/basic/,stubs_math/b7f7.interop | 0 {c64 => src}/basic/,stubs_math/b947.interop | 0 .../,stubs_math/b947.inv_FAC1_mantissa.s | 0 {c64 => src}/basic/,stubs_math/b9ea.interop | 0 .../basic/,stubs_math/b9ea.log_FAC1.s | 0 .../,stubs_math/ba90.get_FAC2_via_INDEX.s | 0 {c64 => src}/basic/,stubs_math/ba90.interop | 0 .../,stubs_math/bba6.get_FAC1_via_INDEX.s | 0 {c64 => src}/basic/,stubs_math/bba6.interop | 0 {c64 => src}/basic/,stubs_math/bc39.interop | 0 .../basic/,stubs_math/bc39.sgn_FAC1.s | 0 .../,stubs_math/bc3c.convert_A_to_FAC1.s | 0 {c64 => src}/basic/,stubs_math/bc3c.interop | 0 .../,stubs_math/bc44.convert_i16_to_FAC1.s | 0 {c64 => src}/basic/,stubs_math/bc44.interop | 0 .../basic/,stubs_math/bc58.abs_FAC1.s | 0 {c64 => src}/basic/,stubs_math/bc58.interop | 0 {c64 => src}/basic/,stubs_math/bc5b.FCOMP.s | 0 {c64 => src}/basic/,stubs_math/bc5b.interop | 0 {c64 => src}/basic/,stubs_math/bc9b.QINT.s | 0 {c64 => src}/basic/,stubs_math/bc9b.interop | 0 .../basic/,stubs_math/bccc.int_FAC1.s | 0 {c64 => src}/basic/,stubs_math/bccc.interop | 0 {c64 => src}/basic/,stubs_math/bcf3.FIN.s | 0 {c64 => src}/basic/,stubs_math/bcf3.interop | 0 {c64 => src}/basic/,stubs_math/bd7e.FINLOG.s | 0 {c64 => src}/basic/,stubs_math/bd7e.interop | 0 {c64 => src}/basic/,stubs_math/bddd.FOUT.s | 0 {c64 => src}/basic/,stubs_math/bddd.interop | 0 {c64 => src}/basic/,stubs_math/bf74.interop | 0 .../basic/,stubs_math/bf74.sqr_FAC2.s | 0 {c64 => src}/basic/,stubs_math/bf7b.interop | 0 .../basic/,stubs_math/bf7b.pwr_FAC2_FAC1.s | 0 .../basic/,stubs_math/bfed.exp_FAC1.s | 0 {c64 => src}/basic/,stubs_math/bfed.interop | 0 {c64 => src}/basic/,stubs_math/e043.interop | 0 .../basic/,stubs_math/e043.poly1_FAC1.s | 0 {c64 => src}/basic/,stubs_math/e059.interop | 0 .../basic/,stubs_math/e059.poly2_FAC1.s | 0 .../basic/,stubs_math/e264.cos_FAC1.s | 0 {c64 => src}/basic/,stubs_math/e264.interop | 0 {c64 => src}/basic/,stubs_math/e26b.interop | 0 .../basic/,stubs_math/e26b.sin_FAC1.s | 0 {c64 => src}/basic/,stubs_math/e2b4.interop | 0 .../basic/,stubs_math/e2b4.tan_FAC1.s | 0 .../basic/,stubs_math/e30e.atn_FAC1.s | 0 {c64 => src}/basic/,stubs_math/e30e.interop | 0 {c64 => src}/basic/a533.interop | 0 {c64 => src}/basic/a533.linkprg.s | 0 {c64 => src}/basic/a68e.interop | 0 {c64 => src}/basic/a68e.runc.s | 0 {c64 => src}/basic/a7ae.interop | 0 {c64 => src}/basic/a7ae.newstt.s | 0 {c64 => src}/basic/ab1e.strout.s | 0 {c64 => src}/basic/assets/packed_as_1n.s | 0 {c64 => src}/basic/assets/packed_as_3n.s | 0 {c64 => src}/basic/assets/packed_dictionary.s | 0 {c64 => src}/basic/assets/packed_errors.s | 0 .../basic/assets/packed_keywords_CC.s | 0 .../basic/assets/packed_keywords_CD.s | 0 .../basic/assets/packed_keywords_V2.s | 0 {c64 => src}/basic/assets/packed_misc.s | 0 .../basic/basic_commands/cmd__jumptable.s | 0 .../basic/basic_commands/cmd__unimplemented.s | 0 {c64 => src}/basic/basic_commands/cmd_clr.s | 0 {c64 => src}/basic/basic_commands/cmd_list.s | 0 .../basic/basic_commands/cmd_load_verify.s | 0 {c64 => src}/basic/basic_commands/cmd_new.s | 0 {c64 => src}/basic/basic_commands/cmd_print.s | 0 {c64 => src}/basic/basic_commands/cmd_rem.s | 0 .../basic/basic_commands/cmd_run_goto.s | 0 {c64 => src}/basic/basic_commands/cmd_save.s | 0 .../basic/basic_commands/cmd_stop_end.s | 0 {c64 => src}/basic/basic_commands/cmd_sys.s | 0 .../basic_commands/helper_load_fetch_devnum.s | 0 .../helper_load_fetch_filename.s | 0 .../helper_load_fetch_secondary.s | 0 .../basic_commands/helper_load_init_param.s | 0 .../basic_commands/helper_load_setnam_any.s | 0 .../basic_commands_CC/cmd__jumptable_CC.s | 0 .../basic_commands_CC/cmd_bload_bverify.s | 0 .../basic/basic_commands_CC/cmd_bsave.s | 0 .../basic/basic_commands_CC/cmd_merge.s | 0 .../helper_bload_fetch_address.s | 0 .../helper_bload_fetch_filename.s | 0 .../basic_commands_CD/cmd__jumptable_CD.s | 0 .../basic/basic_commands_CD/cmd_fast_slow.s | 0 {c64 => src}/basic/basic_delete_line.s | 0 {c64 => src}/basic/basic_do_new.s | 0 {c64 => src}/basic/basic_find_line.s | 0 {c64 => src}/basic/basic_find_next_line.s | 0 .../basic/basic_follow_link_to_next_line.s | 0 .../basic/basic_functions/fun__jumptable.s | 0 .../basic_functions/fun__unimplemented.s | 0 {c64 => src}/basic/basic_insert_line.s | 0 {c64 => src}/basic/basic_main_loop.s | 0 .../basic/basic_operators/oper__jumptable.s | 0 {c64 => src}/basic/basic_operators/oper_add.s | 0 {c64 => src}/basic/basic_operators/oper_and.s | 0 .../basic/basic_operators/oper_cmp_eq.s | 0 .../basic/basic_operators/oper_cmp_gt.s | 0 .../basic/basic_operators/oper_cmp_gteq.s | 0 .../basic/basic_operators/oper_cmp_lt.s | 0 .../basic/basic_operators/oper_cmp_lteq.s | 0 .../basic/basic_operators/oper_cmp_neq.s | 0 {c64 => src}/basic/basic_operators/oper_div.s | 0 {c64 => src}/basic/basic_operators/oper_mul.s | 0 {c64 => src}/basic/basic_operators/oper_or.s | 0 {c64 => src}/basic/basic_operators/oper_pow.s | 0 {c64 => src}/basic/basic_operators/oper_sub.s | 0 .../basic/basic_operators/oper_unary_minus.s | 0 .../basic/basic_operators/oper_unary_not.s | 0 {c64 => src}/basic/basic_parse_line_number.s | 0 {c64 => src}/basic/basic_shift_mem_down.s | 0 {c64 => src}/basic/basic_shift_mem_up.s | 0 {c64 => src}/basic/basic_vector_defaults.s | 0 {c64 => src}/basic/bdcd.interop | 0 {c64 => src}/basic/bdcd.linprt.s | 0 .../board_m65/4000.mega65_vectable_basic_1.s | 0 {c64 => src}/basic/board_m65/mega65_imports.s | 0 .../basic/board_m65/mega65_map_helpers.s | 0 {c64 => src}/basic/board_m65/mega65_proxies.s | 0 {c64 => src}/basic/board_x16/cx16_dummy.s | 0 {c64 => src}/basic/board_x16/cx16_stubs.s | 0 {c64 => src}/basic/c000.skip_gap.s | 0 {c64 => src}/basic/engine/ad9e.frmevl.s | 0 {c64 => src}/basic/engine/ad9e.interop | 0 {c64 => src}/basic/engine/alloc_temp_string.s | 0 {c64 => src}/basic/engine/do_error.s | 0 .../basic/engine/end_of_statement_check.s | 0 .../basic/engine/execute_line_statements.s | 0 {c64 => src}/basic/engine/fetch_character.s | 0 {c64 => src}/basic/engine/fetch_operator.s | 0 {c64 => src}/basic/engine/fetch_uint8.s | 0 {c64 => src}/basic/engine/init_oldtxt.s | 0 {c64 => src}/basic/engine/injest_comma.s | 0 {c64 => src}/basic/engine/injest_spaces.s | 0 .../basic/engine/unconsume_character.s | 0 {c64 => src}/basic/fac1_mul.s | 0 .../basic/init/a000.cold_start_vector.s | 0 .../basic/init/a002.warm_start_vector.s | 0 .../basic/init/basic_cold_start_internal.s | 0 .../basic/init/basic_warm_start_internal.s | 0 .../basic/init/e394.basic_cold_start.s | 0 {c64 => src}/basic/init/e394.interop | 0 .../basic/init/e3b7.basic_warm_start.jmp.s | 0 {c64 => src}/basic/init/e3b7.interop | 0 {c64 => src}/basic/init/e422.initmsg.jmp.s | 0 {c64 => src}/basic/init/e422.interop | 0 {c64 => src}/basic/init/initmsg_bytes_free.s | 0 {c64 => src}/basic/init/initmsg_real.s | 0 {c64 => src}/basic/init/startup_banner.s | 0 {c64 => src}/basic/injest_number.s | 0 {c64 => src}/basic/math/add_FAC2_FAC1_sub.s | 0 {c64 => src}/basic/math/add_align_exponents.s | 0 {c64 => src}/basic/math/b849.add_HALF_FAC1.s | 0 {c64 => src}/basic/math/b849.interop | 0 {c64 => src}/basic/math/b850.interop | 0 {c64 => src}/basic/math/b850.sub_MEM_FAC1.s | 0 {c64 => src}/basic/math/b853.interop | 0 {c64 => src}/basic/math/b853.sub_FAC2_FAC1.s | 0 .../basic/math/b862.add_align_exponent.jmp.s | 0 {c64 => src}/basic/math/b862.interop | 0 {c64 => src}/basic/math/b867.add_MEM_FAC1.s | 0 {c64 => src}/basic/math/b867.interop | 0 {c64 => src}/basic/math/b86a.add_FAC2_FAC1.s | 0 {c64 => src}/basic/math/b86a.interop | 0 {c64 => src}/basic/math/b8fe.interop | 0 .../basic/math/b8fe.normal_FAC1.jmp.s | 0 {c64 => src}/basic/math/ba28.interop | 0 .../basic/math/ba28.mul_MEM_FAC1.jmp.s | 0 {c64 => src}/basic/math/ba2b.interop | 0 {c64 => src}/basic/math/ba2b.mul_FAC2_FAC1.s | 0 {c64 => src}/basic/math/ba8c.interop | 0 .../basic/math/ba8c.mov_MEM_FAC2.jmp.s | 0 {c64 => src}/basic/math/bae2.interop | 0 {c64 => src}/basic/math/bae2.mul10_FAC1.s | 0 {c64 => src}/basic/math/bafe.div10_FAC1_p.s | 0 {c64 => src}/basic/math/bafe.interop | 0 {c64 => src}/basic/math/bb0f.div_MEM_FAC1.s | 0 {c64 => src}/basic/math/bb0f.interop | 0 {c64 => src}/basic/math/bb12.div_FAC2_FAC1.s | 0 {c64 => src}/basic/math/bb12.interop | 0 {c64 => src}/basic/math/bc1b.interop | 0 {c64 => src}/basic/math/bc1b.round_FAC1.jmp.s | 0 {c64 => src}/basic/math/bc2b.interop | 0 {c64 => src}/basic/math/bc2b.sgn_FAC1_A.s | 0 {c64 => src}/basic/math/bf71.interop | 0 {c64 => src}/basic/math/bf71.sqr_FAC1.s | 0 {c64 => src}/basic/math/bf78.interop | 0 {c64 => src}/basic/math/bf78.pwr_FAC2_MEM.s | 0 {c64 => src}/basic/math/bfb4.interop | 0 .../basic/math/bfb4.toggle_sign_FAC1.s | 0 {c64 => src}/basic/math/div_FAC1_denorm.s | 0 {c64 => src}/basic/math/div_mantissas.s | 0 {c64 => src}/basic/math/e097.interop | 0 {c64 => src}/basic/math/e097.rnd_FAC1.s | 0 {c64 => src}/basic/math/e09a.interop | 0 {c64 => src}/basic/math/e09a.rnd_A.s | 0 {c64 => src}/basic/math/e0be.interop | 0 {c64 => src}/basic/math/e0be.rnd_generate.s | 0 {c64 => src}/basic/math/mul10_FAC1_mul2.s | 0 {c64 => src}/basic/math/mul_FAC2_FAC1.s | 0 {c64 => src}/basic/math/mul_FAC2_FAC1_8x8.s | 0 {c64 => src}/basic/math/mul_FAC2_FAC1_shift.s | 0 .../basic/math/muldiv_RESHO_helpers.s | 0 {c64 => src}/basic/math/normal_FAC1.s | 0 {c64 => src}/basic/math/rnd_seed_from_FAC1.s | 0 {c64 => src}/basic/math/rnd_seed_init.s | 0 {c64 => src}/basic/math/round_FAC1.s | 0 .../basic/math_consts/aea8.const_PI.s | 0 {c64 => src}/basic/math_consts/aea8.interop | 0 .../basic/math_consts/b1a5.const_NEG_32768.s | 0 {c64 => src}/basic/math_consts/b1a5.interop | 0 .../basic/math_consts/b9bc.const_ONE.s | 0 {c64 => src}/basic/math_consts/b9bc.interop | 0 .../basic/math_consts/b9d6.const_INV_SQR_2.s | 0 {c64 => src}/basic/math_consts/b9d6.interop | 0 .../basic/math_consts/b9db.const_SQR_2.s | 0 {c64 => src}/basic/math_consts/b9db.interop | 0 .../basic/math_consts/b9e0.const_NEG_HALF.s | 0 {c64 => src}/basic/math_consts/b9e0.interop | 0 .../basic/math_consts/b9e5.const_LOG_2.s | 0 {c64 => src}/basic/math_consts/b9e5.interop | 0 .../basic/math_consts/baf9.const_TEN.s | 0 {c64 => src}/basic/math_consts/baf9.interop | 0 .../basic/math_consts/bf11.const_HALF.s | 0 {c64 => src}/basic/math_consts/bf11.interop | 0 .../basic/math_consts/bfbf.const_INV_LOG_2.s | 0 {c64 => src}/basic/math_consts/bfbf.interop | 0 .../basic/math_consts/bfe8.const_ONE.s | 0 {c64 => src}/basic/math_consts/bfe8.interop | 0 .../basic/math_consts/e2e0.const_HALF_PI.s | 0 {c64 => src}/basic/math_consts/e2e0.interop | 0 .../basic/math_consts/e2e5.const_DOUBLE_PI.s | 0 {c64 => src}/basic/math_consts/e2e5.interop | 0 .../basic/math_consts/e2ea.const_QUARTER.s | 0 {c64 => src}/basic/math_consts/e2ea.interop | 0 .../basic/math_consts/e309.const_DOUBLE_PI.s | 0 {c64 => src}/basic/math_consts/e309.interop | 0 {c64 => src}/basic/math_mov/bba2.interop | 0 .../basic/math_mov/bba2.mov_MEM_FAC1.jmp.s | 0 {c64 => src}/basic/math_mov/bbc7.interop | 0 .../basic/math_mov/bbc7.mov_r_FAC1_TMP2.s | 0 {c64 => src}/basic/math_mov/bbca.interop | 0 .../basic/math_mov/bbca.mov_r_FAC1_TMP1.s | 0 {c64 => src}/basic/math_mov/bbd0.interop | 0 .../basic/math_mov/bbd0.mov_r_FAC1_VAR.s | 0 {c64 => src}/basic/math_mov/bbd4.interop | 0 .../basic/math_mov/bbd4.mov_r_FAC1_MEM.s | 0 {c64 => src}/basic/math_mov/bbfc.interop | 0 .../basic/math_mov/bbfc.mov_FAC2_FAC1.s | 0 {c64 => src}/basic/math_mov/bc0c.interop | 0 .../basic/math_mov/bc0c.mov_r_FAC1_FAC2.s | 0 {c64 => src}/basic/math_mov/bc0f.interop | 0 .../basic/math_mov/bc0f.mov_FAC1_FAC2.jmp.s | 0 {c64 => src}/basic/math_mov/mov_FAC1_FAC2.s | 0 {c64 => src}/basic/math_mov/mov_FAC1_MEM.s | 0 {c64 => src}/basic/math_mov/mov_FAC2_FAC1.s | 0 {c64 => src}/basic/math_mov/mov_MEM_FAC1.s | 0 {c64 => src}/basic/math_mov/mov_MEM_FAC2.s | 0 {c64 => src}/basic/math_mov/mov_r_FAC1_TMP1.s | 0 {c64 => src}/basic/math_mov/mov_r_FAC1_TMP2.s | 0 .../basic/memory/shift_mem_down_38k.s | 0 {c64 => src}/basic/memory/shift_mem_up_38k.s | 0 .../basic/memory/under_rom_routines_46k_50k.s | 0 .../basic/memory/under_rom_routines_60k.s | 0 .../basic/peek_line_pointer_null_check.s | 0 {c64 => src}/basic/print/list_single_line.s | 0 {c64 => src}/basic/print/print_features.s | 0 {c64 => src}/basic/print/print_integer.s | 0 .../basic/print/print_packed_dict_string.s | 0 .../basic/print/print_packed_freq_string.s | 0 .../basic/print/print_packed_search.s | 0 .../basic/rom_revision/a004.identifier.s | 0 {c64 => src}/basic/rom_revision/a483.interop | 0 {c64 => src}/basic/rom_revision/bf52.interop | 0 .../rom_revision/bf52.rom_revision_basic.s | 0 {c64 => src}/basic/rom_revision/e4b7.interop | 0 .../rom_revision/e4b7.rom_revision_kernal.s | 0 {c64 => src}/basic/select_device.s | 0 {c64 => src}/basic/tokenizer/tk_cut_away.s | 0 {c64 => src}/basic/tokenizer/tk_pack.s | 0 {c64 => src}/basic/tokenizer/tk_search.s | 0 {c64 => src}/basic/tokenizer/tk_shorten.s | 0 {c64 => src}/basic/tokenizer/tokenise_line.s | 0 {c64 => src}/basic/wedge/wedge_dos.s | 0 {c64 => src}/basic/wedge/wedge_tape.s | 0 .../kernal/,disabled/,aliases_ultimate64.s | 0 {c64 => src}/kernal/,disabled/u64_load.s | 0 .../kernal/,stubs/e6b6.advance_cursor.s | 0 {c64 => src}/kernal/,stubs/e6b6.interop | 0 {c64 => src}/kernal/,stubs/e701.interop | 0 .../kernal/,stubs/e701.previous_line.s | 0 .../kernal/,stubs/e716.chrout_screen.s | 0 {c64 => src}/kernal/,stubs/e716.interop | 0 .../kernal/,stubs/e96c.insert_line_at_top.s | 0 {c64 => src}/kernal/,stubs/e96c.interop | 0 {c64 => src}/kernal/,stubs/f3f6.interop | 0 {c64 => src}/kernal/,stubs/f3f6.unknown.s | 0 {c64 => src}/kernal/,stubs/f646.iec_close.s | 0 {c64 => src}/kernal/,stubs/f646.interop | 0 {c64 => src}/kernal/,stubs/fd90.interop | 0 {c64 => src}/kernal/,stubs/fd90.unknown.s | 0 .../kernal/assets/cartridge_signature.s | 0 .../kernal/assets/e8da.colour_codes.s | 0 {c64 => src}/kernal/assets/e8da.interop | 0 {c64 => src}/kernal/assets/fd30.interop | 0 .../kernal/assets/fd30.vector_defaults.s | 0 {c64 => src}/kernal/assets/filename_any.s | 0 {c64 => src}/kernal/assets/irq_timing_hi.s | 0 {c64 => src}/kernal/assets/irq_timing_lo.s | 0 {c64 => src}/kernal/assets/kernal_messages.s | 0 .../kernal/assets/programmable_keys.s | 0 {c64 => src}/kernal/board_m65/4000.interop | 0 .../board_m65/4000.mega65_vectable_kernal_1.s | 0 .../kernal/board_m65/mega65_imports.s | 0 .../kernal/board_m65/mega65_map_helpers.s | 0 .../kernal/board_m65/mega65_proxies.s | 0 .../kernal/board_m65/mega65_redirect_tape.s | 0 .../board_m65/mega65_tape_normal_byte_store.s | 0 {c64 => src}/kernal/board_m65/mega65_unhide.s | 0 {c64 => src}/kernal/board_x16/cx16_dummy.s | 0 {c64 => src}/kernal/board_x16/cx16_stubs.s | 0 {c64 => src}/kernal/errors.s | 0 {c64 => src}/kernal/iec/acptr.s | 0 {c64 => src}/kernal/iec/chkin_iec.s | 0 {c64 => src}/kernal/iec/chrin_iec.s | 0 {c64 => src}/kernal/iec/chrout_iec.s | 0 {c64 => src}/kernal/iec/ciout.s | 0 {c64 => src}/kernal/iec/ckout_iec.s | 0 {c64 => src}/kernal/iec/close_iec.s | 0 {c64 => src}/kernal/iec/clrchn_iec.s | 0 {c64 => src}/kernal/iec/iec_check_devnum.s | 0 {c64 => src}/kernal/iec/iec_close_load.s | 0 {c64 => src}/kernal/iec/iec_cmd_close.s | 0 {c64 => src}/kernal/iec/iec_cmd_open.s | 0 {c64 => src}/kernal/iec/iec_pull_release.s | 0 {c64 => src}/kernal/iec/iec_return.s | 0 {c64 => src}/kernal/iec/iec_rx_byte.s | 0 {c64 => src}/kernal/iec/iec_rx_check_eoi.s | 0 {c64 => src}/kernal/iec/iec_send_file_name.s | 0 {c64 => src}/kernal/iec/iec_set_idle.s | 0 .../kernal/iec/iec_turnaround_to_listen.s | 0 .../kernal/iec/iec_turnaround_to_talk.s | 0 {c64 => src}/kernal/iec/iec_tx_byte.s | 0 {c64 => src}/kernal/iec/iec_tx_command.s | 0 .../kernal/iec/iec_tx_command_finalize.s | 0 {c64 => src}/kernal/iec/iec_tx_flush.s | 0 {c64 => src}/kernal/iec/iec_update_eal_by_y.s | 0 {c64 => src}/kernal/iec/iec_wait1ms.s | 0 {c64 => src}/kernal/iec/iec_wait20us.s | 0 {c64 => src}/kernal/iec/iec_wait60us.s | 0 .../kernal/iec/iec_wait_for_clk_release.s | 0 .../kernal/iec/iec_wait_for_data_pull.s | 0 .../kernal/iec/iec_wait_for_data_release.s | 0 {c64 => src}/kernal/iec/listen.s | 0 {c64 => src}/kernal/iec/load_iec.s | 0 {c64 => src}/kernal/iec/open_iec.s | 0 {c64 => src}/kernal/iec/save_iec.s | 0 {c64 => src}/kernal/iec/second.s | 0 {c64 => src}/kernal/iec/talk.s | 0 {c64 => src}/kernal/iec/tksa.s | 0 {c64 => src}/kernal/iec/unlsn.s | 0 {c64 => src}/kernal/iec/untlk.s | 0 .../kernal/iec_fast/burst_cia1_advertise.s | 0 .../kernal/iec_fast/burst_cia2_advertise.s | 0 .../kernal/iec_fast/burst_m65_advertise.s | 0 .../kernal/iec_fast/dolphindos_detect.s | 0 .../kernal/iec_fast/dolphindos_load.s | 0 .../kernal/iec_fast/jiffydos_bittable.s | 0 .../kernal/iec_fast/jiffydos_detect.s | 0 {c64 => src}/kernal/iec_fast/jiffydos_load.s | 0 .../kernal/iec_fast/jiffydos_prepare.s | 0 .../kernal/iec_fast/jiffydos_rx_byte.s | 0 .../kernal/iec_fast/jiffydos_tx_byte.s | 0 .../kernal/iec_fast/jiffydos_wait_line.s | 0 {c64 => src}/kernal/init/cartridge_check.s | 0 .../kernal/init/cint_screen_keyboard.s | 0 {c64 => src}/kernal/init/e518.cint_legacy.s | 0 {c64 => src}/kernal/init/e518.interop | 0 {c64 => src}/kernal/init/e5a0.setup_vicii.s | 0 .../kernal/init/fce2.hw_entry_reset.s | 0 {c64 => src}/kernal/init/fce2.interop | 0 {c64 => src}/kernal/init/fd50.interop | 0 {c64 => src}/kernal/init/fd50.ramtas.s | 0 {c64 => src}/kernal/init/fda3.ioinit.s | 0 {c64 => src}/kernal/init/ff5b.cint.s | 0 {c64 => src}/kernal/init/ff5b.interop | 0 {c64 => src}/kernal/init/fffc.interop | 0 {c64 => src}/kernal/init/fffc.vector_reset.s | 0 {c64 => src}/kernal/init/setup_pal_ntsc.s | 0 .../interrupts/ea31.default_irq_handler.s | 0 {c64 => src}/kernal/interrupts/ea31.interop | 0 .../ea7e.ack_cia1_return_from_interrupt.s | 0 .../interrupts/ea81.return_from_interrupt.s | 0 .../interrupts/fe47.default_nmi_handler.s | 0 {c64 => src}/kernal/interrupts/fe47.interop | 0 .../interrupts/fe66.default_brk_handler.s | 0 {c64 => src}/kernal/interrupts/fe66.interop | 0 {c64 => src}/kernal/interrupts/fffa.interop | 0 .../kernal/interrupts/fffa.vector_nmi.s | 0 {c64 => src}/kernal/interrupts/fffe.interop | 0 .../kernal/interrupts/fffe.vector_irq.s | 0 {c64 => src}/kernal/interrupts/hw_entry_irq.s | 0 {c64 => src}/kernal/interrupts/hw_entry_nmi.s | 0 {c64 => src}/kernal/interrupts/nmi_lock.s | 0 {c64 => src}/kernal/iostack/chkinout.s | 0 {c64 => src}/kernal/iostack/clall_real.s | 0 {c64 => src}/kernal/iostack/e50a.interop | 0 {c64 => src}/kernal/iostack/e50a.plot.s | 0 {c64 => src}/kernal/iostack/f13e.getin.s | 0 {c64 => src}/kernal/iostack/f13e.interop | 0 {c64 => src}/kernal/iostack/f157.chrin.s | 0 {c64 => src}/kernal/iostack/f157.interop | 0 {c64 => src}/kernal/iostack/f1ca.chrout.s | 0 {c64 => src}/kernal/iostack/f1ca.interop | 0 {c64 => src}/kernal/iostack/f20e.chkin.s | 0 {c64 => src}/kernal/iostack/f20e.interop | 0 {c64 => src}/kernal/iostack/f250.ckout.s | 0 {c64 => src}/kernal/iostack/f250.interop | 0 {c64 => src}/kernal/iostack/f291.close.s | 0 {c64 => src}/kernal/iostack/f291.interop | 0 {c64 => src}/kernal/iostack/f32f.clall.jmp.s | 0 {c64 => src}/kernal/iostack/f32f.interop | 0 {c64 => src}/kernal/iostack/f333.clrchn.s | 0 {c64 => src}/kernal/iostack/f333.interop | 0 {c64 => src}/kernal/iostack/f34a.interop | 0 {c64 => src}/kernal/iostack/f34a.open.s | 0 {c64 => src}/kernal/iostack/f49e.interop | 0 {c64 => src}/kernal/iostack/f49e.load_prep.s | 0 {c64 => src}/kernal/iostack/f4a5.interop | 0 {c64 => src}/kernal/iostack/f4a5.load.s | 0 {c64 => src}/kernal/iostack/f5dd.interop | 0 {c64 => src}/kernal/iostack/f5dd.save_prep.s | 0 {c64 => src}/kernal/iostack/f5ed.interop | 0 {c64 => src}/kernal/iostack/f5ed.save.s | 0 {c64 => src}/kernal/iostack/f6ed.interop | 0 {c64 => src}/kernal/iostack/findfls.s | 0 {c64 => src}/kernal/iostack/getin_real.s | 0 .../kernal/iostack/load_save_common.s | 0 .../kernal/iostack/pop_keyboard_buffer.s | 0 {c64 => src}/kernal/iostack/readst.s | 0 {c64 => src}/kernal/iostack/setfls.s | 0 {c64 => src}/kernal/iostack/setmsg.s | 0 {c64 => src}/kernal/iostack/setnam.s | 0 {c64 => src}/kernal/iostack/settmo.s | 0 {c64 => src}/kernal/jumptable/ff81.jcint.s | 0 {c64 => src}/kernal/jumptable/ff84.jioinit.s | 0 {c64 => src}/kernal/jumptable/ff87.jramtas.s | 0 {c64 => src}/kernal/jumptable/ff8a.jrestor.s | 0 {c64 => src}/kernal/jumptable/ff8d.jvector.s | 0 {c64 => src}/kernal/jumptable/ff90.jsetmsg.s | 0 {c64 => src}/kernal/jumptable/ff93.jsecond.s | 0 {c64 => src}/kernal/jumptable/ff96.jtksa.s | 0 {c64 => src}/kernal/jumptable/ff99.jmemtop.s | 0 {c64 => src}/kernal/jumptable/ff9c.jmembot.s | 0 {c64 => src}/kernal/jumptable/ff9f.jscnkey.s | 0 {c64 => src}/kernal/jumptable/ffa2.jsettmo.s | 0 {c64 => src}/kernal/jumptable/ffa5.jacptr.s | 0 {c64 => src}/kernal/jumptable/ffa8.jciout.s | 0 {c64 => src}/kernal/jumptable/ffab.juntlk.s | 0 {c64 => src}/kernal/jumptable/ffae.junlsn.s | 0 {c64 => src}/kernal/jumptable/ffb1.jlisten.s | 0 {c64 => src}/kernal/jumptable/ffb4.jtalk.s | 0 {c64 => src}/kernal/jumptable/ffb7.jreadst.s | 0 {c64 => src}/kernal/jumptable/ffba.jsetfls.s | 0 {c64 => src}/kernal/jumptable/ffbd.jsetnam.s | 0 {c64 => src}/kernal/jumptable/ffc0.jopen.s | 0 {c64 => src}/kernal/jumptable/ffc3.jclose.s | 0 {c64 => src}/kernal/jumptable/ffc6.jchkin.s | 0 {c64 => src}/kernal/jumptable/ffc9.jckout.s | 0 {c64 => src}/kernal/jumptable/ffcc.jclrchn.s | 0 {c64 => src}/kernal/jumptable/ffcf.jchrin.s | 0 {c64 => src}/kernal/jumptable/ffd2.jchrout.s | 0 {c64 => src}/kernal/jumptable/ffd5.jload.s | 0 {c64 => src}/kernal/jumptable/ffd8.jsave.s | 0 {c64 => src}/kernal/jumptable/ffdb.jsettim.s | 0 {c64 => src}/kernal/jumptable/ffde.jrdtim.s | 0 {c64 => src}/kernal/jumptable/ffe1.jstop.s | 0 {c64 => src}/kernal/jumptable/ffe4.jgetin.s | 0 {c64 => src}/kernal/jumptable/ffe7.jclall.s | 0 {c64 => src}/kernal/jumptable/ffea.judtim.s | 0 {c64 => src}/kernal/jumptable/ffed.jscreen.s | 0 {c64 => src}/kernal/jumptable/fff0.jplot.s | 0 {c64 => src}/kernal/jumptable/fff3.jiobase.s | 0 {c64 => src}/kernal/keyboard/chrin_keyboard.s | 0 .../kernal/keyboard/f142.getin_keyboard.s | 0 {c64 => src}/kernal/keyboard/f142.interop | 0 {c64 => src}/kernal/keyboard/f6ed.stop.s | 0 {c64 => src}/kernal/keyboard/kb_matrix.s | 0 {c64 => src}/kernal/keyboard/kb_matrix_128.s | 0 {c64 => src}/kernal/keyboard/kb_matrix_65.s | 0 .../kernal/keyboard/kb_matrix_alwaysrepeat.s | 0 .../kernal/keyboard/kb_matrix_bucky.s | 0 .../kernal/keyboard/kb_matrix_bucky_filter.s | 0 {c64 => src}/kernal/keyboard/kb_matrix_joy.s | 0 .../kernal/keyboard/kb_matrix_lookup.s | 0 .../kernal/keyboard/kb_matrix_lookup_legacy.s | 0 .../kernal/keyboard/kb_matrix_row_keys.s | 0 .../kernal/keyboard/kb_matrix_row_offsets.s | 0 .../kernal/keyboard/keyboard_disconnect.s | 0 {c64 => src}/kernal/keyboard/scnkey.s | 0 {c64 => src}/kernal/keyboard/scnkey_128.s | 0 {c64 => src}/kernal/keyboard/scnkey_65.s | 0 {c64 => src}/kernal/keyboard/scnkey_legacy.s | 0 .../kernal/keyboard/scnkey_set_keytab.s | 0 {c64 => src}/kernal/keyboard/udtim_keyboard.s | 0 {c64 => src}/kernal/memory/fd15.interop | 0 {c64 => src}/kernal/memory/fd15.restor.s | 0 {c64 => src}/kernal/memory/fe25.interop | 0 {c64 => src}/kernal/memory/fe25.memtop.s | 0 {c64 => src}/kernal/memory/membot.s | 0 .../memory/under_rom_routines_46k_50k.s | 0 .../kernal/memory/under_rom_routines_60k.s | 0 {c64 => src}/kernal/memory/vector_real.s | 0 {c64 => src}/kernal/panic.s | 0 {c64 => src}/kernal/print/print_hex_byte.s | 0 .../kernal/print/print_kernal_message.s | 0 {c64 => src}/kernal/print/print_return.s | 0 {c64 => src}/kernal/print/print_space.s | 0 {c64 => src}/kernal/print/printf.s | 0 {c64 => src}/kernal/public_interfaces.md | 0 {c64 => src}/kernal/rom_revision/ff80.interop | 0 .../rom_revision/ff80.kernal_revision.s | 0 .../kernal/rs232/chkin_rs232_up2400.s | 0 .../kernal/rs232/chkin_rs232_up9600.s | 0 .../kernal/rs232/chrin_rs232_up2400.s | 0 .../kernal/rs232/chrin_rs232_up9600.s | 0 {c64 => src}/kernal/rs232/chrout_rs232.s | 0 .../kernal/rs232/ckout_rs232_up2400.s | 0 .../kernal/rs232/ckout_rs232_up9600.s | 0 {c64 => src}/kernal/rs232/close_rs232.s | 0 {c64 => src}/kernal/rs232/getin_rs232.s | 0 {c64 => src}/kernal/rs232/open_rs232.s | 0 .../kernal/rs232/rs232_count_channels.s | 0 {c64 => src}/kernal/rs232/up9600_disable.s | 0 {c64 => src}/kernal/rs232/up9600_enable.s | 0 {c64 => src}/kernal/rs232/up9600_ihitab.s | 0 {c64 => src}/kernal/rs232/up9600_ilotab.s | 0 {c64 => src}/kernal/rs232/up9600_irq.s | 0 {c64 => src}/kernal/rs232/up9600_nmi.s | 0 {c64 => src}/kernal/rs232/up9600_rsin.s | 0 {c64 => src}/kernal/rs232/up9600_rsout.s | 0 {c64 => src}/kernal/screen/chrout_screen.s | 0 .../kernal/screen/chrout_screen_clr.s | 0 .../kernal/screen/chrout_screen_control.s | 0 .../kernal/screen/chrout_screen_crsr.s | 0 .../kernal/screen/chrout_screen_del.s | 0 .../kernal/screen/chrout_screen_gfxtxt.s | 0 .../kernal/screen/chrout_screen_home.s | 0 .../kernal/screen/chrout_screen_ins.s | 0 .../screen/chrout_screen_jumptable_codes.s | 0 .../kernal/screen/chrout_screen_quote.s | 0 .../kernal/screen/chrout_screen_return.s | 0 .../kernal/screen/chrout_screen_rvs.s | 0 .../kernal/screen/chrout_screen_shift_onoff.s | 0 .../kernal/screen/chrout_screen_stop.s | 0 .../kernal/screen/chrout_screen_tab.s | 0 {c64 => src}/kernal/screen/cursor.s | 0 {c64 => src}/kernal/screen/cursor_enable.s | 0 {c64 => src}/kernal/screen/cursor_show.s | 0 .../kernal/screen/e544.clear_screen.s | 0 {c64 => src}/kernal/screen/e566.cursor_home.s | 0 {c64 => src}/kernal/screen/e566.interop | 0 {c64 => src}/kernal/screen/e56c.interop | 0 .../screen/e56c.screen_calculate_pointers.s | 0 {c64 => src}/kernal/screen/e8ea.interop | 0 .../kernal/screen/e8ea.screen_scroll_up.s | 0 {c64 => src}/kernal/screen/e9ff.interop | 0 .../kernal/screen/e9ff.screen_clear_line.s | 0 {c64 => src}/kernal/screen/screen.s | 0 .../screen/screen_advance_to_next_line.s | 0 .../kernal/screen/screen_calculate_pnt_user.s | 0 .../screen/screen_calculate_pntr_lnmx.s | 0 .../screen/screen_check_space_ends_line.s | 0 .../kernal/screen/screen_check_toggle_quote.s | 0 .../kernal/screen/screen_code_to_petscii.s | 0 .../kernal/screen/screen_get_cliped_pntr.s | 0 .../screen/screen_get_logical_line_end_ptr.s | 0 .../kernal/screen/screen_grow_logical_line.s | 0 {c64 => src}/kernal/screen/screen_off.s | 0 {c64 => src}/kernal/screen/screen_on.s | 0 .../kernal/screen/screen_preserve_sal_eal.s | 0 .../kernal/screen/screen_restore_sal_eal.s | 0 {c64 => src}/kernal/status.s | 0 {c64 => src}/kernal/tape/load_tape_normal.s | 0 {c64 => src}/kernal/tape/load_tape_turbo.s | 0 {c64 => src}/kernal/tape/tape_common.s | 0 .../kernal/tape/tape_common_autodetect.s | 0 .../kernal/tape/tape_common_clean_sid.s | 0 .../kernal/tape/tape_common_ditch_verify.s | 0 .../kernal/tape/tape_common_get_pulse.s | 0 {c64 => src}/kernal/tape/tape_common_motor.s | 0 .../kernal/tape/tape_common_prepare_cia.s | 0 {c64 => src}/kernal/tape/tape_common_screen.s | 0 {c64 => src}/kernal/tape/tape_head_align.s | 0 .../kernal/tape/tape_head_align_gen_code.s | 0 .../kernal/tape/tape_head_align_get_pulse.s | 0 .../kernal/tape/tape_head_align_help.s | 0 .../kernal/tape/tape_head_align_irq.s | 0 .../kernal/tape/tape_normal_calibrate.s | 0 .../kernal/tape/tape_normal_get_bit.s | 0 .../kernal/tape/tape_normal_get_byte.s | 0 .../kernal/tape/tape_normal_get_data_1.s | 0 .../kernal/tape/tape_normal_get_data_2.s | 0 .../kernal/tape/tape_normal_get_marker.s | 0 .../kernal/tape/tape_normal_get_pilot.s | 0 {c64 => src}/kernal/tape/tape_normal_sync.s | 0 .../kernal/tape/tape_normal_update_checksum.s | 0 .../kernal/tape/tape_turbo_bytestore.s | 0 {c64 => src}/kernal/tape/tape_turbo_get_bit.s | 0 .../kernal/tape/tape_turbo_get_byte.s | 0 {c64 => src}/kernal/tape/tape_turbo_sync.s | 0 .../kernal/tape/tape_turbo_sync_first.s | 0 {c64 => src}/kernal/time/rdtim.s | 0 {c64 => src}/kernal/time/settim.s | 0 {c64 => src}/kernal/time/udtim.s | 0 {c64 => src}/program_traces/BASIC2.trace | 0 {c64 => src}/program_traces/README.md | 0 697 files changed, 56 insertions(+), 56 deletions(-) rename {c64 => src}/,,config_custom.s (100%) rename {c64 => src}/,,config_cx16.s (100%) rename {c64 => src}/,,config_generic.s (100%) rename {c64 => src}/,,config_mega65.s (100%) rename {c64 => src}/,,config_testing.s (100%) rename {c64 => src}/,,config_ultimate64.s (100%) rename {c64 => src}/aliases/,aliases_config.s (100%) rename {c64 => src}/aliases/,aliases_cpu.s (100%) rename {c64 => src}/aliases/,aliases_error_codes.s (100%) rename {c64 => src}/aliases/,aliases_hardware.s (100%) rename {c64 => src}/aliases/,aliases_hardware_cx16.s (100%) rename {c64 => src}/aliases/,aliases_petscii_codes.s (100%) rename {c64 => src}/aliases/,aliases_ram_lowmem.s (100%) rename {c64 => src}/aliases/,aliases_rom_basic.s (100%) rename {c64 => src}/aliases/,aliases_rom_cart.s (100%) rename {c64 => src}/aliases/,aliases_rom_kernal.s (100%) rename {c64 => src}/basic/,aliases.s (100%) rename {c64 => src}/basic/,imports.s (100%) rename {c64 => src}/basic/,stubs/a408.interop (100%) rename {c64 => src}/basic/,stubs/a408.reason.s (100%) rename {c64 => src}/basic/,stubs/a453.interop (100%) rename {c64 => src}/basic/,stubs/a453.unknown.s (100%) rename {c64 => src}/basic/,stubs/a483.main.s (100%) rename {c64 => src}/basic/,stubs/a57c.chrnch.s (100%) rename {c64 => src}/basic/,stubs/a57c.interop (100%) rename {c64 => src}/basic/,stubs/a644.interop (100%) rename {c64 => src}/basic/,stubs/a644.new.s (100%) rename {c64 => src}/basic/,stubs/a659.interop (100%) rename {c64 => src}/basic/,stubs/a659.setcharptr.s (100%) rename {c64 => src}/basic/,stubs/a71a.interop (100%) rename {c64 => src}/basic/,stubs/a71a.qplop.s (100%) rename {c64 => src}/basic/,stubs/a7e4.gone.s (100%) rename {c64 => src}/basic/,stubs/a7e4.interop (100%) rename {c64 => src}/basic/,stubs/ae86.eval.s (100%) rename {c64 => src}/basic/,stubs/ae86.interop (100%) rename {c64 => src}/basic/,stubs/basic_adray1.s (100%) rename {c64 => src}/basic/,stubs/basic_adray2.s (100%) rename {c64 => src}/basic/,stubs/e38b.error.s (100%) rename {c64 => src}/basic/,stubs/e38b.interop (100%) rename {c64 => src}/basic/,stubs/e3bf.init.s (100%) rename {c64 => src}/basic/,stubs/e3bf.interop (100%) rename {c64 => src}/basic/,stubs/e453.interop (100%) rename {c64 => src}/basic/,stubs/e453.rvect.s (100%) rename {c64 => src}/basic/,stubs_math/a9c4.convert_FAC1_to_INT.s (100%) rename {c64 => src}/basic/,stubs_math/a9c4.interop (100%) rename {c64 => src}/basic/,stubs_math/aabc.interop (100%) rename {c64 => src}/basic/,stubs_math/aabc.print_FAC1.s (100%) rename {c64 => src}/basic/,stubs_math/af7b.compute_TI.s (100%) rename {c64 => src}/basic/,stubs_math/af7b.interop (100%) rename {c64 => src}/basic/,stubs_math/af7e.interop (100%) rename {c64 => src}/basic/,stubs_math/af7e.math_stub.s (100%) rename {c64 => src}/basic/,stubs_math/af87.interop (100%) rename {c64 => src}/basic/,stubs_math/af87.math_stub.s (100%) rename {c64 => src}/basic/,stubs_math/af9a.compute_ST.s (100%) rename {c64 => src}/basic/,stubs_math/af9a.interop (100%) rename {c64 => src}/basic/,stubs_math/b1aa.FACINX.s (100%) rename {c64 => src}/basic/,stubs_math/b1aa.interop (100%) rename {c64 => src}/basic/,stubs_math/b1bf.convert_FAC1_to_s16.s (100%) rename {c64 => src}/basic/,stubs_math/b1bf.interop (100%) rename {c64 => src}/basic/,stubs_math/b391.GIVAYF.s (100%) rename {c64 => src}/basic/,stubs_math/b391.interop (100%) rename {c64 => src}/basic/,stubs_math/b3a2.convert_Y_to_FAC1.s (100%) rename {c64 => src}/basic/,stubs_math/b3a2.interop (100%) rename {c64 => src}/basic/,stubs_math/b794.convert_A_to_FAC1.s (100%) rename {c64 => src}/basic/,stubs_math/b794.interop (100%) rename {c64 => src}/basic/,stubs_math/b7b5.STRVAL.s (100%) rename {c64 => src}/basic/,stubs_math/b7b5.interop (100%) rename {c64 => src}/basic/,stubs_math/b7f7.convert_FAC1_to_ADDR.s (100%) rename {c64 => src}/basic/,stubs_math/b7f7.interop (100%) rename {c64 => src}/basic/,stubs_math/b947.interop (100%) rename {c64 => src}/basic/,stubs_math/b947.inv_FAC1_mantissa.s (100%) rename {c64 => src}/basic/,stubs_math/b9ea.interop (100%) rename {c64 => src}/basic/,stubs_math/b9ea.log_FAC1.s (100%) rename {c64 => src}/basic/,stubs_math/ba90.get_FAC2_via_INDEX.s (100%) rename {c64 => src}/basic/,stubs_math/ba90.interop (100%) rename {c64 => src}/basic/,stubs_math/bba6.get_FAC1_via_INDEX.s (100%) rename {c64 => src}/basic/,stubs_math/bba6.interop (100%) rename {c64 => src}/basic/,stubs_math/bc39.interop (100%) rename {c64 => src}/basic/,stubs_math/bc39.sgn_FAC1.s (100%) rename {c64 => src}/basic/,stubs_math/bc3c.convert_A_to_FAC1.s (100%) rename {c64 => src}/basic/,stubs_math/bc3c.interop (100%) rename {c64 => src}/basic/,stubs_math/bc44.convert_i16_to_FAC1.s (100%) rename {c64 => src}/basic/,stubs_math/bc44.interop (100%) rename {c64 => src}/basic/,stubs_math/bc58.abs_FAC1.s (100%) rename {c64 => src}/basic/,stubs_math/bc58.interop (100%) rename {c64 => src}/basic/,stubs_math/bc5b.FCOMP.s (100%) rename {c64 => src}/basic/,stubs_math/bc5b.interop (100%) rename {c64 => src}/basic/,stubs_math/bc9b.QINT.s (100%) rename {c64 => src}/basic/,stubs_math/bc9b.interop (100%) rename {c64 => src}/basic/,stubs_math/bccc.int_FAC1.s (100%) rename {c64 => src}/basic/,stubs_math/bccc.interop (100%) rename {c64 => src}/basic/,stubs_math/bcf3.FIN.s (100%) rename {c64 => src}/basic/,stubs_math/bcf3.interop (100%) rename {c64 => src}/basic/,stubs_math/bd7e.FINLOG.s (100%) rename {c64 => src}/basic/,stubs_math/bd7e.interop (100%) rename {c64 => src}/basic/,stubs_math/bddd.FOUT.s (100%) rename {c64 => src}/basic/,stubs_math/bddd.interop (100%) rename {c64 => src}/basic/,stubs_math/bf74.interop (100%) rename {c64 => src}/basic/,stubs_math/bf74.sqr_FAC2.s (100%) rename {c64 => src}/basic/,stubs_math/bf7b.interop (100%) rename {c64 => src}/basic/,stubs_math/bf7b.pwr_FAC2_FAC1.s (100%) rename {c64 => src}/basic/,stubs_math/bfed.exp_FAC1.s (100%) rename {c64 => src}/basic/,stubs_math/bfed.interop (100%) rename {c64 => src}/basic/,stubs_math/e043.interop (100%) rename {c64 => src}/basic/,stubs_math/e043.poly1_FAC1.s (100%) rename {c64 => src}/basic/,stubs_math/e059.interop (100%) rename {c64 => src}/basic/,stubs_math/e059.poly2_FAC1.s (100%) rename {c64 => src}/basic/,stubs_math/e264.cos_FAC1.s (100%) rename {c64 => src}/basic/,stubs_math/e264.interop (100%) rename {c64 => src}/basic/,stubs_math/e26b.interop (100%) rename {c64 => src}/basic/,stubs_math/e26b.sin_FAC1.s (100%) rename {c64 => src}/basic/,stubs_math/e2b4.interop (100%) rename {c64 => src}/basic/,stubs_math/e2b4.tan_FAC1.s (100%) rename {c64 => src}/basic/,stubs_math/e30e.atn_FAC1.s (100%) rename {c64 => src}/basic/,stubs_math/e30e.interop (100%) rename {c64 => src}/basic/a533.interop (100%) rename {c64 => src}/basic/a533.linkprg.s (100%) rename {c64 => src}/basic/a68e.interop (100%) rename {c64 => src}/basic/a68e.runc.s (100%) rename {c64 => src}/basic/a7ae.interop (100%) rename {c64 => src}/basic/a7ae.newstt.s (100%) rename {c64 => src}/basic/ab1e.strout.s (100%) rename {c64 => src}/basic/assets/packed_as_1n.s (100%) rename {c64 => src}/basic/assets/packed_as_3n.s (100%) rename {c64 => src}/basic/assets/packed_dictionary.s (100%) rename {c64 => src}/basic/assets/packed_errors.s (100%) rename {c64 => src}/basic/assets/packed_keywords_CC.s (100%) rename {c64 => src}/basic/assets/packed_keywords_CD.s (100%) rename {c64 => src}/basic/assets/packed_keywords_V2.s (100%) rename {c64 => src}/basic/assets/packed_misc.s (100%) rename {c64 => src}/basic/basic_commands/cmd__jumptable.s (100%) rename {c64 => src}/basic/basic_commands/cmd__unimplemented.s (100%) rename {c64 => src}/basic/basic_commands/cmd_clr.s (100%) rename {c64 => src}/basic/basic_commands/cmd_list.s (100%) rename {c64 => src}/basic/basic_commands/cmd_load_verify.s (100%) rename {c64 => src}/basic/basic_commands/cmd_new.s (100%) rename {c64 => src}/basic/basic_commands/cmd_print.s (100%) rename {c64 => src}/basic/basic_commands/cmd_rem.s (100%) rename {c64 => src}/basic/basic_commands/cmd_run_goto.s (100%) rename {c64 => src}/basic/basic_commands/cmd_save.s (100%) rename {c64 => src}/basic/basic_commands/cmd_stop_end.s (100%) rename {c64 => src}/basic/basic_commands/cmd_sys.s (100%) rename {c64 => src}/basic/basic_commands/helper_load_fetch_devnum.s (100%) rename {c64 => src}/basic/basic_commands/helper_load_fetch_filename.s (100%) rename {c64 => src}/basic/basic_commands/helper_load_fetch_secondary.s (100%) rename {c64 => src}/basic/basic_commands/helper_load_init_param.s (100%) rename {c64 => src}/basic/basic_commands/helper_load_setnam_any.s (100%) rename {c64 => src}/basic/basic_commands_CC/cmd__jumptable_CC.s (100%) rename {c64 => src}/basic/basic_commands_CC/cmd_bload_bverify.s (100%) rename {c64 => src}/basic/basic_commands_CC/cmd_bsave.s (100%) rename {c64 => src}/basic/basic_commands_CC/cmd_merge.s (100%) rename {c64 => src}/basic/basic_commands_CC/helper_bload_fetch_address.s (100%) rename {c64 => src}/basic/basic_commands_CC/helper_bload_fetch_filename.s (100%) rename {c64 => src}/basic/basic_commands_CD/cmd__jumptable_CD.s (100%) rename {c64 => src}/basic/basic_commands_CD/cmd_fast_slow.s (100%) rename {c64 => src}/basic/basic_delete_line.s (100%) rename {c64 => src}/basic/basic_do_new.s (100%) rename {c64 => src}/basic/basic_find_line.s (100%) rename {c64 => src}/basic/basic_find_next_line.s (100%) rename {c64 => src}/basic/basic_follow_link_to_next_line.s (100%) rename {c64 => src}/basic/basic_functions/fun__jumptable.s (100%) rename {c64 => src}/basic/basic_functions/fun__unimplemented.s (100%) rename {c64 => src}/basic/basic_insert_line.s (100%) rename {c64 => src}/basic/basic_main_loop.s (100%) rename {c64 => src}/basic/basic_operators/oper__jumptable.s (100%) rename {c64 => src}/basic/basic_operators/oper_add.s (100%) rename {c64 => src}/basic/basic_operators/oper_and.s (100%) rename {c64 => src}/basic/basic_operators/oper_cmp_eq.s (100%) rename {c64 => src}/basic/basic_operators/oper_cmp_gt.s (100%) rename {c64 => src}/basic/basic_operators/oper_cmp_gteq.s (100%) rename {c64 => src}/basic/basic_operators/oper_cmp_lt.s (100%) rename {c64 => src}/basic/basic_operators/oper_cmp_lteq.s (100%) rename {c64 => src}/basic/basic_operators/oper_cmp_neq.s (100%) rename {c64 => src}/basic/basic_operators/oper_div.s (100%) rename {c64 => src}/basic/basic_operators/oper_mul.s (100%) rename {c64 => src}/basic/basic_operators/oper_or.s (100%) rename {c64 => src}/basic/basic_operators/oper_pow.s (100%) rename {c64 => src}/basic/basic_operators/oper_sub.s (100%) rename {c64 => src}/basic/basic_operators/oper_unary_minus.s (100%) rename {c64 => src}/basic/basic_operators/oper_unary_not.s (100%) rename {c64 => src}/basic/basic_parse_line_number.s (100%) rename {c64 => src}/basic/basic_shift_mem_down.s (100%) rename {c64 => src}/basic/basic_shift_mem_up.s (100%) rename {c64 => src}/basic/basic_vector_defaults.s (100%) rename {c64 => src}/basic/bdcd.interop (100%) rename {c64 => src}/basic/bdcd.linprt.s (100%) rename {c64 => src}/basic/board_m65/4000.mega65_vectable_basic_1.s (100%) rename {c64 => src}/basic/board_m65/mega65_imports.s (100%) rename {c64 => src}/basic/board_m65/mega65_map_helpers.s (100%) rename {c64 => src}/basic/board_m65/mega65_proxies.s (100%) rename {c64 => src}/basic/board_x16/cx16_dummy.s (100%) rename {c64 => src}/basic/board_x16/cx16_stubs.s (100%) rename {c64 => src}/basic/c000.skip_gap.s (100%) rename {c64 => src}/basic/engine/ad9e.frmevl.s (100%) rename {c64 => src}/basic/engine/ad9e.interop (100%) rename {c64 => src}/basic/engine/alloc_temp_string.s (100%) rename {c64 => src}/basic/engine/do_error.s (100%) rename {c64 => src}/basic/engine/end_of_statement_check.s (100%) rename {c64 => src}/basic/engine/execute_line_statements.s (100%) rename {c64 => src}/basic/engine/fetch_character.s (100%) rename {c64 => src}/basic/engine/fetch_operator.s (100%) rename {c64 => src}/basic/engine/fetch_uint8.s (100%) rename {c64 => src}/basic/engine/init_oldtxt.s (100%) rename {c64 => src}/basic/engine/injest_comma.s (100%) rename {c64 => src}/basic/engine/injest_spaces.s (100%) rename {c64 => src}/basic/engine/unconsume_character.s (100%) rename {c64 => src}/basic/fac1_mul.s (100%) rename {c64 => src}/basic/init/a000.cold_start_vector.s (100%) rename {c64 => src}/basic/init/a002.warm_start_vector.s (100%) rename {c64 => src}/basic/init/basic_cold_start_internal.s (100%) rename {c64 => src}/basic/init/basic_warm_start_internal.s (100%) rename {c64 => src}/basic/init/e394.basic_cold_start.s (100%) rename {c64 => src}/basic/init/e394.interop (100%) rename {c64 => src}/basic/init/e3b7.basic_warm_start.jmp.s (100%) rename {c64 => src}/basic/init/e3b7.interop (100%) rename {c64 => src}/basic/init/e422.initmsg.jmp.s (100%) rename {c64 => src}/basic/init/e422.interop (100%) rename {c64 => src}/basic/init/initmsg_bytes_free.s (100%) rename {c64 => src}/basic/init/initmsg_real.s (100%) rename {c64 => src}/basic/init/startup_banner.s (100%) rename {c64 => src}/basic/injest_number.s (100%) rename {c64 => src}/basic/math/add_FAC2_FAC1_sub.s (100%) rename {c64 => src}/basic/math/add_align_exponents.s (100%) rename {c64 => src}/basic/math/b849.add_HALF_FAC1.s (100%) rename {c64 => src}/basic/math/b849.interop (100%) rename {c64 => src}/basic/math/b850.interop (100%) rename {c64 => src}/basic/math/b850.sub_MEM_FAC1.s (100%) rename {c64 => src}/basic/math/b853.interop (100%) rename {c64 => src}/basic/math/b853.sub_FAC2_FAC1.s (100%) rename {c64 => src}/basic/math/b862.add_align_exponent.jmp.s (100%) rename {c64 => src}/basic/math/b862.interop (100%) rename {c64 => src}/basic/math/b867.add_MEM_FAC1.s (100%) rename {c64 => src}/basic/math/b867.interop (100%) rename {c64 => src}/basic/math/b86a.add_FAC2_FAC1.s (100%) rename {c64 => src}/basic/math/b86a.interop (100%) rename {c64 => src}/basic/math/b8fe.interop (100%) rename {c64 => src}/basic/math/b8fe.normal_FAC1.jmp.s (100%) rename {c64 => src}/basic/math/ba28.interop (100%) rename {c64 => src}/basic/math/ba28.mul_MEM_FAC1.jmp.s (100%) rename {c64 => src}/basic/math/ba2b.interop (100%) rename {c64 => src}/basic/math/ba2b.mul_FAC2_FAC1.s (100%) rename {c64 => src}/basic/math/ba8c.interop (100%) rename {c64 => src}/basic/math/ba8c.mov_MEM_FAC2.jmp.s (100%) rename {c64 => src}/basic/math/bae2.interop (100%) rename {c64 => src}/basic/math/bae2.mul10_FAC1.s (100%) rename {c64 => src}/basic/math/bafe.div10_FAC1_p.s (100%) rename {c64 => src}/basic/math/bafe.interop (100%) rename {c64 => src}/basic/math/bb0f.div_MEM_FAC1.s (100%) rename {c64 => src}/basic/math/bb0f.interop (100%) rename {c64 => src}/basic/math/bb12.div_FAC2_FAC1.s (100%) rename {c64 => src}/basic/math/bb12.interop (100%) rename {c64 => src}/basic/math/bc1b.interop (100%) rename {c64 => src}/basic/math/bc1b.round_FAC1.jmp.s (100%) rename {c64 => src}/basic/math/bc2b.interop (100%) rename {c64 => src}/basic/math/bc2b.sgn_FAC1_A.s (100%) rename {c64 => src}/basic/math/bf71.interop (100%) rename {c64 => src}/basic/math/bf71.sqr_FAC1.s (100%) rename {c64 => src}/basic/math/bf78.interop (100%) rename {c64 => src}/basic/math/bf78.pwr_FAC2_MEM.s (100%) rename {c64 => src}/basic/math/bfb4.interop (100%) rename {c64 => src}/basic/math/bfb4.toggle_sign_FAC1.s (100%) rename {c64 => src}/basic/math/div_FAC1_denorm.s (100%) rename {c64 => src}/basic/math/div_mantissas.s (100%) rename {c64 => src}/basic/math/e097.interop (100%) rename {c64 => src}/basic/math/e097.rnd_FAC1.s (100%) rename {c64 => src}/basic/math/e09a.interop (100%) rename {c64 => src}/basic/math/e09a.rnd_A.s (100%) rename {c64 => src}/basic/math/e0be.interop (100%) rename {c64 => src}/basic/math/e0be.rnd_generate.s (100%) rename {c64 => src}/basic/math/mul10_FAC1_mul2.s (100%) rename {c64 => src}/basic/math/mul_FAC2_FAC1.s (100%) rename {c64 => src}/basic/math/mul_FAC2_FAC1_8x8.s (100%) rename {c64 => src}/basic/math/mul_FAC2_FAC1_shift.s (100%) rename {c64 => src}/basic/math/muldiv_RESHO_helpers.s (100%) rename {c64 => src}/basic/math/normal_FAC1.s (100%) rename {c64 => src}/basic/math/rnd_seed_from_FAC1.s (100%) rename {c64 => src}/basic/math/rnd_seed_init.s (100%) rename {c64 => src}/basic/math/round_FAC1.s (100%) rename {c64 => src}/basic/math_consts/aea8.const_PI.s (100%) rename {c64 => src}/basic/math_consts/aea8.interop (100%) rename {c64 => src}/basic/math_consts/b1a5.const_NEG_32768.s (100%) rename {c64 => src}/basic/math_consts/b1a5.interop (100%) rename {c64 => src}/basic/math_consts/b9bc.const_ONE.s (100%) rename {c64 => src}/basic/math_consts/b9bc.interop (100%) rename {c64 => src}/basic/math_consts/b9d6.const_INV_SQR_2.s (100%) rename {c64 => src}/basic/math_consts/b9d6.interop (100%) rename {c64 => src}/basic/math_consts/b9db.const_SQR_2.s (100%) rename {c64 => src}/basic/math_consts/b9db.interop (100%) rename {c64 => src}/basic/math_consts/b9e0.const_NEG_HALF.s (100%) rename {c64 => src}/basic/math_consts/b9e0.interop (100%) rename {c64 => src}/basic/math_consts/b9e5.const_LOG_2.s (100%) rename {c64 => src}/basic/math_consts/b9e5.interop (100%) rename {c64 => src}/basic/math_consts/baf9.const_TEN.s (100%) rename {c64 => src}/basic/math_consts/baf9.interop (100%) rename {c64 => src}/basic/math_consts/bf11.const_HALF.s (100%) rename {c64 => src}/basic/math_consts/bf11.interop (100%) rename {c64 => src}/basic/math_consts/bfbf.const_INV_LOG_2.s (100%) rename {c64 => src}/basic/math_consts/bfbf.interop (100%) rename {c64 => src}/basic/math_consts/bfe8.const_ONE.s (100%) rename {c64 => src}/basic/math_consts/bfe8.interop (100%) rename {c64 => src}/basic/math_consts/e2e0.const_HALF_PI.s (100%) rename {c64 => src}/basic/math_consts/e2e0.interop (100%) rename {c64 => src}/basic/math_consts/e2e5.const_DOUBLE_PI.s (100%) rename {c64 => src}/basic/math_consts/e2e5.interop (100%) rename {c64 => src}/basic/math_consts/e2ea.const_QUARTER.s (100%) rename {c64 => src}/basic/math_consts/e2ea.interop (100%) rename {c64 => src}/basic/math_consts/e309.const_DOUBLE_PI.s (100%) rename {c64 => src}/basic/math_consts/e309.interop (100%) rename {c64 => src}/basic/math_mov/bba2.interop (100%) rename {c64 => src}/basic/math_mov/bba2.mov_MEM_FAC1.jmp.s (100%) rename {c64 => src}/basic/math_mov/bbc7.interop (100%) rename {c64 => src}/basic/math_mov/bbc7.mov_r_FAC1_TMP2.s (100%) rename {c64 => src}/basic/math_mov/bbca.interop (100%) rename {c64 => src}/basic/math_mov/bbca.mov_r_FAC1_TMP1.s (100%) rename {c64 => src}/basic/math_mov/bbd0.interop (100%) rename {c64 => src}/basic/math_mov/bbd0.mov_r_FAC1_VAR.s (100%) rename {c64 => src}/basic/math_mov/bbd4.interop (100%) rename {c64 => src}/basic/math_mov/bbd4.mov_r_FAC1_MEM.s (100%) rename {c64 => src}/basic/math_mov/bbfc.interop (100%) rename {c64 => src}/basic/math_mov/bbfc.mov_FAC2_FAC1.s (100%) rename {c64 => src}/basic/math_mov/bc0c.interop (100%) rename {c64 => src}/basic/math_mov/bc0c.mov_r_FAC1_FAC2.s (100%) rename {c64 => src}/basic/math_mov/bc0f.interop (100%) rename {c64 => src}/basic/math_mov/bc0f.mov_FAC1_FAC2.jmp.s (100%) rename {c64 => src}/basic/math_mov/mov_FAC1_FAC2.s (100%) rename {c64 => src}/basic/math_mov/mov_FAC1_MEM.s (100%) rename {c64 => src}/basic/math_mov/mov_FAC2_FAC1.s (100%) rename {c64 => src}/basic/math_mov/mov_MEM_FAC1.s (100%) rename {c64 => src}/basic/math_mov/mov_MEM_FAC2.s (100%) rename {c64 => src}/basic/math_mov/mov_r_FAC1_TMP1.s (100%) rename {c64 => src}/basic/math_mov/mov_r_FAC1_TMP2.s (100%) rename {c64 => src}/basic/memory/shift_mem_down_38k.s (100%) rename {c64 => src}/basic/memory/shift_mem_up_38k.s (100%) rename {c64 => src}/basic/memory/under_rom_routines_46k_50k.s (100%) rename {c64 => src}/basic/memory/under_rom_routines_60k.s (100%) rename {c64 => src}/basic/peek_line_pointer_null_check.s (100%) rename {c64 => src}/basic/print/list_single_line.s (100%) rename {c64 => src}/basic/print/print_features.s (100%) rename {c64 => src}/basic/print/print_integer.s (100%) rename {c64 => src}/basic/print/print_packed_dict_string.s (100%) rename {c64 => src}/basic/print/print_packed_freq_string.s (100%) rename {c64 => src}/basic/print/print_packed_search.s (100%) rename {c64 => src}/basic/rom_revision/a004.identifier.s (100%) rename {c64 => src}/basic/rom_revision/a483.interop (100%) rename {c64 => src}/basic/rom_revision/bf52.interop (100%) rename {c64 => src}/basic/rom_revision/bf52.rom_revision_basic.s (100%) rename {c64 => src}/basic/rom_revision/e4b7.interop (100%) rename {c64 => src}/basic/rom_revision/e4b7.rom_revision_kernal.s (100%) rename {c64 => src}/basic/select_device.s (100%) rename {c64 => src}/basic/tokenizer/tk_cut_away.s (100%) rename {c64 => src}/basic/tokenizer/tk_pack.s (100%) rename {c64 => src}/basic/tokenizer/tk_search.s (100%) rename {c64 => src}/basic/tokenizer/tk_shorten.s (100%) rename {c64 => src}/basic/tokenizer/tokenise_line.s (100%) rename {c64 => src}/basic/wedge/wedge_dos.s (100%) rename {c64 => src}/basic/wedge/wedge_tape.s (100%) rename {c64 => src}/kernal/,disabled/,aliases_ultimate64.s (100%) rename {c64 => src}/kernal/,disabled/u64_load.s (100%) rename {c64 => src}/kernal/,stubs/e6b6.advance_cursor.s (100%) rename {c64 => src}/kernal/,stubs/e6b6.interop (100%) rename {c64 => src}/kernal/,stubs/e701.interop (100%) rename {c64 => src}/kernal/,stubs/e701.previous_line.s (100%) rename {c64 => src}/kernal/,stubs/e716.chrout_screen.s (100%) rename {c64 => src}/kernal/,stubs/e716.interop (100%) rename {c64 => src}/kernal/,stubs/e96c.insert_line_at_top.s (100%) rename {c64 => src}/kernal/,stubs/e96c.interop (100%) rename {c64 => src}/kernal/,stubs/f3f6.interop (100%) rename {c64 => src}/kernal/,stubs/f3f6.unknown.s (100%) rename {c64 => src}/kernal/,stubs/f646.iec_close.s (100%) rename {c64 => src}/kernal/,stubs/f646.interop (100%) rename {c64 => src}/kernal/,stubs/fd90.interop (100%) rename {c64 => src}/kernal/,stubs/fd90.unknown.s (100%) rename {c64 => src}/kernal/assets/cartridge_signature.s (100%) rename {c64 => src}/kernal/assets/e8da.colour_codes.s (100%) rename {c64 => src}/kernal/assets/e8da.interop (100%) rename {c64 => src}/kernal/assets/fd30.interop (100%) rename {c64 => src}/kernal/assets/fd30.vector_defaults.s (100%) rename {c64 => src}/kernal/assets/filename_any.s (100%) rename {c64 => src}/kernal/assets/irq_timing_hi.s (100%) rename {c64 => src}/kernal/assets/irq_timing_lo.s (100%) rename {c64 => src}/kernal/assets/kernal_messages.s (100%) rename {c64 => src}/kernal/assets/programmable_keys.s (100%) rename {c64 => src}/kernal/board_m65/4000.interop (100%) rename {c64 => src}/kernal/board_m65/4000.mega65_vectable_kernal_1.s (100%) rename {c64 => src}/kernal/board_m65/mega65_imports.s (100%) rename {c64 => src}/kernal/board_m65/mega65_map_helpers.s (100%) rename {c64 => src}/kernal/board_m65/mega65_proxies.s (100%) rename {c64 => src}/kernal/board_m65/mega65_redirect_tape.s (100%) rename {c64 => src}/kernal/board_m65/mega65_tape_normal_byte_store.s (100%) rename {c64 => src}/kernal/board_m65/mega65_unhide.s (100%) rename {c64 => src}/kernal/board_x16/cx16_dummy.s (100%) rename {c64 => src}/kernal/board_x16/cx16_stubs.s (100%) rename {c64 => src}/kernal/errors.s (100%) rename {c64 => src}/kernal/iec/acptr.s (100%) rename {c64 => src}/kernal/iec/chkin_iec.s (100%) rename {c64 => src}/kernal/iec/chrin_iec.s (100%) rename {c64 => src}/kernal/iec/chrout_iec.s (100%) rename {c64 => src}/kernal/iec/ciout.s (100%) rename {c64 => src}/kernal/iec/ckout_iec.s (100%) rename {c64 => src}/kernal/iec/close_iec.s (100%) rename {c64 => src}/kernal/iec/clrchn_iec.s (100%) rename {c64 => src}/kernal/iec/iec_check_devnum.s (100%) rename {c64 => src}/kernal/iec/iec_close_load.s (100%) rename {c64 => src}/kernal/iec/iec_cmd_close.s (100%) rename {c64 => src}/kernal/iec/iec_cmd_open.s (100%) rename {c64 => src}/kernal/iec/iec_pull_release.s (100%) rename {c64 => src}/kernal/iec/iec_return.s (100%) rename {c64 => src}/kernal/iec/iec_rx_byte.s (100%) rename {c64 => src}/kernal/iec/iec_rx_check_eoi.s (100%) rename {c64 => src}/kernal/iec/iec_send_file_name.s (100%) rename {c64 => src}/kernal/iec/iec_set_idle.s (100%) rename {c64 => src}/kernal/iec/iec_turnaround_to_listen.s (100%) rename {c64 => src}/kernal/iec/iec_turnaround_to_talk.s (100%) rename {c64 => src}/kernal/iec/iec_tx_byte.s (100%) rename {c64 => src}/kernal/iec/iec_tx_command.s (100%) rename {c64 => src}/kernal/iec/iec_tx_command_finalize.s (100%) rename {c64 => src}/kernal/iec/iec_tx_flush.s (100%) rename {c64 => src}/kernal/iec/iec_update_eal_by_y.s (100%) rename {c64 => src}/kernal/iec/iec_wait1ms.s (100%) rename {c64 => src}/kernal/iec/iec_wait20us.s (100%) rename {c64 => src}/kernal/iec/iec_wait60us.s (100%) rename {c64 => src}/kernal/iec/iec_wait_for_clk_release.s (100%) rename {c64 => src}/kernal/iec/iec_wait_for_data_pull.s (100%) rename {c64 => src}/kernal/iec/iec_wait_for_data_release.s (100%) rename {c64 => src}/kernal/iec/listen.s (100%) rename {c64 => src}/kernal/iec/load_iec.s (100%) rename {c64 => src}/kernal/iec/open_iec.s (100%) rename {c64 => src}/kernal/iec/save_iec.s (100%) rename {c64 => src}/kernal/iec/second.s (100%) rename {c64 => src}/kernal/iec/talk.s (100%) rename {c64 => src}/kernal/iec/tksa.s (100%) rename {c64 => src}/kernal/iec/unlsn.s (100%) rename {c64 => src}/kernal/iec/untlk.s (100%) rename {c64 => src}/kernal/iec_fast/burst_cia1_advertise.s (100%) rename {c64 => src}/kernal/iec_fast/burst_cia2_advertise.s (100%) rename {c64 => src}/kernal/iec_fast/burst_m65_advertise.s (100%) rename {c64 => src}/kernal/iec_fast/dolphindos_detect.s (100%) rename {c64 => src}/kernal/iec_fast/dolphindos_load.s (100%) rename {c64 => src}/kernal/iec_fast/jiffydos_bittable.s (100%) rename {c64 => src}/kernal/iec_fast/jiffydos_detect.s (100%) rename {c64 => src}/kernal/iec_fast/jiffydos_load.s (100%) rename {c64 => src}/kernal/iec_fast/jiffydos_prepare.s (100%) rename {c64 => src}/kernal/iec_fast/jiffydos_rx_byte.s (100%) rename {c64 => src}/kernal/iec_fast/jiffydos_tx_byte.s (100%) rename {c64 => src}/kernal/iec_fast/jiffydos_wait_line.s (100%) rename {c64 => src}/kernal/init/cartridge_check.s (100%) rename {c64 => src}/kernal/init/cint_screen_keyboard.s (100%) rename {c64 => src}/kernal/init/e518.cint_legacy.s (100%) rename {c64 => src}/kernal/init/e518.interop (100%) rename {c64 => src}/kernal/init/e5a0.setup_vicii.s (100%) rename {c64 => src}/kernal/init/fce2.hw_entry_reset.s (100%) rename {c64 => src}/kernal/init/fce2.interop (100%) rename {c64 => src}/kernal/init/fd50.interop (100%) rename {c64 => src}/kernal/init/fd50.ramtas.s (100%) rename {c64 => src}/kernal/init/fda3.ioinit.s (100%) rename {c64 => src}/kernal/init/ff5b.cint.s (100%) rename {c64 => src}/kernal/init/ff5b.interop (100%) rename {c64 => src}/kernal/init/fffc.interop (100%) rename {c64 => src}/kernal/init/fffc.vector_reset.s (100%) rename {c64 => src}/kernal/init/setup_pal_ntsc.s (100%) rename {c64 => src}/kernal/interrupts/ea31.default_irq_handler.s (100%) rename {c64 => src}/kernal/interrupts/ea31.interop (100%) rename {c64 => src}/kernal/interrupts/ea7e.ack_cia1_return_from_interrupt.s (100%) rename {c64 => src}/kernal/interrupts/ea81.return_from_interrupt.s (100%) rename {c64 => src}/kernal/interrupts/fe47.default_nmi_handler.s (100%) rename {c64 => src}/kernal/interrupts/fe47.interop (100%) rename {c64 => src}/kernal/interrupts/fe66.default_brk_handler.s (100%) rename {c64 => src}/kernal/interrupts/fe66.interop (100%) rename {c64 => src}/kernal/interrupts/fffa.interop (100%) rename {c64 => src}/kernal/interrupts/fffa.vector_nmi.s (100%) rename {c64 => src}/kernal/interrupts/fffe.interop (100%) rename {c64 => src}/kernal/interrupts/fffe.vector_irq.s (100%) rename {c64 => src}/kernal/interrupts/hw_entry_irq.s (100%) rename {c64 => src}/kernal/interrupts/hw_entry_nmi.s (100%) rename {c64 => src}/kernal/interrupts/nmi_lock.s (100%) rename {c64 => src}/kernal/iostack/chkinout.s (100%) rename {c64 => src}/kernal/iostack/clall_real.s (100%) rename {c64 => src}/kernal/iostack/e50a.interop (100%) rename {c64 => src}/kernal/iostack/e50a.plot.s (100%) rename {c64 => src}/kernal/iostack/f13e.getin.s (100%) rename {c64 => src}/kernal/iostack/f13e.interop (100%) rename {c64 => src}/kernal/iostack/f157.chrin.s (100%) rename {c64 => src}/kernal/iostack/f157.interop (100%) rename {c64 => src}/kernal/iostack/f1ca.chrout.s (100%) rename {c64 => src}/kernal/iostack/f1ca.interop (100%) rename {c64 => src}/kernal/iostack/f20e.chkin.s (100%) rename {c64 => src}/kernal/iostack/f20e.interop (100%) rename {c64 => src}/kernal/iostack/f250.ckout.s (100%) rename {c64 => src}/kernal/iostack/f250.interop (100%) rename {c64 => src}/kernal/iostack/f291.close.s (100%) rename {c64 => src}/kernal/iostack/f291.interop (100%) rename {c64 => src}/kernal/iostack/f32f.clall.jmp.s (100%) rename {c64 => src}/kernal/iostack/f32f.interop (100%) rename {c64 => src}/kernal/iostack/f333.clrchn.s (100%) rename {c64 => src}/kernal/iostack/f333.interop (100%) rename {c64 => src}/kernal/iostack/f34a.interop (100%) rename {c64 => src}/kernal/iostack/f34a.open.s (100%) rename {c64 => src}/kernal/iostack/f49e.interop (100%) rename {c64 => src}/kernal/iostack/f49e.load_prep.s (100%) rename {c64 => src}/kernal/iostack/f4a5.interop (100%) rename {c64 => src}/kernal/iostack/f4a5.load.s (100%) rename {c64 => src}/kernal/iostack/f5dd.interop (100%) rename {c64 => src}/kernal/iostack/f5dd.save_prep.s (100%) rename {c64 => src}/kernal/iostack/f5ed.interop (100%) rename {c64 => src}/kernal/iostack/f5ed.save.s (100%) rename {c64 => src}/kernal/iostack/f6ed.interop (100%) rename {c64 => src}/kernal/iostack/findfls.s (100%) rename {c64 => src}/kernal/iostack/getin_real.s (100%) rename {c64 => src}/kernal/iostack/load_save_common.s (100%) rename {c64 => src}/kernal/iostack/pop_keyboard_buffer.s (100%) rename {c64 => src}/kernal/iostack/readst.s (100%) rename {c64 => src}/kernal/iostack/setfls.s (100%) rename {c64 => src}/kernal/iostack/setmsg.s (100%) rename {c64 => src}/kernal/iostack/setnam.s (100%) rename {c64 => src}/kernal/iostack/settmo.s (100%) rename {c64 => src}/kernal/jumptable/ff81.jcint.s (100%) rename {c64 => src}/kernal/jumptable/ff84.jioinit.s (100%) rename {c64 => src}/kernal/jumptable/ff87.jramtas.s (100%) rename {c64 => src}/kernal/jumptable/ff8a.jrestor.s (100%) rename {c64 => src}/kernal/jumptable/ff8d.jvector.s (100%) rename {c64 => src}/kernal/jumptable/ff90.jsetmsg.s (100%) rename {c64 => src}/kernal/jumptable/ff93.jsecond.s (100%) rename {c64 => src}/kernal/jumptable/ff96.jtksa.s (100%) rename {c64 => src}/kernal/jumptable/ff99.jmemtop.s (100%) rename {c64 => src}/kernal/jumptable/ff9c.jmembot.s (100%) rename {c64 => src}/kernal/jumptable/ff9f.jscnkey.s (100%) rename {c64 => src}/kernal/jumptable/ffa2.jsettmo.s (100%) rename {c64 => src}/kernal/jumptable/ffa5.jacptr.s (100%) rename {c64 => src}/kernal/jumptable/ffa8.jciout.s (100%) rename {c64 => src}/kernal/jumptable/ffab.juntlk.s (100%) rename {c64 => src}/kernal/jumptable/ffae.junlsn.s (100%) rename {c64 => src}/kernal/jumptable/ffb1.jlisten.s (100%) rename {c64 => src}/kernal/jumptable/ffb4.jtalk.s (100%) rename {c64 => src}/kernal/jumptable/ffb7.jreadst.s (100%) rename {c64 => src}/kernal/jumptable/ffba.jsetfls.s (100%) rename {c64 => src}/kernal/jumptable/ffbd.jsetnam.s (100%) rename {c64 => src}/kernal/jumptable/ffc0.jopen.s (100%) rename {c64 => src}/kernal/jumptable/ffc3.jclose.s (100%) rename {c64 => src}/kernal/jumptable/ffc6.jchkin.s (100%) rename {c64 => src}/kernal/jumptable/ffc9.jckout.s (100%) rename {c64 => src}/kernal/jumptable/ffcc.jclrchn.s (100%) rename {c64 => src}/kernal/jumptable/ffcf.jchrin.s (100%) rename {c64 => src}/kernal/jumptable/ffd2.jchrout.s (100%) rename {c64 => src}/kernal/jumptable/ffd5.jload.s (100%) rename {c64 => src}/kernal/jumptable/ffd8.jsave.s (100%) rename {c64 => src}/kernal/jumptable/ffdb.jsettim.s (100%) rename {c64 => src}/kernal/jumptable/ffde.jrdtim.s (100%) rename {c64 => src}/kernal/jumptable/ffe1.jstop.s (100%) rename {c64 => src}/kernal/jumptable/ffe4.jgetin.s (100%) rename {c64 => src}/kernal/jumptable/ffe7.jclall.s (100%) rename {c64 => src}/kernal/jumptable/ffea.judtim.s (100%) rename {c64 => src}/kernal/jumptable/ffed.jscreen.s (100%) rename {c64 => src}/kernal/jumptable/fff0.jplot.s (100%) rename {c64 => src}/kernal/jumptable/fff3.jiobase.s (100%) rename {c64 => src}/kernal/keyboard/chrin_keyboard.s (100%) rename {c64 => src}/kernal/keyboard/f142.getin_keyboard.s (100%) rename {c64 => src}/kernal/keyboard/f142.interop (100%) rename {c64 => src}/kernal/keyboard/f6ed.stop.s (100%) rename {c64 => src}/kernal/keyboard/kb_matrix.s (100%) rename {c64 => src}/kernal/keyboard/kb_matrix_128.s (100%) rename {c64 => src}/kernal/keyboard/kb_matrix_65.s (100%) rename {c64 => src}/kernal/keyboard/kb_matrix_alwaysrepeat.s (100%) rename {c64 => src}/kernal/keyboard/kb_matrix_bucky.s (100%) rename {c64 => src}/kernal/keyboard/kb_matrix_bucky_filter.s (100%) rename {c64 => src}/kernal/keyboard/kb_matrix_joy.s (100%) rename {c64 => src}/kernal/keyboard/kb_matrix_lookup.s (100%) rename {c64 => src}/kernal/keyboard/kb_matrix_lookup_legacy.s (100%) rename {c64 => src}/kernal/keyboard/kb_matrix_row_keys.s (100%) rename {c64 => src}/kernal/keyboard/kb_matrix_row_offsets.s (100%) rename {c64 => src}/kernal/keyboard/keyboard_disconnect.s (100%) rename {c64 => src}/kernal/keyboard/scnkey.s (100%) rename {c64 => src}/kernal/keyboard/scnkey_128.s (100%) rename {c64 => src}/kernal/keyboard/scnkey_65.s (100%) rename {c64 => src}/kernal/keyboard/scnkey_legacy.s (100%) rename {c64 => src}/kernal/keyboard/scnkey_set_keytab.s (100%) rename {c64 => src}/kernal/keyboard/udtim_keyboard.s (100%) rename {c64 => src}/kernal/memory/fd15.interop (100%) rename {c64 => src}/kernal/memory/fd15.restor.s (100%) rename {c64 => src}/kernal/memory/fe25.interop (100%) rename {c64 => src}/kernal/memory/fe25.memtop.s (100%) rename {c64 => src}/kernal/memory/membot.s (100%) rename {c64 => src}/kernal/memory/under_rom_routines_46k_50k.s (100%) rename {c64 => src}/kernal/memory/under_rom_routines_60k.s (100%) rename {c64 => src}/kernal/memory/vector_real.s (100%) rename {c64 => src}/kernal/panic.s (100%) rename {c64 => src}/kernal/print/print_hex_byte.s (100%) rename {c64 => src}/kernal/print/print_kernal_message.s (100%) rename {c64 => src}/kernal/print/print_return.s (100%) rename {c64 => src}/kernal/print/print_space.s (100%) rename {c64 => src}/kernal/print/printf.s (100%) rename {c64 => src}/kernal/public_interfaces.md (100%) rename {c64 => src}/kernal/rom_revision/ff80.interop (100%) rename {c64 => src}/kernal/rom_revision/ff80.kernal_revision.s (100%) rename {c64 => src}/kernal/rs232/chkin_rs232_up2400.s (100%) rename {c64 => src}/kernal/rs232/chkin_rs232_up9600.s (100%) rename {c64 => src}/kernal/rs232/chrin_rs232_up2400.s (100%) rename {c64 => src}/kernal/rs232/chrin_rs232_up9600.s (100%) rename {c64 => src}/kernal/rs232/chrout_rs232.s (100%) rename {c64 => src}/kernal/rs232/ckout_rs232_up2400.s (100%) rename {c64 => src}/kernal/rs232/ckout_rs232_up9600.s (100%) rename {c64 => src}/kernal/rs232/close_rs232.s (100%) rename {c64 => src}/kernal/rs232/getin_rs232.s (100%) rename {c64 => src}/kernal/rs232/open_rs232.s (100%) rename {c64 => src}/kernal/rs232/rs232_count_channels.s (100%) rename {c64 => src}/kernal/rs232/up9600_disable.s (100%) rename {c64 => src}/kernal/rs232/up9600_enable.s (100%) rename {c64 => src}/kernal/rs232/up9600_ihitab.s (100%) rename {c64 => src}/kernal/rs232/up9600_ilotab.s (100%) rename {c64 => src}/kernal/rs232/up9600_irq.s (100%) rename {c64 => src}/kernal/rs232/up9600_nmi.s (100%) rename {c64 => src}/kernal/rs232/up9600_rsin.s (100%) rename {c64 => src}/kernal/rs232/up9600_rsout.s (100%) rename {c64 => src}/kernal/screen/chrout_screen.s (100%) rename {c64 => src}/kernal/screen/chrout_screen_clr.s (100%) rename {c64 => src}/kernal/screen/chrout_screen_control.s (100%) rename {c64 => src}/kernal/screen/chrout_screen_crsr.s (100%) rename {c64 => src}/kernal/screen/chrout_screen_del.s (100%) rename {c64 => src}/kernal/screen/chrout_screen_gfxtxt.s (100%) rename {c64 => src}/kernal/screen/chrout_screen_home.s (100%) rename {c64 => src}/kernal/screen/chrout_screen_ins.s (100%) rename {c64 => src}/kernal/screen/chrout_screen_jumptable_codes.s (100%) rename {c64 => src}/kernal/screen/chrout_screen_quote.s (100%) rename {c64 => src}/kernal/screen/chrout_screen_return.s (100%) rename {c64 => src}/kernal/screen/chrout_screen_rvs.s (100%) rename {c64 => src}/kernal/screen/chrout_screen_shift_onoff.s (100%) rename {c64 => src}/kernal/screen/chrout_screen_stop.s (100%) rename {c64 => src}/kernal/screen/chrout_screen_tab.s (100%) rename {c64 => src}/kernal/screen/cursor.s (100%) rename {c64 => src}/kernal/screen/cursor_enable.s (100%) rename {c64 => src}/kernal/screen/cursor_show.s (100%) rename {c64 => src}/kernal/screen/e544.clear_screen.s (100%) rename {c64 => src}/kernal/screen/e566.cursor_home.s (100%) rename {c64 => src}/kernal/screen/e566.interop (100%) rename {c64 => src}/kernal/screen/e56c.interop (100%) rename {c64 => src}/kernal/screen/e56c.screen_calculate_pointers.s (100%) rename {c64 => src}/kernal/screen/e8ea.interop (100%) rename {c64 => src}/kernal/screen/e8ea.screen_scroll_up.s (100%) rename {c64 => src}/kernal/screen/e9ff.interop (100%) rename {c64 => src}/kernal/screen/e9ff.screen_clear_line.s (100%) rename {c64 => src}/kernal/screen/screen.s (100%) rename {c64 => src}/kernal/screen/screen_advance_to_next_line.s (100%) rename {c64 => src}/kernal/screen/screen_calculate_pnt_user.s (100%) rename {c64 => src}/kernal/screen/screen_calculate_pntr_lnmx.s (100%) rename {c64 => src}/kernal/screen/screen_check_space_ends_line.s (100%) rename {c64 => src}/kernal/screen/screen_check_toggle_quote.s (100%) rename {c64 => src}/kernal/screen/screen_code_to_petscii.s (100%) rename {c64 => src}/kernal/screen/screen_get_cliped_pntr.s (100%) rename {c64 => src}/kernal/screen/screen_get_logical_line_end_ptr.s (100%) rename {c64 => src}/kernal/screen/screen_grow_logical_line.s (100%) rename {c64 => src}/kernal/screen/screen_off.s (100%) rename {c64 => src}/kernal/screen/screen_on.s (100%) rename {c64 => src}/kernal/screen/screen_preserve_sal_eal.s (100%) rename {c64 => src}/kernal/screen/screen_restore_sal_eal.s (100%) rename {c64 => src}/kernal/status.s (100%) rename {c64 => src}/kernal/tape/load_tape_normal.s (100%) rename {c64 => src}/kernal/tape/load_tape_turbo.s (100%) rename {c64 => src}/kernal/tape/tape_common.s (100%) rename {c64 => src}/kernal/tape/tape_common_autodetect.s (100%) rename {c64 => src}/kernal/tape/tape_common_clean_sid.s (100%) rename {c64 => src}/kernal/tape/tape_common_ditch_verify.s (100%) rename {c64 => src}/kernal/tape/tape_common_get_pulse.s (100%) rename {c64 => src}/kernal/tape/tape_common_motor.s (100%) rename {c64 => src}/kernal/tape/tape_common_prepare_cia.s (100%) rename {c64 => src}/kernal/tape/tape_common_screen.s (100%) rename {c64 => src}/kernal/tape/tape_head_align.s (100%) rename {c64 => src}/kernal/tape/tape_head_align_gen_code.s (100%) rename {c64 => src}/kernal/tape/tape_head_align_get_pulse.s (100%) rename {c64 => src}/kernal/tape/tape_head_align_help.s (100%) rename {c64 => src}/kernal/tape/tape_head_align_irq.s (100%) rename {c64 => src}/kernal/tape/tape_normal_calibrate.s (100%) rename {c64 => src}/kernal/tape/tape_normal_get_bit.s (100%) rename {c64 => src}/kernal/tape/tape_normal_get_byte.s (100%) rename {c64 => src}/kernal/tape/tape_normal_get_data_1.s (100%) rename {c64 => src}/kernal/tape/tape_normal_get_data_2.s (100%) rename {c64 => src}/kernal/tape/tape_normal_get_marker.s (100%) rename {c64 => src}/kernal/tape/tape_normal_get_pilot.s (100%) rename {c64 => src}/kernal/tape/tape_normal_sync.s (100%) rename {c64 => src}/kernal/tape/tape_normal_update_checksum.s (100%) rename {c64 => src}/kernal/tape/tape_turbo_bytestore.s (100%) rename {c64 => src}/kernal/tape/tape_turbo_get_bit.s (100%) rename {c64 => src}/kernal/tape/tape_turbo_get_byte.s (100%) rename {c64 => src}/kernal/tape/tape_turbo_sync.s (100%) rename {c64 => src}/kernal/tape/tape_turbo_sync_first.s (100%) rename {c64 => src}/kernal/time/rdtim.s (100%) rename {c64 => src}/kernal/time/settim.s (100%) rename {c64 => src}/kernal/time/udtim.s (100%) rename {c64 => src}/program_traces/BASIC2.trace (100%) rename {c64 => src}/program_traces/README.md (100%) diff --git a/CONFIG.md b/CONFIG.md index 968487c8..9c1fa54c 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -3,11 +3,11 @@ It's not possible to provide ROM builds that suit everyone needs - therefore configuration files were introduced, few predefined configurations are provided with sane defaults: -* [`c64/,,config_custom.s`](c64/,,config_custom.s) -* [`c64/,,config_generic.s`](c64/,,config_generic.s) -* [`c64/,,config_mega65.s`](c64/,,config_mega65.s) -* [`c64/,,config_ultimate64.s`](c64/,,config_ultimate64.s) -* [`c64/,,config_testing.s`](c64/,,config_testing.s) +* [`src/,,config_custom.s`](src/,,config_custom.s) +* [`src/,,config_generic.s`](src/,,config_generic.s) +* [`src/,,config_mega65.s`](src/,,config_mega65.s) +* [`src/,,config_ultimate64.s`](src/,,config_ultimate64.s) +* [`src/,,config_testing.s`](src/,,config_testing.s) Just edit them and recompile the project. To enable particular option - uncomment it by removing leading `//` from before `#define` directive (as you probably guessed, commenting out disables it). Some options are followed by constants - you can change them too to further fine-tune the build. diff --git a/Makefile b/Makefile index e3102ca5..92dff008 100644 --- a/Makefile +++ b/Makefile @@ -6,51 +6,51 @@ TESTTAPE = testsuite/testtape-c64-pal-turbo.tap # Source files -SRCDIR_COMMON = c64/aliases +SRCDIR_COMMON = src/aliases SRCDIR_BASIC = $(SRCDIR_COMMON) \ - c64/basic \ - c64/basic/,stubs \ - c64/basic/,stubs_math \ - c64/basic/assets \ - c64/basic/basic_commands \ - c64/basic/basic_commands_CC \ - c64/basic/basic_commands_CD \ - c64/basic/basic_operators \ - c64/basic/basic_functions \ - c64/basic/board_m65 \ - c64/basic/board_x16 \ - c64/basic/engine \ - c64/basic/init \ - c64/basic/math \ - c64/basic/math_consts \ - c64/basic/math_mov \ - c64/basic/memory \ - c64/basic/print \ - c64/basic/rom_revision \ - c64/basic/tokenizer \ - c64/basic/wedge + src/basic \ + src/basic/,stubs \ + src/basic/,stubs_math \ + src/basic/assets \ + src/basic/basic_commands \ + src/basic/basic_commands_CC \ + src/basic/basic_commands_CD \ + src/basic/basic_operators \ + src/basic/basic_functions \ + src/basic/board_m65 \ + src/basic/board_x16 \ + src/basic/engine \ + src/basic/init \ + src/basic/math \ + src/basic/math_consts \ + src/basic/math_mov \ + src/basic/memory \ + src/basic/print \ + src/basic/rom_revision \ + src/basic/tokenizer \ + src/basic/wedge SRCDIR_KERNAL = $(SRCDIR_COMMON) \ - c64/kernal \ - c64/kernal/,stubs \ - c64/kernal/assets \ - c64/kernal/board_m65 \ - c64/kernal/board_x16 \ - c64/kernal/iec \ - c64/kernal/iec_fast \ - c64/kernal/init \ - c64/kernal/interrupts \ - c64/kernal/iostack \ - c64/kernal/jumptable \ - c64/kernal/keyboard \ - c64/kernal/memory \ - c64/kernal/print \ - c64/kernal/rom_revision \ - c64/kernal/rs232 \ - c64/kernal/screen \ - c64/kernal/tape \ - c64/kernal/time + src/kernal \ + src/kernal/,stubs \ + src/kernal/assets \ + src/kernal/board_m65 \ + src/kernal/board_x16 \ + src/kernal/iec \ + src/kernal/iec_fast \ + src/kernal/init \ + src/kernal/interrupts \ + src/kernal/iostack \ + src/kernal/jumptable \ + src/kernal/keyboard \ + src/kernal/memory \ + src/kernal/print \ + src/kernal/rom_revision \ + src/kernal/rs232 \ + src/kernal/screen \ + src/kernal/tape \ + src/kernal/time SRC_BASIC = $(foreach dir,$(SRCDIR_BASIC),$(wildcard $(dir)/*.s)) SRC_KERNAL = $(foreach dir,$(SRCDIR_KERNAL),$(wildcard $(dir)/*.s)) @@ -72,12 +72,12 @@ DIR_X16 = build/target_cx16 # List of config files -CFG_CUS = c64/,,config_custom.s -CFG_GEN = c64/,,config_generic.s -CFG_TST = c64/,,config_testing.s -CFG_M65 = c64/,,config_mega65.s -CFG_U64 = c64/,,config_ultimate64.s -CFG_X16 = c64/,,config_cx16.s +CFG_CUS = src/,,config_custom.s +CFG_GEN = src/,,config_generic.s +CFG_TST = src/,,config_testing.s +CFG_M65 = src/,,config_mega65.s +CFG_U64 = src/,,config_ultimate64.s +CFG_X16 = src/,,config_cx16.s # List of files with generated strings @@ -168,7 +168,7 @@ fast: $(MAKE) -j64 --output-sync=target $(TARGET_LIST) $(EXT_TARGET_LIST) clean: - @rm -rf build c64/basic/combined.s c64/kernal/combined.s + @rm -rf build src/basic/combined.s src/kernal/combined.s updatebin: $(MAKE) -j64 --output-sync=target $(TARGET_LIST) $(TOOL_RELEASE) @@ -306,13 +306,13 @@ GEN_STR_cx16 = $(GEN_STR_X16) build/target_%/OUTB_x.BIN build/target_%/BASIC_combined.vs: @mkdir -p build/target_$* @rm -f $@* build/target_$*/BASIC* - @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r STD -s BASIC -i BASIC-$* -o OUTB_x.BIN -d build/target_$* -l a000 -h e4d2 c64/,,config_$*.s $(SRCDIR_BASIC) $(GEN_BASIC) $(GEN_STR_$*) + @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r STD -s BASIC -i BASIC-$* -o OUTB_x.BIN -d build/target_$* -l a000 -h e4d2 src/,,config_$*.s $(SRCDIR_BASIC) $(GEN_BASIC) $(GEN_STR_$*) .PRECIOUS: build/target_%/OUTK_x.BIN build/target_%/KERNAL_combined.vs build/target_%/KERNAL_combined.sym build/target_%/OUTK_x.BIN build/target_%/KERNAL_combined.vs build/target_%/KERNAL_combined.sym: @mkdir -p build/target_$* @rm -f $@* build/target_$*/KERNAL* - @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r STD -s KERNAL -i KERNAL-$* -o OUTK_x.BIN -d build/target_$* -l e4d3 -h ffff c64/,,config_$*.s $(SRCDIR_KERNAL) $(GEN_KERNAL) $(GEN_STR_$*) + @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -r STD -s KERNAL -i KERNAL-$* -o OUTK_x.BIN -d build/target_$* -l e4d3 -h ffff src/,,config_$*.s $(SRCDIR_KERNAL) $(GEN_KERNAL) $(GEN_STR_$*) # Rules - BASIC and KERNAL intermediate files, for Mega65 diff --git a/STATUS.md b/STATUS.md index 384f08d8..145e4a86 100644 --- a/STATUS.md +++ b/STATUS.md @@ -145,7 +145,7 @@ Status of the various APIs and variables from the original ROMs ## Low memory locations (pages 0 - 3) -For the current status of the low memory location implementation andd usage check [this file](c64/aliases/,aliases_ram_lowmem.s). NOTE: available vector to certain routine does not mean that this routine is fully implemented! +For the current status of the low memory location implementation andd usage check [this file](src/aliases/,aliases_ram_lowmem.s). NOTE: available vector to certain routine does not mean that this routine is fully implemented! ## BASIC diff --git a/bin/basic_generic.rom b/bin/basic_generic.rom index 68bc99f4a1ad29ddad7d895cabba1430589546e1..90052287c7dda5ff8e220f0a5a99bf152fb76660 100644 GIT binary patch delta 972 zcmXw2ZERCj7``9vdfVBt-F4D^bUPg%X0S9mGBQlMK!`f=8j0C27Lqe`ql4)WV<3^Q zA>3qv%nVP+(1>a3?#jK1_BK_zwYT2E7_4&}Rs3NBChgtu2S1i-LW2IVzNeG(G#rQE9FdR3TdR4s)UGn}hcrE;^ked= zO|nPjPBl#)*!pWkBg`Vdm1S})4%+~c*X(URcOl~Vc8V)u*X5(bdagBTLJ91Vy%pJ-n zeisU?PrLzS#!E;v&}mbzglfo`9_OW0ObW#l4_%|Yb1Ib=bS@&`#Bfy;D~^4VQ<{L!=$6n4!KkMYnO$T0d7eX2|j_~D{&%2X|7n92r9a0@6DB%API?dS^jq_FMVnris~UxN^B%y?90x+(n$fu~ zTvm6CVavS!@_r5d$>;SQuJR?i%Gs6rzK-5WX;HP?D=GwzwUw8H|HHTR^j~eDbLr^E z@8AFB{;IK-O2#5n)M&E)hQxw+GGcjiys zJ=u3}cpRrP)>Ko0#lEaM|0NkblA&cPpv3XJC`L82C4dF~e-kE?1U^ zJlb?709J{khIK`U06nOe!aRu9LzUA);31TK0;hl7u(s&i7N9a|J=b~`QEfpQ%w(5y zHMHFGWIavN@0Z%nX{dz^_-;2HutIVr$WHb5ZgA*&OuY@~68oDQ*)6*RukR1M!Z0ub vibr)$PGNLDjp_C)gP!nM2HBm$mWedkl)3W=;N=q#Uq%f*O zS2C83<2D1eBU`QRrM1kiHf(mwY>!F9(g6Q(lc4n=&{)gc^|2f}({_p$Gv@U90 zB(K-ob~NnVwR_Lreftj_Jk)sj$kC?eW5-)s+iw3q&uG%%|X zN}-`sPY_zl7Fivt%W$iUi8HPg-l0N~E*2?}9|YC6!H^rBX6G{Q0P?X{7=!9vmy$>4 z6{=1O+t1mDarrsBlOlD59hRCjp?;XtYMwFVmu`xJc8@#-FhLNKa8_K$hdkJ9fuK1o zPY2g;;mPxLe4htb2|m0<2;gcVXn`nZxXhS>=s4$KLX!7Ar_$Ef7;j~3*s6&N8IgqY zoe<1~kY$11x5jo|sz|#QJHPOugts9*mo|abU6JB=Y6Qf;0dc$xlDbzjR!(!MbrRU1 zx^%#y;)Rh!e3DBK9OzfZJLb|DdNW1hh>Qipnt)T8bEcZr3JnY8b%GsI(8Z9mk23dZ zeU+IiX=A(RtR{e{^L9@Cq2pHlOs7u1r4p!f`klgp7_MEB5Ni4DJ>Y|z@9X9VRf+;6 zT_0bJs}vo7DGUZtqh;+pvpSF!*UMQ-dONvpz)Wze!Vse#^vX;bOuE}a(aFBPTCS7( z(fJuA#^ex<$?Ve^l_do+ene#1loXDk^~o^kKE9|KwQl`=U|Z?8XQR)g@lZGx91DcU zg8o<_)Qu{$OV$*`Ae8Uk^Y!%l1HsK3L-)gd(!~c4Tl$;(9}P4OHgZD^!;z87$Kmkk zlQG}lh(gjFw!~IKQA7ghcFT<5hoCJ0 mwdJ*-#xSU;ZRT=@{5&HwXPY{XDk2qUJDL=c?wGF-cm4n$0k{AF diff --git a/bin/basic_ultimate64.rom b/bin/basic_ultimate64.rom index 4876d158c41697d82880660f0eb519e8185debf0..b84cd139b1cf64466f2311fa35034f17f31f2249 100644 GIT binary patch delta 1294 zcmYjQZA@EL7{2$m9i?4+3!_rL$|+=vq%As^Er^z|IhSHi<_}4XL*wlP&YZHTF=)7^|3ns zjWJkGs7pUA#lw7Gtj?y36g&}%KdGjBg#bt1)nob-vaIi_ER}*Za^*6VOmjiK7Ug%O zJ=+^`@da^!{4N6Lt$Gv{D$?;UeWd?`Wf70^o<{ zkSmGy38+*GH~$QY)j2#LL+Lv~9kBI}!7|x{{+d7wcRwY`?}(AB5RB?7mOS^U;e}+tP&~k%~=Lud6Y{ulfi04Hp~0>w1xvGhJw)7<$DeNx zaooz)&*HP!5~B3-OUb#^d|tf%`Sil43tuc+zZ~qi;Z0|58ozS8mu}6*|NXLAHAumJ zDm4YsT0A=&PeLG)A1kX|tTKuyih@RT2NRJ8m=)1INo^OsLN7d=w&^8qe-_pbT zw$N_dW1ob-O@c+1tM7{=A#WYQn@Cl81H+_oc~dPFWe57q#rCpAdTV3|xS+_Wp1 zSG6Bh*lLef9B4f9OygdP0+!&ED8nZ>G$I0NGFV%40+OqO&}ry01oGO{vzdbYCk%NR z47uIGZONn>lN)K8e5wJ}OR7GqGXD)?#2xmA8qs%Kg9tE2prw?mDo)P9td!+8hh%2+ GE$$y{aWU8c delta 1292 zcmZuwZ%i9y7{9v~DD7y0ffN|nKj$Df=zd+xkzNdEstPH8cHjjU>$^Dal+G|Ey!RG4Pn+C&sf4u&7&6Eg>s znrJ}zk{1d~6gS1&hHOE;ddTLc0LC3RHygONpblbkF2$1bsf-4veCdc0QA32!j%jeG z!e^O@U@n}AraWWldh(NglF1awdBfqI+aMubdXi6rdq~_M07%&JEA1rXX(dHY1v?aX zTDjYZ_f4WpSI{FlR2sA5L>@cH!!$&nAVy;q-A?L^7HvD=NxRYBaM6#%S)UHI$vzD_ zvp!nxDdY9%UfiX@^~!1MKn1S{di&;)MM5v}=yJqU^)n>y&*Oz@6nx;;Kuz{RcucgS zKgZGH124thO^8F%O~pB?S`+qR`)xGt!AGY;cfuJ#RRwGs-epr-IRglEW6sBz*@RM+ z8>&tKxSIYw4TOKlXk;29GnJVvo#a$NteMYtKGCFl>5*FZZ&-?xOF6rrb12?8R~2D^ zmQ%SxGa;--WHaY@NpX~Ksf%+h_}DCZBm!l;q)-%sbX%;JZwhO0>L^+w9p(eJg>_#J z2*;?C-84_qM7y5q)*4i!gPHgf$7 z|Lj~q5Qi^H^YTLM=8Z3>7C&EHS~lM7(A}~IL$@2h>h4~-Gv@zi$+8;Au%DDCAzJrG z1iu8qEcr1n-{MdP5JgeYpcZ$)`xKi5XsX&;kVBQ?9b(SEPz>!<$#B)JoNbHkwmr6q z_*)6Avzq^6uR~E?hGI{#cO6|{!~KFM5YhRV5gm(R>rgm7$`suc4#fGUSTf%dX1p{D zd6uH!=8<}QS758|@HrEtb{S4s7K^#VQm3W+MA$M1+s-|;LBzu?P>QnI6=pWO*}nlI CtWEC# diff --git a/bin/kernal_generic.rom b/bin/kernal_generic.rom index 18729a729054a5916325d00e9902073394648461..06a5a7fb7ebd2fba94de9604545364dfabfecb9d 100644 GIT binary patch delta 296 zcmZp0XmFSiZqEBKLE-w+r75hbtcf3(efF+j%760zh3`v~T1A#7w~9(6Cg^xaQ zk0#qPN=;5-GEuMDzd>AK-rA+SKx+@IUz*su9q6>(K&S1INJv<~0Cbqg2_P|fKhtlP z_P+J&C+}lUH_gt;&C4$+EGjN3Ei136tg5c5t*dWnT!$SbC@AkynEq&T6pKBR)}zU@ TS+v;9^xT~F3^$)nkDuq2eCNTT#TJMvw5h%KVQ9qB09xK&b88Z@Af;hH5ybr;QBp`zW%*vdY-EraP zv8-b`$MP}G`(#;0ea5AeeHqml zJ13VgE|{FcWTJlV)goDi@P|vSPX7PEvxr3@7RX#?slc%T=$3>93_yo@oB$G&_cQ%w zdHZGm{>l58(@k5HTa^~DY*cE^?En%vAR-$`a5l7NZB!CqUin{VB|~c-NH}w8VnTv~ h@*aib%O^*%*fYsKoIIOFi_KKe%~{WA^Jx}SX#mSoe`Npw diff --git a/bin/kernal_ultimate64.rom b/bin/kernal_ultimate64.rom index 0880452f31d436301289b3c319c3f6d79f238101..9f4108ffb802d7994b5a6ff67a781a0f02ec893a 100644 GIT binary patch delta 293 zcmZp0XmFSiZLGL=C4<6*{|Z8T6b?Mzz^yQCze45C3Cuof4}EU#1BxzSR8V|$lHmfg z&w-6gCmJyO?AbA~PgcFjyg9FUUoS5Bl;pefeV>!q2E`0QfdogIS7r&Gg)y^$Zyp Mz!q=5#G)q+046ehCIA2c delta 293 zcmZp0XmFSiZG3a-(iGNI*2E9YK9vub@}K;F;rr60R*|L2t)dbM3acM1U{nx!c#`1) zv(JHzOD7sI`y5|Bu}@ZTsdlUFQk_=21n-}G49&M0{!iTFZMIUam2qR0$4d29#*73o z$JU4UA()W_WN?64nG>@+F8n-}bu8yt-i41ofe$BpF-ftl`oMomz;3c2qv~V@MwZED zjQ7|QeBvMa#81v*QsvvTV*;~J{X>P!{Xn{A@?55VCfSFR^_Z173Lh@z1v)Bzas;y~ zW5MJ)W>+Tmhm(&oC+M{(w<;}Q*{IZ-+W{nUKtwi>;B08k+NdPJyz;-!N`}@vkZ|VG b#DvMgEJeJgdT!2oMhpyKi#K0l(US%MNLh4? diff --git a/bin/mega65.rom b/bin/mega65.rom index f70851d7b6317a631fd434c80393b94e118c4f92..6c78832169403e0ea0dfc43c175dd39bf32f652d 100644 GIT binary patch delta 910 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 Date: Sat, 27 Jun 2020 12:01:51 +0200 Subject: [PATCH 103/103] explained all similarities >3 --- strings/012CA9022CA9032CA9042CA9052CA9062CA9072CA9082CA909 | 3 +++ strings/021860A90085 | 5 +++++ strings/0285B960 | 3 +++ strings/0980856A | 3 +++ strings/1860A900 | 5 +++++ strings/209EAD20 | 3 +++ strings/278563A5 | 3 +++ strings/288564A5 | 3 +++ strings/309004C93C90 | 3 +++ strings/48A56348 | 3 +++ strings/60A9012CA9 | 3 +++ strings/60A9012CA900 | 3 +++ strings/60C922D0 | 3 +++ strings/60C922D008A5D449 | 3 +++ strings/61A56585 | 3 +++ strings/62666366646665 | 3 +++ strings/626663666466656670 | 3 +++ strings/65358535 | 3 +++ strings/6662666366646665 | 3 +++ strings/6662666366646665667060A5 | 3 +++ strings/6663666466656670 | 3 +++ strings/68856A6885 | 3 +++ strings/68856B6885 | 3 +++ strings/69D0034C | 3 +++ strings/85358436 | 3 +++ strings/85658564 | 3 +++ strings/91F38810F5 | 3 +++ strings/A001B1B285 | 3 +++ strings/A004B12285 | 3 +++ strings/A004B122856588B122856488B122856388B122 | 3 +++ strings/A004B122856D88B122856C88B122856B88B122 | 3 +++ strings/A2198616 | 3 +++ strings/A5012910F0 | 3 +++ strings/A56248A5 | 4 ++++ strings/A5648563 | 3 +++ strings/A62DA42E | 3 +++ strings/A63AE8D0 | 3 +++ strings/A63AE8F0 | 3 +++ strings/A9EFA0E2 | 3 +++ strings/AE209EAD | 3 +++ strings/AE209EAD20 | 3 +++ strings/B7F00A20 | 3 +++ strings/C4B7F00A | 3 +++ strings/C4D3D0EF | 3 +++ strings/CAA000B1 | 3 +++ strings/D0FBC898 | 3 +++ strings/F9F00720 | 3 +++ strings/FF00000000000000000000 | 3 +++ 48 files changed, 149 insertions(+) create mode 100644 strings/012CA9022CA9032CA9042CA9052CA9062CA9072CA9082CA909 create mode 100644 strings/021860A90085 create mode 100644 strings/0285B960 create mode 100644 strings/0980856A create mode 100644 strings/1860A900 create mode 100644 strings/209EAD20 create mode 100644 strings/278563A5 create mode 100644 strings/288564A5 create mode 100644 strings/309004C93C90 create mode 100644 strings/48A56348 create mode 100644 strings/60A9012CA9 create mode 100644 strings/60A9012CA900 create mode 100644 strings/60C922D0 create mode 100644 strings/60C922D008A5D449 create mode 100644 strings/61A56585 create mode 100644 strings/62666366646665 create mode 100644 strings/626663666466656670 create mode 100644 strings/65358535 create mode 100644 strings/6662666366646665 create mode 100644 strings/6662666366646665667060A5 create mode 100644 strings/6663666466656670 create mode 100644 strings/68856A6885 create mode 100644 strings/68856B6885 create mode 100644 strings/69D0034C create mode 100644 strings/85358436 create mode 100644 strings/85658564 create mode 100644 strings/91F38810F5 create mode 100644 strings/A001B1B285 create mode 100644 strings/A004B12285 create mode 100644 strings/A004B122856588B122856488B122856388B122 create mode 100644 strings/A004B122856D88B122856C88B122856B88B122 create mode 100644 strings/A2198616 create mode 100644 strings/A5012910F0 create mode 100644 strings/A56248A5 create mode 100644 strings/A5648563 create mode 100644 strings/A62DA42E create mode 100644 strings/A63AE8D0 create mode 100644 strings/A63AE8F0 create mode 100644 strings/A9EFA0E2 create mode 100644 strings/AE209EAD create mode 100644 strings/AE209EAD20 create mode 100644 strings/B7F00A20 create mode 100644 strings/C4B7F00A create mode 100644 strings/C4D3D0EF create mode 100644 strings/CAA000B1 create mode 100644 strings/D0FBC898 create mode 100644 strings/F9F00720 create mode 100644 strings/FF00000000000000000000 diff --git a/strings/012CA9022CA9032CA9042CA9052CA9062CA9072CA9082CA909 b/strings/012CA9022CA9032CA9042CA9052CA9062CA9072CA9082CA909 new file mode 100644 index 00000000..ca77c0d2 --- /dev/null +++ b/strings/012CA9022CA9032CA9042CA9052CA9062CA9072CA9082CA909 @@ -0,0 +1,3 @@ +$01 + BIT + LDA #$02 + BIT + LDA #$03 + ... + LDA #$09 + +Ledder of LDA's and BIT's - a common 6502 space-saving trick to set the CPU register value depending on the jump address and perform common action. Not creative - not copyrightable. diff --git a/strings/021860A90085 b/strings/021860A90085 new file mode 100644 index 00000000..046d28ca --- /dev/null +++ b/strings/021860A90085 @@ -0,0 +1,5 @@ +$18 + CLC + RTS + LDA #$00 + STA (zeropage address does not match) + +End of a routine reporting a success (by clearing Carry) followed by start of another routine, starting from putting 0 into .A register - plus some parts. Trivial - not copyrightable. + +BTW, most of the time the routines are placed in the order determined by algorithm, using a specialized tool (without human intervention), and this order can undergo major changes after a small code modification - and this similarity is most likely caused by the currently determined ROM layout. diff --git a/strings/0285B960 b/strings/0285B960 new file mode 100644 index 00000000..981bab45 --- /dev/null +++ b/strings/0285B960 @@ -0,0 +1,3 @@ +$02 + STA $B9 + RTS + +Routine ending by setting a zeropage variable + plus some part. Trivial - not copyrightable. diff --git a/strings/0980856A b/strings/0980856A new file mode 100644 index 00000000..d63a76be --- /dev/null +++ b/strings/0980856A @@ -0,0 +1,3 @@ +ORA #$80 + STA $6A + +Part of the code setting highest bit in a zeropage variable. Trivial - not copyrightable. diff --git a/strings/1860A900 b/strings/1860A900 new file mode 100644 index 00000000..15604581 --- /dev/null +++ b/strings/1860A900 @@ -0,0 +1,5 @@ +CLC + RTS + LDA #$00 + +End of a routine reporting a success (by clearing Carry) followed by start of another routine, starting from putting 0 into .A register. Trivial - not copyrightable. + +BTW, most of the time the routines are placed in the order determined by algorithm, using a specialized tool (without human intervention), and this order can undergo major changes after a small code modification - and this similarity is most likely caused by the currently determined ROM layout. diff --git a/strings/209EAD20 b/strings/209EAD20 new file mode 100644 index 00000000..03ccdf59 --- /dev/null +++ b/strings/209EAD20 @@ -0,0 +1,3 @@ +JSR $AD9E (CHRGOT) + JSR (address does not match) + +Call of a well-known subroutine + some part of other instruction. Trivial - not copyrightable. diff --git a/strings/278563A5 b/strings/278563A5 new file mode 100644 index 00000000..975d4737 --- /dev/null +++ b/strings/278563A5 @@ -0,0 +1,3 @@ +$27 + STA $63 + LDA (zeropage address does not match) + +Instruction (accessing well-known zeropage location) + some parts. Trivial - not copyrightable. diff --git a/strings/288564A5 b/strings/288564A5 new file mode 100644 index 00000000..d246494e --- /dev/null +++ b/strings/288564A5 @@ -0,0 +1,3 @@ +$28 + STA $64 + LDA (zeropage address does not match) + +Instruction (accessing well-known zeropage location) + some parts. Trivial - not copyrightable. diff --git a/strings/309004C93C90 b/strings/309004C93C90 new file mode 100644 index 00000000..17bda5a2 --- /dev/null +++ b/strings/309004C93C90 @@ -0,0 +1,3 @@ +$30 + BCC (offset matches) + CMP #$3C + BCC (offset does not match) + +Part of code checking whether the valu is within the given range. Not creative - not copyrightable. diff --git a/strings/48A56348 b/strings/48A56348 new file mode 100644 index 00000000..6a8bda71 --- /dev/null +++ b/strings/48A56348 @@ -0,0 +1,3 @@ +PHA + LDA $63 + PHA + +Part of the code storing several values on stack. Trivial - not copyrightable. diff --git a/strings/60A9012CA9 b/strings/60A9012CA9 new file mode 100644 index 00000000..b332d9e6 --- /dev/null +++ b/strings/60A9012CA9 @@ -0,0 +1,3 @@ +RTS + LDA #$01 + BIT + LDA + +Routine starting by setting .A to 1 or some other value, depending on entry address (common 6502 trick to save memoryy using BIT instruction). Not creative - not copyrightable. diff --git a/strings/60A9012CA900 b/strings/60A9012CA900 new file mode 100644 index 00000000..b98146f4 --- /dev/null +++ b/strings/60A9012CA900 @@ -0,0 +1,3 @@ +RTS + LDA #$01 + BIT + LDA #$00 + +Routine starting by setting .A to 0 or 1 depending on entry address (common 6502 trick to save memoryy using BIT instruction). Not creative - not copyrightable. diff --git a/strings/60C922D0 b/strings/60C922D0 new file mode 100644 index 00000000..7ae0b049 --- /dev/null +++ b/strings/60C922D0 @@ -0,0 +1,3 @@ +RTS + CMP #$22 + BNE (offset does not match) + +Routine starting by comparing accumulator to a predefined value - trivial, not copyrightable. diff --git a/strings/60C922D008A5D449 b/strings/60C922D008A5D449 new file mode 100644 index 00000000..cf26cf03 --- /dev/null +++ b/strings/60C922D008A5D449 @@ -0,0 +1,3 @@ +RTS + CMP #$22 + BNE (offset matches) + LDA $D4 + EOR (value does not match) + +Part of a routine handling quote flag (QTSW - $D4 on zeropage) depending on quote symbol ($22). Not creative (nothing complicated here and the similarity doesn't even cover the whole flow) - not copyrightable. diff --git a/strings/61A56585 b/strings/61A56585 new file mode 100644 index 00000000..e57488f7 --- /dev/null +++ b/strings/61A56585 @@ -0,0 +1,3 @@ +$61 + LDA $65 + STA (zeropage addres does not match) + +Instruction (accessing well-known zeropage location) + some parts. Trivial - not copyrightable. diff --git a/strings/62666366646665 b/strings/62666366646665 new file mode 100644 index 00000000..26e602d9 --- /dev/null +++ b/strings/62666366646665 @@ -0,0 +1,3 @@ +$62 + ROR $63 + ROR $64 + ROR $65 + +Right-rotate on a multibyte variable (typical 6502 code) - trivial, not copyrightable. diff --git a/strings/626663666466656670 b/strings/626663666466656670 new file mode 100644 index 00000000..21a369de --- /dev/null +++ b/strings/626663666466656670 @@ -0,0 +1,3 @@ +$62 + ROR $63 + ROR $64 + ROR $65 + ROR $70 + +Right-rotate on a multibyte variable (typical 6502 code) - trivial, not copyrightable. diff --git a/strings/65358535 b/strings/65358535 new file mode 100644 index 00000000..a2dfcd26 --- /dev/null +++ b/strings/65358535 @@ -0,0 +1,3 @@ +ADC $35 + STA $35 + +Adding a value to a zeropage variable. Trivial - not copyrightable. diff --git a/strings/6662666366646665 b/strings/6662666366646665 new file mode 100644 index 00000000..0f61ac66 --- /dev/null +++ b/strings/6662666366646665 @@ -0,0 +1,3 @@ +ROR $62 + ROR $63 + ROR $64 + ROR $65 + +Rotate-right operation done on a 32-bit value (floating point accumulator mantissa) - trivial, not copyrightable. diff --git a/strings/6662666366646665667060A5 b/strings/6662666366646665667060A5 new file mode 100644 index 00000000..43e94fa5 --- /dev/null +++ b/strings/6662666366646665667060A5 @@ -0,0 +1,3 @@ +ROR $62 + ROR $63 + ROR $64 + ROR $65 + ROR $70 + RTS + LDA (zeropage address does not match) + +Unrolled loop that performs a simple operation (shift by one bit) on a well-known variable - floating point accumulator mantissa. Plus some p[art of another instruction, from a different subroutine. Not creative and rather trivial - not copyrightable. diff --git a/strings/6663666466656670 b/strings/6663666466656670 new file mode 100644 index 00000000..8f8d4226 --- /dev/null +++ b/strings/6663666466656670 @@ -0,0 +1,3 @@ +ROR $63 + ROR $64 + ROR $65 + ROR $70 + +Right-rotate on a multibyte variable (typical 6502 code) - trivial, not copyrightable. diff --git a/strings/68856A6885 b/strings/68856A6885 new file mode 100644 index 00000000..0d77a3f6 --- /dev/null +++ b/strings/68856A6885 @@ -0,0 +1,3 @@ +PLA + STA $6A + PLA + STA (address does not match) + +Part of sequence storing several values on the stack. Trivial - not copyrightable. diff --git a/strings/68856B6885 b/strings/68856B6885 new file mode 100644 index 00000000..bf7bcfd1 --- /dev/null +++ b/strings/68856B6885 @@ -0,0 +1,3 @@ +PLA + STA $6B + PLA + STA (address does not match) + +Part of sequence storing several values on the stack. Trivial - not copyrightable. diff --git a/strings/69D0034C b/strings/69D0034C new file mode 100644 index 00000000..a2e1eabc --- /dev/null +++ b/strings/69D0034C @@ -0,0 +1,3 @@ +$69 + BNE (skip next instruction) + JMP (address does not match) + +Instruction plus some parts - trivial, not copyrightable. diff --git a/strings/85358436 b/strings/85358436 new file mode 100644 index 00000000..c61d15cc --- /dev/null +++ b/strings/85358436 @@ -0,0 +1,3 @@ +STA $35 + STY $36 + +Store two CPU registers in a 16-bit zeropage variable (FRESPC). Trivial - not copyrightable. diff --git a/strings/85658564 b/strings/85658564 new file mode 100644 index 00000000..1fe03e76 --- /dev/null +++ b/strings/85658564 @@ -0,0 +1,3 @@ +STA $65 + STA $64 + +Part of the code zeroing a temporary storage on zeropage. Trivial - not copyrightable. diff --git a/strings/91F38810F5 b/strings/91F38810F5 new file mode 100644 index 00000000..eadda531 --- /dev/null +++ b/strings/91F38810F5 @@ -0,0 +1,3 @@ +STA ($F3),Y + DEY + BPL (offset matches) + +Small part of the loop moving screen content. Not creative - not copyrightable. diff --git a/strings/A001B1B285 b/strings/A001B1B285 new file mode 100644 index 00000000..44f9cfdc --- /dev/null +++ b/strings/A001B1B285 @@ -0,0 +1,3 @@ +LDY #$01 + LDA ($B2),Y + STA (zeropage address does not match) + +Small part of the code (only 2 instructions fully match) fetching multi-byte value via zeropage pointer - trivial, not copyrightable. diff --git a/strings/A004B12285 b/strings/A004B12285 new file mode 100644 index 00000000..dd3688f6 --- /dev/null +++ b/strings/A004B12285 @@ -0,0 +1,3 @@ +LDY #$04 + LDA ($22),Y + STA (address does not match) + +Small part of the code (only 2 instructions fully match) fetching multi-byte value via zeropage pointer - trivial, not copyrightable. diff --git a/strings/A004B122856588B122856488B122856388B122 b/strings/A004B122856588B122856488B122856388B122 new file mode 100644 index 00000000..11b6c674 --- /dev/null +++ b/strings/A004B122856588B122856488B122856388B122 @@ -0,0 +1,3 @@ +LDY #$04 + LDA ($22),Y + STA $65 + DEY + LDA ($22),Y + STA $64 + DEY + LDA ($22),Y + STA $63 + DEY + LDA ($22),Y + +Unrolled loop that performs a simple operation (fetch from memory) on a well-known variable - floating point accumulator. Not creative and rather trivial - not copyrightable. diff --git a/strings/A004B122856D88B122856C88B122856B88B122 b/strings/A004B122856D88B122856C88B122856B88B122 new file mode 100644 index 00000000..316de38e --- /dev/null +++ b/strings/A004B122856D88B122856C88B122856B88B122 @@ -0,0 +1,3 @@ +LDY #$04 + LDA ($22),Y + STA $6D + DEY + LDA ($22),Y + STA $6C + DEY + LDA ($22),Y + STA $6B + DEY + LDA ($22),Y + +Part of unrolled loop that performs a simple operation (shift by one bit) on a well-known variable - floating point accumulator mantissa. Not creative and rather trivial - not copyrightable. diff --git a/strings/A2198616 b/strings/A2198616 new file mode 100644 index 00000000..b32f9e0f --- /dev/null +++ b/strings/A2198616 @@ -0,0 +1,3 @@ +LDX #$19 + STX $16 + +Store predefined value in a well-known zeropage location. Trivial - not copyrightable. diff --git a/strings/A5012910F0 b/strings/A5012910F0 new file mode 100644 index 00000000..4c011c4d --- /dev/null +++ b/strings/A5012910F0 @@ -0,0 +1,3 @@ +LDA $01 + AND #$10 + BEQ (offset does not match) + +Decision based on a state of a bit in a documented hardware register. Trivial - not copyrightable. diff --git a/strings/A56248A5 b/strings/A56248A5 new file mode 100644 index 00000000..13add0f8 --- /dev/null +++ b/strings/A56248A5 @@ -0,0 +1,4 @@ +LDA $62 + PHA + LDA (zeropage address does not match) + +Store zeropage variable on stack + some part - trivial, not copyrightable. + diff --git a/strings/A5648563 b/strings/A5648563 new file mode 100644 index 00000000..026aecf8 --- /dev/null +++ b/strings/A5648563 @@ -0,0 +1,3 @@ +LDA $64 + STA $63 + +Small part (2 instructions) of code manipulating a floating code mantissa. Trivial - not copyrightable. diff --git a/strings/A62DA42E b/strings/A62DA42E new file mode 100644 index 00000000..60368dc1 --- /dev/null +++ b/strings/A62DA42E @@ -0,0 +1,3 @@ +LDX $2D + LDY $2E + +2 instructions to fetch zeropage variable (VARTAB) for usage by Kernal documented API. Trivial - not copyrightable. diff --git a/strings/A63AE8D0 b/strings/A63AE8D0 new file mode 100644 index 00000000..cc32abeb --- /dev/null +++ b/strings/A63AE8D0 @@ -0,0 +1,3 @@ +LDX $3A + INX + BNE (offset does not match) + +Check whether a zeropage variable contains $FF. Trivial - not copyrightable. diff --git a/strings/A63AE8F0 b/strings/A63AE8F0 new file mode 100644 index 00000000..361fd785 --- /dev/null +++ b/strings/A63AE8F0 @@ -0,0 +1,3 @@ +LDX $3A + INX + BEQ (offset does not match) + +Check whether a zeropage variable contains $FF. Trivial - not copyrightable. diff --git a/strings/A9EFA0E2 b/strings/A9EFA0E2 new file mode 100644 index 00000000..bc12528b --- /dev/null +++ b/strings/A9EFA0E2 @@ -0,0 +1,3 @@ +LDA #$EF + LDY #$E2 + +2 instructions fetching known zeropage variables. Trivial - not copyrightable. diff --git a/strings/AE209EAD b/strings/AE209EAD new file mode 100644 index 00000000..a797f38b --- /dev/null +++ b/strings/AE209EAD @@ -0,0 +1,3 @@ +$AE + JSR $AD9E (FRMEVL) + +Instruction (calls a well-known routine) + some part. Trivial - not copyrightable. diff --git a/strings/AE209EAD20 b/strings/AE209EAD20 new file mode 100644 index 00000000..271509c4 --- /dev/null +++ b/strings/AE209EAD20 @@ -0,0 +1,3 @@ +$AE + JSR $AD9E (FRMEVL) + JSR (address does not match) + +Instruction (calls a well-known routine) + some parts. Trivial - not copyrightable. diff --git a/strings/B7F00A20 b/strings/B7F00A20 new file mode 100644 index 00000000..1dfc3334 --- /dev/null +++ b/strings/B7F00A20 @@ -0,0 +1,3 @@ +$B7 + BEQ (offset matches) + JSR (address does not match) + +Instruction + some parts - trivial, not copyrightable. diff --git a/strings/C4B7F00A b/strings/C4B7F00A new file mode 100644 index 00000000..b84110a2 --- /dev/null +++ b/strings/C4B7F00A @@ -0,0 +1,3 @@ +CPY $B7 + BEQ (offset matches) + +Decision based on a fact whether CPU register is equal to zeropage variable. Trivial - not copyrightable. diff --git a/strings/C4D3D0EF b/strings/C4D3D0EF new file mode 100644 index 00000000..4200de6e --- /dev/null +++ b/strings/C4D3D0EF @@ -0,0 +1,3 @@ +CPY $D3 + BNE (offset matches) + +Decision based on a fact whether CPU register is equal to zeropage variable. Trivial - not copyrightable. diff --git a/strings/CAA000B1 b/strings/CAA000B1 new file mode 100644 index 00000000..a3bc6511 --- /dev/null +++ b/strings/CAA000B1 @@ -0,0 +1,3 @@ +$CA + LDY #$00 + LDA (zeropage address does not match), Y + +Instruction + some parts. Trivial - not copyrightable. diff --git a/strings/D0FBC898 b/strings/D0FBC898 new file mode 100644 index 00000000..2b7528bb --- /dev/null +++ b/strings/D0FBC898 @@ -0,0 +1,3 @@ +BNE (offset matches) + INY + TYA + +Check for zero in some variable (or CPU register - similarity does not cover this part) + simple register manipulation. Not creative (too small fragment, this can be a piece of various routines) - not copyrightable. diff --git a/strings/F9F00720 b/strings/F9F00720 new file mode 100644 index 00000000..fce8ac5e --- /dev/null +++ b/strings/F9F00720 @@ -0,0 +1,3 @@ +$F9 + BEQ (offset matches) + JSR (address does not match) + +Instruction + some parts - trivial, not copyrightable. diff --git a/strings/FF00000000000000000000 b/strings/FF00000000000000000000 new file mode 100644 index 00000000..2c98882f --- /dev/null +++ b/strings/FF00000000000000000000 @@ -0,0 +1,3 @@ +$FF followed by several 0's + +Meaningless sequence of bytes, most likely caused by ROM not being full to the last byte. Not copyrightable.