From 5db25db3b503e72014c8e03088fef04821ebb9cd Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 28 Jun 2020 04:05:32 +0200 Subject: [PATCH 01/24] some cleanup, BASIC line finding now properly uses stack --- Makefile | 2 +- src/basic/basic_commands/cmd_list.s | 2 +- src/basic/basic_commands/cmd_load_verify.s | 2 +- src/basic/basic_commands/cmd_new.s | 2 +- src/basic/basic_commands/cmd_run_goto.s | 2 +- src/basic/basic_commands/cmd_stop_end.s | 2 +- .../basic_commands_CC/cmd_bload_bverify.s | 2 +- src/basic/basic_commands_CC/cmd_merge.s | 2 +- src/basic/basic_delete_line.s | 2 +- .../{basic_find_line.s => editor/find_line.s} | 69 +++++++----- .../{basic_main_loop.s => editor/shell.s} | 101 +++++++++++------- src/basic/{tokenizer => editor}/tk_cut_away.s | 0 src/basic/{tokenizer => editor}/tk_pack.s | 0 src/basic/{tokenizer => editor}/tk_search.s | 0 src/basic/{tokenizer => editor}/tk_shorten.s | 0 .../{tokenizer => editor}/tokenise_line.s | 0 src/basic/engine/do_error.s | 2 +- src/basic/engine/execute_line_statements.s | 6 +- src/basic/init/basic_warm_start_internal.s | 2 +- src/basic/wedge/wedge_dos.s | 4 +- 20 files changed, 116 insertions(+), 86 deletions(-) rename src/basic/{basic_find_line.s => editor/find_line.s} (60%) rename src/basic/{basic_main_loop.s => editor/shell.s} (64%) rename src/basic/{tokenizer => editor}/tk_cut_away.s (100%) rename src/basic/{tokenizer => editor}/tk_pack.s (100%) rename src/basic/{tokenizer => editor}/tk_search.s (100%) rename src/basic/{tokenizer => editor}/tk_shorten.s (100%) rename src/basic/{tokenizer => editor}/tokenise_line.s (100%) diff --git a/Makefile b/Makefile index 92dff008..7dcd2041 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ SRCDIR_BASIC = $(SRCDIR_COMMON) \ src/basic/basic_functions \ src/basic/board_m65 \ src/basic/board_x16 \ + src/basic/editor \ src/basic/engine \ src/basic/init \ src/basic/math \ @@ -28,7 +29,6 @@ SRCDIR_BASIC = $(SRCDIR_COMMON) \ src/basic/memory \ src/basic/print \ src/basic/rom_revision \ - src/basic/tokenizer \ src/basic/wedge SRCDIR_KERNAL = $(SRCDIR_COMMON) \ diff --git a/src/basic/basic_commands/cmd_list.s b/src/basic/basic_commands/cmd_list.s index be79ad4c..d1b8b75b 100644 --- a/src/basic/basic_commands/cmd_list.s +++ b/src/basic/basic_commands/cmd_list.s @@ -31,7 +31,7 @@ list_loop: // LIST terminates any running program, // because it has fiddled with the current line pointer. // (Confirmed by testing on a C64) - jmp basic_main_loop + jmp shell_main_loop list_more_lines: lda STKEY diff --git a/src/basic/basic_commands/cmd_load_verify.s b/src/basic/basic_commands/cmd_load_verify.s index aab37558..868c7406 100644 --- a/src/basic/basic_commands/cmd_load_verify.s +++ b/src/basic/basic_commands/cmd_load_verify.s @@ -80,4 +80,4 @@ cmd_load_no_error: cmd_load_end: - jmp basic_main_loop + jmp shell_main_loop diff --git a/src/basic/basic_commands/cmd_new.s b/src/basic/basic_commands/cmd_new.s index ce879826..d2186c3f 100644 --- a/src/basic/basic_commands/cmd_new.s +++ b/src/basic/basic_commands/cmd_new.s @@ -9,4 +9,4 @@ cmd_new: // NEW command terminates execution (confirmed on a C64) - jmp basic_main_loop + jmp shell_main_loop diff --git a/src/basic/basic_commands/cmd_run_goto.s b/src/basic/basic_commands/cmd_run_goto.s index 65570149..dc93da96 100644 --- a/src/basic/basic_commands/cmd_run_goto.s +++ b/src/basic/basic_commands/cmd_run_goto.s @@ -18,7 +18,7 @@ cmd_goto: bcs !+ jsr basic_parse_line_number - jsr basic_find_line + jsr find_line bcc !+ // Line does not exist, so report error jmp do_UNDEFD_STATEMENT_error diff --git a/src/basic/basic_commands/cmd_stop_end.s b/src/basic/basic_commands/cmd_stop_end.s index 51c4906e..3cf6f64c 100644 --- a/src/basic/basic_commands/cmd_stop_end.s +++ b/src/basic/basic_commands/cmd_stop_end.s @@ -27,4 +27,4 @@ cmd_stop: cmd_end: - jmp basic_main_loop + jmp shell_main_loop diff --git a/src/basic/basic_commands_CC/cmd_bload_bverify.s b/src/basic/basic_commands_CC/cmd_bload_bverify.s index a85891f5..2b6db9fb 100644 --- a/src/basic/basic_commands_CC/cmd_bload_bverify.s +++ b/src/basic/basic_commands_CC/cmd_bload_bverify.s @@ -39,4 +39,4 @@ cmd_bload: // XXX when number parsing is done, change to continue execution - jmp basic_main_loop + jmp shell_main_loop diff --git a/src/basic/basic_commands_CC/cmd_merge.s b/src/basic/basic_commands_CC/cmd_merge.s index 5734b68d..bf157798 100644 --- a/src/basic/basic_commands_CC/cmd_merge.s +++ b/src/basic/basic_commands_CC/cmd_merge.s @@ -50,4 +50,4 @@ cmd_merge_no_error: // XXX when number parsing is done, change to continue execution - jmp basic_main_loop + jmp shell_main_loop diff --git a/src/basic/basic_delete_line.s b/src/basic/basic_delete_line.s index 864fd0c7..fdeff539 100644 --- a/src/basic/basic_delete_line.s +++ b/src/basic/basic_delete_line.s @@ -3,7 +3,7 @@ // #LAYOUT# * * #IGNORE // Delete the current BASIC line, which is assumed to have already -// been found with basic_find_line. +// been found with find_line. // Really only consists of copying memory down. // The only complication is that we have to do the copy with ROMs // banked out. Oh, yes, and we have to update all the links in diff --git a/src/basic/basic_find_line.s b/src/basic/editor/find_line.s similarity index 60% rename from src/basic/basic_find_line.s rename to src/basic/editor/find_line.s index be9a962e..a98cc91c 100644 --- a/src/basic/basic_find_line.s +++ b/src/basic/editor/find_line.s @@ -5,19 +5,24 @@ // Find the BASIC line with number LINNUM +// XXX it should be possible to start from the current line (OLDTXT), or from the startup, +// depending on the current and target line number + + +find_line: -basic_find_line: // Get pointer to start of BASIC text lda TXTTAB+0 sta OLDTXT+0 lda TXTTAB+1 sta OLDTXT+1 -basic_find_line_loop: - // Then search for line number - // Line number - - ldy #3 + // FALLTROUGH + +find_line_loop: + + // Fetch the high byte of line number and compare + ldy #$03 #if CONFIG_MEMORY_MODEL_60K ldx # Date: Sun, 28 Jun 2020 08:32:25 +0200 Subject: [PATCH 02/24] small cleanup in BASIC --- .../delete_line.s} | 13 ++++++------- .../insert_line.s} | 18 ++++++++++-------- src/basic/editor/shell.s | 16 +++++++--------- 3 files changed, 23 insertions(+), 24 deletions(-) rename src/basic/{basic_delete_line.s => editor/delete_line.s} (86%) rename src/basic/{basic_insert_line.s => editor/insert_line.s} (85%) diff --git a/src/basic/basic_delete_line.s b/src/basic/editor/delete_line.s similarity index 86% rename from src/basic/basic_delete_line.s rename to src/basic/editor/delete_line.s index fdeff539..792d1237 100644 --- a/src/basic/basic_delete_line.s +++ b/src/basic/editor/delete_line.s @@ -2,14 +2,12 @@ // #LAYOUT# * BASIC_0 #TAKE // #LAYOUT# * * #IGNORE -// Delete the current BASIC line, which is assumed to have already -// been found with find_line. -// Really only consists of copying memory down. -// The only complication is that we have to do the copy with ROMs -// banked out. Oh, yes, and we have to update all the links in -// the following basic lines. +// +// Delete the current BASIC line, which is assumed to have already been found with find_line. +// Consists of copying memory down and lline linkage update. +// -basic_delete_line: +delete_line: // jsr printf // .text "DELETING LINE AT $" @@ -61,6 +59,7 @@ basic_delete_line: sbc #0 cmp #$00 beq !+ + // Line length is <0 or >255 bytes. // Either way, things are bad, so abort. jmp do_MEMORY_CORRUPT_error diff --git a/src/basic/basic_insert_line.s b/src/basic/editor/insert_line.s similarity index 85% rename from src/basic/basic_insert_line.s rename to src/basic/editor/insert_line.s index 7aff08ab..a96d521a 100644 --- a/src/basic/basic_insert_line.s +++ b/src/basic/editor/insert_line.s @@ -2,17 +2,18 @@ // #LAYOUT# * BASIC_0 #TAKE // #LAYOUT# * * #IGNORE +// // Insert the tokenised line stored at $0200. -// First work out where in the list to put it -// (basic_find_line with the line number can be used to work -// out the insertion point, as it should abort once it finds a -// line number too high). +// +// First work out where in the list to put it (find_line with the line number can be used to work +// out the insertion point, as it should abort once it finds a line number too high). // Then all we have to do is push the rest of the BASIC text up, // and update the pointers in all following basic lines. +// -basic_insert_line: +insert_line: - // ASSUMES basic_find_line has been called to set the insert point. + // ASSUMES find_line has been called to set the insert point. // We need to insert space for the link link token, the line number, // and the zero-terminated line itself. This means 2+2+1 plus length // of tokenised string after the line number @@ -36,6 +37,7 @@ basic_insert_line: lda __tokenise_work2 sec sbc __tokenise_work1 + // Add on the four bytes space we need clc adc #5 @@ -82,7 +84,7 @@ basic_insert_line: // Now store the line body itself inc __tokenise_work2 -line_store_loop: +!: ldx __tokenise_work1 lda $0200,x inc __tokenise_work1 @@ -97,7 +99,7 @@ line_store_loop: lda __tokenise_work1 cmp __tokenise_work2 - bne line_store_loop + bne !- dec __tokenise_work2 clc diff --git a/src/basic/editor/shell.s b/src/basic/editor/shell.s index 4602dc9b..537242ea 100644 --- a/src/basic/editor/shell.s +++ b/src/basic/editor/shell.s @@ -148,24 +148,22 @@ shell_add_delete_line: // First, clear all variables, so that we only have to shove BASIC text around jsr basic_do_clr -.break - // Delete line if present + + // Check if line already present jsr find_line - -// XXX - bcs !+ - // Delete the line, whether we are deleting or - // replacing the line - jsr basic_delete_line + // Line already present - delete it +.break + jsr delete_line + !: // Insert new line if non-zero length, i.e., that // we are not just deleting the line. lda __tokenise_work1 cmp __tokenise_work2 beq !+ - jsr basic_insert_line + jsr insert_line !: // No READY message after entering or deleting a line of BASIC jmp shell_read_next_line From 2ddfacd8e91225dd892a701f1c4acee5e60e7519 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 28 Jun 2020 09:14:06 +0200 Subject: [PATCH 03/24] fixed VARTAB handling, tokenizer now needs sloghtly less memory --- doc/Extended-BASIC.md | 2 +- src/basic/basic_commands_CC/cmd_merge.s | 2 -- src/basic/editor/insert_line.s | 2 +- src/basic/editor/shell.s | 1 - src/basic/editor/tk_cut_away.s | 9 +++++++++ src/basic/editor/tk_pack.s | 12 ++++++------ src/basic/editor/tokenise_line.s | 14 ++++---------- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/doc/Extended-BASIC.md b/doc/Extended-BASIC.md index c5ebca1b..235a0ed9 100644 --- a/doc/Extended-BASIC.md +++ b/doc/Extended-BASIC.md @@ -15,7 +15,7 @@ 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! +Appends the BASIC program from a storage medium to the one currently present in memory. ### `BLOAD "file_name", device_number, start_address` diff --git a/src/basic/basic_commands_CC/cmd_merge.s b/src/basic/basic_commands_CC/cmd_merge.s index bf157798..049f049e 100644 --- a/src/basic/basic_commands_CC/cmd_merge.s +++ b/src/basic/basic_commands_CC/cmd_merge.s @@ -18,8 +18,6 @@ cmd_merge: // 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 diff --git a/src/basic/editor/insert_line.s b/src/basic/editor/insert_line.s index a96d521a..afe16dfe 100644 --- a/src/basic/editor/insert_line.s +++ b/src/basic/editor/insert_line.s @@ -43,7 +43,7 @@ insert_line: adc #5 pha tax - + // Make the space jsr basic_shift_mem_up_and_relink diff --git a/src/basic/editor/shell.s b/src/basic/editor/shell.s index 537242ea..d4a366d7 100644 --- a/src/basic/editor/shell.s +++ b/src/basic/editor/shell.s @@ -154,7 +154,6 @@ shell_add_delete_line: bcs !+ // Line already present - delete it -.break jsr delete_line !: diff --git a/src/basic/editor/tk_cut_away.s b/src/basic/editor/tk_cut_away.s index c88e3c6a..4741388c 100644 --- a/src/basic/editor/tk_cut_away.s +++ b/src/basic/editor/tk_cut_away.s @@ -18,6 +18,15 @@ tk_cut_away_1: // for single-byte tokenized keywords dec tk__len_unpacked // keyword length, afterwards number of bytes to cut away + // Correct the line length + + sec + lda tk__length + sbc tk__len_unpacked + sta tk__length + + // Copy the remaining,. untokenized part in the proper place + inc tk__offset ldy tk__offset diff --git a/src/basic/editor/tk_pack.s b/src/basic/editor/tk_pack.s index 99c27e12..26114fde 100644 --- a/src/basic/editor/tk_pack.s +++ b/src/basic/editor/tk_pack.s @@ -26,14 +26,14 @@ tk_pack: - // Reuse the CPU stack - addresses below $102 are used by 'tokenise_line.s' + // Reuse the CPU stack - address $100 is 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 // 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__len_unpacked = $101 // length of unpacked data; it could replace 'tk__nibble_flag', but at the cost of code size/performance + .label tk__shorten_bits = $102 // 2 bytes for quick shortening of packed candidate + .label tk__nibble_flag = $104 // $00 = start from new byte, $FF = start from high nibble + .label tk__byte_offset = $105 // offset of the current byte (to place new data) in tk__packed - .label tk__packed = $108 // packed candidate, 25 bytes is enough for worst case - a 16 byte keyword + .label tk__packed = $106 // packed candidate, 25 bytes is enough for worst case - a 16 byte keyword // Initialize variables diff --git a/src/basic/editor/tokenise_line.s b/src/basic/editor/tokenise_line.s index dc52f9de..7fd6216e 100644 --- a/src/basic/editor/tokenise_line.s +++ b/src/basic/editor/tokenise_line.s @@ -21,22 +21,20 @@ tokenise_line: #else - // Reuse the CPU stack - addresses above $101 are used by 'tk_pack.s' + // Reuse the CPU stack - addresses above $100 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? + .label tk__length = __tokenise_work1 // length of the raw string // Initialize variables lda #$00 sta tk__offset - ldx __tokenise_work1 - stx tk__length - // Terminate input string with $00 // XXX do we need this? + ldx tk__length sta BUF, x // FALLTROUGH @@ -123,7 +121,6 @@ tokenise_line_keyword_V2: sta BUF, x // Cut away unnecessary bytes - jsr tk_cut_away_1 // Special handling for REM command - after this one nothing more should be tokenised @@ -136,10 +133,7 @@ tokenise_line_keyword_V2: tokenise_line_done: - // Update line length and quit - - lda tk__length - sta __tokenise_work1 + // Quit rts From 0460777fe911fdf76d319103e60328c31c540812 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 28 Jun 2020 11:35:29 +0200 Subject: [PATCH 04/24] fixed NEW/CLR commands, implemented RESTORE --- src/aliases/,aliases_ram_lowmem.s | 4 +- src/basic/basic_commands/cmd__unimplemented.s | 2 - src/basic/basic_commands/cmd_clr.s | 2 +- src/basic/basic_commands/cmd_load_verify.s | 2 +- src/basic/basic_commands/cmd_new.s | 2 +- src/basic/basic_commands/cmd_restore.s | 12 ++ src/basic/basic_commands/cmd_run_goto.s | 2 +- src/basic/basic_commands_CC/cmd_merge.s | 2 +- src/basic/basic_do_new.s | 99 ----------------- .../board_m65/4000.mega65_vectable_basic_1.s | 10 +- src/basic/board_m65/mega65_imports.s | 1 + src/basic/board_m65/mega65_proxies.s | 8 ++ src/basic/editor/shell.s | 2 +- src/basic/engine/do_new_clr_restore.s | 103 ++++++++++++++++++ src/basic/init/initmsg_bytes_free.s | 55 +++++++++- 15 files changed, 191 insertions(+), 115 deletions(-) create mode 100644 src/basic/basic_commands/cmd_restore.s delete mode 100644 src/basic/basic_do_new.s create mode 100644 src/basic/engine/do_new_clr_restore.s diff --git a/src/aliases/,aliases_ram_lowmem.s b/src/aliases/,aliases_ram_lowmem.s index 3e206102..08c6d7e9 100644 --- a/src/aliases/,aliases_ram_lowmem.s +++ b/src/aliases/,aliases_ram_lowmem.s @@ -37,14 +37,14 @@ .label VARTAB = $2D // $2D-$2E end of BASIC code, start of variables .label ARYTAB = $2F // $2F-$30 -- NOT IMPLEMENTED -- .label STREND = $31 // $31-$32 -- NOT IMPLEMENTED -- - .label FRETOP = $33 // $33-$34 -- NOT IMPLEMENTED -- + .label FRETOP = $33 // $33-$34 pointer to bottom of strings area .label FRESPC = $35 // $35-$36 [!] our implementation uses this as temporary string pointer .label MEMSIZ = $37 // $37-$38 highest address of BASIC memory + 1 .label CURLIN = $39 // $39-$3A current BASIC line number .label OLDLIN = $3B // $3B-$3C previous BASIC line number .label OLDTXT = $3D // $3D-$3E current BASIC line pointer .label DATLIN = $3F // $3F-$40 -- NOT IMPLEMENTED -- - .label DATPTR = $41 // $41-$42 -- NOT IMPLEMENTED -- + .label DATPTR = $41 // $41-$42 pointer for READ/DATA copmmands .label INPPTR = $43 // $43-$44 -- NOT IMPLEMENTED -- .label VARNAM = $45 // $45-$46 -- NOT IMPLEMENTED -- .label VARPNT = $47 // $47-$48 -- NOT IMPLEMENTED -- diff --git a/src/basic/basic_commands/cmd__unimplemented.s b/src/basic/basic_commands/cmd__unimplemented.s index 4e67d479..6495feb6 100644 --- a/src/basic/basic_commands/cmd__unimplemented.s +++ b/src/basic/basic_commands/cmd__unimplemented.s @@ -27,8 +27,6 @@ cmd_let: nop cmd_if: nop -cmd_restore: - nop cmd_gosub: nop cmd_return: diff --git a/src/basic/basic_commands/cmd_clr.s b/src/basic/basic_commands/cmd_clr.s index 6b4b493c..f944eacc 100644 --- a/src/basic/basic_commands/cmd_clr.s +++ b/src/basic/basic_commands/cmd_clr.s @@ -5,7 +5,7 @@ cmd_clr: - jsr basic_do_clr + jsr do_clr // CLR command does not stop execution (confirmed on a C64) diff --git a/src/basic/basic_commands/cmd_load_verify.s b/src/basic/basic_commands/cmd_load_verify.s index 868c7406..9a0d59fd 100644 --- a/src/basic/basic_commands/cmd_load_verify.s +++ b/src/basic/basic_commands/cmd_load_verify.s @@ -56,7 +56,7 @@ cmd_load_no_error: // C64 BASIC apparently does not clear variables after a LOAD in the // middle of a program. For safety, we do. - jsr basic_do_clr + jsr do_clr // Now relink the loaded program, as we cannot trust the line // links supplied. For example, the VICE virtual drive emulation diff --git a/src/basic/basic_commands/cmd_new.s b/src/basic/basic_commands/cmd_new.s index d2186c3f..e7d7189f 100644 --- a/src/basic/basic_commands/cmd_new.s +++ b/src/basic/basic_commands/cmd_new.s @@ -5,7 +5,7 @@ cmd_new: - jsr basic_do_new + jsr do_new // NEW command terminates execution (confirmed on a C64) diff --git a/src/basic/basic_commands/cmd_restore.s b/src/basic/basic_commands/cmd_restore.s new file mode 100644 index 00000000..034db54e --- /dev/null +++ b/src/basic/basic_commands/cmd_restore.s @@ -0,0 +1,12 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +cmd_restore: + + jsr do_restore + + // RESTORE command does not stop execution (confirmed on a C64) + + jmp execute_statements diff --git a/src/basic/basic_commands/cmd_run_goto.s b/src/basic/basic_commands/cmd_run_goto.s index dc93da96..4282ca1c 100644 --- a/src/basic/basic_commands/cmd_run_goto.s +++ b/src/basic/basic_commands/cmd_run_goto.s @@ -5,7 +5,7 @@ cmd_run: // RUN clears all variables - jsr basic_do_clr + jsr do_clr cmd_goto: // Disable Kernal messages lda #$00 diff --git a/src/basic/basic_commands_CC/cmd_merge.s b/src/basic/basic_commands_CC/cmd_merge.s index 049f049e..6bcabe8d 100644 --- a/src/basic/basic_commands_CC/cmd_merge.s +++ b/src/basic/basic_commands_CC/cmd_merge.s @@ -40,7 +40,7 @@ cmd_merge_no_error: sty VARTAB+1 // Clear the variables - jsr basic_do_clr + jsr do_clr // Now relink the loaded program, line links supplied are almost certainly wrong diff --git a/src/basic/basic_do_new.s b/src/basic/basic_do_new.s deleted file mode 100644 index 0c9119eb..00000000 --- a/src/basic/basic_do_new.s +++ /dev/null @@ -1,99 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# M65 * #TAKE -// #LAYOUT# X16 BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - - -basic_do_new: - -#if (ROM_LAYOUT_M65 && SEGMENT_BASIC_0) - - jsr map_BASIC_1 - jsr_ind VB1__basic_do_new - jmp map_NORMAL - -basic_do_clr: - - jsr map_BASIC_1 - jsr_ind VB1__basic_do_clr - jmp map_NORMAL - -#else - - // Setup pointers to memory storage XXX should depend on text start vector - lda #<$0801 - sta TXTTAB+0 - lda #>$0801 - sta TXTTAB+1 - sta VARTAB+1 - lda #<$0803 - sta VARTAB+0 - - // Zero line pointer - // XXX - We should also zero $0800, i.e., TXTTAB - 1 - ldy #$00 - tya - sta (TXTTAB),y - iny - sta (TXTTAB),y - - - // Get top of memory. - // If a cart is present, then it is $7FFF, - // if not, then it is $F7FF, since we support having - // programs and variables under ROM. - // i.e., we support 56KB RAM for BASIC, keeping some space - // free for some optimisation structures, e.g., FOR/NEXT loop - // records (without them going on the stack), GOSUB stack - // (same story), expression value cache? - - sec // Read, not write value - jsr JMEMTOP - cpx #$80 - beq !+ -#if CONFIG_MEMORY_MODEL_60K - lda #>$F7FF -#elif CONFIG_MEMORY_MODEL_50K - lda #>$D000 -#elif CONFIG_MEMORY_MODEL_46K - lda #>$C000 -#else // CONFIG_MEMORY_MODEL_38K - lda #>$A000 -#endif - skip_2_bytes_trash_nvz -!: - lda #>$8000 - sta MEMSIZ+1 - sta FRETOP+1 -#if CONFIG_MEMORY_MODEL_60K - 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 - - // FALLTHROUGH - -basic_do_clr: - - // XXX shouldnt FRETOP go here? - - // Clear variables, arrays and strings - - lda VARTAB+0 - sta ARYTAB+0 - sta STREND+0 - lda VARTAB+1 - sta ARYTAB+1 - sta STREND+1 - - rts - - -#endif // ROM layout diff --git a/src/basic/board_m65/4000.mega65_vectable_basic_1.s b/src/basic/board_m65/4000.mega65_vectable_basic_1.s index 9239e233..d83bbfdd 100644 --- a/src/basic/board_m65/4000.mega65_vectable_basic_1.s +++ b/src/basic/board_m65/4000.mega65_vectable_basic_1.s @@ -17,8 +17,9 @@ .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__basic_do_clr = $4000 + 2 * 6 - .label VB1__basic_do_new = $4000 + 2 * 7 + .label VB1__do_new = $4000 + 2 * 6 + .label VB1__do_clr = $4000 + 2 * 7 + .label VB1__do_restore = $4000 + 2 * 8 #else @@ -30,7 +31,8 @@ .word list_single_line .word print_packed_error .word print_packed_misc_str - .word basic_do_clr - .word basic_do_new + .word do_new + .word do_clr + .word do_restore #endif diff --git a/src/basic/board_m65/mega65_imports.s b/src/basic/board_m65/mega65_imports.s index 3cf9df91..4235e8f7 100644 --- a/src/basic/board_m65/mega65_imports.s +++ b/src/basic/board_m65/mega65_imports.s @@ -11,6 +11,7 @@ .label peek_via_OLDTXT = BASIC_0.proxy_B1_peek_via_OLDTXT .label poke_via_OLDTXT = BASIC_0.proxy_B1_poke_via_OLDTXT .label JCHROUT = BASIC_0.proxy_B1_JCHROUT +.label JCLALL = BASIC_0.proxy_B1_JCLALL .label JMEMTOP = KERNAL_0.JMEMTOP .label plot_set = KERNAL_0.plot_set .label init_oldtxt = BASIC_0.init_oldtxt diff --git a/src/basic/board_m65/mega65_proxies.s b/src/basic/board_m65/mega65_proxies.s index c746d06f..191f4e81 100644 --- a/src/basic/board_m65/mega65_proxies.s +++ b/src/basic/board_m65/mega65_proxies.s @@ -30,6 +30,13 @@ proxy_B1_poke_via_OLDTXT: jmp map_BASIC_1 +proxy_B1_JCLALL: + + jsr map_NORMAL + jsr JCLALL + jmp map_BASIC_1 + + proxy_B1_JCHROUT: jsr map_NORMAL @@ -57,6 +64,7 @@ proxy_B1_print_space: jsr print_space jmp map_BASIC_1 + #if CONFIG_SHOW_FEATURES proxy_B1_print_features: diff --git a/src/basic/editor/shell.s b/src/basic/editor/shell.s index d4a366d7..845ab364 100644 --- a/src/basic/editor/shell.s +++ b/src/basic/editor/shell.s @@ -147,7 +147,7 @@ shell_process_line: shell_add_delete_line: // First, clear all variables, so that we only have to shove BASIC text around - jsr basic_do_clr + jsr do_clr // Check if line already present jsr find_line diff --git a/src/basic/engine/do_new_clr_restore.s b/src/basic/engine/do_new_clr_restore.s new file mode 100644 index 00000000..3a249d2a --- /dev/null +++ b/src/basic/engine/do_new_clr_restore.s @@ -0,0 +1,103 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# M65 * #TAKE +// #LAYOUT# X16 BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +// See https://www.c64-wiki.com/wiki/Memory_(BASIC) for BASIC memory organization + + +do_new: + +#if (ROM_LAYOUT_M65 && SEGMENT_BASIC_0) + + jsr map_BASIC_1 + jsr_ind VB1__do_new + jmp map_NORMAL + +do_clr: + + jsr map_BASIC_1 + jsr_ind VB1__do_clr + jmp map_NORMAL + +do_restore: + + jsr map_BASIC_1 + jsr_ind VB1__do_restore + jmp map_NORMAL + +#else + + // See Computes Mapping the Commodore 64 - page 96 + + ldy #$00 + tya + sta (TXTTAB),y + iny + sta (TXTTAB),y + + // The book does not mention this, but IMHO it is necessary to initialize VARTAB here too + + clc + lda TXTTAB+0 + adc #$02 + sta VARTAB+0 + lda TXTTAB+1 + adc #$00 + sta VARTAB+1 + +do_clr: + + // See Computes Mapping the Commodore 64 - page 96 + + // XXX check on real ROMs that it is being done too when entering new line + jsr JCLALL + + lda MEMSIZ+0 + sta FRETOP+0 + lda MEMSIZ+1 + sta FRETOP+1 + + // The book is not precise here $31-$32 is definitely not the end of BASIC text + + lda VARTAB+0 + sta ARYTAB+0 + sta STREND+0 + + lda VARTAB+1 + sta ARYTAB+1 + sta STREND+1 + + // FALLTROUGH (confirmed on real C64 that CLR indeed resets DATPTR) + +do_restore: + + // See Computes Mapping the Commodore 64 - page 98 + // Initial DATPTR value checked on real C64 + +#if HAS_OPCODES_65CE02 + + lda TXTTAB+0 + sta DATPTR+0 + lda TXTTAB+1 + sta DATPTR+1 + + dew DATPTR + +#else + + sec + lda TXTTAB+0 + sbc #$01 + sta DATPTR+0 + lda TXTTAB+1 + sbc #$00 + sta DATPTR+1 + +#endif + + rts + + +#endif // ROM layout diff --git a/src/basic/init/initmsg_bytes_free.s b/src/basic/init/initmsg_bytes_free.s index b277340f..ed8db16f 100644 --- a/src/basic/init/initmsg_bytes_free.s +++ b/src/basic/init/initmsg_bytes_free.s @@ -10,7 +10,59 @@ initmsg_bytes_free: - jsr basic_do_new + // Setup pointers to BASIC memory storage + + lda #<$0801 + sta TXTTAB+0 + lda #>$0801 + sta TXTTAB+1 + + // Get top of memory. + // If a cart is present, then it is $7FFF, + // if not, then it is $F7FF, since we support having + // programs and variables under ROM. + // i.e., we support 56KB RAM for BASIC, keeping some space + // free for some optimisation structures, e.g., FOR/NEXT loop + // records (without them going on the stack), GOSUB stack + // (same story), expression value cache? + + sec // Read, not write value + jsr JMEMTOP + cpx #$80 + beq !+ +#if CONFIG_MEMORY_MODEL_60K + lda #>$F7FF +#elif CONFIG_MEMORY_MODEL_50K + lda #>$D000 +#elif CONFIG_MEMORY_MODEL_46K + lda #>$C000 +#else // CONFIG_MEMORY_MODEL_38K + lda #>$A000 +#endif + skip_2_bytes_trash_nvz +!: + lda #>$8000 + sta MEMSIZ+1 +#if CONFIG_MEMORY_MODEL_60K + 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 + + // XXX move the part above to a more suitable place + + // Initialize other variables by performing NEW + + jsr do_new + + // Print number of bytes free + sec lda MEMSIZ+0 sbc TXTTAB+0 @@ -20,6 +72,5 @@ initmsg_bytes_free: jsr print_integer - // Print rest of the start up message ldx #IDX__STR_BYTES jmp print_packed_misc_str From 758c0a934377924c5779c9f60e904d954379f3f2 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 28 Jun 2020 12:02:33 +0200 Subject: [PATCH 05/24] fixed memory corrupt error when adding line after NEW --- 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 src/basic/editor/delete_line.s | 1 + src/basic/editor/find_line.s | 32 ++++++++++++++++++++++++++++++++ src/basic/editor/insert_line.s | 2 +- 9 files changed, 34 insertions(+), 1 deletion(-) diff --git a/bin/basic_generic.rom b/bin/basic_generic.rom index 90052287c7dda5ff8e220f0a5a99bf152fb76660..24f25b284ba8ef6157d9df3beb1d0f00cb7b5821 100644 GIT binary patch delta 3261 zcmZu!4RjRM6`tA2ZZ=Dj-NXbofAC1iCNWD4P-OYDfJ8PhkrWjFj&(LaOO^zrt+j2i zZc=)y&9QxF zGjr#?d*8gd_q*S{X<65@E}%A$LVI! z!VA_>xZt}Q@LB<-N8BttNsP?#BLn16ImiEQ7<~~z_jU3+I|UzW_JK(RZJamh)e?r8q>IJEplb*z0uS!vQG<@cyIA43e z_>#WTnK{|uNBT(*hcYM0Dk-KUdlKTJcO_cU?fL5W@LswSO85}}>ba_P86W7VQh$hlP25#E@8E;{@d<{M zS}w7;nV2szPP|V*PYnmk!Lib6#SE@SM|w$$!Qf_Iw<$Vw`vvrNY?Ob+OSN>8S(yMe zwfr7>>l5&j2WfVjnoNzRU8WLKv8l*pvXGMLdR$0~r|a+{QZ!wQ3y5jD#+8BdNg*yF zi*PY1z(phGukXw>8-o?6vkfd%b-xHJ3jX=n4icOf4MPCJ@`SLqdT&V7Dydpu0Ip6W&c4aTD2v z8$o}Ua&E?9EVl2mH`<%*yW<=ElWqjdn5x>aL%4-IKRvE4yv%sI(3i{!XOF;y2juP?|}6Jt-@Bpo`eh@h;+ki+Cw1clAJ* zk?ch~{pgX9OEqI6^|R!2Q%1TEtJwBahR+-L+HP@)VV?Q@?!(N@nO}Cd)1e!2 zx<2x7QI?f-uH>&6)^bUAm}PlaxA=tN(K$ZmFr$LEqOP#`v^Lur?2#6Mqu%V1%3TI& zRUmnEpjk0XNGayadXS|TMPq1$QbTz!wQB9@WmHnR{Ae#rZ#($gd(r+d$y7N0b3!sC ztw9~&_-h1*AU2R7z&PJ*;L)R#H@0#!Bh^X<3dWYndNg)p?nOp5${+4&7vLoxroB8V z3I}~Vc2WKUUgBfCA-8}+F*uUAIq5OgSt52PWgW_?5|5-LspBXTds6b(UnM{g?i8~- zmEX_@c}yWxqAUg&z&!jsv9^?pZ8mRnTa9;LTPROSWIk6HFD!b5Lk@rgOb|&f1g8^`&sV$y_lqP~wgC z+`0TtMkxGt95%9rMHwVIrOeG;u zB&W7hIRoSz8IFKn9df0AtLE^p^jnVIIp;XL!qr0QdHcEN-k%!0FbHZH7iOAe)yzIY z@Th>8eJ#ip^Dq$Wz?V{rk~&cho&slon6@;T>51p+*&u2>FJ`CbW&@y_aiTX703acm zyC`36OQgli$^I017{o!MWZ@b3j)1m<6JTFe%XgS9TIBeB~N}(DQ!F*f-?*_5X&3Y06VEi9C8R0FKRTiXjY?+D;EbLLU<^(oi zXg{E4hcs-7@}h=)D}e>if^ZoGQ1CHSMb{29pv9*Qf^hSJYB26$UmCw`=O8MaBKAs% z8oz508M-0Z{L-UPI$_$OtS2^^<0FG;=}}^@*kj;$sZ(q<=2D`0**IV9Sdd%%brr9O zppPOh`XM-ko+^Y7k%XT@W$VcyxR8K{=dHV`b#Hj z>rVE(F)C?KUAgk+>EYnb5e^3jgF!DmcMf;LoHy8cA=n2(I7mn^$N*vMk+UB?+efd? zeu#wt2zmxi&j1$e?vU>~uMeXsr=PMI#D>P@Q$ieYJK>|T!FHb;n?SiJUQUP!N-;JC zR40o_5yTCYOxT9z4x@oC^q!aOhKk$-6}b`DLM^R<_yC?E`&=<-nkaJT0F(jW5Ko0b zr-cmtq)uILQrna`u>uXq{{}c`0Gu<80>eK8e({DTv;mbzD~Lzt&AW|X8{yxL!e_WQ zdn!@X&wn;4evnhJBQi*n185E@*Li4dVCC7qTLd8R@HkGe4$6U>;X^TSjfU7|m5-$! z5g@1CjOPLVov;8sqbr4kO0L0)t`l*4u37aS5nFR}oIVzp0==0n=*8GXi^BP2Gn76H zIA;Z#@>|G?=~6$jOq*#l$3o)=TLQDp?p!Yq2MkCRnO#XBXQ6z=`N&F%$ln0wNP>cb z-?`OW)=ByD93tlAnF@0zd3#hkBd6V9GQYLMdI~M1lT>`J#OX&xlcGJZLA#d zyI#F%Gg_jD)%GC`n?wargKfmr1=UVV**$lcEnyfqJ>-5sg+l^hm<9>~9^#}6e5s+t z|I{$hxkg$=i-(1J(vt@*_WyR*w1bL=oN|)TYVofwK?M;SYZ~QS|04KGy^A}`3efws aQlBNjTJbE8_h)7$37~Zax@L=D6#fe(la(_7 delta 3250 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 HUF<&qp1$}{ delta 2825 zcmZWr3vd(H72VZJmMqzp`50vI=h=WA$FdBe4#r?e`7{C+LZ$>t(x&Ui7=N(obeMh! zsZ7I5JQNzcJIUabv|EjyVEvJ$0F`Y?$bkk1kF*_a7l3}LqUCE@$ zbVqu7-@W(UeS6P6_igJltvWfv*jqNy854M%Yz zb(EsL#^2HOdz7x1qOZ`j`jU^LBa}`mRCh@K$WUvg)#@u~)5%_jRyn>;pUtvjH?9!l z_-XX{K>Hf>Fv$8mhn=v>*3b%J&|zP_WMw-%y)=!D+$2RO1FH8Sq*=bNZK4zWz`%C! zR>PcvH+|rZW`+eC6^u%hOml)hA*m@b`Clwj_~#7yF1Och?DgtYojZkfdpYzVT6wpt zJwr14&5}{INU3VJjYHyCrDl@eSB)TxM)`BmEPs~NSfqez(X^@Zb>7c;C~;cpnX=$3W!MWzL&W!)kr$td@7$G`>bS5xT4ingxsm{U~0UKXndTkJ?;abZ2-lEJBvYor&#(>!4?<`ZyC+iL2;jD&i^)&|HMCWo zje=9M6G@emf!fvJUV~mE{_2zU&YMLZzA&SxI8PZ^=Wz~Hz`w}jWdGa?mAr{;l85U#@7#Dk zJSQ&^#Xo-;UG?bEN#r^Y z3CAOk30^A|$`&%RVG56kh3wDzyd&}^Ame(;)xK65mS@BgeW1&E%y}7|^s=>m(v@#3 zeVS6UA1-lqq0`>_ll9VDvJQ{L$%hRO*Gcr@PCJessg6WIfkJ-1st&1mCjJ+=rG zIyc~l{sBV4Xu@CHwzfi`NJB?;j5KyslLlN(8u2RdW&Ag6r{-n0(aYLff#}?C$6ogw zAoEU)pLoOf)*uOij^f-p_+7N$F}vd@H0K`r)TDo}v%&)|o2}z>!}K zoZ33mN$c#&sds1P=ymt*@dxs4E~^54t17MoFzkxP1vVjx6b@puK)a1ls_X@yRu5`^ zhJkkIX@3Eb8;I`DYy(;Yc}r9vFVG*_9SG1QIB*at&BfdX8t`J%`$3qVXdaXh6=$%! zOZw3^52=GR*0GKKP#sVs>^_B}GOuPy{+G5z8vFlb%UutAbmyYuUQz{B zkmlAy4oH=EIaCgm)7Le*K8ykV!s1L-kV7xyV z0U;Drlwgn|HL4Z4`q06UHoE!%G7kFAAp|c3NvabD#jjXv2t5dEv<3t<^cEqo9I49_EtCcP3L`kE{Q0 z&Q^!n8xgIYZgg)zXGZzI%`aM*>H&q;RFV1>3r+OQD0?vU7;uh-DfHNaoH;pGg#+#h zlzRs|65^oqwWpK8l7}k8mMi@CbL=_k3b8o5&>#AM_*%!X;42Jtd3Ig6pWl$Te9P4! zIBPFT0Wfw&G9*@aMVww|WS!TU_%xa}G1I2dm@_gk=H#Gn!+m24b)%IFIv(a<&CkvR=_VnyhFyjl wRr^liJ^3X|%azAxh*;_^^El8a$uk7{LV`D105)x1x!IUy7TYdqs%+H@c15`)9!M(N*3XvE>nG?_ox3ZTOwP=A&Ntt=bLQN@>cDEh z2$AO#;*{P?=3NaVy?_+H6^C*N=g^HT5?l0siy~*8Gs|pHeOZ)|gLYUX6LodE8|baSwBGFAEjsOBX5Tr!D&^XHiRR# zi%7bT@O_)PBZhDvl2VG_tV_K%cc)gFyNK)Vb&Sm&;t;D4H&`Y4*xOFT7=Ym%*dQ7J z#ByLI`PD;%L#;KSOQd#K1L# zJCKyIwU8-ebLSCpD&Wy&-s*TRVQ)kf&fkz~9g+V}7>gp>i*#E6< znk;zRbQv0=i^YlZhW3oKlpIrZ#9cwfRFb?osPMf;K5s7d2LU!&#%CFC5Lhkyxl5%e z-BQ97Juj}X<`ZC=EaL++DZspO#V%Wqf!IFF?STW(8)QL(tn(+JzE!+zRAOb(F6n{u zl9LyZ7ZXtOXZ%=MixVD&tl;!s{I7narLo5{4LN=HKmEOy+m-z!sKosDo9b}&x~i&jtDNiCI+q~?zW~hEa8bI@D7^V9Z{ghEGM1c} delta 925 zcmZuvU2GFa5WeJM6s2;Lx&cg~WJ$s$hBOIC35JS_KbKIgaby(wgmh=0Pr2A`U7)li zl$eK6B_NPsr1F%WfK9km&Ds1Y4|a$pnl^_}b%m-(4V4^+b48_!d#Kb$y65oN(Q0Qj z^UbH3Z#TIoxo7w~S{3JFT$CH&JX|Z+!f{^WF(a^57Sae@DgMyN^E@&qy<~^Eb&7b+HdLLyUV)uUJbFrq=!iH3i^a1VsnuT@|B?{Y zlQ67y^T?G`D$u5mqRtpB&S%J2CyRfYME~T_y&@hepsl%bWxl8<(=5JUz~eI*XU3*K z?tL_&?ohrn)~F52Eu&6-sT7SGbyCS1Rq83_Hu^oQFqtk-t#weZwLDX^k8F`GKZx`)LqMd6)GJQ3z)t2Z4Wvey*!)^wL%J^C&Y+;TMt zBmxN{LWHg$(pADL10n0TlHis?QdknDh?KC~jlX%j0u%*yhYSLxHDw*8J1E;aBHL^- zi9wu1Aw~uu+Cm!!ti_V-mIkD#6qDj*qL(%iErSgeK;~0#R|Z$%8yY>SXeH{KSX*cq zW$|r0fzHgO*P`+7iIYm1*C>954w2poqs(OLGV2c1E|Wp;iwYPd zLoXN@;_+hc>r0x(P}!_TlBj#96fxG6M8j1I8*i3E^u3c1DhWpAj{+Sn!S~NQEf(L? z%B$bd#^mPVyBfMs#K)%b;#4#i|K!ueXU9*R{QT4xU!EQuI`h@p;pDmL|2G~r<T?@bqqkWFigOrG(a(S3U(yYK27(m_d`H{2cXoDf?{5EafBQCuS$WtyPpaNq F{~!PGr9%J! diff --git a/bin/kernal_ultimate64.rom b/bin/kernal_ultimate64.rom index 9f4108ffb802d7994b5a6ff67a781a0f02ec893a..4124be18a7549c09bf410ebf82ce13d1d0ba5021 100644 GIT binary patch delta 889 zcmZ`%T}TvB7`?NzxVe*My<|VsZKDTKH#MjwSo<}tZhw;YQZz!r&aP|kS*?&)#DdnA zvY=!T@7nB??B+vh>smy#6B$#jLKLyBZT>_tL2m`yHwr}$4VRDaoO|ZZch20_ZLQk^ zN(jHsDeL4uyjtx=vK=qXD*5w>n@2TsNU4`cO$k3o;+yf_JQ;zQ_?W10z1!vQWF!|} zmR=L&$pMvYRYlL!0)r=qRaQ{W1NKm#hk89!GFG!jeKC`0BlFVGX?{_~AryU4;W6o+uJ=a#rR+R@(t3;=w;}<0rEUqAA%5 zgocchnnM>@3g$>D4r0%QQ~EwFXH;u};7;v@zQp{7h9b4sYoFr@Mt*(N#{MPWo20ql zSsaMq4D;OfXqR{}^@6 zM1qSnd(^Jk3_;5`mP3}xq)UV??Ve$SUa{$46uUk(&j?z~5KJ~-A6EqZm9kJDBPiV# zSVtYQHRhoH4k%4#@j=ONrQVpMkXLfxg*KbC#2Q5rG6HYG99|m7&f%zluZ`k!3`{ks z1twkerDvg}VtjH5_Cxo5G*QwA+C^ zDBV3RA(_F+XSA=H!SR>yV+bC-!aY;4Ild6Fj!1zRgU6&6WUB+V%Mvi+_-2v_s}va~MH5(mn|HBVk5kv_Z=T-@oD-F zby5*cLWkfJI)$zUpKn~$paqB~(xf~QLq=U&0WL~uE9BEz^jlLPCbXtkr9%C>l@`jY zWwhJ4TJg#&6pvi2xaH-FOV&pN#HH}E?k%s?>E;j$eb#L|l$%>M%q66qY86Chp#Lc~ z7>xtyHLvPn(=@!xj^oOioJucMsZ*LPU;YT=8N7F_{f$9oaA}Gfw7C|g`os!7q`*Cd zPY!A3y$tx9hv{kCY#upHdu9>o;qYV}J0lUq4In6)mOw6m`2@V|J*kMQe*6F2d0NhZ)u{62pUq{Z2k|+OfUys2vbKIMQQ1 zbM~A+aQ?!@OXPCzm8;jT-?(|}cCat;Z*ZYn=7bsjg$-XEPG-OTxV5Ibx~`_q+O*HQ O4WY%(KYzbu%bMS4-jCD( diff --git a/bin/mega65.rom b/bin/mega65.rom index 6c78832169403e0ea0dfc43c175dd39bf32f652d..d63794212d8e956b72e6e98c639b9cf00f164f21 100644 GIT binary patch delta 2588 zcmYjT3se->8NPRUEeiq?l|`anl%SLqv4U=WrKC1u98%My=PV<}K}5kJXc>7!&#rVCtSZ_kRE5 z-ueIU|L@&#I?Ya}SrSsaO2yJmD+l;D_{vWsEUcRwMtXX;gxU*3D$)k6$0`fOLK#)g73XrYL%4u3Joc72bO+-Dap*3> z?<3rTY446F=!BiNS{aMEvRSm*Nz+i+sYl70O?HZQ8Hw}A^QCq+?^>>h*{|71IcvsT zJr5By=7t(`tt_|NB+g{EY9!{7pD{L1oWty50h=k#5@)kKF<<;4%N2{5O?>8~B7q!^ zNSG{S8WyBzm{p|5hP1Ca%I{1pS;}Ux#nlKLmNId1mAHtjFO?~AF!{7pMjVc2laxsk zugOknl_AAQ$dG;^1xKV*kjUiH<~Rv)iPz|zooP6h#?)ljVysU|io$s&+?M%%47Nq% zwv_t)G1wQ2bM&TId?6YOG6HZH0656VaEY%64R|?wU>?PWgZ!TKvNl2fQgUc1@>Uov zauJNtawCMr97YLplJ%u(vYzAVTIL{*S_T?jpR4M6!gKI5w4BC=+6z5hZ-JeKwDX3C zzZg_G$=25pK0a#UPVoZSz@#Xks<<8oPZbn^Y-3QDo?!xYUY)8Xu%2Z@VvjtPt6b^s z(Tda|eSuor@FVq{HYP-BVOcTXO%C$T4E4OB8C4wSoffd{&8hW}<9tn(dPp;gJt0k& ze>)u2JHW~Tgxzr`kf{aXvvE4#if|V)sZ;eA)T{c->eKovGPbM*22_49$=s_e1?b6=b>qvkm=^$(EedSK6V%uBu#3b3t$6Fz&(p)Uj^K!H=HAG5#@>YW~ojpD}`^|x*@;Vn`4=3NY@1FLabi*O8F zzz$uK-)pSP{g`iDft$k!|!-u0QLOID`tWWaA;&=lYZWp4xUAwvIDf{}~ zbnRvnPxhbO(|X9y0+e?b&=S|Cv=7s`%|22cRMGu+$Eh*iKaaC`cJm6=Tx*Lf+*3_I z=I#v;c(NiY;wsz#8yAhtmt=rzNvwXcdzc>MSO6 zGu&2z%%cBbd3XkWz;ctXGcYupkCb<(d?RiZ=mPhY0s=8a8!?!RukfGC=-uTqX?}(q z9Du`^7Ey^7OSS~LZEoXWtMiS$?Sl89dm4`7R`_U{Ki}Kz4P$ynPA@+ZVdcaVVb#Wv zeak6kx0%`WTd3iJIGs(uBqgzIv7DTUSlL!m;UVd+2GjLyR{0oS`xvfx46hl%bg^fe zsmntvJUl(!SMHtsUY*Ib%}re`Yh#v&37|2pD<|)AU;N6`wxsY}<@WC;9sMX6=<>Ip zRFpt47*P6x-aV~RI2DpM4-*f-VgR8XTTF=!PK1yEi4mtl+uN;ppSQdHVvGr-w>z?8 za{CSanGRALA0~4c+N|jQrY*02To0LRvZkcv@rX)Z3ZqLlRJct7bfUIerKhJ^?SLPQ4qX38fFaDr1LVnju zV62Ql$OfHt1bBs>TqpVEK`uE!P#D%i0%HSDnmiFYD`2&rh>+C*wppxXo5ZzjqgcT< zh--`>R|l5FojNHP`%q6HGkZxGkn~*hGLjMI2KvY}1*+mb_$}Gr=M}#t=anlw40Irn zo&ik(J`fC)Io2pM2jU8!Xd(OPQ_8&fJb!oaO5o!lq63lf^ygGdvs9rL&(fRJ{|I|9RzA# z2fom7J#BitO7yRwdftb@Xp&*1lK7}~lOBN-1JLct^i@cZP;(jA6JRy=TUe}NyKW(I z*Kl##@{M*_pxa=x;S^I+By^@+w-8%|d@>Z`UNO#4n?<$hVQ`Dl{zc%LsdGWAJ7#TMgNdsJ$(cTgszG<~6V3{@MM{&pdNUB19@8#z8e;+9n$GDC)b7*+h zXTu+MR^;q>J-RJhOR6{UIKUG%xDLtReGOybvdoGU8{Wg;InIlA0X3Q?(2oA3BzxYo XKgpX7B&Hf?_svWF9hds?%#8m5a>Q}p delta 2526 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 QKk$EjXrymw1l7&{AO6;GtpET3 diff --git a/bin/mega65_pxlfont.rom b/bin/mega65_pxlfont.rom index 2b2c51e82c077b8a2a15fa462cb044d2bf719cbe..f56acc9fb3a63bcb853abec92fa85dee9549bae6 100644 GIT binary patch delta 2588 zcmYjT3se->8NPRUEeiq?l|`anl%SLqv4U=WrKC1u98%My=PV<}K}5kJXc>7!&#rVCtSZ_kRE5 z-ueIU|L@&#I?Ya}SrSsaO2yJmD+l;D_{vWsEUcRwMtXX;gxU*3D$)k6$0`fOLK#)g73XrYL%4u3Joc72bO+-Dap*3> z?<3rTY446F=!BiNS{aMEvRSm*Nz+i+sYl70O?HZQ8Hw}A^QCq+?^>>h*{|71IcvsT zJr5By=7t(`tt_|NB+g{EY9!{7pD{L1oWty50h=k#5@)kKF<<;4%N2{5O?>8~B7q!^ zNSG{S8WyBzm{p|5hP1Ca%I{1pS;}Ux#nlKLmNId1mAHtjFO?~AF!{7pMjVc2laxsk zugOknl_AAQ$dG;^1xKV*kjUiH<~Rv)iPz|zooP6h#?)ljVysU|io$s&+?M%%47Nq% zwv_t)G1wQ2bM&TId?6YOG6HZH0656VaEY%64R|?wU>?PWgZ!TKvNl2fQgUc1@>Uov zauJNtawCMr97YLplJ%u(vYzAVTIL{*S_T?jpR4M6!gKI5w4BC=+6z5hZ-JeKwDX3C zzZg_G$=25pK0a#UPVoZSz@#Xks<<8oPZbn^Y-3QDo?!xYUY)8Xu%2Z@VvjtPt6b^s z(Tda|eSuor@FVq{HYP-BVOcTXO%C$T4E4OB8C4wSoffd{&8hW}<9tn(dPp;gJt0k& ze>)u2JHW~Tgxzr`kf{aXvvE4#if|V)sZ;eA)T{c->eKovGPbM*22_49$=s_e1?b6=b>qvkm=^$(EedSK6V%uBu#3b3t$6Fz&(p)Uj^K!H=HAG5#@>YW~ojpD}`^|x*@;Vn`4=3NY@1FLabi*O8F zzz$uK-)pSP{g`iDft$k!|!-u0QLOID`tWWaA;&=lYZWp4xUAwvIDf{}~ zbnRvnPxhbO(|X9y0+e?b&=S|Cv=7s`%|22cRMGu+$Eh*iKaaC`cJm6=Tx*Lf+*3_I z=I#v;c(NiY;wsz#8yAhtmt=rzNvwXcdzc>MSO6 zGu&2z%%cBbd3XkWz;ctXGcYupkCb<(d?RiZ=mPhY0s=8a8!?!RukfGC=-uTqX?}(q z9Du`^7Ey^7OSS~LZEoXWtMiS$?Sl89dm4`7R`_U{Ki}Kz4P$ynPA@+ZVdcaVVb#Wv zeak6kx0%`WTd3iJIGs(uBqgzIv7DTUSlL!m;UVd+2GjLyR{0oS`xvfx46hl%bg^fe zsmntvJUl(!SMHtsUY*Ib%}re`Yh#v&37|2pD<|)AU;N6`wxsY}<@WC;9sMX6=<>Ip zRFpt47*P6x-aV~RI2DpM4-*f-VgR8XTTF=!PK1yEi4mtl+uN;ppSQdHVvGr-w>z?8 za{CSanGRALA0~4c+N|jQrY*02To0LRvZkcv@rX)Z3ZqLlRJct7bfUIerKhJ^?SLPQ4qX38fFaDr1LVnju zV62Ql$OfHt1bBs>TqpVEK`uE!P#D%i0%HSDnmiFYD`2&rh>+C*wppxXo5ZzjqgcT< zh--`>R|l5FojNHP`%q6HGkZxGkn~*hGLjMI2KvY}1*+mb_$}Gr=M}#t=anlw40Irn zo&ik(J`fC)Io2pM2jU8!Xd(OPQ_8&fJb!oaO5o!lq63lf^ygGdvs9rL&(fRJ{|I|9RzA# z2fom7J#BitO7yRwdftb@Xp&*1lK7}~lOBN-1JLct^i@cZP;(jA6JRy=TUe}NyKW(I z*Kl##@{M*_pxa=x;S^I+By^@+w-8%|d@>Z`UNO#4n?<$hVQ`Dl{zc%LsdGWAJ7#TMgNdsJ$(cTgszG<~6V3{@MM{&pdNUB19@8#z8e;+9n$GDC)b7*+h zXTu+MR^;q>J-RJhOR6{UIKUG%xDLtReGOybvdoGU8{Wg;InIlA0X3Q?(2oA3BzxYo XKgpX7B&Hf?_svWF9hds?%#8m5a>Q}p delta 2526 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 QKk$EjXrymw1l7&{AO6;GtpET3 diff --git a/src/basic/editor/delete_line.s b/src/basic/editor/delete_line.s index 792d1237..6b981003 100644 --- a/src/basic/editor/delete_line.s +++ b/src/basic/editor/delete_line.s @@ -62,6 +62,7 @@ delete_line: // Line length is <0 or >255 bytes. // Either way, things are bad, so abort. + jmp do_MEMORY_CORRUPT_error !: // Length can now be safely assumed to be in the low diff --git a/src/basic/editor/find_line.s b/src/basic/editor/find_line.s index a98cc91c..0a7bcab1 100644 --- a/src/basic/editor/find_line.s +++ b/src/basic/editor/find_line.s @@ -17,6 +17,38 @@ find_line: lda TXTTAB+1 sta OLDTXT+1 + // Check if BASIC text actually contains any program + + lda #$00 + +#if CONFIG_MEMORY_MODEL_60K + ldx #OLDTXT // .byte $f0,OLDTXT // .byte $0d,0 - + lda OLDTXT+0 pha lda OLDTXT+1 From d397e3abfccac438723f7d32c9dcab884fae9e50 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 28 Jun 2020 12:14:17 +0200 Subject: [PATCH 06/24] saved several bytes in BASIC editor --- src/basic/editor/find_line.s | 38 ++++++------------------------------ 1 file changed, 6 insertions(+), 32 deletions(-) diff --git a/src/basic/editor/find_line.s b/src/basic/editor/find_line.s index 0a7bcab1..47569971 100644 --- a/src/basic/editor/find_line.s +++ b/src/basic/editor/find_line.s @@ -17,42 +17,16 @@ find_line: lda TXTTAB+1 sta OLDTXT+1 - // Check if BASIC text actually contains any program - - lda #$00 - -#if CONFIG_MEMORY_MODEL_60K - ldx # Date: Sun, 28 Jun 2020 12:21:33 +0200 Subject: [PATCH 07/24] fixed problem with BASIC line inserted in a wrong place --- src/basic/editor/shell.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/basic/editor/shell.s b/src/basic/editor/shell.s index 845ab364..fe4eafe1 100644 --- a/src/basic/editor/shell.s +++ b/src/basic/editor/shell.s @@ -155,7 +155,7 @@ shell_add_delete_line: // Line already present - delete it jsr delete_line - + jsr find_line // refresh OLDTXT !: // Insert new line if non-zero length, i.e., that // we are not just deleting the line. From 7117255ced55e3931998b4d61cca0dc672718ac6 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 28 Jun 2020 15:45:22 +0200 Subject: [PATCH 08/24] another tokenizer bugfix, 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 src/basic/editor/tk_shorten.s | 7 +++---- 7 files changed, 3 insertions(+), 4 deletions(-) diff --git a/bin/basic_generic.rom b/bin/basic_generic.rom index 24f25b284ba8ef6157d9df3beb1d0f00cb7b5821..6291a248bc5580455ba872e913ffe59a6e38276e 100644 GIT binary patch delta 1433 zcmYjReQZ-z6uQe+YCf4&djJ)KX`#a~J z+;h(FoO^p3dKyATEs?Bt;-%a}8RX#NxU?jUjNSFo8u@{;~>GH0r53=n)H z8+gW>#LGV&Kwc9zX9Beg8nd7sp4S3R-jwR1nK$BoX+RIznKS%8iij;|oQ&p|vcC?J z+5A;Yw?*XVA;BGUc;C%4h?QNQC*|7EX5uKQC<^=W7w1BHyi0j%GnAK{56b?KX((Bn za3}K*NRWjI&mYOkZ8Sb6KrJ$fs+gIkc!A5V=>f2 z-Zid2jsxWMqApXfFI4}@9`|&GkCf%DG&TC%@wM=S+LZS!$>eNbDm&90<>aiwT7>`- zIlgn)D&T{pfO9gPWDB>-;uwaF0mJ((S1f;vhXh2rIlCIB+Hg90n>)Z1d3vDNg7nne z+lJyZamc4|=2lmlz12;ATUO0BM2N#)va}{5Po(qJ!IIIC`$P8?Tsq6wL`bt8zh`zF z{U;(n3gr|;p>-CyE@U1HcPW)JR#xzbBlu_(C$o4|CGnLg{vnIUBJ*8NKX-ty~pyW>~CV&?_c?Wv){{aIWzPxah7mYrx6ykH)HE9lCTd=-{6=@THx0P1rYlZb_Zy`BCYf&`F1;T3Qq3n`H)^LF!Sn0l0pkdn&3YmqH_e6d4o zrmMtyS}AUV&Ui?atKNA2+y+6IWEiC+Ps2D_CR7^KF_l`zW$AlI$Heu_O75hdnba~s zHGrQ1fI|SOE@ZXUSw80HQIJ11j1YFr(Y?wR+5&VLefZQc-M#goMZ=Gi9;;oQ#gDCa z<__7PXCq0|V;UYTOwl$nZ7t6SDqc%@H2i()Md7aL&*MbOTc3l1+2Fdh>qw&LW#TS! z9_=j`%e>lfnb^?>qFohjAdEd?Yq-p!31ll_PIjy2mfl0OMc^HCf)E;!lIK&S7ryLl zzu5fMrN$2~e|`Vr-7)#ftK)6$SNBg$UNfZc-MfAx6?^cFjHtj5x|EUt&Bc5(u{Z$z zNQ}~0jNG)X)b;ySTDjsaP3U`iK%4iDh-9SG)QV6kNE;5ZqsP8)BRYs>vQH+8TY`o?)yt y2&pH2CxuusA>d8n;q0LhO4uFuOsp3jYF7DQ!Cd delta 1471 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 F{|nH%q~QPn delta 2107 zcma)7eN0=|6@Ty92J>NT0tsdixN(BP4Izn=GzlvqNz3G*Vo(JU5D{AuhCO5=^@Ejb&N2v|WOMWk^Y%luBKesor^p zY5QY;?CR;>bI;d3_nzN5uV;VHemO;dxTd!18B|wOU5|cHQ-_}8j~uE#aHI-7zLUvc zGqf^Hr&lRc!3tq|FR{L9VCt&)ssr^^h=D=s_0O4}K0C^?YJ>PP-X*?IF6e*F)k>ts zP*|+cK=NpiQ@KDAuTX(*#uc;_?-LocVLr+z#+k&bl82RYU|YkAPd7mGw)lT-RzaS#*}oNCdljnwIG-I~DrWS2#hAE{7H-&5#oft0_8SK{BuHNI+ zCG>85-R5VgtKX*DW@uNxjk=X2+U4l(hi#`eb!bz2KWHTkNI_a|_poZ7wd`B^f5$Ri zayokOQd_EF+0i{rmtnKq=L|4Np>4xxmIib{(eh|qO%Lc3WNTr~U5Xd+JBmaOiEk?1Bx$Nyv`y3J>amdoigp;y$>C{j!KISG9+f+BG=9fu6w z7}1Q2Mn)Mfx=lGc%4*B={PmIl&ScbRF~~apMF~%6sh?Q}*!{;rz>Kb}xbid8wQ4pR zkMB^-=(82x0K?7j2S&UC91>u>+fpJB?_B(@@(mm!GQkPI06{}YWOHV9cHbT9Q!hbC zaE=p}Hh#B6PG;uz=ZWOBDTM>TiKZgdDDjn&-&E?);17-gz|c2SQHQz(Fa~`1$bC~` zdaZ=SmhbL|i z=olbH{uDssg;SY2Q989o2gs0d2-z0+@fdYo_NcXT4fX631Zgm5)E_;-Ff+oSBRf9DX4|WOEwdjc=c`LZf zr5??lhj!vF+JQT1JMI93cJSNldtj}( zIJM4#_qE{)fe`{6QpkJebt$zH!0s;pX^4Di-kdWeMUMg6=EhO)Py$H4{n5Sh6K`4^ zS-+&R4mDn+$(N0)4zXc=Hbg2dYtIj+<*_LOv<<*uqjdh=tb9F*q^@s_(C<$Gjwbj$I2T<3~Z^Ml`YJ;g;EJKfCnPPk(p)!Dme^%C+Cm{lR#n zq2Z4=!?D$|un_wo7R$K}jD@KMU|x)k&Bua3OvWUM{N;OATcy;CAa(FuZvTY%kT*}F z*TP!C!gaN))=MNeZ#Q>ng4E?b%SDC>&2ywfnhysKp+9}V-y0@>&a-c*l(cF>>O&r? z2iR|n{rhJl@UVsA+K|64zfuwaBz`9FL;l93fUchLndpS$?~t!!5~ z-yz=oiX>=PEU%Dj`MGB3Wg(PxpUN<4ulgYWmhsV9@TFxLWf? diff --git a/bin/kernal_generic.rom b/bin/kernal_generic.rom index ed644e42fd924ceb7fdab35ac34797fa409dffc6..e9d83db5ef73dafd330e90237ee159f25b9acaf6 100644 GIT binary patch delta 274 zcmV+t0qy>PK!89)q96usCTu2aCTb=rCMYH+CMGzgDdlB_C8a3kWQ8Q9C*@;>Bc&$g zVvrPtBBdpTDWxQZD5WEXC#52VCgyF*(7<4kL&5^Bu9F7=kOiKFHL0kRoB_%Ov8GG_ ztdna3r5iY)u+SE%eW0b#5UKB=;?N4IW1z0k1gV~&sFN!L_yX3ZlO+T&fB%I#-~#Xi zO!lR%0RqWP@B>WtrKtdgw}lFz0ip*Wy8lcJy&!zQurMIAvB^8|EFh`lAfBzI4G<8Z z0K{SN3Lq-tAkzQHOp)Xue7~>?$t>{T$vf}`(AOZ&>P!Hv0000V=TA}rL`7CEGB7YU YGB_?qLoPA^08H7XOxdN1v(yAE8-zx6r2qf` delta 274 zcmZp0XmD^|Ia%S-|CN0Ub}GoNUc|6~OM&O<$}$L#5yIO9=B*4}upgv^87!zUXU`(G z1q?vNKG{nrIv-+sx_mM_;{?{SR@0T6CeL9!#rkuV&-oRTvzeAkzgV#Tg4oL11xqgo ztbD)V(FLxR$qUw9U;)~)X|gu+4KPOi_b9mTQOMkHu~hdZQ>*T(4NS-M zmgp_zQn>nm0<+J>rER(`dI~>RDHt#HIk2%sxm9Ta%SNTv)D9q#0wR)u1ZP8Q(nci# z=9T|-Rx-4vfrJxV3YI1&FfcI4Klcw}ba4&SGcqtRGqTWgbJjCtVDP!Q6o|SuUt!Ua F1^^qCbJhR= diff --git a/bin/kernal_ultimate64.rom b/bin/kernal_ultimate64.rom index 4124be18a7549c09bf410ebf82ce13d1d0ba5021..d40bcbbd5fb5ee237c2193c5feff4c12148eb05f 100644 GIT binary patch delta 708 zcma)3&ubGw6y9di5?fY$622_2kVuoB9Vh4Bvcj-g_V4o5@Y(rnD;U z%L*AGEu;id@Ca@}2%y+XfD1jXIEwJGnsE1GuwB&}Tez~F9isw-tR&C5y0+ulj35-D;qY$fc5H-HE=VGuVV#^6{EqMN*f z)DFj)h+4hP}T-9Nd@(0qJZ+Yi^zQUng;tl>IW=lLO%|6VET8V`j6VfK6O023o j1ULFU6ec%*M(4 zii${7$pk`2i3@s}VWm;<5mn20OUxfNPUxvbvn~xc>TisE^9&sYoDZC@@f_uUE$MIn zCl^f8%n$6B0ysv6aX}w47!tKcjECw~c#DW}SI%SlEax>W&cJ1!)8t1?kECXltI$da zH;3@VSehr(`1T~V;EySQ)f)eNf?M5*k_As!3zG$$5w2XxLEPBjk34R@2rUIv)Kh}E z)q=IGYr8oH^?xry3+sj4W^`-0;l}onwS4D0A9shl^t-UF^=IyEvZVT39%Ny-@Ps_b z?qD82kyX~t)M;`Z+rsi_QQnt%P{Q}8z}avLZwq1DbkK_L&EP8(EVXO=eE6^LrbRqE z7Tf|&1zCLa(`dQ>z(4Q(6@4~pNwECUFqFfGC=~M_`2xgz*zD``sWWU-bGxm|Za-XA UV>{Mpt3(Js70k&GnH9VK0E6c@1ONa4 diff --git a/bin/mega65.rom b/bin/mega65.rom index d63794212d8e956b72e6e98c639b9cf00f164f21..d6ac550404c1714eb69965cc047cd6b84d9de6b5 100644 GIT binary patch delta 97 zcmV-n0G|JVfCzwq2(U(a3osCfj0FL?1_3D#lTmsY0Wh;_dig{FGP7jA{UHTI$vLn; zlV;&82L>R0r65$~la}Frvlrq;0t6tzxsa1=8lj$$?c8j2kv*RsD2fG~ArB|F0se!%52xHj~pH z>aZ{?)GnPo^I_d)kw+d(0xKC5R34pVxWI7&On;c1@Whb$yhXx9M)Aqpp9nJ=HlKd7 K{qz$?Q)vLzAuIj> diff --git a/bin/mega65_pxlfont.rom b/bin/mega65_pxlfont.rom index f56acc9fb3a63bcb853abec92fa85dee9549bae6..d04867f434592ed481816fe9e30b08c5ec34fcca 100644 GIT binary patch delta 97 zcmV-n0G|JVfCzwq2(U(a3osCfj0FL?1_3D#lTmsY0Wh;_dig{FGP7jA{UHTI$vLn; zlV;&82L>R0r65$~la}Frvlrq;0t6tzxsa1=8lj$$?c8j2kv*RsD2fG~ArB|F0se!%52xHj~pH z>aZ{?)GnPo^I_d)kw+d(0xKC5R34pVxWI7&On;c1@Whb$yhXx9M)Aqpp9nJ=HlKd7 K{qz$?Q)vLzAuIj> diff --git a/src/basic/editor/tk_shorten.s b/src/basic/editor/tk_shorten.s index 1d3fe0a1..916a8f41 100644 --- a/src/basic/editor/tk_shorten.s +++ b/src/basic/editor/tk_shorten.s @@ -31,9 +31,8 @@ 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 + bmi tk_shorten_1n_lo // FALLTROUGH @@ -45,7 +44,7 @@ tk_shorten_1n_hi: // tk__nibble_flag = $00, both nibbles fr sty tk__byte_offset lda tk__packed, y - and #$F0 + and #$0F sta tk__packed, y // Adjust remaining counters / flags, and quit @@ -78,7 +77,7 @@ tk_shorten_3n: // Now we need to check which nibble to cut away bit tk__nibble_flag - bcs tk_shorten_3n_2bytes + bmi tk_shorten_3n_2bytes // FALLTROUGH From c88cce6045543688662e301aca32e1103e62a2b0 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 28 Jun 2020 16:24:11 +0200 Subject: [PATCH 09/24] implemented BASIC command OLD --- doc/Extended-BASIC.md | 4 ++ .../basic_commands_CC/cmd__jumptable_CC.s | 4 +- src/basic/basic_commands_CC/cmd_old.s | 64 +++++++++++++++++++ tools/generate_strings.cc | 1 + 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 src/basic/basic_commands_CC/cmd_old.s diff --git a/doc/Extended-BASIC.md b/doc/Extended-BASIC.md index 235a0ed9..2f9088b3 100644 --- a/doc/Extended-BASIC.md +++ b/doc/Extended-BASIC.md @@ -13,6 +13,10 @@ Tries to switch the machine to turbo mode - details differ depending on the conf Tries to switch the machine back to 1 MHz operation mode. +### `OLD` + +Tries to restore program destroyed by NEW or a reset. + ### `MERGE "file_name" [, device_number]` Appends the BASIC program from a storage medium to the one currently present in memory. diff --git a/src/basic/basic_commands_CC/cmd__jumptable_CC.s b/src/basic/basic_commands_CC/cmd__jumptable_CC.s index 72168c3e..52a9cb50 100644 --- a/src/basic/basic_commands_CC/cmd__jumptable_CC.s +++ b/src/basic/basic_commands_CC/cmd__jumptable_CC.s @@ -13,7 +13,9 @@ cmd_bload, cmd_bsave, - cmd_bverify + cmd_bverify, + + cmd_old ) diff --git a/src/basic/basic_commands_CC/cmd_old.s b/src/basic/basic_commands_CC/cmd_old.s new file mode 100644 index 00000000..ff601281 --- /dev/null +++ b/src/basic/basic_commands_CC/cmd_old.s @@ -0,0 +1,64 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +cmd_old: + + // First make sure we are in direct mode + + ldx CURLIN+1 + inx + bne_16 do_DIRECT_MODE_ONLY_error + + // Now try to restore program linkage + + ldy #$01 + tya + sta (TXTTAB),y + + jsr LINKPRG + + // Now we have to restore VARTAB XXX deduplicate this with line editor + + lda TXTTAB+0 + sta OLDTXT+0 + lda TXTTAB+1 + sta OLDTXT+1 +!: + lda OLDTXT+0 + sta VARTAB+0 + lda OLDTXT+1 + sta VARTAB+1 + + jsr basic_follow_link_to_next_line + + lda OLDTXT+0 + ora OLDTXT+1 + bne !- // branch if pointer not NULL + + // Correct VARTAB by 2 bytes NULL pointer + +#if HAS_OPCODES_65CE02 + + inw VARTAB + inw VARTAB + +#else + + clc + lda VARTAB+0 + adc #$02 + sta VARTAB+0 + bcc !+ + inc VARTAB+1 +!: +#endif + + // Call CLR to restore remaining variables + + jsr do_clr + + // Quit + + jmp shell_main_loop diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index 790aaa8a..5a6cafb1 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -181,6 +181,7 @@ const StringEntryList GLOBAL_Keywords_CC = { ListType::KEYWORDS, "keywords_CC", { 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", }, + { true, true, true, "KCC_05", "OLD", }, // OpenROMs specific, not present in CBM BASIC dialects } }; // extended BASIC keywords - reserved for BASIC commands likely making sense on most C64-compatible machines From ba704cc5a720afd0f756a48e7c02ff47b24cbd4b Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 28 Jun 2020 17:25:40 +0200 Subject: [PATCH 10/24] LIST command is now more foolproof --- STATUS.md | 1 + src/basic/ab1e.strout.s | 1 + src/basic/assets/str_rev_question.s | 9 ++++ src/basic/board_m65/mega65_imports.s | 1 + src/basic/print/list_single_line.s | 75 ++++++++++++++++++++++++---- 5 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 src/basic/assets/str_rev_question.s diff --git a/STATUS.md b/STATUS.md index 145e4a86..9f31e493 100644 --- a/STATUS.md +++ b/STATUS.md @@ -22,6 +22,7 @@ Here are the features of the Open ROMs not found in the original ROMs from the 8 * 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 * command without parameters tries to load first file from drive chosen as above +* `LIST` command should never damage the screen if trying to list memory content which is not a BASIC program * 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 diff --git a/src/basic/ab1e.strout.s b/src/basic/ab1e.strout.s index 0c2e99b7..9f99e7bf 100644 --- a/src/basic/ab1e.strout.s +++ b/src/basic/ab1e.strout.s @@ -10,6 +10,7 @@ // print string routine STROUT: + // Setup pointer sty FRESPC+1 sta FRESPC+0 diff --git a/src/basic/assets/str_rev_question.s b/src/basic/assets/str_rev_question.s new file mode 100644 index 00000000..ba0c8302 --- /dev/null +++ b/src/basic/assets/str_rev_question.s @@ -0,0 +1,9 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// String - question mark in reverse + +str_rev_question: + + .byte $12, $3F, $92, $00 diff --git a/src/basic/board_m65/mega65_imports.s b/src/basic/board_m65/mega65_imports.s index 4235e8f7..210dac22 100644 --- a/src/basic/board_m65/mega65_imports.s +++ b/src/basic/board_m65/mega65_imports.s @@ -23,3 +23,4 @@ .label print_features = BASIC_0.proxy_B1_print_features #endif .label do_STRING_TOO_LONG_error = BASIC_0.do_STRING_TOO_LONG_error +.label str_rev_question = BASIC_0.str_rev_question diff --git a/src/basic/print/list_single_line.s b/src/basic/print/list_single_line.s index a97077b5..021584fa 100644 --- a/src/basic/print/list_single_line.s +++ b/src/basic/print/list_single_line.s @@ -67,7 +67,9 @@ list_print_loop: lda (OLDTXT),y #endif - beq list_end_of_line + bne !+ + rts // end of line +!: cmp #$22 bne list_not_quote lda QTSW @@ -118,6 +120,10 @@ list_display_token_CC: // Subtract $1 from token to get offset in token list dex + // Check if token is known + cpx #TK__MAXTOKEN_keywords_CC + bcs list_display_unknown_token // XXX consider displaying two question marks here + // Now ask for it to be printed jsr print_packed_keyword_CC @@ -156,6 +162,10 @@ list_display_token_CD: // Subtract $1 from token to get offset in token list dex + // Check if token is known + cpx #TK__MAXTOKEN_keywords_CD + bcs list_display_unknown_token // XXX consider displaying two question marks here + // Now ask for it to be printed jsr print_packed_keyword_CD @@ -174,9 +184,13 @@ list_display_token_V2: // Subtract $80 from token to get offset in token list txa - and #$7f + and #$7F tax + // Check if token is known + cpx #TK__MAXTOKEN_keywords_V2 + bcs list_display_unknown_token + // Now ask for it to be printed jsr print_packed_keyword_V2 @@ -188,12 +202,14 @@ list_token_displayed: ply_trash_a pla - cmp #$8f + cmp #$8F bne list_not_rem // REM command locks quote flag on until the end of the line, allowing // funny characters in REM statements without problem. sta QTSW // Any value other than $00 or $FF will lock quote mode on, so the token value of REM is fine here - // FALL THROUGH + + // FALLTHROUGH + list_not_rem: iny @@ -205,13 +221,50 @@ list_is_pi: // FALLTROUGH list_is_literal: - jsr JCHROUT - iny - bne list_print_loop - -list_end_of_line: - - rts + pha + and #$7F + cmp #$12 + beq list_is_literal_known // branch if quote mode on/off + and #%01100000 + bne list_is_literal_known + pla + + // FALLTROUGH + +list_is_unknown: + + phy_trash_a + lda #str_rev_question + jsr STROUT + ply_trash_a + +#if HAS_OPCODES_65C02 + bra !+ +#else + jmp !+ +#endif + +list_is_literal_known: + + pla + jsr JCHROUT +!: + iny + bne_16 list_print_loop + + rts // end of line + +list_display_unknown_token: + + pla + pla + +#if HAS_OPCODES_65C02 + bra list_is_unknown +#else + jmp list_is_unknown +#endif #endif // ROM layout From 0a85c12f42b28fbcd0d14da44a1a1a6059444ee3 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 28 Jun 2020 17:32:26 +0200 Subject: [PATCH 11/24] fix for regression in LIST --- src/basic/print/list_single_line.s | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/basic/print/list_single_line.s b/src/basic/print/list_single_line.s index 021584fa..65581a6e 100644 --- a/src/basic/print/list_single_line.s +++ b/src/basic/print/list_single_line.s @@ -223,9 +223,11 @@ list_is_pi: list_is_literal: pha + bit QTSW + bpl list_is_literal_known // in quote mode every character is allowed and #$7F cmp #$12 - beq list_is_literal_known // branch if quote mode on/off + beq list_is_literal_known // enabling/disabling reverse mode is allowed and #%01100000 bne list_is_literal_known pla From 2085e426c8e1c20470619b391c2453d240fc1325 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 28 Jun 2020 20:52:49 +0200 Subject: [PATCH 12/24] more cleanup in BASIC --- src/aliases/,aliases_ram_lowmem.s | 6 ++ src/basic/,aliases.s | 6 -- src/basic/basic_shift_mem_down.s | 76 +++++++-------- src/basic/basic_shift_mem_up.s | 94 +++++++++---------- src/basic/memory/shift_mem_down_38k.s | 18 ++-- src/basic/memory/shift_mem_up_38k.s | 18 ++-- src/basic/memory/under_rom_routines_46k_50k.s | 36 ++++--- src/basic/memory/under_rom_routines_60k.s | 52 +++++----- 8 files changed, 149 insertions(+), 157 deletions(-) diff --git a/src/aliases/,aliases_ram_lowmem.s b/src/aliases/,aliases_ram_lowmem.s index 08c6d7e9..b6e5dbed 100644 --- a/src/aliases/,aliases_ram_lowmem.s +++ b/src/aliases/,aliases_ram_lowmem.s @@ -71,6 +71,12 @@ .label FAC2_mantissa = $6A // $6A - $6D .label FAC2_sign = $6E + // We re-use FAC2 for memory move pointers, since we cannot be doing calculations while moving memory + .label memmove__src = $69 + .label memmove__dst = $6B + .label memmove__size = $6D + + .label ARISGN = $6F // -- NOT IMPLEMENTED -- .label FACOV = $70 // FAC1 low order mantissa .label FBUFPT = $71 // $71-$72 -- NOT IMPLEMENTED -- diff --git a/src/basic/,aliases.s b/src/basic/,aliases.s index 37741819..291df1a7 100644 --- a/src/basic/,aliases.s +++ b/src/basic/,aliases.s @@ -11,9 +11,3 @@ .label __tokenise_work3 = $0B // COUNT .label __tokenise_work4 = $0F // GARBFL .label __tokenise_work5 = $0C // DIMFLG - - // We re-use FAC2 for memory move pointers, since - // we can't be doing calculations while moving memory - .label __memmove_src = $69 - .label __memmove_dst = $6B - .label __memmove_size = $6D diff --git a/src/basic/basic_shift_mem_down.s b/src/basic/basic_shift_mem_down.s index 2653049f..b3594092 100644 --- a/src/basic/basic_shift_mem_down.s +++ b/src/basic/basic_shift_mem_down.s @@ -9,28 +9,28 @@ basic_shift_mem_down_and_relink: // Destination is OLDTXT lda OLDTXT+0 - sta __memmove_dst+0 + sta memmove__dst+0 lda OLDTXT+1 - sta __memmove_dst+1 + sta memmove__dst+1 // Source is that plus X txa pha // also keep for later clc adc OLDTXT+0 - sta __memmove_src+0 + sta memmove__src+0 lda OLDTXT+1 adc #0 - sta __memmove_src+1 + sta memmove__src+1 // Size is distance from source to end of BASIC text. lda VARTAB+0 sec - sbc __memmove_src+0 - sta __memmove_size+0 + sbc memmove__src+0 + sta memmove__size+0 lda VARTAB+1 - sbc __memmove_src+1 - sta __memmove_size+1 + sbc memmove__src+1 + sta memmove__size+1 // jsr printf // .text "TOP OF BASIC = $" @@ -38,14 +38,14 @@ basic_shift_mem_down_and_relink: // .byte $f0,VARTAB // .byte $0d // .text "SHIFTING DOWN $" - // .byte $f1,<__memmove_size,>__memmove_size - // .byte $f0,<__memmove_size,>__memmove_size + // .byte $f1,memmove__size + // .byte $f0,memmove__size // .text " BYTES FROM $" - // .byte $f1,<__memmove_src,>__memmove_src - // .byte $f0,<__memmove_src,>__memmove_src + // .byte $f1,memmove__src + // .byte $f0,memmove__src // .text " TO $" - // .byte $f1,<__memmove_dst,>__memmove_dst - // .byte $f0,<__memmove_dst,>__memmove_dst + // .byte $f1,memmove__dst + // .byte $f0,memmove__dst // .byte $0d,0 // The copy routine that copies under the ROMs is as simple @@ -59,44 +59,44 @@ basic_shift_mem_down_and_relink: // This means we have to then reduce the source and // target pointers by the same amount - lda __memmove_size+0 + lda memmove__size+0 eor #$ff sta __tokenise_work3 - sta __memmove_size+0 + sta memmove__size+0 - lda __memmove_src+0 + lda memmove__src+0 sec sbc __tokenise_work3 - sta __memmove_src+0 - lda __memmove_src+1 + sta memmove__src+0 + lda memmove__src+1 sbc #0 - sta __memmove_src+1 + sta memmove__src+1 - lda __memmove_dst+0 + lda memmove__dst+0 sec sbc __tokenise_work3 - sta __memmove_dst+0 - lda __memmove_dst+1 + sta memmove__dst+0 + lda memmove__dst+1 sbc #0 - sta __memmove_dst+1 + sta memmove__dst+1 // Increase copy page count so we can post-decrement compare with $00 - inc __memmove_size+1 + inc memmove__size+1 // jsr printf // .text "REVISED BOUNDS $" - // .byte $f1,<__memmove_size,>__memmove_size - // .byte $f0,<__memmove_size,>__memmove_size + // .byte $f1,memmove__size + // .byte $f0,memmove__size // .text " BYTES FROM $" - // .byte $f1,<__memmove_src,>__memmove_src - // .byte $f0,<__memmove_src,>__memmove_src + // .byte $f1,memmove__src + // .byte $f0,memmove__src // .text " TO $" - // .byte $f1,<__memmove_dst,>__memmove_dst - // .byte $f0,<__memmove_dst,>__memmove_dst + // .byte $f1,memmove__dst + // .byte $f0,memmove__dst // .byte $0d,0 // Get Y value ready for the copy - ldy __memmove_size+0 + ldy memmove__size+0 jsr shift_mem_down @@ -131,7 +131,7 @@ relink_down_next_line: sec sbc __tokenise_work3 - sta __memmove_src+0 + sta memmove__src+0 iny #if CONFIG_MEMORY_MODEL_60K @@ -143,10 +143,10 @@ relink_down_next_line: #endif sbc #0 - sta __memmove_src+1 + sta memmove__src+1 ldy #0 - lda __memmove_src+0 + lda memmove__src+0 #if CONFIG_MEMORY_MODEL_60K ldx #VARTAB // .byte $0d // .text "SHIFTING UP $" - // .byte $f1,<__memmove_size,>__memmove_size - // .byte $f0,<__memmove_size,>__memmove_size + // .byte $f1,memmove__size + // .byte $f0,memmove__size // .text " BYTES FROM $" - // .byte $f1,<__memmove_src,>__memmove_src - // .byte $f0,<__memmove_src,>__memmove_src + // .byte $f1,memmove__src + // .byte $f0,memmove__src // .text " TO $" - // .byte $f1,<__memmove_dst,>__memmove_dst - // .byte $f0,<__memmove_dst,>__memmove_dst + // .byte $f1,memmove__dst + // .byte $f0,memmove__dst // .byte $0d,0 // To make life simple for the copy routine that lives in RAM, // we have to adjust the end pointers down one page and set Y to the low // byte of the copy size. - lda __memmove_src+0 + lda memmove__src+0 sec - sbc __memmove_size+0 - sta __memmove_src+0 - lda __memmove_src+1 + sbc memmove__size+0 + sta memmove__src+0 + lda memmove__src+1 sbc #0 - sta __memmove_src+1 + sta memmove__src+1 - lda __memmove_dst+0 + lda memmove__dst+0 sec - sbc __memmove_size+0 - sta __memmove_dst+0 - lda __memmove_dst+1 + sbc memmove__size+0 + sta memmove__dst+0 + lda memmove__dst+1 sbc #0 - sta __memmove_dst+1 + sta memmove__dst+1 // Now make exit easy, by being able to check for zero on size high byte when done - inc __memmove_size+1 + inc memmove__size+1 // Then set Y to the number offset required - ldy __memmove_size+0 + ldy memmove__size+0 iny stx __tokenise_work3 // jsr printf // .text "REVISED BOUNDS $" - // .byte $f1,<__memmove_size,>__memmove_size - // .byte $f0,<__memmove_size,>__memmove_size + // .byte $f1,memmove__size + // .byte $f0,memmove__size // .text " BYTES FROM $" - // .byte $f1,<__memmove_src,>__memmove_src - // .byte $f0,<__memmove_src,>__memmove_src + // .byte $f1,memmove__src + // .byte $f0,memmove__src // .text " TO $" - // .byte $f1,<__memmove_dst,>__memmove_dst - // .byte $f0,<__memmove_dst,>__memmove_dst + // .byte $f1,memmove__dst + // .byte $f0,memmove__dst // .byte $0d,0 // Do the copy @@ -143,10 +143,10 @@ relink_up_next_line: lda (OLDTXT),y #endif - sta __memmove_dst+0 + sta memmove__dst+0 clc adc __tokenise_work3 - sta __memmove_src+0 + sta memmove__src+0 iny php @@ -159,27 +159,27 @@ relink_up_next_line: lda (OLDTXT),y #endif - sta __memmove_dst+1 + sta memmove__dst+1 plp adc #0 - sta __memmove_src+1 + sta memmove__src+1 // jsr printf // .text "LINE ADDR = $" // .byte $f1,VARTAB // .byte $f0,VARTAB // .text $d," BEFORE = $" - // .byte $f1,<__memmove_dst,>__memmove_dst - // .byte $f0,<__memmove_dst,>__memmove_dst + // .byte $f1,memmove__dst + // .byte $f0,memmove__dst // .text ", AFTER = $" - // .byte $f1,<__memmove_src,>__memmove_src - // .byte $f0,<__memmove_src,>__memmove_src + // .byte $f1,memmove__src + // .byte $f0,memmove__src // .byte $d // .byte 0 - // Write __memmove_src back to current line pointer + // Write memmove__src back to current line pointer ldy #0 - lda __memmove_src+0 + lda memmove__src+0 #if CONFIG_MEMORY_MODEL_60K ldx # __memmove_src + // 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. + // This routine assumes the pointers are already pointed to the end of the areas, and that .Y is correctly initialized php !: - lda (__memmove_src),y - sta (__memmove_dst),y + lda (memmove__src),y + sta (memmove__dst),y iny bne !- - inc __memmove_src+1 - inc __memmove_dst+1 - dec __memmove_size+1 + inc memmove__src+1 + inc memmove__dst+1 + dec memmove__size+1 bne !- plp rts diff --git a/src/basic/memory/shift_mem_up_38k.s b/src/basic/memory/shift_mem_up_38k.s index c8fab14b..81c0d9f3 100644 --- a/src/basic/memory/shift_mem_up_38k.s +++ b/src/basic/memory/shift_mem_up_38k.s @@ -7,22 +7,20 @@ shift_mem_up: - // Move __memmove_size bytes from __memmove_src to __memmove_dst, - // where __memmove_dst > __memmove_src + // 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. + // This routine assumes the pointers are already pointed to the end of the areas, and that .Y is correctly initialized php !: - lda (__memmove_src),y - sta (__memmove_dst),y + lda (memmove__src),y + sta (memmove__dst),y dey bne !- - dec __memmove_src+1 - dec __memmove_dst+1 - dec __memmove_size+1 + dec memmove__src+1 + dec memmove__dst+1 + dec memmove__size+1 bne !- plp rts diff --git a/src/basic/memory/under_rom_routines_46k_50k.s b/src/basic/memory/under_rom_routines_46k_50k.s index 7ceb7a84..d7f7beef 100644 --- a/src/basic/memory/under_rom_routines_46k_50k.s +++ b/src/basic/memory/under_rom_routines_46k_50k.s @@ -72,12 +72,10 @@ peek_under_roms_via_FAC1_PLUS_1: shift_mem_up: - // Move __memmove_size bytes from __memmove_src to __memmove_dst, - // where __memmove_dst > __memmove_src + // 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. + // This routine assumes the pointers are already pointed to the end of the areas, and that .Y is correctly initialized // Unmap BASIC lower ROM @@ -88,13 +86,13 @@ shift_mem_up: // Perform the copying !: - lda (__memmove_src),y - sta (__memmove_dst),y + lda (memmove__src),y + sta (memmove__dst),y dey bne !- - dec __memmove_src+1 - dec __memmove_dst+1 - dec __memmove_size+1 + dec memmove__src+1 + dec memmove__dst+1 + dec memmove__size+1 bne !- #if HAS_OPCODES_65C02 @@ -106,12 +104,10 @@ shift_mem_up: shift_mem_down: - // Move __memmove_size bytes from __memmove_src to __memmove_dst, - // where __memmove_dst > __memmove_src + // 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. + // This routine assumes the pointers are already pointed to the end of the areas, and that .Y is correctly initialized // Unmap BASIC lower ROM @@ -122,13 +118,13 @@ shift_mem_down: // Perform the copying !: - lda (__memmove_src),y - sta (__memmove_dst),y + lda (memmove__src),y + sta (memmove__dst),y iny bne !- - inc __memmove_src+1 - inc __memmove_dst+1 - dec __memmove_size+1 + inc memmove__src+1 + inc memmove__dst+1 + dec memmove__size+1 bne !- // FALLTROUGH diff --git a/src/basic/memory/under_rom_routines_60k.s b/src/basic/memory/under_rom_routines_60k.s index 0a07dbc7..a3b72346 100644 --- a/src/basic/memory/under_rom_routines_60k.s +++ b/src/basic/memory/under_rom_routines_60k.s @@ -70,44 +70,44 @@ memmap_allram_routine: rts shift_mem_up_routine: - // Move __memmove_size bytes from __memmove_src to __memmove_dst, - // where __memmove_dst > __memmove_src + + // 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. + // This routine assumes the pointers are already pointed to the end of the areas, and that .Y is correctly initialized + php jsr memmap_allram -smu1: - lda (__memmove_src),y - sta (__memmove_dst),y +!: + 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 + bne !- + dec memmove__src+1 + dec memmove__dst+1 + dec memmove__size+1 + bne !- plp jmp memmap_normal shift_mem_down_routine: - // Move __memmove_size bytes from __memmove_src to __memmove_dst, - // where __memmove_dst > __memmove_src + + // 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. + // This routine assumes the pointers are already pointed to the end of the areas, and that .Y is correctly initialized + php jsr memmap_allram -smd1: - lda (__memmove_src),y - sta (__memmove_dst),y +!: + 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 + bne !- + inc memmove__src+1 + inc memmove__dst+1 + dec memmove__size+1 + bne !- plp jmp memmap_normal From 01775af002cb623c8dfeea35bb92a313decc0367 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 28 Jun 2020 21:09:01 +0200 Subject: [PATCH 13/24] more cleanup in BASIC --- src/basic/basic_commands_CC/cmd_old.s | 43 ++---------------------- src/basic/basic_shift_mem_down.s | 6 ++-- src/basic/basic_shift_mem_up.s | 4 +-- src/basic/{ => editor}/a533.interop | 0 src/basic/{ => editor}/a533.linkprg.s | 0 src/basic/editor/calculate_vartab.s | 47 +++++++++++++++++++++++++++ 6 files changed, 54 insertions(+), 46 deletions(-) rename src/basic/{ => editor}/a533.interop (100%) rename src/basic/{ => editor}/a533.linkprg.s (100%) create mode 100644 src/basic/editor/calculate_vartab.s diff --git a/src/basic/basic_commands_CC/cmd_old.s b/src/basic/basic_commands_CC/cmd_old.s index ff601281..210ed801 100644 --- a/src/basic/basic_commands_CC/cmd_old.s +++ b/src/basic/basic_commands_CC/cmd_old.s @@ -11,53 +11,14 @@ cmd_old: inx bne_16 do_DIRECT_MODE_ONLY_error - // Now try to restore program linkage + // Now try to restore program linkage and VARTAB ldy #$01 tya sta (TXTTAB),y jsr LINKPRG - - // Now we have to restore VARTAB XXX deduplicate this with line editor - - lda TXTTAB+0 - sta OLDTXT+0 - lda TXTTAB+1 - sta OLDTXT+1 -!: - lda OLDTXT+0 - sta VARTAB+0 - lda OLDTXT+1 - sta VARTAB+1 - - jsr basic_follow_link_to_next_line - - lda OLDTXT+0 - ora OLDTXT+1 - bne !- // branch if pointer not NULL - - // Correct VARTAB by 2 bytes NULL pointer - -#if HAS_OPCODES_65CE02 - - inw VARTAB - inw VARTAB - -#else - - clc - lda VARTAB+0 - adc #$02 - sta VARTAB+0 - bcc !+ - inc VARTAB+1 -!: -#endif - - // Call CLR to restore remaining variables - - jsr do_clr + jsr calculate_VARTAB // Quit diff --git a/src/basic/basic_shift_mem_down.s b/src/basic/basic_shift_mem_down.s index b3594092..7def6575 100644 --- a/src/basic/basic_shift_mem_down.s +++ b/src/basic/basic_shift_mem_down.s @@ -114,9 +114,9 @@ basic_shift_mem_down_and_relink: relink_down_next_line: - // inc $d020 - // jmp relink_down_next_line - + + // XXX reuse code from cmd_old + // Subtract __tokenise_work3 from the pointer ldy #0 diff --git a/src/basic/basic_shift_mem_up.s b/src/basic/basic_shift_mem_up.s index 68d1b317..9b203555 100644 --- a/src/basic/basic_shift_mem_up.s +++ b/src/basic/basic_shift_mem_up.s @@ -128,8 +128,8 @@ basic_shift_mem_up_and_relink: #endif relink_up_next_line: - // inc $d020 - // jmp relink_up_next_line + + // XXX reuse code from cmd_old // Advance pointer by tokenise_word3 bytes ldy #0 diff --git a/src/basic/a533.interop b/src/basic/editor/a533.interop similarity index 100% rename from src/basic/a533.interop rename to src/basic/editor/a533.interop diff --git a/src/basic/a533.linkprg.s b/src/basic/editor/a533.linkprg.s similarity index 100% rename from src/basic/a533.linkprg.s rename to src/basic/editor/a533.linkprg.s diff --git a/src/basic/editor/calculate_vartab.s b/src/basic/editor/calculate_vartab.s new file mode 100644 index 00000000..b883a335 --- /dev/null +++ b/src/basic/editor/calculate_vartab.s @@ -0,0 +1,47 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Calculate the VARTAB value - to mark the end of BASIC program code +// + +calculate_VARTAB: + + lda TXTTAB+0 + sta OLDTXT+0 + lda TXTTAB+1 + sta OLDTXT+1 +!: + lda OLDTXT+0 + sta VARTAB+0 + lda OLDTXT+1 + sta VARTAB+1 + + jsr basic_follow_link_to_next_line + + lda OLDTXT+0 + ora OLDTXT+1 + bne !- // branch if pointer not NULL + + // Correct VARTAB by 2 bytes NULL pointer + +#if HAS_OPCODES_65CE02 + + inw VARTAB + inw VARTAB + +#else + + clc + lda VARTAB+0 + adc #$02 + sta VARTAB+0 + bcc !+ + inc VARTAB+1 +!: +#endif + + // Call CLR to set-up remaining variables + + jmp do_clr From 3b11d1b881d62d03011cc697504406df1145b11b Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 28 Jun 2020 22:47:55 +0200 Subject: [PATCH 14/24] tape wedge now accepts file name --- CONFIG.md | 4 +- STATUS.md | 2 +- src/basic/editor/shell.s | 30 +++----- src/basic/engine/prepare_direct_execution.s | 27 +++++++ src/basic/wedge/wedge_tape.s | 85 ++++++++++++++++----- 5 files changed, 106 insertions(+), 42 deletions(-) create mode 100644 src/basic/engine/prepare_direct_execution.s diff --git a/CONFIG.md b/CONFIG.md index 9c1fa54c..6aae84a7 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -285,9 +285,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 tape loading - supports `←L` only. +If enabled, a simple DOS wedge is available from the direct mode for tape loading - supports `←L` only, optionally with a file name. -Feature needs few bytes in BASIC segment. If unsure - enable. +Feature needs several bytes in BASIC segment. If unsure - enable. ### `CONFIG_TAPE_HEAD_ALIGN` diff --git a/STATUS.md b/STATUS.md index 9f31e493..4504bd90 100644 --- a/STATUS.md +++ b/STATUS.md @@ -12,7 +12,7 @@ Here are the features of the Open ROMs not found in the original ROMs from the 8 * 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 +* turbo tape load support (as device 7, or using `←L`, optionallly with a file name), 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) * 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 diff --git a/src/basic/editor/shell.s b/src/basic/editor/shell.s index fe4eafe1..da8ba2a3 100644 --- a/src/basic/editor/shell.s +++ b/src/basic/editor/shell.s @@ -37,7 +37,10 @@ shell_got_line: // Store length of input buffer ready for tokenising stx __tokenise_work1 - // XXX we should probably store 0 at the end of used BUF + + // Store 0 as the sentinel + lda #$00 + sta BUF, x // FALLTROUGH @@ -76,10 +79,13 @@ shell_process_line: // Check if a wedge should take over +#if CONFIG_DOS_WEDGE + + ldx __tokenise_work1 // size of the input, DOS wedges needs this XXX this should not be needed + +#endif #if CONFIG_DOS_WEDGE || CONFIG_TAPE_WEDGE - ldx __tokenise_work1 // size of the input, wedges need this XXX this should not be needed - // Check if DOS wedge should take over lda BUF @@ -170,20 +176,6 @@ shell_add_delete_line: shell_execute_line: - // Setup pointer to the statement - lda #BUF - sta TXTPTR+1 - - // There is no stored line, so zero that pointer out - lda #$00 - sta OLDTXT+0 - sta OLDTXT+1 - - // Put invalid line number in current line number value, - // so that we know we are in direct mode (Computes Mapping the 64 p19) - lda #$FF - sta CURLIN+1 - + jsr prepare_direct_execution jmp execute_statements + diff --git a/src/basic/engine/prepare_direct_execution.s b/src/basic/engine/prepare_direct_execution.s new file mode 100644 index 00000000..1b2b1bb0 --- /dev/null +++ b/src/basic/engine/prepare_direct_execution.s @@ -0,0 +1,27 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + +// +// Prepare interpreter to execute commands in direct mode +// + +prepare_direct_execution: + + // Setup pointer to the statement + lda #BUF + sta TXTPTR+1 + + // There is no stored line, so zero that pointer out + lda #$00 + sta OLDTXT+0 + sta OLDTXT+1 + + // Put invalid line number in current line number value, + // so that we know we are in direct mode (Computes Mapping the 64 p19) + lda #$FF + sta CURLIN+1 + + rts diff --git a/src/basic/wedge/wedge_tape.s b/src/basic/wedge/wedge_tape.s index ac89415d..f2608a1f 100644 --- a/src/basic/wedge/wedge_tape.s +++ b/src/basic/wedge/wedge_tape.s @@ -6,17 +6,16 @@ #if CONFIG_TAPE_WEDGE -// .X has to contain size of the buffer - wedge_tape: - lda #$FF - sta CURLIN+1 // in case of error do not print line number + // Prepare for execution - cpx #$02 - bne_16 do_SYNTAX_error + jsr prepare_direct_execution + jsr fetch_character - lda BUF+1 + // First character is a 'left arrow', we can ignore it - determine the command + + jsr fetch_character cmp #$4C // 'L' beq wedge_arrow_L @@ -30,12 +29,69 @@ wedge_tape: jmp do_SYNTAX_error +#if CONFIG_TAPE_HEAD_ALIGN + +wedge_arrow_H: + + // Make sure the syntax is correct + + jsr injest_spaces + jsr fetch_character + + cmp #$00 + bne_16 do_SYNTAX_error + + jsr tape_head_align + + jsr print_return + jmp do_BREAK_error + +#endif + wedge_arrow_L: - // Execute 'arrow + L' + // Make sure the syntax is correct + + jsr injest_spaces + jsr fetch_character + cmp #$00 + beq wedge_arrow_L_no_filename // branch if no file name given + cmp #$22 + bne_16 do_SYNTAX_error // branch if no opening quote + + // Fetch the file name + + lda TXTPTR+0 + sta FNADDR+0 + lda TXTPTR+1 + sta FNADDR+1 + + ldx #$00 +!: + jsr fetch_character + + cmp #$00 + beq !+ + cmp #$22 + beq !+ + + inx + bne !- +!: + stx FNLEN + lda #$00 - sta FNLEN // default file name is empty + beq wedge_arrow_L_got_filename + +wedge_arrow_L_no_filename: + + sta FNLEN // .A is 0 here, default file name is empty + + // FALLTROUGH + +wedge_arrow_L_got_filename: // .A has to be 0 + sta VERCKB // operation is LOAD, not VERIFY ldy #$01 @@ -51,16 +107,5 @@ wedge_arrow_L: jmp cmd_load_got_params -#if CONFIG_TAPE_HEAD_ALIGN - -wedge_arrow_H: - - jsr tape_head_align - - jsr print_return - jmp do_BREAK_error - -#endif - #endif // CONFIG_TAPE_WEDGE From c9c45622d7e618db6850ff9a3d65563991fc431b Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Sun, 28 Jun 2020 22:54:11 +0200 Subject: [PATCH 15/24] MERGE command is now safer --- src/basic/basic_commands_CC/cmd_merge.s | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/basic/basic_commands_CC/cmd_merge.s b/src/basic/basic_commands_CC/cmd_merge.s index 6bcabe8d..e3e2194e 100644 --- a/src/basic/basic_commands_CC/cmd_merge.s +++ b/src/basic/basic_commands_CC/cmd_merge.s @@ -16,6 +16,10 @@ cmd_merge: jsr helper_load_fetch_devnum + // Make sure VARTAB is correctly set + + jsr calculate_VARTAB + // Perform loading - just for a different address sec From 4f4e7d63fd0722c38fc542566685ee574fd4376f Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 29 Jun 2020 16:30:36 +0200 Subject: [PATCH 16/24] tape wedge can now invoke MERGE, documentation update --- CONFIG.md | 2 +- STATUS.md | 2 +- doc/Extended-BASIC.md | 42 +- src/basic/basic_commands_CC/cmd_merge.s | 4 + src/basic/wedge/wedge_tape.s | 65 +- src/basic/wedge/wedge_tape_prepare_load.s | 68 + tools/generate_strings.cc | 2592 +++++++++++---------- 7 files changed, 1423 insertions(+), 1352 deletions(-) create mode 100644 src/basic/wedge/wedge_tape_prepare_load.s diff --git a/CONFIG.md b/CONFIG.md index 6aae84a7..e94e7ac6 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -285,7 +285,7 @@ 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 tape loading - supports `←L` only, optionally with a file name. +If enabled, a simple DOS wedge is available from the direct mode for tape loading - supports `←L` (for `LOAD`) and `←M` (for `MERGE`), optionally with a file name. Feature needs several bytes in BASIC segment. If unsure - enable. diff --git a/STATUS.md b/STATUS.md index 4504bd90..276414db 100644 --- a/STATUS.md +++ b/STATUS.md @@ -12,7 +12,7 @@ Here are the features of the Open ROMs not found in the original ROMs from the 8 * DOS wedge (direct mode only) - `@`, `@`, `@$`, `@$`, `@` * BASIC extensions, see the [documentation](doc/Extended-BASIC.md) -* turbo tape load support (as device 7, or using `←L`, optionallly with a file name), quite sophisticated: up to 250 blocks (can store bytes under I/O), automatically adjusts for tape speed differences +* turbo tape load support (as device 7, or using `←L` / `←M`, optionally with a file name), 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) * 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 diff --git a/doc/Extended-BASIC.md b/doc/Extended-BASIC.md index 2f9088b3..dd48b323 100644 --- a/doc/Extended-BASIC.md +++ b/doc/Extended-BASIC.md @@ -1,9 +1,45 @@ # 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. +NOTE: Command syntax, behaviour details, and tokens are still subject to change! Currently the availability of some depends on the build configuration, in the future most (if not all) extended commands will be available only on machines with extended ROM, like the Mega65 or Ultimate 64. -## Additional commands +## DOS Wedge + +The DOS Wedge commands are only available in direct mode, and they have to start from the first character of the line. + +### `@` + +Displays the error/status read from the current drive. Current drive is either the last device used by any I/O command, the one set by DOS Wedge command, or 8 as a fallback. + +### `@$` + +Displays the directory of the current drive. Does not destroy BASIC program in memory. + +### `@device_number` + +Changes the current drive number. + +### `@command` + +Sends the DOS command to the current drive. + +## Tape Wedge + +The Tape Wedge commands are only available in direct mode, and they have to start from the first character of the line. + +### `←L ["file_name"]` + +Loads the file from tape. Depending on the configuration, it tries to load the file in TurboTape 64 format, in the standard CBM format, or autodetects the file format. + +### `←M ["file_name"]` + +Like above, but merges a BASIC program to the one already stored in memory. + +### `←H` + +Launches a built-in tape head alignment tool. Destorys program in memory. Press `RUN/STOP` to terminate the tool. + +## Additional BASIC commands ### `FAST` @@ -15,7 +51,7 @@ Tries to switch the machine back to 1 MHz operation mode. ### `OLD` -Tries to restore program destroyed by NEW or a reset. +Tries to restore program destroyed by `NEW` or a reset. ### `MERGE "file_name" [, device_number]` diff --git a/src/basic/basic_commands_CC/cmd_merge.s b/src/basic/basic_commands_CC/cmd_merge.s index e3e2194e..43c8cd17 100644 --- a/src/basic/basic_commands_CC/cmd_merge.s +++ b/src/basic/basic_commands_CC/cmd_merge.s @@ -16,6 +16,10 @@ cmd_merge: jsr helper_load_fetch_devnum + // FALLTROUGH + +cmd_merge_got_params: + // Make sure VARTAB is correctly set jsr calculate_VARTAB diff --git a/src/basic/wedge/wedge_tape.s b/src/basic/wedge/wedge_tape.s index f2608a1f..951ced7e 100644 --- a/src/basic/wedge/wedge_tape.s +++ b/src/basic/wedge/wedge_tape.s @@ -19,6 +19,8 @@ wedge_tape: cmp #$4C // 'L' beq wedge_arrow_L + cmp #$4D // 'M' + beq wedge_arrow_M #if CONFIG_TAPE_HEAD_ALIGN @@ -50,62 +52,21 @@ wedge_arrow_H: wedge_arrow_L: - // Make sure the syntax is correct - - jsr injest_spaces - jsr fetch_character - - cmp #$00 - beq wedge_arrow_L_no_filename // branch if no file name given - cmp #$22 - bne_16 do_SYNTAX_error // branch if no opening quote - - // Fetch the file name - - lda TXTPTR+0 - sta FNADDR+0 - lda TXTPTR+1 - sta FNADDR+1 - - ldx #$00 -!: - jsr fetch_character - - cmp #$00 - beq !+ - cmp #$22 - beq !+ - - inx - bne !- -!: - stx FNLEN - - lda #$00 - beq wedge_arrow_L_got_filename - -wedge_arrow_L_no_filename: - - sta FNLEN // .A is 0 here, default file name is empty - - // FALLTROUGH - -wedge_arrow_L_got_filename: // .A has to be 0 - - sta VERCKB // operation is LOAD, not VERIFY - - ldy #$01 -#if CONFIG_TAPE_TURBO - ldx #$07 // turbo tape device -#else - ldx #$01 // normal tape device -#endif - - jsr JSETFLS + jsr wedge_tape_prepare_load // Perform loading jmp cmd_load_got_params +wedge_arrow_M: + + jsr wedge_tape_prepare_load + ldy #$00 + sty SA // for MERGE secondary address has to be 0! + + // Perform merging + + jmp cmd_merge_got_params + #endif // CONFIG_TAPE_WEDGE diff --git a/src/basic/wedge/wedge_tape_prepare_load.s b/src/basic/wedge/wedge_tape_prepare_load.s new file mode 100644 index 00000000..cac50b40 --- /dev/null +++ b/src/basic/wedge/wedge_tape_prepare_load.s @@ -0,0 +1,68 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +#if CONFIG_TAPE_WEDGE + +// +// Common part for LOAD and MERGE operations via tape wedge +// + +wedge_tape_prepare_load: + + // Make sure the syntax is correct + + jsr injest_spaces + jsr fetch_character + + cmp #$00 + beq wedge_tape_prepare_load_no_filename // branch if no file name given + cmp #$22 + bne_16 do_SYNTAX_error // branch if no opening quote + + // Fetch the file name + + lda TXTPTR+0 + sta FNADDR+0 + lda TXTPTR+1 + sta FNADDR+1 + + ldx #$00 +!: + jsr fetch_character + + cmp #$00 + beq !+ + cmp #$22 + beq !+ + + inx + bne !- +!: + stx FNLEN + + lda #$00 + beq wedge_tape_prepare_load_got_filename + +wedge_tape_prepare_load_no_filename: + + sta FNLEN // .A is 0 here, default file name is empty + + // FALLTROUGH + +wedge_tape_prepare_load_got_filename: // .A has to be 0 + + sta VERCKB // operation is LOAD, not VERIFY + + ldy #$01 +#if CONFIG_TAPE_TURBO + ldx #$07 // turbo tape device +#else + ldx #$01 // normal tape device +#endif + + jmp JSETFLS + + +#endif // CONFIG_TAPE_WEDGE diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index 5a6cafb1..69dd66f8 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -27,26 +27,26 @@ std::string CMD_cnfFile = ""; 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 + 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, - DICTIONARY // for internal use only + KEYWORDS, + STRINGS_BASIC, + DICTIONARY // for internal use only }; typedef struct StringEntryList { - ListType type; - std::string name; - std::vector list; + ListType type; + std::string name; + std::vector list; } StringEntryList; typedef std::vector StringEncoded; @@ -83,93 +83,93 @@ typedef std::vector StringEncodedList; 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 + 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 + 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 + // 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 @@ -177,64 +177,64 @@ const StringEntryList GLOBAL_Keywords_V2 = { ListType::KEYWORDS, "keywords_V2", const StringEntryList GLOBAL_Keywords_CC = { ListType::KEYWORDS, "keywords_CC", { // 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", }, - { true, true, true, "KCC_05", "OLD", }, // OpenROMs specific, not present in CBM BASIC dialects + { 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", }, + { true, true, true, "KCC_05", "OLD", }, // OpenROMs specific, not present in CBM BASIC dialects } }; // 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 - { 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 + // STD M65 X16 + { 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 const StringEntryList GLOBAL_Keywords_CE = { ListType::KEYWORDS, "keywords_CE", { - // STD M65 X16 - { false, false, false, "KCE_01", "TESTCMD", }, + // 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", }, + // 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", }, + // 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", }, + // 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", }, + // 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", }, + // STD M65 X16 + { false, false, false, "KD3_01", "TESTFUN", }, } }; @@ -252,66 +252,66 @@ const StringEntryList GLOBAL_Keywords_D3 = { ListType::KEYWORDS, "keywords_D3", 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 - { 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 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" }, + // 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 + { 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 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" }, } }; // 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_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 - { 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", "\rBRK AT $" }, - // Note: depending on configuration, additional strings will be added here + // 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 + { 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", "\rBRK AT $" }, + // Note: depending on configuration, additional strings will be added here } }; @@ -319,129 +319,129 @@ const StringEntryList GLOBAL_MiscStrings = { ListType::STRINGS_BASIC, "misc", - 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 + "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 + "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 + "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 + "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 + "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 + "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 + "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 + "BACKGROUND" // $FE $3B + "BORDER" // $FE $3C // https://en.wikipedia.org/wiki/Sinclair_BASIC + "HIGHLIGHT" // $FE $3D */ std::map GLOBAL_ConfigOptions; @@ -450,94 +450,96 @@ std::map GLOBAL_ConfigOptions; // Work class definitions // +// This class encapsulates the optional dictionary encoding of selected string lists class DictEncoder { public: - void addString(const std::string &inString, StringEncoded *outPtr); + void addString(const std::string &inString, StringEncoded *outPtr); - void process(StringEntryList &outDictionary); + void process(StringEntryList &outDictionary); private: - bool optimizeSplit(); - bool optimizeJoin(); - void optimizeOrder(); + bool optimizeSplit(); + bool optimizeJoin(); + void optimizeOrder(); - void cleanupDictionary(); + void cleanupDictionary(); - void extractWords(std::vector &candidateList); - int32_t evaluateCandidate(std::string &candidate); + void extractWords(std::vector &candidateList); + int32_t evaluateCandidate(std::string &candidate); - std::vector encodings; - std::vector dictionary; + std::vector encodings; + std::vector dictionary; }; +// Main class to encode strings based on character frequency class DataSet { public: - void addStrings(const StringEntryList &stringList); + void addStrings(const StringEntryList &stringList); - const std::string &getOutput(); + const std::string &getOutput(); private: - void process(); + void process(); - void generateConfigDepStrings(); - void validateLists(); - void calculateFrequencies(); - void encodeStringsDict(); - void encodeStringsFreq(); + void generateConfigDepStrings(); + void validateLists(); + void calculateFrequencies(); + void encodeStringsDict(); + void encodeStringsFreq(); - void encodeByFreq(const std::string &plain, StringEncoded &encoded) const; + 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 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); + void putCharEncoding(std::ostringstream &stream, uint8_t idx, char character, bool is3n); - bool isCompressionLvl2(const StringEntryList &list) const; + bool isCompressionLvl2(const StringEntryList &list) const; - virtual bool isRelevant(const StringEntry &entry) const = 0; - virtual std::string layoutName() const = 0; + virtual bool isRelevant(const StringEntry &entry) const = 0; + virtual std::string layoutName() const = 0; - std::vector stringEntryLists; - std::vector stringEncodedLists; + 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 + 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; + uint8_t tk__packed_as_3n = 0; + uint8_t tk__max_keyword_len = 0; - size_t maxAliasLen = 0; - std::string outFileContent; + 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"; } + 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"; } + 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"; } + bool isRelevant(const StringEntry &entry) const { return entry.enabledX16; } + std::string layoutName() const { return "X16"; } }; // @@ -546,1119 +548,1119 @@ class DataSetX16 : public DataSet void DictEncoder::addString(const std::string &inString, StringEncoded *outPtr) { - // Store the pointer to encoding + // Store the pointer to encoding - encodings.push_back(outPtr); + encodings.push_back(outPtr); - // Check if string is already present in the dictionary + // Check if string is already present in the dictionary - auto pos = std::find(dictionary.begin(), dictionary.end(), inString); + auto pos = std::find(dictionary.begin(), dictionary.end(), inString); - // Create initial encoding + // Create initial encoding - if (pos != dictionary.end()) - { - encodings.back()->push_back(pos - dictionary.begin()); - } - else - { - if (dictionary.size() > 255) - { - ERROR("max 255 strings allowed for dictionary compression"); - } + if (pos != dictionary.end()) + { + encodings.back()->push_back(pos - dictionary.begin()); + } + else + { + if (dictionary.size() > 255) + { + ERROR("max 255 strings allowed for dictionary compression"); + } - dictionary.push_back(inString); - encodings.back()->push_back(dictionary.size() - 1); - } + dictionary.push_back(inString); + encodings.back()->push_back(dictionary.size() - 1); + } } void DictEncoder::extractWords(std::vector &candidateList) { - for (const auto &dictionaryEntry : dictionary) - { - // Split the dictionary entry into words - - std::istringstream entryStream(dictionaryEntry); - while (entryStream) - { - std::string word_1; - entryStream >> word_1; + for (const auto &dictionaryEntry : dictionary) + { + // Split the dictionary entry into words + + std::istringstream entryStream(dictionaryEntry); + while (entryStream) + { + std::string word_1; + entryStream >> word_1; - if (word_1.empty()) continue; - - // Create possible variants with spaces + if (word_1.empty()) continue; + + // Create possible variants with spaces - std::string word_2 = " " + word_1; - std::string word_3 = word_1 + " "; - std::string word_4 = word_2 + " "; + 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 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; + 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); - } - } + candidateList.push_back(word); + }; + + addToList(word_1); + addToList(word_2); + addToList(word_3); + addToList(word_4); + } + } } int32_t DictEncoder::evaluateCandidate(std::string &candidate) { - // XXX it looks like this is not 100% right - debug the algorithm if dictionary compression is reintroduced + // 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 - - int32_t score = -(candidate.size() + 1); - uint32_t targetSize = dictionary.size() + 1; + // 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 + // 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 + for (const auto &dictionaryEntry : dictionary) + { + if (dictionaryEntry == candidate) + { + // Candidate equals the string - score += candidate.size() + 1; - targetSize--; - continue; - } - } + score += candidate.size() + 1; + targetSize--; + continue; + } + } - // Now check the remaining cases + // Now check the remaining cases - for (const auto &dictionaryEntry : dictionary) - { - if (dictionaryEntry == candidate) continue; // already handled + for (const auto &dictionaryEntry : dictionary) + { + if (dictionaryEntry == candidate) continue; // already handled - // Find all the occurences of the candidate in the current string + // 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 + 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 - std::string otherStr = std::string(dictionaryEntry.begin(), dictionaryEntry.end() + occurences[0]); + 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++) - { - // With a replacement, we should gain some bytes - score += candidate.size() - 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++; + } + } + + 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 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; + // 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 + // 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 - 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)); - } + 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 (leave one free for the work buffer), - // do not consider this candidate - - if (targetSize > 254) return -1; - } - - return score; + 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 (leave one free for the work buffer), + // do not consider this candidate + + 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; - } - } + // 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 - - std::vector candidateList; - extractWords(candidateList); + // 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 + + std::vector candidateList; + extractWords(candidateList); - // 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 - - auto bestCandidate = candidateList.end(); - int32_t bestCandidateScore = 0; - - for (auto iter = candidateList.begin(); iter < candidateList.end(); iter++) - { - int32_t candidateScore = evaluateCandidate(*iter); + // 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 + + 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 = candidateScore; - } - } - - // Only allow for replacements that brings some size benefit - - if (bestCandidateScore < 1) return false; - - // Extract the best candidate to a separate string - - // 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); + if (candidateScore > bestCandidateScore) + { + bestCandidate = iter; + bestCandidateScore = candidateScore; + } + } + + // Only allow for replacements that brings some size benefit + + if (bestCandidateScore < 1) return false; + + // Extract the best candidate to a separate string + + // 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); - 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(); - } + 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(); + } - cleanupDictionary(); + cleanupDictionary(); - // Now handle normal cases, when the string needs to be split - // XXX - this is not time-effective, optimize this in the future + // Now handle normal cases, when the string needs to be split + // XXX - this is not time-effective, optimize this in the future - bool optimizeAgain = true; - bool nexIteration = true; - while (nexIteration) - { - nexIteration = 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(); + 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(); + 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); - } + break; + } + } + + if (found) + { + replacement.push_back(pos2); + } + else + { + dictionary.push_back(newStr); + replacement.push_back(dictionary.size() - 1); + } - replacement.push_back(currentStrIdx); - } + replacement.push_back(currentStrIdx); + } - // Now replace all the occurences of 'selectedStrIdx' with a 'replacement' vector + // 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(); - } - } + 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; + return optimizeAgain; } bool DictEncoder::optimizeJoin() { - // Try to optimize by joining two substrings - - // XXX - possible future improvement - - return false; + // Try to optimize by joining two substrings + + // XXX - possible future improvement + + return false; } void DictEncoder::optimizeOrder() { - // XXX - it would be better to do this after the dictionary is compressed + // 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 - - 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--; - } - } + // 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; + // Create new entry + + Entry newEntry; + newEntry.word = dictionaryStr; + newEntry.penalty = sizePenalty * 65536 + freqPenalty; - optimizedOrder.push_back(newEntry); - } - + 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; }); + // 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); - } + // 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; + // 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) { - if (dictionary.empty()) return; - // Optimize as long as it brings any improvement + if (dictionary.empty()) return; + // Optimize as long as it brings any improvement - while (optimizeSplit() || optimizeJoin()) ; - optimizeOrder(); + while (optimizeSplit() || optimizeJoin()) ; + optimizeOrder(); - // Export the dictionary to external format + // Export the dictionary to external format - outDictionary.type = ListType::DICTIONARY; - outDictionary.name = "DICTIONARY"; + outDictionary.type = ListType::DICTIONARY; + outDictionary.name = "DICTIONARY"; - for (const auto &dictionaryStr : dictionary) - { - StringEntry newEntry = { true, true, true, "", dictionaryStr }; - outDictionary.list.push_back(newEntry); - } + for (const auto &dictionaryStr : dictionary) + { + StringEntry newEntry = { true, true, true, "", dictionaryStr }; + outDictionary.list.push_back(newEntry); + } - // Adapt the encoding to external format (0 = end of string) + // Adapt the encoding to external format (0 = end of string) - for (auto &encoding : encodings) - { - for (auto &byte : *encoding) byte++; - encoding->push_back(0); - } + for (auto &encoding : encodings) + { + for (auto &byte : *encoding) byte++; + encoding->push_back(0); + } } bool DataSet::isCompressionLvl2(const StringEntryList &list) const { - return (GLOBAL_ConfigOptions["CONFIG_COMPRESSION_LVL_2"] && list.type == ListType::STRINGS_BASIC); + return (GLOBAL_ConfigOptions["CONFIG_COMPRESSION_LVL_2"] && list.type == ListType::STRINGS_BASIC); } void DataSet::addStrings(const StringEntryList &stringList) { - // Import the new list of strings + // Import the new list of strings - stringEntryLists.push_back(stringList); - stringEncodedLists.emplace_back(); + stringEntryLists.push_back(stringList); + stringEncodedLists.emplace_back(); - // Clear strings not relevant for the current configuration - - while (1) - { - if (isRelevant(stringEntryLists.back().list.back())) break; + // 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 + 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(); + outFileContent.clear(); } void DataSet::process() { - std::cout << "Processing file '" << CMD_cnfFile << "', layout '" << layoutName() << "'" << std::endl; + std::cout << "Processing file '" << CMD_cnfFile << "', layout '" << layoutName() << "'" << std::endl; - generateConfigDepStrings(); - validateLists(); - encodeStringsDict(); - calculateFrequencies(); - encodeStringsFreq(); - prepareOutput(); + generateConfigDepStrings(); + validateLists(); + encodeStringsDict(); + calculateFrequencies(); + encodeStringsFreq(); + prepareOutput(); } const std::string &DataSet::getOutput() { - if (outFileContent.empty()) - { - process(); - } + if (outFileContent.empty()) + { + process(); + } - return outFileContent; + 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"; + // 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; + // Add strings to appropriate list + + for (auto &stringEntryList : stringEntryLists) + { + if (stringEntryList.name != std::string("misc")) continue; - // List found + // 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 }; + 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); + stringEntryList.list.push_back(newEntry1); + stringEntryList.list.push_back(newEntry2); + stringEntryList.list.push_back(newEntry3); - break; - } - } + break; + } + } } void DataSet::validateLists() { - for (const auto &stringEntryList : stringEntryLists) - { - for (const auto &stringEntry : stringEntryList.list) - { - // Check for maximum allowed string length - if (stringEntry.string.length() > 255) ERROR("string cannot be longer than 255 characters"); + for (const auto &stringEntryList : stringEntryLists) + { + for (const auto &stringEntry : stringEntryList.list) + { + // 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() > 16) ERROR("keyword cannot be longer than 16 characters"); - tk__max_keyword_len = std::max(tk__max_keyword_len, (uint8_t) stringEntry.string.length()); - } + // Check mor maximum keyword length + if (stringEntryList.type == ListType::KEYWORDS) + { + 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()); + } - // Update maximum alias length too - maxAliasLen = std::max(maxAliasLen, stringEntry.alias.length()); + // Update maximum alias length too + maxAliasLen = std::max(maxAliasLen, stringEntry.alias.length()); - for (const auto &character : stringEntry.string) - { - if ((unsigned char) character >= 0x80) - { - ERROR(std::string("character above 0x80 in string '") + stringEntry.string + "'"); - } - } - } - } + for (const auto &character : stringEntry.string) + { + if ((unsigned char) character >= 0x80) + { + ERROR(std::string("character above 0x80 in string '") + stringEntry.string + "'"); + } + } + } + } } void DataSet::encodeStringsDict() { - DictEncoder dictEncoder; + DictEncoder dictEncoder; - // Add strings for dictionary compresssion + // Add strings for dictionary compresssion - for (uint8_t idx = 0; idx < stringEntryLists.size(); idx++) - { - const auto &stringEntryList = stringEntryLists[idx]; - auto &stringEncodedList = stringEncodedLists[idx]; + 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; + // Skip lists not to be encoded using the dictionary + if (!isCompressionLvl2(stringEntryList)) continue; - stringEncodedList.resize(stringEntryList.list.size()); - for (uint8_t idxEntry = 0; idxEntry < stringEntryList.list.size(); idxEntry++) - { - dictEncoder.addString(stringEntryList.list[idxEntry].string, - &stringEncodedList[idxEntry]); - } - } + stringEncodedList.resize(stringEntryList.list.size()); + for (uint8_t idxEntry = 0; idxEntry < stringEntryList.list.size(); idxEntry++) + { + dictEncoder.addString(stringEntryList.list[idxEntry].string, + &stringEncodedList[idxEntry]); + } + } - // Perform the compression + // Perform the compression - StringEntryList dictionary; - dictEncoder.process(dictionary); + StringEntryList dictionary; + dictEncoder.process(dictionary); - // Add new lists + // Add new lists - stringEntryLists.push_back(dictionary); - stringEncodedLists.emplace_back(); + stringEntryLists.push_back(dictionary); + stringEncodedLists.emplace_back(); } void DataSet::calculateFrequencies() { - as1n.clear(); - as3n.clear(); - - std::map freqMapGeneral; // general character frequency map - std::map freqMapKeywords; // frequency map for keywords + 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 + // 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 &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 &stringEntry : stringEntryList.list) + { + if (!isRelevant(stringEntry)) continue; - for (const auto &character : 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]; }); + for (const auto &character : 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 + // 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"); + 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 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 + // Extract characters to be encoded as 3 nibbles, which actually exist in keywords - std::vector freqVector2; + 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); + 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]; }); + // 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 + // Finally extract the remaining characters to be encoded as 3 nibbles - for (const auto &character : freqVector2) - { - as3n.push_back(character); - } + for (const auto &character : freqVector2) + { + as3n.push_back(character); + } } void DataSet::encodeByFreq(const std::string &plain, StringEncoded &encoded) const { - bool fullByte = true; + 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 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); - } - }; + 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 + // 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); + 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); - } - } + 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 + // Make sure the last byte of encoded stream is 0 - if (encoded.size() == 0 || encoded.back() != 0) encoded.push_back(0); + if (encoded.size() == 0 || encoded.back() != 0) encoded.push_back(0); } void DataSet::encodeStringsFreq() { - // Encode every relevant string from every list - by character frequency + // Encode every relevant string from every list - by character frequency - for (uint8_t idx = 0; idx < stringEntryLists.size(); idx++) - { - const auto &stringEntryList = stringEntryLists[idx]; - auto &stringEncodedList = stringEncodedLists[idx]; + for (uint8_t idx = 0; idx < stringEntryLists.size(); idx++) + { + const auto &stringEntryList = stringEntryLists[idx]; + auto &stringEncodedList = stringEncodedLists[idx]; - // Skip lists encoded by the dictionary - if (isCompressionLvl2(stringEntryList)) continue; + // Skip lists encoded by the dictionary + if (isCompressionLvl2(stringEntryList)) continue; - // Perform frequency encoding of the list + // Perform frequency encoding of the list - for (const auto &stringEntry : stringEntryList.list) - { - stringEncodedList.emplace_back(); - auto &stringEncoded = stringEncodedList.back(); + for (const auto &stringEntry : stringEntryList.list) + { + stringEncodedList.emplace_back(); + auto &stringEncoded = stringEncodedList.back(); - if (isRelevant(stringEntry)) - { - encodeByFreq(stringEntry.string, stringEncoded); - } - } - } + 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; + 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; + 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 + "'"; - } + 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; + stream << petscii << std::endl; } void DataSet::prepareOutput_1n_3n(std::ostringstream &stream) { - uint8_t idx; + uint8_t idx; - // Export all nibble-encoded characters + // 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; + 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 + // Export all byte-encoded characters - stream << std::endl << ".macro put_packed_as_3n() // characters encoded as 3 nibbles" << std::endl << "{" << std::endl; + 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 << + 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); - } + putCharEncoding(stream, ++idx, encoding, true); + } - stream << "}" << std::endl; + stream << "}" << std::endl; } void DataSet::prepareOutput_labels(std::ostringstream &stream, - const StringEntryList &stringEntryList, - const StringEncodedList &stringEncodedList) + const StringEntryList &stringEntryList, + const StringEncodedList &stringEncodedList) { - // For the dictionary we do not have any labels - if (stringEntryList.type == ListType::DICTIONARY) return; + // For the dictionary we do not have any labels + if (stringEntryList.type == ListType::DICTIONARY) return; - stream << std::endl; - for (uint8_t idx = 0; idx < stringEncodedList.size(); idx++) - { - const auto &stringEntry = stringEntryList.list[idx]; - const auto &stringEncoded = stringEncodedList[idx]; + stream << std::endl; + for (uint8_t idx = 0; idx < stringEncodedList.size(); idx++) + { + 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) << +idx << std::endl; - } - } + if (!stringEncoded.empty()) + { + stream << ".label IDX__" << stringEntry.alias << + std::string(maxAliasLen - stringEntry.alias.length(), ' ') << " = $" << + std::uppercase << std::hex << std::setfill('0') << std::setw(2) << +idx << std::endl; + } + } } void DataSet::prepareOutput_packed(std::ostringstream &stream, - const StringEntryList &stringEntryList, - const StringEncodedList &stringEncodedList) + const StringEntryList &stringEntryList, + const StringEncodedList &stringEncodedList) { - if (isCompressionLvl2(stringEntryList)) - { - stream << std::endl << ".macro put_packed_dict_"; - } - else - { - stream << std::endl << ".macro put_packed_freq_"; - } + 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; + 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]; + 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 (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 (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; - // Output the label - as a comment + // Output the label - as a comment - if (stringEntryList.type != ListType::DICTIONARY) - { - stream << "\t// IDX__" << stringEntryList.list[idxString].alias << std::endl; - } + if (stringEntryList.type != ListType::DICTIONARY) + { + stream << "\t// IDX__" << stringEntryList.list[idxString].alias << std::endl; + } - // Output the source string - as a comment + // Output the source string - as a comment - 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// '"; + 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; - // Output the encoding + // Output the encoding - stream << "\t.byte "; + stream << "\t.byte "; - bool first = true; - for (const auto &charEncoded : stringEncoded) - { - if (first) - { - first = false; - } - else - { - stream << ", "; - } + 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::uppercase << std::hex << std::setfill('0') << std::setw(2) << +charEncoded; + } - stream << std::endl; - lastStr = LastStr::WRITTEN; - } - } + stream << std::endl; + lastStr = LastStr::WRITTEN; + } + } - // For the token list - put the 'end of keywords' mark + // 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; - } + 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; + stream << "}" << std::endl; } void DataSet::prepareOutput() { - // Convert our encoded strings to a KickAssembler source + // Convert our encoded strings to a KickAssembler source - std::ostringstream stream; - stream << std::endl << "#if ROM_LAYOUT_" << layoutName() << std::endl; + std::ostringstream stream; + stream << std::endl << "#if ROM_LAYOUT_" << layoutName() << std::endl; - // Export 1-nibble and 3-nibble encoding data + // Export 1-nibble and 3-nibble encoding data - prepareOutput_1n_3n(stream); + prepareOutput_1n_3n(stream); - // Export additional data for the tokenizer + // Export additional data for the tokenizer - stream << std::endl << ".label TK__PACKED_AS_3N = $" << std::hex << +tk__packed_as_3n << + 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 encoded strings + // Export encoded strings - for (uint8_t idx = 0; idx < stringEntryLists.size(); idx++) - { - const auto &stringEntryList = stringEntryLists[idx]; - const auto &stringEncodedList = stringEncodedLists[idx]; + for (uint8_t idx = 0; idx < stringEntryLists.size(); idx++) + { + const auto &stringEntryList = stringEntryLists[idx]; + const auto &stringEncodedList = stringEncodedLists[idx]; - if (stringEncodedList.empty()) continue; + if (stringEncodedList.empty()) continue; - // Export labels for the current list + // Export labels for the current list - prepareOutput_labels(stream, stringEntryList, stringEncodedList); + prepareOutput_labels(stream, stringEntryList, stringEncodedList); - // For the token list - put the number of tokens available + // 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; - } + if (stringEntryList.type == ListType::KEYWORDS) + { + stream << std::endl << ".label TK__MAXTOKEN_" << stringEntryList.name << " = " << + std::dec << stringEncodedList.size() << std::endl; + } - // Export the packed data + // Export the packed data - prepareOutput_packed(stream, stringEntryList, stringEncodedList); - } + prepareOutput_packed(stream, stringEntryList, stringEncodedList); + } - // Finalize the file stream + // Finalize the file stream - stream << std::endl << "#endif // ROM_LAYOUT_" << layoutName() << std::endl; - outFileContent = stream.str(); + stream << std::endl << "#endif // ROM_LAYOUT_" << layoutName() << std::endl; + outFileContent = stream.str(); } @@ -1668,52 +1670,52 @@ void DataSet::prepareOutput() void parseConfigFile() { - GLOBAL_ConfigOptions.clear(); - - // Open the configuration file - + 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 - + + // Parse the file + size_t lineNum = 0; - while (!cnfFile.eof()) - { - lineNum++; - std::string workStr; - - // Read a single line, remove leading spaces and tabs + while (!cnfFile.eof()) + { + lineNum++; + std::string workStr; + + // Read a single line, remove leading spaces and tabs - 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 - - 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)); - } + 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 + + 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]+.*"), ""); + // 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 + // Add definitin to config option map - if (workStr.empty()) ERROR(std::string("error parsing config file - line ") + std::to_string(lineNum)); + if (workStr.empty()) ERROR(std::string("error parsing config file - line ") + std::to_string(lineNum)); - GLOBAL_ConfigOptions[workStr] = true; - } - - cnfFile.close(); + GLOBAL_ConfigOptions[workStr] = true; + } + + cnfFile.close(); } void printUsage() @@ -1740,7 +1742,7 @@ void parseCommandLine(int argc, char **argv) switch(opt) { case 'o': CMD_outFile = optarg; break; - case 'c': CMD_cnfFile = optarg; break; + case 'c': CMD_cnfFile = optarg; break; default: printUsage(); ERROR(); } } @@ -1748,61 +1750,61 @@ void parseCommandLine(int argc, char **argv) void writeStrings() { - std::string outputString; - - if (GLOBAL_ConfigOptions["CONFIG_PLATFORM_COMMANDER_X16"]) - { - DataSetX16 dataSetX16; + std::string outputString; + + if (GLOBAL_ConfigOptions["CONFIG_PLATFORM_COMMANDER_X16"]) + { + DataSetX16 dataSetX16; - // 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); + // 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); - // Retrieve the results - - outputString = dataSetX16.getOutput(); - } - else if (GLOBAL_ConfigOptions["CONFIG_PLATFORM_COMMODORE_64"] && GLOBAL_ConfigOptions["CONFIG_MB_MEGA_65"]) - { - DataSetM65 dataSetM65; + // Retrieve the results + + outputString = dataSetX16.getOutput(); + } + else if (GLOBAL_ConfigOptions["CONFIG_PLATFORM_COMMODORE_64"] && GLOBAL_ConfigOptions["CONFIG_MB_MEGA_65"]) + { + DataSetM65 dataSetM65; - // Add input data to computation objects + // Add input data to computation objects - 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; + 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; - // Add input data to computation objects + // 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); + 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 + // Retrieve the results - outputString = dataSetSTD.getOutput(); - } - else - { - ERROR("unable to determine string set"); - } - + outputString = dataSetSTD.getOutput(); + } + else + { + ERROR("unable to determine string set"); + } + // Remove old file unlink(CMD_outFile.c_str()); @@ -1823,7 +1825,7 @@ void writeStrings() outFile << std::endl << std::endl; // Close the file - + outFile.close(); std::cout << std::string("Compressed strings written to: ") + CMD_outFile + "\n\n"; @@ -1838,7 +1840,7 @@ int main(int argc, char **argv) printBanner(); parseCommandLine(argc, argv); - parseConfigFile(); + parseConfigFile(); writeStrings(); From e8567cc0438e1d8cc58c7c1bed01e3918d9cb4bd Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 29 Jun 2020 17:26:20 +0200 Subject: [PATCH 17/24] fixed tape filename matching, broken long time ago --- src/kernal/tape/tape_common.s | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/kernal/tape/tape_common.s b/src/kernal/tape/tape_common.s index f254dc43..e46ce6b1 100644 --- a/src/kernal/tape/tape_common.s +++ b/src/kernal/tape/tape_common.s @@ -282,10 +282,20 @@ tape_match_loop: cmp #KEY_ASTERISK beq tape_return_ok + iny + iny + iny + iny + iny + cmp (TAPE1), y bne tape_return_not_ok - iny + dey + dey + dey + dey + cpy #$10 bne tape_match_loop From afc74bf1ec01081802dd1a1a096d7467c61880da Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 29 Jun 2020 19:59:18 +0200 Subject: [PATCH 18/24] packed string generator has now separate configuration for Ultimate 64 --- tools/generate_strings.cc | 343 ++++++++++++++++++++------------------ 1 file changed, 183 insertions(+), 160 deletions(-) diff --git a/tools/generate_strings.cc b/tools/generate_strings.cc index 69dd66f8..bfbd08e0 100644 --- a/tools/generate_strings.cc +++ b/tools/generate_strings.cc @@ -1,5 +1,5 @@ // -// Utility to generate compressed messages and BASIC tokens +// Utility to generate compressed messages and BASIC keywords // #include "common.h" @@ -22,13 +22,14 @@ std::string CMD_outFile = "out.s"; std::string CMD_cnfFile = ""; // -// Type definition for text/tokens to generate +// Type definition for strings/keywords to generate // typedef struct StringEntry { - bool enabledSTD; // whether enabled for basic build - bool enabledM65; // whether enabled for Mega65 build + bool enabledSTD; // whether enabled for standard build + bool enabledM65; // whether enabled for Mega 65 build + bool enabledU64; // whether enabled for Ultimate 64 build bool enabledX16; // whether enabled for Commander X16 build std::string alias; // alias, for the assembler std::string string; // string/token @@ -91,150 +92,150 @@ typedef std::vector StringEncodedList; 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 + // STD M65 U64 X16 + { true, true, true, true, "KV2_80", "END", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_81", "FOR", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_82", "NEXT", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_83", "DATA", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_84", "INPUT#", 2 }, // https://www.atariarchives.org/creativeatari/Using_Disks_With_Atari_Basic.php + { true, true, true, true, "KV2_85", "INPUT", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_86", "DIM", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_87", "READ", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_88", "LET", 2 }, // https://en.wikipedia.org/wiki/Atari_BASIC + { true, true, true, true, "KV2_89", "GOTO", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_8A", "RUN", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_8B", "IF", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_8C", "RESTORE", 3 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_8D", "GOSUB", 3 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_8E", "RETURN", 3 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_8F", "REM", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_90", "STOP", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_91", "ON", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_92", "WAIT", 2 }, // http://www.picaxe.com/BASIC-Commands/Time-Delays/wait/ + { true, true, true, true, "KV2_93", "LOAD", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_94", "SAVE", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_95", "VERIFY", 2 }, // https://en.wikipedia.org/wiki/Sinclair_BASIC + { true, true, true, true, "KV2_96", "DEF", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_97", "POKE", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_98", "PRINT#", 2 }, // https://www.atariarchives.org/creativeatari/Using_Disks_With_Atari_Basic.php + { true, true, true, true, "KV2_99", "PRINT", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_9A", "CONT", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_9B", "LIST", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_9C", "CLR", 2 }, // Apple I Replica Creation: Back to the Garage, p125 + { true, true, true, true, "KV2_9D", "CMD", 2 }, // https://en.wikipedia.org/wiki/List_of_DOS_commands + { true, true, true, true, "KV2_9E", "SYS", 2 }, // https://www.lifewire.com/dos-commands-4070427 + { true, true, true, true, "KV2_9F", "OPEN", 2 }, // https://www.atariarchives.org/creativeatari/Using_Disks_With_Atari_Basic.php + // STD M65 U64 X16 + { true, true, true, true, "KV2_A0", "CLOSE", 3 }, // https://www.atariarchives.org/creativeatari/Using_Disks_With_Atari_Basic.php + { true, true, true, true, "KV2_A1", "GET", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_A2", "NEW", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_A3", "TAB(", 2 }, // http://www.antonis.de/qbebooks/gwbasman/tab.html + { true, true, true, true, "KV2_A4", "TO", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_A5", "FN", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_A6", "SPC(", 2 }, // http://www.antonis.de/qbebooks/gwbasman/spc.html + { true, true, true, true, "KV2_A7", "THEN", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_A8", "NOT", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_A9", "STEP", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_AA", "+", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_AB", "-", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_AC", "*", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_AD", "/", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_AE", "^", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_AF", "AND", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_B0", "OR", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_B1", ">", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_B2", "=", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_B3", "<", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_B4", "SGN", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_B5", "INT", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_B6", "ABS", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_B7", "USR", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_B8", "FRE", 2 }, // http://www.antonis.de/qbebooks/gwbasman/fre.html + { true, true, true, true, "KV2_B9", "POS", 0 }, // http://www.antonis.de/qbebooks/gwbasman/pos.html + { true, true, true, true, "KV2_BA", "SQR", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_BB", "RND", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_BC", "LOG", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_BD", "EXP", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_BE", "COS", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_BF", "SIN", 2 }, // https://www.landsnail.com/a2ref.htm + // STD M65 U64 X16 + { true, true, true, true, "KV2_C0", "TAN", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_C1", "ATN", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_C2", "PEEK", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_C3", "LEN", 0 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_C4", "STR$", 3 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_C5", "VAL", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_C6", "ASC", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_C7", "CHR$", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_C8", "LEFT$", 3 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_C9", "RIGHT$", 2 }, // https://www.landsnail.com/a2ref.htm + { true, true, true, true, "KV2_CA", "MID$", 2 }, // https://www.landsnail.com/a2ref.htm + { true, 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 - { 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", }, - { true, true, true, "KCC_05", "OLD", }, // OpenROMs specific, not present in CBM BASIC dialects + // STD M65 U64 X16 + { true, true, true, true, "KCC_01", "MERGE", }, // OpenROMs specific, not present in CBM BASIC dialects + { true, true, true, true, "KCC_02", "BLOAD", }, // http://www.antonis.de/qbebooks/gwbasman/bload.html + { true, true, true, true, "KCC_03", "BSAVE", }, // http://www.antonis.de/qbebooks/gwbasman/bsave.html + { true, true, true, true, "KCC_04", "BVERIFY", }, + { true, true, true, true, "KCC_05", "OLD", }, // OpenROMs specific, not present in CBM BASIC dialects } }; // 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 - { 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 + // STD M65 U64 X16 + { true, true, true, true, "KCD_01", "SLOW", }, // https://en.wikipedia.org/wiki/Sinclair_BASIC - ZX81 variant + { true, true, true, true, "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", }, + // STD M65 U64 X16 + { false, false, false, false, "KCE_01", "TESTCMD", }, } }; const StringEntryList GLOBAL_Keywords_CF = { ListType::KEYWORDS, "keywords_CF", { - // STD M65 X16 - { false, false, false, "KCF_01", "TESTCMD", }, + // STD M65 U64 X16 + { false, 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", }, + // STD M65 U64 X16 + { false, 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", }, + // STD M65 U64 X16 + { false, 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", }, + // STD M65 U64 X16 + { false, false, false, false, "KD2_01", "TESTFUN", }, } }; const StringEntryList GLOBAL_Keywords_D3 = { ListType::KEYWORDS, "keywords_D3", { - // STD M65 X16 - { false, false, false, "KD3_01", "TESTFUN", }, + // STD M65 U64 X16 + { false, false, false, false, "KD3_01", "TESTFUN", }, } }; @@ -252,65 +253,65 @@ const StringEntryList GLOBAL_Keywords_D3 = { ListType::KEYWORDS, "keywords_D3", 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 - { 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 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" }, + // STD M65 U64 X16 --- error strings compatible with CBM BASIC V2 + { true, true, true, true, "EV2_01", "TOO MANY FILES" }, + { true, true, true, true, "EV2_02", "FILE OPEN" }, + { true, true, true, true, "EV2_03", "FILE NOT OPEN" }, + { true, true, true, true, "EV2_04", "FILE NOT FOUND" }, + { true, true, true, true, "EV2_05", "DEVICE NOT PRESENT" }, + { true, true, true, true, "EV2_06", "NOT INPUT FILE" }, + { true, true, true, true, "EV2_07", "NOT OUTPUT FILE" }, + { true, true, true, true, "EV2_08", "MISSING FILENAME" }, + { true, true, true, true, "EV2_09", "ILLEGAL DEVICE NUMBER" }, + { true, true, true, true, "EV2_0A", "NEXT WITHOUT FOR" }, + { true, true, true, true, "EV2_0B", "SYNTAX" }, + { true, true, true, true, "EV2_0C", "RETURN WITHOUT GOSUB" }, + { true, true, true, true, "EV2_0D", "OUT OF DATA" }, + { true, true, true, true, "EV2_0E", "ILLEGAL QUANTITY" }, + { true, true, true, true, "EV2_0F", "OVERFLOW" }, + { true, true, true, true, "EV2_10", "OUT OF MEMORY" }, + { true, true, true, true, "EV2_11", "UNDEF\'D STATEMENT" }, + { true, true, true, true, "EV2_12", "BAD SUBSCRIPT" }, + { true, true, true, true, "EV2_13", "REDIM\'D ARRAY" }, + { true, true, true, true, "EV2_14", "DIVISION BY ZERO" }, + { true, true, true, true, "EV2_15", "ILLEGAL DIRECT" }, + { true, true, true, true, "EV2_16", "TYPE MISMATCH" }, + { true, true, true, true, "EV2_17", "STRING TOO LONG" }, + { true, true, true, true, "EV2_18", "FILE DATA" }, + { true, true, true, true, "EV2_19", "FORMULA TOO COMPLEX" }, + { true, true, true, true, "EV2_1A", "CAN\'T CONTINUE" }, + { true, true, true, true, "EV2_1B", "UNDEF\'D FUNCTION" }, + { true, true, true, true, "EV2_1C", "VERIFY" }, + { true, true, true, true, "EV2_1D", "LOAD" }, + { true, true, true, true, "EV2_1E", "BREAK" }, + // STD M65 U64 X16 --- error strings compatible with CBM BASIC V7 + { false, false, false, false, "EV7_1F", "CAN'T RESUME" }, // not used for now + { false, false, false, false, "EV7_20", "LOOP NOT FOUND" }, // not used for now + { false, false, false, false, "EV7_21", "LOOP WITHOUT DO" }, // not used for now + { true, true, true, true, "EV7_22", "DIRECT MODE ONLY" }, + { false, false, false, false, "EV7_23", "NO GRAPHICS AREA" }, // not used for now + { false, false, false, false, "EV7_24", "BAD DISK" }, // not used for now + { false, false, false, false, "EV7_25", "BEND NOT FOUND" }, // not used for now + { false, false, false, false, "EV7_26", "LINE NUMBER TOO LARGE" }, // not used for now + { false, false, false, false, "EV7_27", "UNRESOLVED REFERENCE" }, // not used for now + { true, true, true, true, "EV7_28", "NOT IMPLEMENTED" }, // this message actually differs from the CBM one + { false, false, false, false, "EV7_29", "FILE READ" }, // not used for now + // STD M65 U64 X16 --- error strings specific to OpenROMs, not present in CBM BASIC dialects + { true, 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_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 - { 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", "\rBRK AT $" }, + // STD M65 U64 X16 --- misc strings as on CBM machines + { true, true, true, true, "STR_RET_QM", "\r?" }, + { true, true, true, true, "STR_BYTES", " BASIC BYTES FREE" }, // https://github.com/stefanhaustein/expressionparser + { true, 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, 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, true, "STR_IN", " IN " }, + // STD M65 U64 X16 --- misc strings specific to OpenROMs, not present in CBM ROMs + { true, true, true, true, "STR_BRK_AT", "\rBRK AT $" }, // Note: depending on configuration, additional strings will be added here } }; @@ -536,6 +537,12 @@ class DataSetM65 : public DataSet std::string layoutName() const { return "M65"; } }; +class DataSetU64 : public DataSet +{ + bool isRelevant(const StringEntry &entry) const { return entry.enabledU64; } + std::string layoutName() const { return "STD"; } // XXX to be changed for 'U64' once the layout is finished +}; + class DataSetX16 : public DataSet { bool isRelevant(const StringEntry &entry) const { return entry.enabledX16; } @@ -1190,9 +1197,9 @@ void DataSet::generateConfigDepStrings() 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 }; + StringEntry newEntry1 = { true, true, true, true, "STR_PAL", "PAL\r" }; + StringEntry newEntry2 = { true, true, true, true, "STR_NTSC", "NTSC\r" }; + StringEntry newEntry3 = { true, true, true, true, "STR_FEATURES", featureStr }; stringEntryList.list.push_back(newEntry1); stringEntryList.list.push_back(newEntry2); @@ -1784,6 +1791,22 @@ void writeStrings() outputString = dataSetM65.getOutput(); } + else if (GLOBAL_ConfigOptions["CONFIG_PLATFORM_COMMODORE_64"] && GLOBAL_ConfigOptions["CONFIG_MB_ULTIMATE_64"]) + { + DataSetU64 dataSetU64; + + // Add input data to computation objects + + dataSetU64.addStrings(GLOBAL_Keywords_V2); + dataSetU64.addStrings(GLOBAL_Keywords_CC); + dataSetU64.addStrings(GLOBAL_Keywords_CD); + dataSetU64.addStrings(GLOBAL_Errors); + dataSetU64.addStrings(GLOBAL_MiscStrings); + + // Retrieve the results + + outputString = dataSetU64.getOutput(); + } else if (GLOBAL_ConfigOptions["CONFIG_PLATFORM_COMMODORE_64"]) { DataSetSTD dataSetSTD; From 3bcbfc8a34ef47bbb53d316dbe134a98029b0658 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 29 Jun 2020 20:00:40 +0200 Subject: [PATCH 19/24] 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 6291a248bc5580455ba872e913ffe59a6e38276e..908d3719a23f9e64c95b545277b51ba872314d93 100644 GIT binary patch delta 3393 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 delta 3097 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 EUzhv1TL1t6 delta 4126 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 delta 3232 zcmY*b3s6&68otRTgoH;T4++TQfIRDq+EVFbEUu#1If|vWYp2uo@|+;B({{Hzj(vbD z*Rt#~g&sSAS{ow=4KrfUc5SFAYE{CP;bL3G=aQBL%>yq;6?~BWZ?H362G05abN}<7 z?|)OBU7cNJME;d26)EK@TT;?f(o#}WQnF~ey@XGuY4&11iKg0%`1v%&Uf2-MC(>j- zohI>VbUvR-6ZsTJWuMT)aVD8@g<%|bd)p$1;~Q8UXTusBr#}}gvN*v;gELs*^?bRW z-=gQs#5h_YXlNNN3^0qd{t9 z(Pc_suzJNHqo0p#dmddlYMj}P_Z*=G=gPzl<~&-KWiPO%nKP{c4Y9O9R~7)+O89qZ zF<(N9_+nbf7nvBoP`u>f zmPzW$Xa!#hmR5kt<#1t(c+F9!E8S9BURqIF=~Hw^QUqUlNwR=1;~0h^;qrV%lLi0b zBq^7pbTt12x^NKOw8VzWPQkv=hCVx1m)o2Ro1Tx*^Wmm&eB%^DzLLLK6>obG5yHf; z`iFvv|7t1>$jPvdW$}#HyJM~9s*$Ui&nFuEIurSlT3Cvur3e;PHDB17sAWywg#f5j zIxeUITRAj&D(iN8Lx@#vR$G-~pj9PC={RKiB}@8bJt``JHYo*{NiB?`$pq;r(Ap^m zO2;bUCsUv>XbKYg!7hg3Q0GDNDXWXxI6}8&-Inp&=m)nM{sRtQJAw1t+8Bt9d}3!$yQ`V*z78iZ$%e8W-Ti4;_VX>L+TYTDHbv}HasMM)ufP?xV7@9 z9b_afF*aN>?I=1kg+`p{n6&n3uWd4V4>LEk0e!+$28;K5aMQ6X%2=6>ch?G2 z2F7xgX}QAm_UMFPP1XE3>LMYkKL-}N(BEB1??F3f$S11IKw#Qt%-%-6U@ZKb5%Mqd$b6xr_ZCgW_F)x*dwQUb5N8fLn+u7^!x+ zrRYFl$i?7IviHe?kTpTYV*u9VUylTIf_xmZMzPY!h+-}@Q zw*76%@&w(Z7cQVYkwynIV+!F|DF79{M>{jJ!1Dkg-WP*K_%cO z54>bflPcY3(byQ-AG%Ea#0)1Q*Z0$$#nR#IIVQt&A5VP*I|rC^>~FO zgYt^jC8(NpAL+>Yh?MZx+@fEtc8asS<>r62Y>7;A+<&s%vXP?~9O#{p7>B&%*fboEux!GA0J~X{S)%IC^#lzk09RJl5X5 zZ%o_|C%1%OX`|N9 zrJvsRdFYw8m`Xc2igvJi6h$H+uj@535EqIEC(e>7&!Mn}kIT}@tEf}gh-qJ|Ec~tYNOWXs#9EO9Hc{F`A{89hSkvtPffe= z`1sZa`S}CBB)m0+pk!!kx~9GRFFr!dZQCW`X(Nr%nGsE%dgcZsDcyySKWG~g74UDx zDsn9v`P*DIKR^Iw^Kez51AlTG?R|*ar_B=vrt_#(0WN*rYn6!sP;di~v=$WTkQ((_ z)F~Pmw0^2V5`b0>i2yr%Y@hZWLAR#I`0waZ{wznoyLpGBLy$X;(2n$YK~tBDhCRr04?L3bNZ+2+ zu;DU#PkIlaG&{&ZOcbQr?U<#qK@t;tRaQ^#$G!n4>*E#%LF>zS2-9g39j3U_JosA|o^ax6awDxil^9$g)9!fgDp<1wi~V+ P8SeAsXWTzOiWL6`G2{h? diff --git a/bin/mega65.rom b/bin/mega65.rom index d6ac550404c1714eb69965cc047cd6b84d9de6b5..09a7addcfaaef96685981678320b3b1a3a45df98 100644 GIT binary patch delta 3622 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 M+TEgdv&AF-1CvsFxc~qF diff --git a/bin/mega65_pxlfont.rom b/bin/mega65_pxlfont.rom index d04867f434592ed481816fe9e30b08c5ec34fcca..d5b3b234751115c653be476da2efe31443b90de0 100644 GIT binary patch delta 3622 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 M+TEgdv&AF-1CvsFxc~qF From 4bae8ae8783ee11033ff608cc0ab74e00c2f766b Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 29 Jun 2020 22:28:05 +0200 Subject: [PATCH 20/24] started BASIC editor size optimization --- src/basic/basic_shift_mem_down.s | 179 ++++++---------------------- src/basic/editor/calculate_vartab.s | 2 +- src/basic/editor/delete_line.s | 2 +- src/basic/editor/shell.s | 4 +- 4 files changed, 42 insertions(+), 145 deletions(-) diff --git a/src/basic/basic_shift_mem_down.s b/src/basic/basic_shift_mem_down.s index 7def6575..791446f2 100644 --- a/src/basic/basic_shift_mem_down.s +++ b/src/basic/basic_shift_mem_down.s @@ -3,27 +3,33 @@ // #LAYOUT# * * #IGNORE +// +// Shift the BASIC program down to cover the area of removed line +// + + basic_shift_mem_down_and_relink: - // Shift memory down to basic_current_line_pointer - // from X bytes further along. // Destination is OLDTXT + lda OLDTXT+0 sta memmove__dst+0 lda OLDTXT+1 sta memmove__dst+1 - - // Source is that plus X - txa - pha // also keep for later + + // Source is OLDTXT + .X + clc + txa + adc OLDTXT+0 sta memmove__src+0 lda OLDTXT+1 - adc #0 + adc #$00 sta memmove__src+1 - // Size is distance from source to end of BASIC text. + // Size is distance from source (OLDTXT) to the end of BASIC text (VARTAB) + lda VARTAB+0 sec sbc memmove__src+0 @@ -32,148 +38,39 @@ basic_shift_mem_down_and_relink: sbc memmove__src+1 sta memmove__size+1 - // jsr printf - // .text "TOP OF BASIC = $" - // .byte $f1,VARTAB - // .byte $f0,VARTAB - // .byte $0d - // .text "SHIFTING DOWN $" - // .byte $f1,memmove__size - // .byte $f0,memmove__size - // .text " BYTES FROM $" - // .byte $f1,memmove__src - // .byte $f0,memmove__src - // .text " TO $" - // .byte $f1,memmove__dst - // .byte $f0,memmove__dst - // .byte $0d,0 - - // The copy routine that copies under the ROMs is as simple - // as possible to be as small as possible, so we have - // to adjust the pointers and counts so that the simple - // increment and decrement bounds checks work. + // The copy routine is simplified, so that it is fast and (for memory model 60K) + // can fit in a small RAM area - therefore it requires to pre-set .Y, so that + // the copy ends when it reaches 0; so if copying one byte we want .Y = $FF - // Specifically we want Y pre-set so that the end of the - // copy ends when Y = $00. - // So if copying 1 byte, we want Y=$FF - // This means we have to then reduce the source and - // target pointers by the same amount - - lda memmove__size+0 - eor #$ff - sta __tokenise_work3 - sta memmove__size+0 - - lda memmove__src+0 sec + lda #$00 + sbc memmove__size+0 + tay + sty __tokenise_work3 + + // Now we have to move down the memmove_src and memmove_dst pointers + // to compensate for .Y not being 0 + + sec + lda memmove__src+0 sbc __tokenise_work3 sta memmove__src+0 - lda memmove__src+1 - sbc #0 - sta memmove__src+1 - - lda memmove__dst+0 + bcs !+ + dec memmove__src+1 +!: sec + lda memmove__dst+0 sbc __tokenise_work3 sta memmove__dst+0 - lda memmove__dst+1 - sbc #0 - sta memmove__dst+1 + bcs !+ + dec memmove__dst+1 +!: + // Perform the copy XXX add more documentation inside the copy routine! - // Increase copy page count so we can post-decrement compare with $00 inc memmove__size+1 - - // jsr printf - // .text "REVISED BOUNDS $" - // .byte $f1,memmove__size - // .byte $f0,memmove__size - // .text " BYTES FROM $" - // .byte $f1,memmove__src - // .byte $f0,memmove__src - // .text " TO $" - // .byte $f1,memmove__dst - // .byte $f0,memmove__dst - // .byte $0d,0 - - // Get Y value ready for the copy - ldy memmove__size+0 - jsr shift_mem_down - // Get length of deletion back - pla - sta __tokenise_work3 + // Now fix program linkage and calculate VARTAB - // Check if we still have any lines left - ldy #0 - jsr peek_line_pointer_null_check - bcs relink_down_next_line - // Nope, so just return - clc - rts - - -relink_down_next_line: - - // XXX reuse code from cmd_old - - // Subtract __tokenise_work3 from the pointer - ldy #0 - -#if CONFIG_MEMORY_MODEL_60K - ldx # Date: Wed, 1 Jul 2020 03:39:37 +0200 Subject: [PATCH 21/24] BASIC editor rework finished --- 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 src/aliases/,aliases_ram_lowmem.s | 18 +- src/basic/basic_commands_CC/cmd_merge.s | 14 +- src/basic/basic_commands_CC/cmd_old.s | 3 +- src/basic/basic_shift_mem_down.s | 76 ------- src/basic/basic_shift_mem_up.s | 211 ------------------ src/basic/editor/delete_line.s | 20 +- src/basic/editor/insert_line.s | 63 +++--- src/basic/editor/shell.s | 2 +- src/basic/editor/shift_txt_down.s | 43 ++++ src/basic/editor/shift_txt_up.s | 58 +++++ ...culate_vartab.s => update_vartab_do_clr.s} | 2 +- src/basic/memory/shift_mem_adapt_pointers.s | 36 +++ src/basic/memory/shift_mem_down.s | 59 +++++ src/basic/memory/shift_mem_down_38k.s | 28 --- src/basic/memory/shift_mem_up.s | 56 +++++ src/basic/memory/shift_mem_up_38k.s | 28 --- src/basic/memory/under_rom_routines_46k_50k.s | 11 +- 23 files changed, 302 insertions(+), 426 deletions(-) delete mode 100644 src/basic/basic_shift_mem_down.s delete mode 100644 src/basic/basic_shift_mem_up.s create mode 100644 src/basic/editor/shift_txt_down.s create mode 100644 src/basic/editor/shift_txt_up.s rename src/basic/editor/{calculate_vartab.s => update_vartab_do_clr.s} (96%) create mode 100644 src/basic/memory/shift_mem_adapt_pointers.s create mode 100644 src/basic/memory/shift_mem_down.s delete mode 100644 src/basic/memory/shift_mem_down_38k.s create mode 100644 src/basic/memory/shift_mem_up.s delete mode 100644 src/basic/memory/shift_mem_up_38k.s diff --git a/bin/basic_generic.rom b/bin/basic_generic.rom index 908d3719a23f9e64c95b545277b51ba872314d93..2d4664acf070770c7ba595b720694e21c4f93e36 100644 GIT binary patch delta 2949 zcma)8eQ*=U6+h`LTb4g0j4?8pu$b6jY#b9BteBdw;8e70a1*`~NI2P+V%dh0&U894 zX=SFY@c>S&+++sYKyNf&nX_W&jGJJ|lFhV)`e9OVnbW$Gbzc zgN)GwBpTqLU0iN2$`kO~kjx=t6umrwE=AFmQE?)pprks4ruy-rJ|SR4xBKNz)SHAk ze@rT0syTXYyrGxJ4IxoVt2VAz#H(qg#>-LBV4A)9$|!p0tdfrQMWLh_@0xWU4fo?$ z`cNp2H;f~9R5HN!R8BJpQd&yV(ydZX;E};8VU za>RMu2}KK;(?as)d|Wq8%N;ijq=Q!6 zv19&Hah7$h@lsHH%DQ;hr68Aj@Yd_p?3l^0drbrA=rzf3++RCM^Vx5XzcyhGX2dvS zB4g5D%j~D=XeGs0Mg@7RbXqHr&q>3YO}0wYnnm6y#kDlKPYQ{n>1D>1r^V^?5`OM! zVPw6n+2BXn;`z+NY=4Bh(5VRZ!cV-JS+v?8vD5wNg#q;9Sg$crO5G30%@4>;56F%8 zWO1FPgdOJv%l0g)n1*$0zy$CR%K-puL!z^=QhX?@&^Mr4FWS~5{@>>oO*qRsNutGK zx>e>IptqoM>xdKZcDui20L}CVc#vp~n$)ucX(=)II68kO@YT-&p?@%OqJ{g|`T<9J zxZjrk%fgMcXFm$ZeW7jGCsrv_PglJ7>k>UGSx)TPQ}s=0Rob=kdU;-YS{pEeUWZ6eLIku<@)M*YtTm)+CoY4S9C z+@Aexy7pH9J%N7GyoazUUg8p{YsRZ0`f`U!xTX;VIy6{D+nAX^zB8_QM~e6DlU&&zqKO&%%H)b?~?n-V{(YBLbt=c zNVY;{`d;Nb@zXSFvf)!ZF>@LY}mAZ%TrHp-dZQF%GxHn9#X`~yrS&-k&{M4_eI-3 zTCgtadG>Pm$Vu*gL%~Qldo1UCy&nYln8Bc0db7Xc433+YlLiA`Ag-MKyp8dUfV$s; z?E{Hjj*gt1eV2b|ZHVp#1hoT#+DH?)zLD-D9tM#B*R@~#)!dD90a~xtHIY~9nn_Qc zn;ffik)wD#E`C~6b5QThGU8Q?7g`;(4a7DO+Y|c)T25+d1zAID$#S}e zRHA3&wAQpnyJM%zy+*PexT+FAJc=&`;b4l5rM3tBYZm}Q<+7PnIM9h?yi@08twQc3 z4nT1=vW_}v^-TG|3hJ1tV9a4)$puzwgO%FtN8D{JB)kB4y4*421;kg*w32$fvZ;&!MWm}Wy3sB;1o3^#6Z3J&b%DiD zDOp06k}|SPu)9l1DI8;oxT|P^@0(1>15&8JipK+EXvc>rvkzYY&epBy*fcsk#Qw*o z!Po+hjUPhbSy1YcBJy2q9fOm>WM+G2_oqYD3&p!Kvpw<15-EkTOH$NNOMz5KDHwYR zT>^fogi)o$g$gE+KY}(z{u>%#=iuD^puI+K2^WUg9u>3-lZw3P$2)#TYOP7^UD5 zh5&n5)ui@0ghoDXB6IA5z!E?e+v{q*g5`r#gEYrxleqIP-GY`~18$ha*)cZCqE_f} z7-rJ0fYI0m=zcz8BzN`4F>Mx*8b7K1UCxHvh1pEzXgt7L++tpoxnVr{=Bme5ah&+m z1r7D*&ww4a``xc>?3)NqL>aPL(ERa0#@mgr@3?5Y3o^VCAK>h7H~whH>y0wsWj!sP%d#J7Qs92|jWi3W+-u#*KXkAp|+0r$duD-PChHlMOvp H8o2h~J$WCE delta 3126 zcmZWre{dAl9pBr_{U9N^gCueU36CIwNOFQ!2*FDOuRY5oqGN51vO50 zcK7}Ge&6?f-}`>PKlat_tBcOcDWgr~6=ySf+1Wx4J3Zu((@hTIcT+TK7*s7m0}6_K zGPk_ZlI8>kEuL^C;YVt{#KEEZl%Ru=%qV)iKSX<0>T!4!8MtGf}aNVo~`onP4h@PE-mYU9(RXx(3 z!Y_xAGmZ})pRt>c6LPZqs>Y=9r6#S>uxM^j44MW+R%L@m927aUCB^SE%rDxKl800i zk|rgS@~M=oe5?@$40Y`G6#toFo_QdGSBYpK!WS49+rNpR?J4{jF(e$9Q(`Zalq zT5dEK`XB@q?41@3sL1ZX^n7P zu}T+(xRNVffPaqksL;>r%oXe>B424<>i?6-F+Y5`12#_;X`^-@L)vMZCbW&VgV1(b zr44-44ue)0Ty~JX)PA{^JV|}km-hmtHA`vJ2DjE+c`~#&*_DUxnGhK2=y4=zZI2^s zK+5zCd&Fj3_3FcY?Wz&8SJ?9be}S3utU`+l`o{(q)0N8VnvSt zIy)CGE}k=L{!R1U5>>* z6qQgSgHCG)=##WnH~R({R$i$*KA_W@hjCDX9cVEqRFS4dve{~g>ajgdVw!emKY=rT zFCb_^XQxF8%;{}v5gN|iqgVjt-;8eJDep^GoEJky~iHmVpA`*9T@_DsDzMw9Z z|ETD3V+gDX?w1W1m1)@s5-Zc;gb|o^z&wMbzeU<4x)SxGivw7I00=T`$vRp??n666 zyi#fh%gc2@C{D{i%{CzKWGJs*S0FL2Z}Fo!e1Cq~&dN0StdL(R6yOaJ^yYxJU4>c& zOJE+}V5TeoYL{E==xP!>yP7p}8EDU_rYmmca|kmKM6~PJfPO`zjy|vJl0C+k6_n?f zrcdFR>y!gNn0ct+Ck}}rUi3*MXnLpVwO!||H=z%&pbs*(cba~_>$Rq<-PSLu*YgDN zQm?|=IP^{AikrHvpX23eenIJSexs>Yv&M_2CAXa()FK53FX*AizaQbU!R?^sN2}cL z4(N31W74DKUa6m~MxUMvAn76u;?slsr3>E=9H=M8tCj~(?liaPN&@>dq0=Wv4{gHr z+Zxt4Zr`zWr;|T#-0BB-3wnqUu5S2+y(l?^-UGms@mrx+(Q$H_l1IlIGGtsT!@nI8 z$CX`jMtxBB2O8z`O0kwGWG3u7;yRZyL_Mfa#D|9D3qK^VQH&xQLE}46;SZ;9vsMZ39%xkT3bM8Yt9$mrlgC(H_c`moy!bl*_qn#&zLUp*FFR4f zTMJ8di}||>pP0>|?h^qGo`C(6#|m%iOD$>5`11fbG=HT=p>8q^*>jXOlemq4dtN=? zQ!>ww7RR$V2F#a%PQcayES)3{Nl=5nYSQMfDqnOBON`2rVUjE8f+ifx2xHP5yk`V0 zoua$pR(Ipp5p+EcpvTXo8AhA-sq3i*f!8O{Gikcp`J`2k=bW(7y&ezo&~{G?Y2jbC zSv26hWn1VMV<~f#4VtygT{Iyh#i(VsGb5mcQLa$|cGVoZL}`n`V{n765acX!M)?mM zst68MY~%3hLF#bPS{F4}UpCo%23Hs@==Exusw$hQ?A~lGAh5JZOCZHPjw@!-1i|f! zDVY!11k$*oo;BMzj#qQ-n;N${x1#NhTXvxPom-vT8#ba14>jO==JvUv=_miqTfO|! z=}!Jz+4fZfv)zfE>vuR2!|?I>PgfZXMx&Y4(b(`P|Auju0WX~bHQMLb!NnXk>bl`OWYGOHN5?VLty+-(1bQi={rxB4 z>NVHc51TnVM&_$pgALHmLR(&fs_O9vTQV_<<*znq#V-Z zGP(?`1We_`jcyx5H-^!jABE{&&0wU3wvlE?w@q--0Jx}CL(hzqW8+Iq%d7DlaZXbQ zd@{HYy&=*X@Uz*$94N17jkp$kQv-=3j+-OEC2S5hpw3bJSd9PMf+bJ9J^^#lhY#*} zq<3m;Dy30gib%TPdf{_OBN&Dt7=Ve?n^>BJi!jpN3M=Wf4LOJq0u$VY$48+eA{`P- zI-zxtS}8+nI3V-AB@35)n1C!F(Br$(-zIu#g;*7`qrXlU2XJTn?{2?)*#kEVm=`}{ zGMPo`uZjzpMfJZnFpJ*4Q3&1Zg^@Ljm<9t7Io@Kc+4laL>a{iN?sL?R#eZzBTmOu- zVdKZYn5uVfD!9M7#Z}R;`GLpqiWOV7j@|-JC>#z!e+<6fcrQ#&hC&meKIn{u(&&_;5EyVcjyj-TswM3QTsDsb>Zn@ZtqRMRt*~05!rBX-meZ76AdW)gCB1gND^SQ diff --git a/bin/basic_ultimate64.rom b/bin/basic_ultimate64.rom index f0967126e27ca95fccc47d157d85335fc3386549..1d45b875eb779a128fe167e9cd828d661a89e4e7 100644 GIT binary patch delta 2844 zcma)8eQ*=U72nfYmMnirHkK{(r8Qt18{?WX1O?X)1k8wJDHPK5D-0*Fjb%OtGM#A( zNewez;t-tRTt6TrovX$x>11PM$kev1!^|{LD-G#2ZHK1GFv7Of;10=AAS95YzLRN7 z+kbi^?Y-T7xBK?J-}}8ixboo2a8AbD(sB0~E*+;0t+ZairBS>-9z$ALY@WswOHdR` zDy;&!9*_|>L~-u`ZuE;$Q%PAOfUg8dM~~n$V7nq8#K%%Tgnyd~-;3pHdGU?Mcyd1= zN*T+mp6!ioReAFEDBgYb6f(qWkFAb98h(tKs98qT1pocAfgZq0NaTz&>MjrAUk-*d z@t!EWndyRA{2Ep_&kG-SvBLCu^8vLgej3xs5n&&4#v;-wIu>XT=OwAwIukmB* z-{c%xD4VHW<#ppM=F;|)r&E28EPDhw@61Fu3Wx3#-6(Xb=ax+6A!p!~+cxLDVstem zqkXeMqwsFdp*c51ec5wyMy@oQS!vN(6wI$6T1%R?Xv$oP1Nt`>$@^y8YRm&%e0)^yYit`||I%<@>4cKfe!ghDZ3{H)Tl1 zOq1E1m6c@~i9UEHC!<5rXaxF`Y*JB_UL`uNFc3zRU{Fy6=F#S{y|$UjX0<5Uq!uK% zt9i+7szp9Xw(i*~6#m9rhR>V?TjxQrE`X9w(XMFcx z2e6-Y*>-c?*eJf8RgzN^VIEu;VP0s&Ygx1FY9bD{7w-t+eIv&V$#T~Gklgf;y!|10 z+q5jMw7f7E-&9zWvDxSWCz*oG8cV5n*fv_owo|)95ZBFIEzZp@Sqo?l*XmhXr&VKl z0{{FJ%eC1g^tMN{;Hq)_erk+t=+(6>v1(0MGpd*I`6FkT%xtgh zi!D%jQr`zjX^X80=ZpdJt7BMONTgmI>cdJ3pV!mG*QbAVvp1c;>XuU+q_O%mc>^>; z%sy>zVa#kZhIx_`q!I8H>BKkzW1;GK>*xU#9?@ z_)uqU7DO9P^09ggHj$A(A_+K>0+Ymrxm)uS0VxHhs`rlj_xBtiN~$|Qku4+lKNDG$ zbIY(L2pE%ctED{hct3bacUh&j81fv(b@+Xf>$C&>z=hze$MJ^~;rd{!`-8T)I4`ff z;mg2qXWTvfL-@DF-Q*Xi0M1XcC)IabbvlHf{#9|>`?WfGFb^GsXpKO$q7bdac@;~f z?BVamPawY2c1Ow>Zi%1Z5r{JBvhlL1E1#ExT?ITW8>Rzz-Xs~E5Kmg)!~!ru&u%^Y zmyQd%(bZZOgyc3D>Jl7+AWoR)@BB_U<_}v!%CmmA@`T?l#NO5NVwZrnf1~mwTLF90 zJPsX8FqR1}wgf}UWyP($uej5TqUkCA!PLlvTN$2k3;q=!!$e09dz99(74&O3t4G|I zRWsw{>DWq`xEV-u`ON^VcXoO9Os+e>)N$+}(#Z>0HkU;zKi71wg;NcRO1{r9OA$Q< z#f7B`IeI1pJaq)pE>6NLaD^fsEhyzbkw(RE!N*20SP7kdbH*3^-0K0hn>Mpuw2AGc z+gTgk#`e$_=A|AVI=okWt9VT@IQrGb?evw#Cfe25Opi8t=*#3>Ty&SLa7m+bKG`vZ z%O+XNx)g08Z9}+j2+&Wi^dqDXd$m=}1E)DYh_Cdsmc~6cNVu!wA;*rItR7ZxY*0US zu*F^jT?~0#Llz8?^8>i^bl9es$A(pc33^#$r|V` z$C2ip)XR2x5p83OT?sGU&1w>DbPrkYe~;rdXCBYh7`Sk0pOLH1;A(B1M~&QYCRb@a zk;%Q6!3i<~;S&%*K}NcYr4vR#iyRsTq0=(m(^bT1$+Jb^`Epu87t%^vB{-VPX*nFC zLVVunwv)0+L68vC%!f+8*p@fDUFNF)Rp7bdV>(=D1WF3C;6FYnlYj}2X2nM*@QeL= zdvpREE0Cga2Zr#&t}RkT{(@LXuysgJfAF*JV=l)3C>cK^$xF&)>4E;9@APoNExD(9#GM&I%GMBi>8&N?|NT3_v9N_Q& zrEV~W)JMssC}>Gf_}1ZB0rGf2{PV2&3yu%M7_|T$N{9fxz|4#N{z%*$Hu%f}fiBQQ z>FlDW>j42EE+OBy$R9@ZB+>L-(2LZf2iG8&mO0-l=?1V7TSV(wHEo#oHO)@nudFQF zm8hrL%$jJRR%X41;F`sgzXtr-*gZ_H1jLiGzghuXJOf)ibjwL+V|Oi2LL)f$4DODQ z%TYmGGSfb9YHAAXlQ&60wMhO{VyaF4nKTL&c#RZSGvqcYEDmK>R&7zn29|{sDWX>f z_0qtyN-g4sp-QXc1;oAnV1}$x1o206HkVxwJU!YRUDFfsN1{TkMg>!$7#bXaL~12Z zo^uFz(>d`YW0kpL0=l?jLd?r7wLdq3H^oWTIZ*SNf8u$^b`OfbxYS%_kRsw%bB6&T z(dH!W%WId^tX*BR1R=0}`oc3T0Ho3}gjjY|xtKRmMZICe#Wok)3F1x=cO~}-&Z~Fr zaM4=xk`X!I`g{h6w`TM&ccOJhlu7|OGpF-iIOGb|Rl;o%7*HocqM2grwJd-%F6k*F mM<(GVp^jm)t>+LR7YPNAy@v2N*OE0G*R9&HY4g{gYWxSfaPWNq delta 3132 zcmZ`*eQ;A%7Jo^aCT;o=ut+QvE`{>Zk1Wanp=>HBbpu|NMRu880bg1QN!mK-xc`7| zigJ;ypy|GKgh6+n+1}T_NYfPTwn>w=&RQnVE%H`ZcU@IRIli5tb;q1|Fg##mS@nS zDOVC+q`^a+EZUUfbQPV-J5V4OWYC3N40t@v@p)^je|cJZ8m4|QhJ2%aj9yw9cvxB&d61fjS!9R_{s%-oIf%Z@a602X z>vu)bUxy<3XiEmZ)HGpM3`iHnuXUrwIL`FmaU31X=V=F1@{{s)b-O2w3rm7R(9|dB z6@4%t2L*0ZxyvTm*EGd?aCis#{-C$8n+(P zlSeFQ)fCTAXO}Zc8@imTpZ!y$)z)Gm-lSReciVE<&IdYPRma!mq+a5rKGJ~Rk49t` zk7q;%eUd=$rjU0G{cG4k>n`g_T_~bIXYaPtLiA}4+}@KuQg_&nz>lja0ER^c-7q?t z=9z&5pV#%uvjz?*hNS#Iv50VSqgfArKWAKI&h+L^uUWl@;dU>m)`NLE7aZnJl`i(b zBT7P~FqG&|xe~9WT&y&ylt|~5D(UY4s>T>Bj2=sA;G9fL`PxpQM1I_r(8XQs9U{YR z(X}yG;=f}qR;a%O3jmje%|8#+sCKTFdXr^hz5*FqqbmJeY<} zxibYdMLXlvjl6N{g%@|ZVE+1@aU0!__JzoL4p3jSJ z7fu=&Xo~o_)gVg8XBouw@!1BL9U%j#avBe1xCNH`&ibt7I*Z7>&FIlrIrPF9_oAiT zZ|;+pz#ZrJL4aDN`bbd{{8TF;WjXerMt|r-i5wbN{d=fSo%Qi)Etch7eL4tf`PcYh zA4D*nqZqK1re%`ZYK$20M`;oR8>8_nfSex}2$rIAGfVNz_*SJ14dqtJrNAEA@+TR6 z5??)il!Z-#%+Zwv2{`D-xl8i5u!+bBF`h-S92|+;T=aBhPnyrcQRSN_gah3NaUwSp zNh0I=0eGBPT!kjn5U_l4Enk8k3Zp;wsmNHN)PW~qT#ezpFveAuEUg?(M?Z55e`nFoN zru9AbR1*(tqaGje@P=p;<2%^|4!+LPrU_qQy<9K*e`pDFw( zfev-LYWBNR3YVA_)b|RUd-mM2uz-)93As+VI#>8ZDIBRs?+M(o*^3M@KEp+3Uot{? zf0;S^_B}TY3;NTlYvzLUXz@ywQK*{?(IzrNn@QZpy*GDL6$G`S#wo8m(NzQd10)6T z^Gp=O==*7H8o2r;(~=F~>Xs3_E6k6Hv+%xQR5eZaZqAXt*f$K329xlqeuhzpy~;+a z-v7-hbgG~3ZG6URz_a?fL$-bFZOXW2qjg>&LI`;~-W3JwQm2bHxTx8YHQBsIR|w7P z@u-Ymr!l(Sqor0}Ps>!IozvyKXckO>@{6VA64@;SWvaz-_q0zp9xX5AlWPOWGN^w)2Nd!1?Z5a zkVcl#WmZjTDRHBF$I#9=+8m=QhE)Ws_?$fdd5vE6`g4t%o|GD3}LD3#}K{0gvYc33dPz zs5ORG(!keA8pIr_XH_w0FQ2>oZg;>P0N{T-+X)c>9}k)1A!TA24#l`r^B*X9^hOEu z@)t}l$Gy3*!p~ACWb_8o*6FgfI3d$FcyHGLUabc3K@HFj7`8wUf)UdCkF|gWW@`0= zS__~pQyyZONpiqHT6k*uYSnl7r%HgLXyh{++(Ub~-&Z{8?@yCLNFO|dV>wpT)y`B0 zv*Uobi1`Pwb=L|tcb5jVP%)^;&?*F|=VpTTfT$*l$5M{Vp+JdL7%7xYibX0=?gN5U zsYZ=~Gl~h?qDlT*ER?_U&kR|l0mY&Y7s#KA7Wp4yk$hfcjx##J1R1W6(M_0?r^1X5 z;tK+3oAjmfwDh2|8?EZ?)9I9_#Iy6FiwZ=W< zcw-AW*61d$;?We17zdQnpixEi04lypBk%%SLY(H$a2k8a5n8_j>Sr*RYBQ{uq{oy3 r6?!j4tMK&%e0b(?6vulGsorHf15;DzSC8OLTQ_ffV%w9CZ*TlRIh~GJ diff --git a/bin/kernal_generic.rom b/bin/kernal_generic.rom index 4e44e9bee2b9852c1c76ddf352c2d5e2c48fd22c..cf478edec450357c981dae1d08aa16e0aae23ae5 100644 GIT binary patch delta 920 zcmY*WU2GFa5MKN25QUncLD)+HM~ht#)U= zZ#47GPXCtvErJ|?-wX09F$=5JK_phedpY@GIWm=_m7+m8dAFD-rZ6QCmX8irh=?ZR z9*O(p%@TC-J}MNNWt2NQ1X>h-oZ%?FCgYl*7ir^3D`&MIRyo(zHUB)O{AY%t zL=|O>#zxkln5K+nlyU0B6jfCe_;p@nisH}EOX1ROCcL{SC!(THa42 z4E{3B@jPBg2Wrf_taVY`9uM@Gp}tvi%$Z2H#Lgjdc*R+NH|dcMcO!B{ax~{!$x(^T zwUJ|3xEQ!<_I~L-eujf-AeB|8j^t!h}`))VxK&xtkWwV{H3EE4pZFL#5{ZM+pvm&n( zJGc6r5Ljc`C_r6QMletSzgFzH7^XG27NJvhs(2fKA3wM*)F4&C zbb0*Kj#I2uMaOTC({iv;qQycj&nPex$ESk!ryj4V!`aDhXl!h1T+e>Eja`or{Umy> J{9$pt|1Y3BtEvD1 delta 920 zcma)4U1(Eh82*yeXqy-k>%@#P{VI+b^JAx|(a|XQLxpcRI_uSB=k({$)1=ZXFWQR) z^cynisOH9wF%E~mfiGnv{y>-7s25gxyb3FuOhIy*Cfa~_E(Y7xy7xr9-^bzbKHvMi z&-?Se*%R3l8IhyEZHVvn65Tmx5Zz0+)Wzj@$n_50X(7?CKXfQk>ykdI8Jl#1WR?OM zBD@EpJSpSN2dj;Vin}o>%lTukZHaBSbl0sL5qc2lc$Hn9eb0p+9)l!L#_9Q4=y*3K0e=HoELhhdNp!2ln`8VBq@8cIkVPzTi^ zbyyvD;wx`t$HS4uod}I9GAMP;q{aQH_91AFng(e;1}UC~QJzBnsQsd$h15|srKZ)f zmd;yQ1kk~egj9uVGRbwi&wDz`?D||T<)-2Mj_R&yiS4vlz=AQXERB_=_#kQyz$LCa zxefB|xSYG^{;DrvT{#Rd(?g(mFC7zF&0nlB{nl^*#Kv zv}SvRD?PtJer_08`Z2WiAq#tc>>3B zg#NXdfFt!t0TT77^G+^iNA8vabJBo+oU9ZmdxlWzF5I@k}efYr9_?eUO P&j`U$;dghXE%woW=?$jN diff --git a/bin/kernal_ultimate64.rom b/bin/kernal_ultimate64.rom index 7126d2b937ecf537b4aba216d02913b4d31b2bc5..666837c790e543633732d3e644fb8a92d18eb415 100644 GIT binary patch delta 953 zcmXYvZ)g)|9LJx#YZ6V=6s9cO==RY0M%#v3aSI*ogxUSQF^H&$qrF~paQV|AW3tf> zQmBtex3P>&Mj3;U^+|kmjaRicv5D!Mz;0AL9ln^ts7GRoI_Ehfct8~%fa5^`MLQCUuNgscr{d?nJ z|FWijo4L`pZ#i2oFV<#ix!l5HsaRaZ9Yqsal3dK26NV&TTao`+V2F${k&MH)kMy%T z>HVhkZk(!>Na8iCjgC~JiM`ei8mhz+9oAN=RYnspTMnRyl>pW3QKHe19U~z+Vn@jc zRqY5-<)t~CF9#U1kCWqc)Ybrs*&%?U_6R@`TWvrLeT9UK>jxyxBBA2q$8tz0A<=A) z^Pu@VA2MI(gLv@TtRV1XEJF4%gS>(t6cU(y2cp~*Z?OX)R+^#@#|m=t-qhQW!({EQ(YS*I@K-Fr{K@3Yr}N7^-tM(_J3@5gZi85yNRy&s2(ADN-C%*GOflD{H`c# z!*K9F=9Sblg<$!&LXA6^5L>97Zsqc9j*bOjL1T0r7BsHN-s;hzOa>{9t7l@%iGwTh zQq@G~_$K1@HgPE~vqh(&?E~uHydcfM;)_tJC@|bhn z^VHsK-DV!^Cfj0NPqw%8#PQBNLpV{#S`jZ*4G%7z!&ep(lH77u?lG9q30<*>KP=*K z&e((pGKPf1<(bY*2X*7ybpY+`sjicL>gE!h5yauW6v8sS>tOU4u*omo{~#zG7&z?j b>F$2DdyoIkH~f1Lk{@PaT>7=8>xKUSE|RTT delta 953 zcma)4U1$?o6uy&Wx|-C^sA(;(?%evaMAMjdU2Sz6>sqBQBVt7#6k*aIskSQ>78X*L zMD$7(E7dIQ4`m5MZ|g**VHMkqtq~P%RNPr*SrnB_(~dN-GG)~+3TDr!Pd<6>58rpr zcka2|dm^=w+OQJE_wve5F^WGsBcqrT7fvcaykpEecIhosw#QPI#QxTaN8@rq41ri| zqY_<4YN(e4B=ES$jgV$DIwc8r4JLS8HiDmIX|ZV+(>isRN;GILp&k4}qeUw*nzg_@ zqe&|=8a1a9A&o{*v)u?Ph;&GJ*+?2`c5!4l9ZA^5%NdcR@Xtd%bExY14^I0-2iefc z(Qm@n%6-fI6_sDCxSINM*2-1iDOJ^(p2w@#d{tD_)Et;tTf1)8*SBx4ue+qaw`^7g zoPsq9LsheC-?%yeU|7|4RlUnFrch*Od^RRgc9vzl4#v-S9cP(j0psC*DPZn87)e0@ zo&h);W*G%p8fO={Kqj{90NxWz5;wV9e8Biv%Tc4=6Cp;clg)X;ahd~?J610vEcds@ zac{qD2Sit=^Jby!z?_BqtMS> zI(5~@@$->Z2$fe&x=11#tXUkNAcn_8K@0OcXXoSQ|GA@|CI+ipu@wW=n_X|SeRLerrpCc zCDU#}yIhegLc+j_7rgL#0n+0NIM+mWca(qn EKbvK*CjbBd diff --git a/bin/mega65.rom b/bin/mega65.rom index 09a7addcfaaef96685981678320b3b1a3a45df98..cbdb8191ad7d89703f6bb4467248d98f6a592c1c 100644 GIT binary patch delta 2674 zcmZuze^gV~9e+uHgr7lv3|e(ug@ZpJDO#;e4YhUbfW6eUdS-EYd;wtu(0OL(TB`>( zeXOEeN8s{soXPdni1zJrc1#5|cXOM}+^-A|}y?fW|Cl{B>ds*U) zbw#w+SY-Z?xX`w5i4zKZ&?Ycwo*#9(P>hJ$x{8TzOv&jSPUR8V96IBLCsCi* zL{!Mtj*r+-sUPnr%+wDB9P^cH@ZE6)|GZF;!2t(^X2bLo-HJX6F3kj|Iv>?|?>-8$ zl5au85_9_V1{81OcMt2z^Gfg@5nh7KgeN^1=XR$jIQDJtp02T{2UYGr(Hf6zUwM1N z_K^I5TSZoKtC8MI46!8>M;}@k^s&evddQCr&(`iI!8H?W(}UY4O48xGW<}0A7Jbw0 zOhHONg3V_RHY2#E3fixQc;Lz=u;+!tTSfRDyUoO(ig# zlXIc@VcaG2N9+|!^)P?Ko(m7NB0GzP<~sCByH$Ors%=wW>LkSQ=jRU3NoZ^zH4n`ttEOYV#6fq)S35QvHD%W}Ul*7UUJ#J=c|19OaB(p)jV$I&ptbs9 z(g0xtgpH#+S#-kd%tR+ok>vE>q!1(5MXER-spkCIELBa?lxiSInF&&9;QoHcL8az| z*DWPdEjUii0m3LP$%U2_ys{HMNJX$HqMNRVCTp}M`F4xZzPF{y{zgkRZJr-Vf#gw- z8l`buFQPLcx|lWSy3D6_7Ah9;&vq`J`|3rr~;__*JKUikIB?PoIowA_bg*6mliR!0AW{r+*}5 z>8`AkbvUVm6%>WjNv@S)GN%SI-Kj$F$hJaz!E}bdrfAU}glr#p?`xFQ0V+XeFJuQy zIzb@u*&CscMUXtgP_iWnyr7NCv8{2tFd<BYF|=`)x#9LQoB>hd8Y(ZMA=&v zDWsH9>7=Gwm~+NR0xArlOVM7OCsHO8f`ySG=oTwoMPMWQ32XNbX`D){hIK@=eW@k< zOJY9%s`xDL7mH?9QvKAOPagPXlq46aa3%jh%w1a^MQ?}jhE7-}?i0W+@#riOUc)T&AP~-{42&c}w<_=%1fi{tScP3bX7C zjVydGD+FE|hf-|#gqJ#baAic9%@(u#3v%wJO`<&!o$JOo+leuvMO!@Rx1F@y;sFp@ ze4QLbAT5wmt;H)$VyzElcECO}`I? zcC^h$c5pSMk=srhxN1_*RRP-kHeXp2%JqYU+LtR26VlR)s}%rpm;$Ro#A5y4R{gjqQ}m zoB&K@)wCJ=QorMNvA_}ktH9>uN>Nx-C_Kk8REsXf(~72MXky@`1Vkt(IFb{rh|CL? zK{~?02FDImG6N<5L3Q`3gsVlguNzLM3^~~oLTP?<)QyjY_`ifUG*yZR%C*<5V0+f*EaNy3rAmsSN_ty9VB1HY zY!A1$biV5)J`^7y+hc2Djesn;E2Z^5oHQA5(qw`dk~+XPTca>1HI78cTDZ-$s_-rm zY_THdOYX>_iZqFP=U7GTm)yI=QZf5-#g8Ta#c*8mv@eM)-f9Pl9+z`8vup!_D*=Y( z$3vM-ckbMoR($c8qctU%0IsBtBnIOnPr$TiLd6uz;OU4OVnHqaQ%I0*P1hs_U6Dju z8!rtCiPGmnlGIPP$I$Ir80!{%+4n!YhdW)V-Mws(^FqE&8@+On+IccuVBB*DVMF!| hTPE*sU&!a#^mF3B`+vd#7(kf^2EttfVTEq?e*wwc)<*yU delta 2818 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 delta 2818 zcmZuzdvFuS89zzbk}bf-4-nBGTqShIWA+een>2T(8_ z@liIzK{o=c6G|Od!M__{reOGuj#|Y9{u4)K+A0&u2=lib^E-U~q#diBY9FJ7qpEws zZ@Sg!u!O$sccr8CF?bU7XPSfxDMWU^169jxYlKPtp);NWWfgn>0fPS}(E!7q@qlSF zPCn7y43l@hm9IoYPe>6~;C`YHG=*V$0BRkv9TrejxQF#pc?EZ zs0qKwH%Ft6fCo}Xc$07O>dg^asu+Qjy_y5&%h`|cE^acr$&o`}`&~1UQbtgx{Lt)N zlBeT1woc@)cvkTHog0*!;`}XVAv|mfT?e;U*Qm#>#9(1?8)>Z=Q^2Hcj861)Vj%{Y zw7}$!5nGAjjtTE1mWn%8*l9`aw9?7cnbDmN>u|RgJr}hz#Aq`P6O+woXQ0-&RoAG+ zmSGLG+e+YVE#P7)q&_V+Be7s3X~8CRR&)h9_FxnOCS|Zzj!nEdUgGX`hZXzZirw8~V2_L{|vek=B@IPN>)xkv1*(kksQm(tz`I9Ipyjsi5lag-5%Tnhb~g zk`@rb_aC3nT17~}KBL?|lU+Rk;Gjq;P3R}rVXHUUJ>y=t+1cJ*?|i4bfo>NhW&-}z zqvqfP)+|y?0eGrVwZ!KPlq(Rwc3|lO*TH}7edGM|e|qxc1%H0y?_ys}iiZ8N*Xx&k zPLb~(n3#{Moh~I7IgVmolfpU}nbhD06`9JSo=%9EbFRJ@a;oi$4{c@Wdj$1)*)9h_ z>Jvr@BtYB3{2vFm|1>0Nw1>D{qW?GX&tCgMwcXaNP&JGbE#0r z38BoXcNoxLlkN``fOAezlnV@6EF&fijxNnpKS#NnkkWNT0X;3;TxurwVgV9q`hWE5oe@6OBJRcpBJd!wcVCc+{ zC`po6`ZTFdcV(3Ja{j*$FZAy zr!U^uJ@6ZecvC2^8K&?yHDe>6?U-B3Zi*9Q4KdXaO~oCx&XQKskLL9?Q^x62j59Q+ zob5`IM~RScGmdIf!ZxZN22y~G1rrxFfV4WXEn|}3F!Hjvd{!U=Flzp6MyM@GW-M2+ zb^K$ou%s%9%Hr(C0Z4?sEC>uP!o|1*m*SIn8#mz zLM-F`Uz4Wlow!M`<09}YPEns<=FOis+YdxX+r7k!8%Z19L0WMGs7O83o!{=Q>3FIj z#0d2^VFSAEA;vUQ@P14m)3eZaqs(5BAqM*^y|u{K$2NthK)wGlfYps3qpkAIEig3W z{AQddope*tJhq7dnAixU#BY9-sB51Ub@WQK8EXOKpwDn^*~@?`(bNHo_^~N9{}wU74&eQnZ_D&L zQK%{xUc?Oamfsk;V9VZ>)(MSg`0etVmwxz~a$WV03@eu}U$ycD!%IIftYDZH`Lh3} z_mcnUAOn!0NI@UV9KG0}^h}~KP!Nhuz?XoRyo2RlhJyM-f4Ls~{---o)M}^u-~^VS zg_E`1F#%=z1${B4f%}0!3v~#J-WToAxFl`jG}=VFR=nsr#HilQerTU2UiBPOF<=Vp zzHF7yvTv435clP%0E;d>hzjEDP>jo2`#u9A*P|s;>Ayn@ZouYH>e_WmVU0`KtKqr| zy9?mTGusLh1;fN@D*#ZW6KiP)-w|G@{6NM3Hr%A!6o-S&XkDaNeY*a@>zA`9z=nT* zMc@3)&5=Mj5AIsOrumjxdwRpabPVEg#XBk;R?ZuGVE zQSLnC4nivk-Givu+Y6^(kTrJ*&~QS(FkjkHBXyZ!9vLonKzE|L9-%%7GD%U%_U z78LZKz(y^_u$HPQV9%iAXggCkpTw~_Vc^-J*dqO?C*-^CgPjZq1Z0Jn2itFG;=x&i z?FrRz@E^i-ptJ_(2UQR?-ykhkw?>l3Rz1JUrpV8wSYRj?oO8m9+=gqAGjEM8;?VARTAB - // .byte $f0,VARTAB - // .byte $0d - // .text "SHIFTING UP $" - // .byte $f1,memmove__size - // .byte $f0,memmove__size - // .text " BYTES FROM $" - // .byte $f1,memmove__src - // .byte $f0,memmove__src - // .text " TO $" - // .byte $f1,memmove__dst - // .byte $f0,memmove__dst - // .byte $0d,0 - - // To make life simple for the copy routine that lives in RAM, - // we have to adjust the end pointers down one page and set Y to the low - // byte of the copy size. - lda memmove__src+0 - sec - sbc memmove__size+0 - sta memmove__src+0 - lda memmove__src+1 - sbc #0 - sta memmove__src+1 - - lda memmove__dst+0 - sec - sbc memmove__size+0 - sta memmove__dst+0 - lda memmove__dst+1 - sbc #0 - sta memmove__dst+1 - - // Now make exit easy, by being able to check for zero on size high byte when done - inc memmove__size+1 - - // Then set Y to the number offset required - ldy memmove__size+0 - iny - - stx __tokenise_work3 - - // jsr printf - // .text "REVISED BOUNDS $" - // .byte $f1,memmove__size - // .byte $f0,memmove__size - // .text " BYTES FROM $" - // .byte $f1,memmove__src - // .byte $f0,memmove__src - // .text " TO $" - // .byte $f1,memmove__dst - // .byte $f0,memmove__dst - // .byte $0d,0 - - // Do the copy - jsr shift_mem_up - - // Now fix the pointer to the next line - - // First, we need to point the current BASIC line - // pointer to itself, so that we can add the shift - // to make it end up pointing to the next line - ldy #0 - - lda OLDTXT+0 - -#if CONFIG_MEMORY_MODEL_60K - ldx #VARTAB - // .byte $f0,VARTAB - // .text $d," BEFORE = $" - // .byte $f1,memmove__dst - // .byte $f0,memmove__dst - // .text ", AFTER = $" - // .byte $f1,memmove__src - // .byte $f0,memmove__src - // .byte $d - // .byte 0 - - // Write memmove__src back to current line pointer - ldy #0 - lda memmove__src+0 - -#if CONFIG_MEMORY_MODEL_60K - ldx #OLDTXT // .byte $f0,OLDTXT // .byte $0d,0 - - lda OLDTXT+0 - pha - lda OLDTXT+1 - - pha // Get number of bytes in tokenised line after line number lda __tokenise_work2 sec sbc __tokenise_work1 - // Add on the four bytes space we need + // Add on the five bytes space we need (2 bytes for linkage, 2 bytes for line number, 1 byte for terminator) clc - adc #5 - pha + adc #$05 tax // Make the space - jsr basic_shift_mem_up_and_relink + jsr shift_txt_up - // Now increase top of BASIC mem - pla - clc - adc VARTAB+0 - sta VARTAB+0 - lda VARTAB+1 - adc #0 - sta VARTAB+1 - - // Get pointer back - pla - sta OLDTXT+1 - pla - sta OLDTXT+0 - - // Write the line number - ldy #2 - lda LINNUM+0 + // Put dummy linkage, we will correct it later + ldy #$01 + tya #if CONFIG_MEMORY_MODEL_60K ldx # 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 initialized + + 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 + +#else + + jmp shift_mem_down_internal + +#endif diff --git a/src/basic/memory/shift_mem_down_38k.s b/src/basic/memory/shift_mem_down_38k.s deleted file mode 100644 index 583fe3c7..00000000 --- a/src/basic/memory/shift_mem_down_38k.s +++ /dev/null @@ -1,28 +0,0 @@ -// #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 initialized - - 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/src/basic/memory/shift_mem_up.s b/src/basic/memory/shift_mem_up.s new file mode 100644 index 00000000..320c01db --- /dev/null +++ b/src/basic/memory/shift_mem_up.s @@ -0,0 +1,56 @@ +// #LAYOUT# STD * #TAKE +// #LAYOUT# * BASIC_0 #TAKE +// #LAYOUT# * * #IGNORE + + +// +// Copies the memory up +// +// Input: +// - memmove__src - pointer to the last byte of source +// - memmove__dst - pointer to the last byte of destination +// - memmove__size - number of bytes to copy +// +// All the input variables, .A, and .Y register, are destroyed. Also uses RESHO+4 variable. +// + + +shift_mem_up: + + // The copy routine is simplified, so that it is fast and (for memory model 60K) + // can fit in a small RAM area - therefore it requires to pre-set .Y, so that + // the copy ends when it reaches 0; so if copying one byte we want .Y = $01 + + ldy memmove__size+0 + + // Now we have to move down the memmove_src and memmove_dst pointers to compensate for .Y not being 0 + + jsr shift_mem_adapt_pointers + +#if CONFIG_MEMORY_MODEL_38K + +shift_mem_up_internal: + + // 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 initialized + + 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 + +#else + + jmp shift_mem_up_internal + +#endif diff --git a/src/basic/memory/shift_mem_up_38k.s b/src/basic/memory/shift_mem_up_38k.s deleted file mode 100644 index 81c0d9f3..00000000 --- a/src/basic/memory/shift_mem_up_38k.s +++ /dev/null @@ -1,28 +0,0 @@ -// #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 initialized - - 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/src/basic/memory/under_rom_routines_46k_50k.s b/src/basic/memory/under_rom_routines_46k_50k.s index d7f7beef..261ae7da 100644 --- a/src/basic/memory/under_rom_routines_46k_50k.s +++ b/src/basic/memory/under_rom_routines_46k_50k.s @@ -70,7 +70,7 @@ peek_under_roms_via_FAC1_PLUS_1: -shift_mem_up: +shift_mem_up_internal: // Move memmove__size bytes from memmove__src to memmove__dst, where memmove__dst > memmove__src // @@ -96,13 +96,13 @@ shift_mem_up: bne !- #if HAS_OPCODES_65C02 - bra shift_mem_finalize + bra shift_mem_internal_finalize #else - jmp shift_mem_finalize + jmp shift_mem_internal_finalize #endif -shift_mem_down: +shift_mem_down_internal: // Move memmove__size bytes from memmove__src to memmove__dst, where memmove__dst > memmove__src // @@ -126,9 +126,10 @@ shift_mem_down: inc memmove__dst+1 dec memmove__size+1 bne !- + // FALLTROUGH -shift_mem_finalize: +shift_mem_internal_finalize: // Restore memory mapping and quit From eab79e05b49e4ea691e8c8baefb67157003518ff Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 1 Jul 2020 15:13:31 +0200 Subject: [PATCH 22/24] deduplicated even more code --- empty.d64 | Bin 174848 -> 0 bytes .../{ => assets}/basic_vector_defaults.s | 0 src/basic/{ => assets}/c000.skip_gap.s | 0 src/basic/basic_commands/cmd_list.s | 4 +- src/basic/basic_find_next_line.s | 35 ------------------ src/basic/editor/update_vartab_do_clr.s | 2 +- src/basic/engine/execute_line_statements.s | 2 +- .../follow_link_to_next_line.s} | 4 +- src/basic/{ => engine}/select_device.s | 0 9 files changed, 7 insertions(+), 40 deletions(-) delete mode 100644 empty.d64 rename src/basic/{ => assets}/basic_vector_defaults.s (100%) rename src/basic/{ => assets}/c000.skip_gap.s (100%) delete mode 100644 src/basic/basic_find_next_line.s rename src/basic/{basic_follow_link_to_next_line.s => engine/follow_link_to_next_line.s} (94%) rename src/basic/{ => engine}/select_device.s (100%) diff --git a/empty.d64 b/empty.d64 deleted file mode 100644 index cb9940fe5673892917c5bdd13b14f06db3e94499..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 174848 zcmeF(`#;n1|M>ssHjIsJ&U2p1nM^8k+Eywma+YIF2}y_w<*<_IFmxbi60$ioIiH6j z<*-UpIm{tMF^8DrzP;YB@8$CSUM}Cy_aAs)wx4#{Puq1aE|qcmg~Do&ZmPC%_Zn3Gf7X0z3hp08fA?z!TsJ@C0}Q zJOQ2nPk<-D6W|H(1b6~G0iFO)fG5Bc;0f>qcmg~Do&ZmPC%_Zn3Gf7X0z3hp08fA? zz!TsJ@C0}QJOQ2nPk<-D6W|H(1b6~G0iFO)fG5Bc;0f>qcmg~Do&ZmPC%_Zn3Gf7X z0z3hp08fA?z!TsJ@C0}QJOQ2nPk<-D6W|H(1b6~G0iFO)fG5Bc;0f>qcmg~Do&ZmP zC%_Zn3Gf7X0z3hp08fA?z!TsJ@C0}QJOQ2nPk<-D6W|H(1b6~G0iFO)fG5Bc;0f>q zcmh0u|IGq|uoJB_JDSm>U(z=rm7E5g@X)u`XoA5q`x)BA1h{yicM9Me5=S0yxfJ#{ z>m8&0mYC9B#hk^l8fZI^Azx1EWJ{Z0ec9?XATMtkzRVh(T2DO9Z?*d=$tOH{c56CO zyk}%A(Ju7Yl@DVRO{aqsEc+G-Is5UPt^vrjPl&#_P|(&ga_t@ni%&%PaAY;E09z27 zXU_@?UZoTK?LG8_5tH0^L>s86N;eFn1tbTHV z=<|cX7pI$!E`J<-svL8EDJ3ov`qrZtw!;@pwLjK*TpQCka?WZ1m|!bSbCedgr1eY` zGyIjl@|XPBdYv4PL45zTyhGUJM&IlU?~&aIpWr;rQ&#=E*%!SYa%Z9siHczZog9Gf zYI3~3oD57eKocy;7#qUkKv@ycQvCo(fR1Ua=qpC&IwR(h!KJ}>kj_+SA`Yn-rf3pI z+KFa|EwaKUqcmn^c1@!gFNYzfp3D)0b_Es2| z6Go`}gd~SiQ_j&UxUY%MLGih@%ozZUwIGH4jGPi@0;vB@9zw9tSm%|q)l_IKn<^c< zh{-TKa>~T2dZN?uhQsbo_h@am>Rf1^?BR&4!S`KzFVEz&10oW!ci4>cOClDj7WXZt z=huB{zD2&cQm-e!h!UaN^xWRWUT2BAL`$9O3%LBnGZS5UUtN#2#{hSiU=ylKSA)5< zf+eJM$D&Lhy7X)fTL4}8fUohm0wrYR#0eo*&qg(SI&G6khum>6>Ax8`JK)9ixlZ zU6}b|UsD$?;ox2ZXu{D2&t+O;yA>H;@iSy2Sm(#;A7v>0lC}B!vW~_ZQ$3+ArqIxp+AIj4CRC+Y=k1p7*$8OT~T5`hFS^fQ$)aUc{&=8-ssYgKT)RaZqLDWeU9CEYR!{k=S z7HgyWShqYrTGYKxt$psr<7e1NuohL*o2l2H7#HVw zH?a7~g0>*=^oC{V@et6eeDnla@oc$P_{dP5zK?ZnblxMAukKpbiRM1%tA5^}Vz56q z`S?#5{Wh~mo*STdEsim|vt8!Yt-}n3TI+>Gw))PV-3VIjE*&5kR%*K#%h_bIh9>G3 ztZzLn`0<(i$*e3+t!vo3uLs?I264X#k>KMqLfw=e(7rLTWizSxwLBM(Cj~A3yrmWx znDIGlPhXJ}XLC9+aT%zO7@vv)7(0C{hLOQnvQ$ock1n>yX?V?bFBP>bUBa8lqfu#F zIX*s>!`aq1UPNQE5z|E{o{Z&uwQW1t!2iR#Y_8s|&u20*x=$tb{UdWL7t&6we0F_n z`<*)K6~f^7(2DmZM7!&x;6VveBIxbYz|STT3w;CMpTv!=PmZ7!cUG{K^rgekQaF>; z*n*Tt0}}40HV&B(s<5-o{`G04mPT(O#O8I)oP9eimfPbxC_nVxbWBbLbD{59#VPy9 z`Q*brl{tNvvBqL?-$A=Bj+{Xxnxwrp4KrzsAA_WwRRyNpSyu-V|2)aS3j<@D-R3b? zC#F~MOIC|HSV$s1?C92pVEb~IVfZ45JOu>j#D_e2QwDo3lrHr7{gB;`On4!Ltoz%2SSbcB2oSGcv{+=#FI=0=aqCDqczt#9_is(l zE|sTatsHVx52c$@_-9ty^{b*bK07NTGsAa%I@^AS*1i#LY7>{Lrqxpr&afC9Zxcjw zZYpJ0Z+*?*4p>yoY#bUKtpCd|C->tA^;_4knZco<#!55&)(gwe9XHh@k3EQ4H%WWa z+4-|uvG+^swdjPHu$ot+oUhB_bwj@=^q=nAZeNWE4{1??o)6zbCa@TccY_?rvD4#N zuM|IvHx33q;rHjZx5-Bz!d~2hK#_B4VaG<9QERD!o$M*Iz1tZL6P~}jy4u@|j9U>& z%*hnzCrsRf^2&4(Sw;OiA=Jjkx_@cJCTKCYuUI$v{*^lqGZhs_+A+}@5pq7dto0p( z^G_;dVmj+`I@@nO?ulz1{A#X@t6N?D3)KK58tTURpYbTwx_$S5(`N!uQXSZrv`{Dh|>6kB~rb5qZ^X`QmezM#*ik2Pd`SEqM zkHs8aOKD*G{E%U=#0S>TBcYJN@cAi|jv<4v&ftc95$atFRW2*YsvL`oKzI2M#QmVH zg{p`VQ^QWKH@?^3u(jX4>&Eakk5}}art*t}v z-)86goo^W(U04gf8EM1W-W<(oIeP(-MBi8&eRa~}`BgT<2MPJqA1}7`oAM6 zz8PQi$DD69Kq&I4-%pUfsV)W)Od797(!8C_Llz4Ae%GP3y`w+`*+Om>grjL3Why^XbiI^Mv9j&$Du_x`46hjlX|R4s}Sd-gE}J*p#cD2t~9ujVsrH6tD& zy|0^e4D2A}aY42mlQgs{O4utzRP@PGM8vapK@_G3R0TA^ zM+$Iz;EVnKkn|Q6#f*^JY9z*Mn9@rA_UJzY51q>OfDE08QDg%{dEh1?2{xMOn^emZ z#5$9Ua>|cb1f?<>(pJW-3&$fT#FxqWGNbnw7nhg+{#{#JU*Fu^-p*7aOGPLWW)u|U z;5wCdU*G7Zye$gTf;BlhuR#&Z`VSG=ntG%)o#>NO>7qxVR`% zVYh-JQW`)YB}8;jAk=^-;;LF2vWAe~>~=5X&DJ+#6XQDDSzB_mS1JHOZnnv!$e0jFoe%Sd*Iep{SCsMAz$r&BZ zF)3(-cPidApW5x_5ZEs9h|JotK5uPX-OeI}2L)aU3v29^jIvtIReJv5TW=;dvp*18 z++DumLv1IfMx2FSz8n$K5)R+?>4J46lyx6xe{Q}Q7^!WDePx0t5 z90$C_QO01y!Z@(>n0oo3X6T7qF`x3jk6VMAatS6=3BB`Ezy`9@C2Ft0YV_)2>psTo zn7(~d(l@SU{Aq{7+kbq|DRVz#Y8aQCB-J*0DR#W0Hz7OQ{MUNj;<=XQ=Ehn&mZYnn zn}gUogq&F#coNHi5T-QnpP200mMGKKrp~do1*H=yjI@^eaZ)?dgT?w2HzDzd3s7-`+K~^yM*O1avtr zVr3esXwo#gZgd-%W*LdIHUo0EgdjflCk(z-m?S*R%#I?4u-8pZl}2M1Vx@Y|*y&Al zmQamv77${X=lt3UirL*0?N7uFu1`%x;|0%$44k)P+*wY$)l*{8^qThm`P_ieP>A|67gJ1<_Y zeZa~oJ{MU~d*IN;?(x-~Rka(B zeR6O$Pi8tpLu+ap8iL9PyL*NBjAPE1GtW5R$q6G|Jpetn_Iqw=7|HO-OvvmpU>(?1 zd+81`@=kev&kq3UmLWW_#@Sqr4jgTc+^jE}h+-bRx;!AJ^b$8QV>-tAz4=;uZN0pN zGxgV+&I#G@Y#A9VdHv+cuR|WX(qW4^(QZ$DD2dy;aUF~;_Of;qH(bzg^bNdoYJQ@X z(fL6d4v{HiFD_qdWSLsP&b;zm)a^+ta46Ydc#?MIIOn9fh)i08-0kK!jNXxpF(q5U zSr-cm`Lc{r&wh^S#mK$(GTcUZ`IwN)^^lN|aDI`kV|V7Qee~exy~s|*SJ&E*3rbkwZY%QuUn_;~-}A4Mrd&%8A*}Z75FqS7*9ABeB3BhZwDige!l06CfNmiGImGqqAD8y)Ro>&+dF*=^blp{jis};yUGp!*=2HAm-LF z=GKRnk6+@PJts(Nb{7)ZDsygKCehX>QrVCv?mh=^4oc#;mJ`dmMoY?MwzpU@C*Lt3 zox%c0fZd&~d@ucE87pq#(5Ds+L~CTA?nTibKwhtOd=4^L=MUl%kc zAs3%Qy~KyOkT4y?^}fX2jZ%q0gMH@l(6|$yWER-_w5R)fHytJTJ~X=bh;ob&=7QDj zk$9Ov2}1gMWMl-sx%qm1>O1zz{JfU0tz}N%R}qrWFY?&(#@zJV&KJ^1rReaJJNFE? z!PM^J$Of&m5aMl@IST>Vh6`KliO$5h4>?MNTbkM3Gk>C=ET4yxE3VYOzOwo5-EL*Je0aT6!SO53UBYJe>lTMJfSoG!Xo$WA5^?V^AH5vJ{ zFLlJxa4A&)dV_|NRX{3PCm`Wy2?3&Rf)HF@5fFvrPio6b!FQ{96fRskt2%qhUFfIS zb15XC_)=I{#$`9MVDu?kroa8*4Cb`B)RmO8G6;nmU_i6=rc_dx6+&zHHbgZ6+#2GG zMey4U8@MP__SPe%<|wFO#Z-mlZZYIpvazhTf|!glFq$kPDN0cKp#suTR?wEz<_cz5 zTqg5F6-KHNqEgai@gF&vN=dhG-N~hI&R-NnW3d(%?*0*Rsbz1zOmSdJ`;VWw99vsk zhp$ijL&xDPJ0iSr0ZaBc^k45NAff|d62{sAqJ+^V0v!=Ew@hHL1McVG{%z_&U)$Z! zd=H4kA3*;SO8d9=gbvH<#=?zXxnyB+z$5PpxP{;B6jn`lV-&X2qYrp(i&3aTg>9ef zSv&NCY=w=n+rY?+u~pc`*$kNO>5>^Dl&Ja>z)GsKoY_Ot{L-vgW^xh&eOW~HGx2$S zWKZm3>}qU>&yQ%wK|mYQxc_j;NbVt}JsHPl+<}k1Mp7Ht^fyyXwkKql{4;>{4ptj%RY4hqPr&D2gDacVDvqK>Dzpz}KGxPZ8_?h0w0< z$Si~|M&+KYq`1`h5LYNCDw$86Ep)VAcvoU#E2M}R+nUpN4%xcKtxyp(s%RG9-aY;I zuSq~{-ENc~Zf2h>`<7p?5!6+C2VOcle~M`|?^0vgQrU%J$|J~HRAI{FvJZWRDryw< zyOuQwEK{&fdQd%GKjraDZwfx*_&X3xxSlk6p?XxVZ#@^Ns}sRO?Fa_%W|%7^p!A&s z6GSRot}R`uWy5Az$Rt?kpoV1z{WSQPb3%60MC~%=0s3|GvDlq?5B4l_{>(MlbJu^9 z=q*Z8DXPrXiN$4u*9x{Vg|G7>6F3ty3G4drHzx9u5;je@EUDYcJNnMt392Cl#H2u+ z`JJK8Le6k!5f@}*hE*&#r7nCwsbKr0ngE?#z_p+V-`wxpBgSMRj>}WgZb;?4mgjBC z>h~;F&eQxvs57`+^rxfs^yaNP*vTYC*$lIF*FyEs#sDczJCY4M< zGfRPCjV&R7vO@(?&el*!HJJKpYC|5N)y8TYo9i6Uni+r3T+EAO!j&rm8n`HkA zHo$uim-Sk~&0FotN-uUb(!bf8Ad^`&>5xt84kfyb%AiCI07YqBZaj0N*PyLzHiWf6 zXH)OS3Yp~bSAmZTLAqc`;N#Gvk6D6>($fV(Zw1-o0#c62;DlPt;;RBaA#$!jT1tHZ zxC_kYlPYHl=fbF{wD|fEk+ghUNU=1XzwC6v#R>##Hx*0KuAr(@^dry|BPFOjIaF|S^eF#PfjB7qyuCu+95I)^Fp+X})=Qz|vhWgEIQq{D{h zPiz(6^>=lmWFW5v7idRk7d^Lch=>ZlAcc!+jEdNA(jK<`@`OaB-vP6pjff$X)AX+q zZ>J(Z>!Ynh7cXA8;{=O(`{m8r+A@gX`DJ+c+n1TGO0!9>W8d>H*?+b)ow`8R8T<)yS`kzuA!T3iX?d?Mdt?eCmwzd#pq?wz& zo(vL-!tAP_8e=dZP`TF@1z;kRZTy-<21Sye{D$OsF;>G2s$P8i4PvEwd8K0RD9w@K zsxmUFg3and_qJOI2gKPMP7$;VO0Bfj>(_5wW4A<~s7l%&>gwlLiZM(nq*Bq29!B*h zj!2P6k5c3ql0*u;;795Ov!c(w+CU1yb67C2&>&}UdxkXF8YC|bl6e6`Q6(y+7!u6c zL|y2GUNF{!iaMy^AtD5uA!Tf6m!5($LGgETKnFbqz+BH*EzpN^9MIZ1b&#re!IQv% zaSrzCDUf^ETaZYUR-kB9FxVQr7mNVa9DQ03dJeh|x(YfAIw=Jj?#+<~K>FK`NQ2b=*r-~@0Ozyk*XJwOe>@F_qf!Oh@Q z&==qw-@mC35xsI7A|Tu@wkKsGK57qGfKONqEqHyNA0i|orvIns8B;RSYGe=)>|@^( zOk`M3$i1`dv^L-Z68~1xvj1P(XS0Qsy82M-YC%T_iRNyQ3`5}!{Rnx0DFN6N zU>Y6;HaOc{NEl#T^rBbUJo!Nk7dgt1Hn%x(f%ZmblTyIn1!BXyxJ-de+p3=+QUQqK z$foX(1yNmMZK&*6+u*z9Hb?|plVZkx_l-gjt0c1XfPDWfE_a4?g#GtjD*A%Wi?O87 zQ?{17U|eNCHVJeajAzq;+6*9)^lXI&jrQHk3pyVWwi;a+< zGtAEy=He@KHgy!*y#nfH3Uj+nmiq`TEvf;qmRz+4u+7=xD3VZeDlEC^V=Div0F_ig zs3-tV7}OXtyY5shn;_@d+maNp_Z2IX4y40!G&@uu{;~0u*CsHu?SO*n8FYA>Jn*0pB^`w>d)q7Z7DMd>#{34Z;9PZ$N|g5Kn7FdW^$q zY=|El>B>~Sx9RvcWF8})A;EAKw8p%pZxt;I4}y0X zA~1=72yjWS0Gag46hN62ZFtxHLVW;ET?JAhK{~K>1@)gmv1#4R3qAcg!Si!huWN+L z64wSFtu6l&p8oK#@SalhdKy3km-k`9oHI-!leP!~VnD_BpEGwo=X5=_&Kd(#e`J)4 z4;j`qH$Mr+3i}GcegSG$002|a1r7mDhlR?o0wd`_uEQ_jT+^+YPD?n`jW{Sb2pA6m zH%9<<375NdF?A96`~Tj^;EWVwd0X&y_c@@q0^+^_(JTgLw63cA0!61q0Cxg~^W-%Qy25hH0rA1^+nFK%3uzb%pCjD`9$lUC8B z>RrZGQvIoa0Fn55bRRnrH%_m7y_QQY$B7MZ?0WlX>-) z%ftcyyhciSbwYLZpYEMBk&iCf)gNtg&cf4bC^prU(+X#HQ}bxC$dAkW!h@3 z4wjAAb^&pQf=^x>3d&YDeX5ORU3ct2RI!rB`h3<&Q#<)Ph1*SaHPtMMrlYuDy18c_ z0S-gw9=-F1j_{P{SK==@I3Ccwh zo`ne#$}kn|J-x~mr5?9X@>D)b`}>5z*DN?2#e%`Wl%s5AidB@;U5aHzE);L4#{9|f z97io7`yZ$AKFLY+;NPQ_HPF zt=RJ1tKAe#6n&^1b9rxO=4(vNbv_zFXZ!7Hd8tbcQ;=#*$?CGizY4Q;p=z1^%oVDW zeXS8qdw&=E7$mPe#s+=J6Uc?D4#Yw+ij}?$!ES~iIJh%yFSwgQ8a86&gX?UYDOc!q z?ghbK>j8ACY8JX~W+op}XV)@}a2(`2hCoTqK!5%BcDmuK9jck2!lLwAv+5d0sFcFwd%Bzw*H+M2~WLn02+tpF8_Z{ zjDWn!zg{FP{6D$qR-6gxiiv>qPRAJbEvTm_82_JK1mOIQ+jj1QsrWbb#3E{(rUT-oWu!^R;c%2$c7liT~yQiA6q~ zyV#Yj2Uk&##~J-+u$aSX&!49q)}7{ifutW%N2wn%l#rNu-Mq^T#+P0*^sr}hWcX4> z5?3$mN%R+jhDY^QT66VvcFNSo$bjFp{lH(P?^Ma?!0X{R6H6R+HnIce1InTZ_XdWXRu@?bYwD)3q^F+<`^fw- z_Oa^9u{}JM**Yv$Vp?#d(McBSQoCBz#=H!^-fLyVGHW=P&;J*}i6_JM?-s zlKN!v%USy8oE^gG>7CW#9N3Zh(Pu4ZTrIyB&rVIvmz~)xt|$A=<^n6MfOQ-J_$n}= zWEcuCSge)i5tmxRIRHgxZ*+Xzk`obtzM9Htk!LJN$pcC-{%r;biu^ZuidF(a%mVzC zB8kA8p{?yGT-PVZtZ~TMUgG*u&SKn8IiOKW*nvqIy38J#XFlhk~JFvFVLJFab4({`MqMqc7>-F=2K@S+vzY_6$&8#Y$u zgk2Fous{2FZFYQQvxz!tV`r<#%WM1MyEjc2MNWy|AbB;ao7tgGOMf9)L`F9y=QwE& zAR--)2R^!eng;#!cYFJE_KRKj;`5?^;fq{m-y{WsYHqp6r6~cp9C@RLSQyt;y1{Uup4AY*aqbv5(ZV7 z*^Mepn2AAtnJH2EK-*@{;B)4yi=ZeAVds7etl6JM;bjZae;IMNx+H3swvrr3_xJ|L z_;^ULp5>}ft5uj$<*7|j<0*Q5&#AFSb89$w+!_i3#o06$*f=N%x;c@ZQDm~rsDS8A zry$U6r=$ZuuHs;#JMNt@+Z_fq5d_FWAaa^pl?cF42j%WP#?l1mYMJL69it=eGcw)a z#g%rN&=GAc%LL0d)~6%&!+qz*4|R^k2X^C#kOz{zo#XHaWRiO?x#R#Uz>4{lF5CB_ zD2Uixz9TzoSN}Dp`m|qs*-XpFBlUxtrLbK`!E#U)_{%qCK-b0fMcUsdPTS37#gRvl z`7}^=8nD+5Q1G8L^tv7X_Py)No>f5Dvwyz=px+9Je|$^dB`&Zi+MGt%a6|s`15+Ps zyw1KwH?Z}#0R;r{(KkzqC1vP#;XQCR|Q3o^$@d!tXj3vzOI zB^MU#Bk$IHWZwmoVFldtJ-1XcD&bV&tHVh#?q`2DqilTI$&ST0{99{~CmE+mL_@cP zA38;{C-%NUY%mTKFbp1EGjaelXYN{vtv)9N*{h^5RGe6<-WeR&Y!R|}hOofVea2F8 zoF~GB{EGjj@l{&IcUs^7-&4G%G?hjMH+R0ug_W{k#Vi6X7d}g*t5#_qI5Ki$3%J1q z&e{Md;@e9j8(SccCXls6j>Ii#t6nvR|Frhky)!kv0C$eOe2Lf|Kx)597nx<5)=U4K zXMu`yL1q0SH*AoOK|`32^f#Uer1B3_&yOOWZ$LOm+$4m-29_C2Q3=R(2WgOvS}RfQ zEpxh)__fof<}Hystvh*vOeG#^-Pbf;)9E1ZU>5Hfe1TkE?kiC7i!WU+K#32kBp)y_ zAH+W!1e>NyzKrS$EK&`8s`(w`^Eb$I7!CtWJ6>3RDtM#N+i0LWA?5h=bExep;8(%? zquNi$8bYn?hH*e4r2g2?x!V-Ri-(gBcNHRO`Zq?Ty70efOnetRNu53T`p4_}(r%_~ z%QKfE4~j~u53~HhPYqVLk+x)ZX z`oZRrVR%~-f-O8{^Wj6z088>+w;prkGKl%PG&la5m*Z9FHH6~>w`}#&=kaNtq&)R= z>M82y)ic$-)N|D@sHdxYt3OlsQHR5~ZwZ0{5bVVB|Na@Q$diFR^_}+N-kTngq%9yQ z;;#ragc72-x=m0AqW4Qr9{{2b0$UP!COs`eVPX&$r7^DO9?uC+_UTBGAo0t%6FA}v zaK${oCgWofpv%_CsNB*&k4%t;Fveb-d$o~qr1+y7KkYX^d_(Xy-{nH1F*tlSYXb@L z!Vctb+;+aq=Dr2Q#1zEY`lwq6qPD|Iaiz*_V#K9fz~D-<+NIs+d^v~sy@X`5o`Qr> z+9YkV=Dq!4J=$cm1O3H!0Son)V0Rc@ibfZf+LGd)0Q?f9AkzFW#wpK%65m(eW4AR` z^sUys206dt*;q1MIB!oEaP2`?SVRnEn^{-(rX{zzZq9bv z>m>JGxs8$cL4hn8!JcJ-Gz?6$j2k8PAexo!y z2b50I{7Zh{?}*X9$)+{_l*pv0J{C6jdK49iT0kwM>os6_kb#4 zc7>W1YnKa@+jdbp?6XwWp5}tB%)c;EO;T?k*(ONbu+>mfkd2zMWrC;d3ibgj%mTZv z9Oipc{};H(afBzTr=gdzE$|t(0HXRPZ!87;`)>4viJ~-6yHIpwFbO)Tv z7k>vrD)9Sspp|;C^Mrv}4=@sg=s~iCdgSN$dPTryg#-*~9&1AHrCZgpg~D5&JYN|g z75L`1QV8WP*IHHg94QTa-(~c+fiLK?v`VhtPa-C^HIJ+-mHRnB@?oN$BjrYv_%QI9 z2|Ld1a%3*;#gouU>m+VL$!y!3AhSjo$cPQG#DjcZ%at~^c97Xi`oRscK;OK=eI|OJ z5c!-BTllKbt{NwPOB2kD+UubQpnLIqjh}yU5O9k*EEnW!79fHcDuxD^9;H8*FZ~8b z>}6;&yhC2=GJG7Arrv}e6%=3M?jeu;R7NFk)G~hp+_L2?AuafV(cD8?ZY^Sv^e{93gDRLD&m=f&M zt4@7!ZgC57CZEuI_Mj)V*zw?6*j1sU#t3k{u#dH>|15z4I9>5hR@U%@okE^BJ^@w- z&xUqRfxd%hz!P0&`c{HfcaU|H2>t~3dWPIZ2Kjz zH9S4*^r3PZGvfee!8uqJSxe2xJOvc^yh3wLf{DKcH7^$D*EZ@Ihuo0J-A~5_nXsjEQD1+{ z`=o~S&teUwvQ+KpFOKXY@-g(^9Ui`oXA2yjWB4o7nwSWVyjPINiQYL}3GO2vG%mrn zl|%)gg|XTWIVTSh{6L4m;OkLE)zx?>np0s-jZe-qGanzb(JP7=B8i;Km_2j40!y?Z z1(B0->D@D{VzRsT9kx4n<8ey$hq+@9Jp8<#HuwLQa&+8@K0>1{upxQ2WLGD_mYr7{ z1Hl2$??e3AtOeX%LJ{G&F?V)#b9Q5Mhs)LQ<+tHy$^jrE9JQJLcvtNaVRcMqj?#&c z+iyd=`xJL!^TNh^NQ*05BO+H(0Ls}RHWl;qG!ch#ckmy=Vo98>{#t`$hb5)0JEYLG zjVE_NfKo0dr$81BhFrTWBq%Hh)A&E$gQl_Dosr|CTOk0Y9TH33Ec@C`REin;LpMcuIB+)W46B~ynmJO&E54K9-Q#OaNxVV zl_8;YLD>EjjbeA8!>-US<_YS19I@ULnVml*@>iw9pE!oHzFs9{o$rwoqpM)}$II@r zbv`WTv@SeV^5F(w&JkeoQ{2m<-*EA5R0#z`EA1=Z#+IPFjJjre%Jg?M#Y-tBv^q4* zRHKs(N{cKm#%HO+NU`_=yDaT7->j5UM{3?*_jb~Kzh4>*l3=LsOLbC04EpL=e3o0jE1;zz@{HCs8yC;Z&GdyaOIL7Acz+BMy* z|0Ma*vdOCcyTp}?^|4kzO|q7Y^6(6Ry*uH{YV5D4e=?^eX7`%U(}v%^uYe;jEauz2 zt7~YDN3VBUSk%Q-V7*~j?C|{uxvIq!%{pxHpsm`7mb9{7@vEhBORXW)A8>KTVJF=- z_mAg&%}~LenV+>N*T8OEV63T)ffFO=3{qfS+2F)|XP^ zbCmuD@nxSXKd40M`*7}^Jj1MXmzJK&xAR(DeCH^iyK(OTP%5=)ztxOf5Qxr>~d&q{tNQ zt3<_ulLYK#9UhiWQM0&igU?>xzd`(o>)E@f^zJ2!dCp7h9ttj>s$FAiURn@e?l7sx zzfC5q?RvlQ@+uAnXf6f9zO)18r?;^$xA9WWD!LeLtTswJNqzVR@~0LN!W?sB^)B;4 z*v4agLD_U{8@YqUDuN0FBHG(^Yb9?Wnp#+K1H&55{#;|N=l6E)*lMswaO|g+PQVm;ETr{GiI{;KddBEN1Lj`ApLUwtf3lK6A3}pgV znU(50X8uDC{?2NrS>lis6Y&JNr$awnRMfVUEVOB*o-yaHwY8t0qKojK$-O#zdrXT~ z+7rpt2j>G~gu-vE)F1ENc5;Wl3#Z?@3jDL;07}9LGycZ1c zf}-Hd2!c`zC@)u#6y@mXGcPFo(U@(q`K!>MVmqFvqR@ToNWr*&iYfG zab?Xi5?)$^rWD^67q;xMdqxN6N$jn)Lv1c$Hw~{%D?G$7^Y%8Wb^uPy(6glm9e;-@ z+)V|Ozp~Hc|68n+pomgDIxjv!x~^nsg$x-YA+O0Boct^e^dbY`;9yBT!O7Lj$846S zXm*($wEKS=yF`;fGt8>+2`e8alyZZqzhTl?y2BiMlL%;1Y_BzTaoGrJE@hb+Q_}#u z?EXIg`(0ZBTff7B=q%vfThI@SB(M-T`3Q(6sA9{fiMi*1I*~_qARd1Mp2_xi*xz&$ zoGX%tXu@`71$8yihuB^3QH%4?_Ia3;h_o)M-OA)JRV3Cn*Q6O(zx*T(^tBlzIsr5h zMJEn59TJ@&Hb;@W9tqqUxfQ=i9$~~UwvM#MZ!x~cYt?_`pTDqCmsxeX z|BdYMd))sptZf1Ze`*Me#^FrD3~|P_I4?G#qJ%3JfjmCFWmF=t z#%GLh_*Y73CEM(eTTI{+^W!&W|Hu9?>Vbb@FPb7U1mR5)dG3!or|DST4= z2ZnF;*npI08S2roq*7NwN_ISz@t-w^&C@|gxjx#b1RhWinD2c=*{KquaFHS$iYw;d z99kpAuOUWOVqJ!*9dPfoGwD$D;SQqE;aEf~Wq?sCdEp1ckvyNr`Ca7{Du*#|dl~Di zE7giI)V9@rzW26g8zyp!#c(@9pCz4x^RXozlvZw(lFaBo>i{zOcJBS6`|3q9cgAu- z#y8VL0!o}E#W0*aR=D>KD+y+!>7bdaN=yEsU6@=@NcA&~_)czl zsv8|c&``RJJPH+sfIyvf$Nv3r2cQ%X1FZn2K)Wy(Y*bFIhXw^>&S8?(1F|!Z+Qizd z1ubFnFaOdSKh7y$1MB5bhXfY0})W(Pu7JX+i_p0c4L(z1o14?&EEUWl#4ex z>WH_q&){+@9ME9sFdBm9=sv!1et-`UW|D-1fZ5-gNO}xdq*jwWo4A?yo~)U>@9J;| zgCoLFB*~)`?-q~h0W2sRN~Z6IC0%5h-GKua?woNNClJK|ajYO3LI&YPIUo+eMgT~_ zo*V(_O7QCl5ZK%;{#+PcH}{LyVc)&E$XxG-c#%%vt{O}YE-K8;;=|8GUm<|r=Aj@s z2+{5A01})CD~2y2ca8vHne)eNie`&87Ty;doy#ZsFplxFA?)<`Z>GPBtn>&ZzOF-9s7TM-q~xNQ-R~V#)*PgW#@a(wz;42ZAgN zAwgXj!f*lg`m%=EdTpF~S^a!*8BW_|VROD^VR!iELc`9cHugVb@5UR^(GJxW+4KL# z-X$%-f5+ZiJ5e`wXp)W>oLpQS9UYuQQoQlVLZ?YbCvQhu3X4RV@N>Or-R|e-Kr8f1 zPw?y=A9L}e#ZaD~P=rL>F~EsHiA?5ITeH6+$p0*jxDmgP@e9Z>e90tIs?mL=A_0ET z^Nv~aw^sTC%~{r1Zf;S(&BQhEQG|g9`Bn^6fy`tC1r1%3Fo6|AQAc9@?X#s-~i%uA!o- zrLD797pu2V|KFVvga7B!h%!<6&|$M9M~}MVo|r3JC?7v@(vspWV0Fsc<_g``&fnf1 zV((yY>uB$E+O7fT?BaR@l-Y%Ia~C+}amG*aZ1hW#CtT2XR(tSX9X#pivkZm%V~;{o zi**W9yt97Y$Es&ZH+Z)AwpYApY-H%XdHTcq0%|GwLHc_D5L)E|`a6JaWYK4!H$w|1X}-J)G%3{`)&`W@gTFUXCM&g(Nyq2+c8s(8~E#h@zB3PGQU`6j_)Io8=J0 zB;Uv(tOJ#hM986$LzLWpzx%rHe?EVG{(WE9>+pCyU%?yzs0f*wM1F*s;&)1Zl^Ms( zNMODNzbka+=UX6I$=g=yPJs+noGoxZ%;*Dw4J*^buJ;%G`EV^i=D+p!oMSi%=2tcy zpeNHSK~oZxt?AoFcg1cWvK6v&wif2|vhewg4OPch5JG|);6g!G+CU}dgQ+u|pCbf_ z7gPV6LG_=~`OHzNr{Di*Xnuta{%6IKq(3iHYMW4>eA^9TVRXJydj_A5jK5TzcWybL zq4nKCiiumEdd`E+zf+QU=cSU=?|^^GakF z7yyKV03axki{RtqS3Vh*dA>Tswc3J;W6m`U9mScE%gP&57Y6*jSVZUMfz#X?-XX?N zjR6YD0E*A@#n%eOa}l*i?~Wwo?Zpx>Ls7NDt{+9>se2g$UHhoY9V(Q4ES~Jv!1{Em z{IOu!Ugi+<=+~(|u?uY;shBAO0?e(iBQeXCv^;oLG}D&a{n?bs6o@6rnO**(`}8YbFt1HAecj)Um+iXEM7|P%^}a{;O4&JGR|wG5Y`Cy z_%pHe`0~0y`17vFm1>VSX(+sVe_XF`GV#Rzu0f8WKF>ojFprKyAXt-0qknefzc33m zf~FOm$LFs${EX-t=TA0BSJd2<&^%k9vFlS4kr$?L)MFmX#Z;QRFdpXfq4;CJls-nB zEEBy`;-Fbla546~Oc|IXQd-hoJuBY7PB$SpmbJy+g$t42>%~WY^y>Ypj?I|Qj~%(T zlXwZ6bSe32N>RqK54jsSski^#xE;O)oF(B#f!(FZy%8-~-2We|?^^%c-B}JBwHx6yPSY+O1_`z*%Wg1`ry^*x*xqN_VQ@?qE0H!-cz;+_n6Da zmN-9EjG`0j=u573BS%W;8){M=*Ghw<56ca1^LJ)zU3p`N7emejwKY&#gL1OV{(gs z#WZIWlXHqg^agLek-U}1EkTwC3r46olRt39-GV;mFcH;{Ps^eo)9cDg8YfISTY$&r z<&U?>(ptV#DGO835(dKXvCJe8XJoi_R8?`RGNughXojCJ^I1+N%k61)XgR00S+nI5 zs4H`n#cg_H*mfC74SKN8@}{nwtk-gxa6B?VncuI7cO7r@#;ZlYIFa>pD^tiva&4lnX!Ucq zRv!H(8!YD!>*Q-;|C0=vuWBp{nW*-N63htBOtZHR@$qv=)n(*s8qh?SA9=Vu7F`Cu zs}7Dx;hn1)sLJ{oAsYI zXh9D3W3Oz#pxFI6R?+yjx!%7}MZqKem>>2R*tc`4*vUCO$(HKsLkk~62F-i9(`9v> zMOItqT_jKFu2(bpiCKs4hyMGP)GtGabB1hk80Y#T_TJK2WTRJPk%FD@z@<}bc~o$b zNW%uAgs?MliF$bq1&DkfTh_lC%lrR*)5x8!3i$xVSts}>R2C^b+&rJVUApvb>1e++LrIQj)A3h zKP&5EVojF0ov*!+^*2>pW@#3t`fqim)_Bk!;m&lXJ&~T(;$HN=((Y_I>A$-{4Oxu( zEYAWL&fSKhll4l)kW2?mPPT~B98bf!I6|z0q=?!g!QT9W8 zD!xH85QPDo?^pt@C{Q|I%U9+NC>6qiWE7>O7xfH$N-w|I!>e@Y=W1^3>;IqrC|z`W zaJKhN-xvk5fTV6P8}C%7GcK;YCN~+qahGcjx!~X(Q1623oMrV>5t%$Lu(v}h<8Bov zF@3*dR3wi(agr2XKuwZ;VB`pOlZYtQ-p)Pl`us_4;z95$VTXjvG#1kDsUvQYU#0dOV)v#J-GwoVtIJ=<=4JqE^D6*Jr^7ZVAzmdx zZ)E-5w?nCA;*7mFriTxG$M$)IknPXrnWkiD;6qF~tzYf65ayWi17c$@ui1o(=}8*Vc)3)GaMJfB^v#{M>S3sk1UvHMtp|Hz3-uuGsOL?!g@ ze|ZVLTYh88om6hX5%>&6MvHy6N<@{NsB*XtYk`*fcY8EaWNs7#G$7> z23^CdM&pjW;F?sK{5IkG<35-C7Pa`FKSE6`ObSgxO*+v(28`m>pootmKz*7b2mnKg z%N*G1XgZWmv$HxL`6Dk`O|TEfva~=}bpp6(wrKi95R!Z+o&F0YEK3m`?5Sg=>Lf22 z^!$GDD)X1YaucRV)mZT?))!__=CfitculOQ%x!2f$vI&yiTrj}JX!n`SXwsuqB7Hd zz++&Y{9oa#JT|PB1-^a4)=A?X;u!_DRnxh+lz`vp{7H;*z76RC{PF$M& z-?*CpD{EhUS@A!%HupE~e{5~Qa2fD6NcRW$)?X2ZZOPG@A>Kj8xLVSV*D-o(p9mRK z(>j@Z@9}x3l{gQ>ly?X18{6GexQgkSc=eiOl!!;oLznx*HD&T8nA#FT?e$^uD7`G9 ziL*~*^=B5Sr#~pem-Mzh`B4H**jHB8GJhRgr2`=!H9l#KX@2%tCAB>yN5G$+7{W6o z0x{BbFj@cpb-0?~#_4z{hx^y+&d0xZv`T)FboLY9pj-iyFz?b?h$ZArgly zN86%(Zz{49fo{4=n@#Pn@0dnX=gM3vE{Kvuy+r**gTz9`O-UX6 z7dgw%N}_f*o>%e6_(b|gvZnk87cxo|lU+t4bqGAJ6#3DEV*hO*fXd?g(~5!~vY*i{ z_tfO8IWqAVI9zzgcnM!zwSmikMB1hTOwjlbAFjH^m`6DJ{8}AGoqc}wQCyF38Ul$} zIf=*A&S@JNSC`s?xO{14d}%c~CF+JGUG>tqxTdtd?p5&qWB`Ep64?Yo!q7lIr~sHB zE@*6FN<3v{ZewC;W_|kX8QXs+?PFv23#P5z*grom&(E%WpIm%B_HBM`X?c2l2Cy){ zxE$ZS1^7Nc;TPz-G&wstzC1ah^HBP5^BZzPe40x14f>G-oItg2Z&Uj*Tg1NmWI_7s zl7aHsZgWf?EZ8IM9zS(w`R(wo!Xr1E>fr}|`2MPa%?>FY<@ zJeiKtQchIOKIkdT!=y18EPwrx)V^2TnH8&{SB~i<#$-9~!kr-5zBQJkgppl>De)zJ z?KJu2DW??*8MiIUGydbaO1Vj-eVFGY zuXKzset~2UFN_fXmDm+=krPsfp=9Cr4&x(WN#Aas9eb6vR(?f;*>Md0KFSX-fN#U| z<6H4adphu=j0?5xue&iSuiTsE} zAU`1C$WbH=`5p;DzC(hMZ;(JF7YT5+9e*@!dtkX%^!;*~)Ajd4!q2FJ`HeQ`$J!=t zzq|aWvU|%qedS?0T3P{;K$hx~?80_Qbcufxi%o=edZ`GD#3pnJbz!;$yU<+%vnUj( z)!>~-u^IpS@bv++gaEVNxjwVr`9ZUdcYsk7v+8xJm)fV^nzaNxFgqo~H9IwD#>dIg z#+k{Pnkk=Aer=ZY$*fZNaHEdd(e?zh>ycZhqRp;{I{KO!t(m!c4<4H_tM*y~Qq8`R z6IzRk&2}IBGJAx0c+Cv`aL8;F{*Wy2P)g6&tRck^B@t`xKJz8uvnG(&U97W0Ud%(feXv_1Ht%B*}YSb3DNS|Jdqz6!dTFAje8L8)^C5Rm&}$9!xWD{@>Q!psYL0L&xgkvSe6g}+^^^C*LtH2tqs(}w2ImSf4y?fY5G*8PJ%k%D%&mBx`H&xWxBVdsbNgv?*%d9?bQtZ5CasXaJP4U3d5aeJiqrGWA(F6(QGw~ zxprIuW)cZ_>g=*^I!4~eqGh~?F|S=%1x{MfuK70jH@@j-Eq;7`CVP;v!3<-}Fl-<9 zDR0O2NwaP-HXJj|pm|ik3KNxV^1*OIcK_qP@|H7vkjV#R)$E4H*&5l*g+tjZDz#4@ zDm|zvo~II}vl(XgcIS7*D10lbmo!ZOu|2X^9X}9^K%fCm(!k7lXD)HnPY%2 zmAp^b2#nX-cSeM4))DvnLJe!*8?GNbVJSr#-9uy7Hs5^uIC7wOx}~FOVt!A+ckPYG zli9JgOScxUSPDE_drJ!EhyP+1FR0zy+2HOQJ9x*Sv_}oy`w4h9RUP*;i|fkB4aOBF zoN}^XfWveqc`lPvL6({E|CZ_NKYtkcibTqspRa#&KWR=b>?f~iov zbULR)hQKXRpp31Ppf#z{VQ-pK|6F_An!5fQ+L_9mU!0u)4y69sgZHl9|Gk3dQ&~-? zZCvk$ORV{|@b5uaPPc_GPye_*xU$e@x_nT4ZECD}dj99+;+|MGI&X4zd|vR|@;rby zwzvTJH9t4Gv-h1b9T|LTdTJU1?hsUhDgpLWWok9ox|RpsF5JL}yt4}_MbyK(ZF%R)JmG13SK$p=YMn@R^(ywc zh9nsKd=;Gi@M)4AyHx(LJt=DicZAdWX4tJ-c$nosg4j+M(6$& zei`V>Xv!NyQro8|NqlRwZh0w>itXd;(F?8e!{R%v2MC};()yJjnGcU#De^aZ_T-pm z>VwLy+&L^t8D#xrGn*ZO_wLJxN0CU=lNVDfAXg za1h03@uiPWT059dvIl&bD+0XY?$mw?ez9*5K{H@B+$Dk><44@}Yvket=CaYiO8j(^ zL#3mAuU-DLBxo`uG3J(0L6TFM7|c$^Ud2J>oQk80lL77AEVzp1I14F|JL)tGt+?53 z0m@7~_x(9rc!cIqb7@bj)1Ew-OS9XG%U`igSaD3?!dC3wI3?6BwjS4Dgtm6hGI%rS;c^=M+ zz}5Ts8h!VEu;9b{-KWU)?iV`he+IRFv^U3RKF|GKBF3rjlLwOUN+7E!%HhlnV^F>v zZ*Tj<)A3)s8~5I4?|#1cn#PRQ)jI1VFdup6nCE|9(aki-9j(Q&*6`yb()rX{Rt(4o z#oInC)6?eVCRMiH`#|hkhKAvZkU(Sb-1^URKBN+{aB_ei`bOVfMBRq33=i{Ww{XPV z%km)J$KFvQZp~WpJ;~*{#3e@cH#Y;}D!Y4dw`4wJBEW~u@zQmEzvCrO6@QbpaemRm z8FdhrakfkK+wf@5rR`2EWsWojJ%&=W$!_>1lNeEY)li$5V?)%q=srCwz+a(vAzQB^ z5P27nNMR+~*|7kH_w#b{?z`+6nYx>nmOm~}Dxa!Ud|6s@8DIK#hrj7*UD7ZkDL;C< zIxsNEvm{Z&-6BNcz`_~f{uhoi>Mq&XN%8Q$Jm#$05i`{1Y`u401dM`~csus@mbi}L1Cg>`xE_(A7$qIttjC(k5{$BTnsAZhuHQiI>(@OY+RiiTcd z=g*lu)ZNRNMB%%~<=)lWXp>LgiTL_Wc5+H_DKdh$zWL*j=3QY?2vz`PG>S^lOVk5O zeoZz^Pof?;uze7^FIy#IABTEDE}m03M0p$r?gpGH5q=qypyDZ*s-LU^s8#ileWY1i zdhYFJq%t8+-FIq5-FVkfKcO({#kVcq#%hhiBTGiQ+;MdUg$p_gG^-XRqZ zz&|k9tn3hLb$M~>>}7=loc?tcf4!<;2m5EYg#d91cmtAxQXF6F%ODU=N~zKv|4OJ< zKn+j8>*Q$>6E%Xsb^u7|mEbF(;VQl1?)tsl>rvMu{KL&H<`Sju$|5#1@5=P`$Vg?| z7`$LaC(5K;wp2;XE>NcAeZVLOk|c(M)oCAbzqwMUo|+^hZhpY<0ypQAvK~PBVaSf z+kuD%ZM-#vO<+^&SInffEAEKx@JG8kdb=JwbT+`#+;&G}T>mUNAmD1`)muaHDe;d3 za*J|HUxyZFIUr(hsbX>6QCd>QIL@u(2XHU{o|MJP#jLeRH|2y6#v}a&H4`;X<|PQA3mk(ZfM~P;KMW;^b!|kjUb5s;~me^@7ld%Jt0d zf;w`>OL*dXUt1~RoouF!pof?|_-ft3>{l&`^GPpNE}>WYYbC@xb?OSJLfn}q&WSWg7c& zI9afBAt6OU%u1q>I#5>1D6?^1{Sh=i(1|#lP7U*+m!@e^8s&VGMSf2vuU7BZ^&e-* zhaaUS=B7DPwWlN>=V5{b);CrN*<}v`jTp9^&1)_oM`s&Tq65+5gub*L0dHkz<$X*i z#6&~M(A!W?L!oI+MpP7{pd^413Z)7nU7|gl{`DZMseGIH4f}5#x8r zvJ^@w_Cea;G1m1ELb(pjz8)_Aqj)U(YiKn|t#wna@qN&jdb&s$avN$F6}?wQ+i$1A z4ri-Bi~%uxbc4N`Q3Q@2#*q)JgyS_pDjcN+4fNyg<*qQA};sS*%~zsb|!zIRi$RE1fgw(FV6EBZF#XL$P9a!5%_h!O+W;J z>21|8J!5j!GZVtD_QOWHW*A$GUl@Yz!F|3FnwVM$2-#do^KTAZm{3e8&CzvS`?B3nmn{R;o|dSy zHj^t8EV`ErcH{=X@IALrh~7B^%?Vl*JABp2V7lBp_;THVdhBEEzX8P2&jO;!2F&sc ziN5#FXw>FTc&sZMQEgB3nUa*f6=bNhpd0roLbmZy(TTP2lMda|1>4u1WrHFS54{BF zf1634%Uw{$<*7)(q;2cMhZ04q7?Cv0Ip8+WK)TMuI@X&;`rMrk;O;X`Wy(h-nkx4f zwuW3$`j5)j1BRrxYQOVG>R#Ce(WSo~jv|2&XdGBn00$BkCD7gzQk!?szu_}by-uQ^ACjKPlH=W znMu!0a+amw1Q^twwEK5a^9^|K@)}o?80R~W(+TVE`^OSsq5xqI{FWbOuosM4&Hz#Y z+B>l{P$ei1vJu zr~r`JFbcQ)X{$HYpFcAD~o^O9dQ}o~=B`+^O|9(LsB|9f4 z_jum0bnz;^cD4CoUar{Uw1fm!Qc~(bkF4zbCi#E+m^`rG?Oc;+iv|F8bK%K*!T1bJ zd};;7A(DY!u`YFgMO%4A^tpqJ|hS(CquyGQ z7;=ShelGCYX;F>KDj0kmM7|dx=ZPgrDW*x`?n+_B58XPBMv31QUHAJlouVWqjJb^d z`b697g$&L+1aB;}8tk}Hd1gUJFCOBp`8DE$++Cgi8|hL>kocPfEy9&TtwqXR1rLJZ z-0IhO+Jcf_FEXF30H{z_u23tJEzS>?em{Lg zy$GUJTjj;sj+9DN5GY;l!qpvc7sAL^aDu7aKHhgxk6YFXLp zJ!cOi7`fi$5909x5OIi-3KpV*mxAEcWgzMrau5wI97Kzt03qnm50{bqM%&v8$((fk zkO!x51*1kjeT2*tj%49;Ck~Z(3^wP{J-PhXN{000t4E@SiL{Rqbp7y}+DdQ!d4-W{ zWghv@@8%A1?&+*~>TCdYYMphGbaZHI`yE(N#Xp{6;u^uk{2wc!(lu14P{=PEFBQ>L zrE^lPw*Q`LrHD95+(SG;9G>y_rW%Qek0AQhB^U_%y^OFC@T>lmOs$~1)#M8KcxMud zFZq;#Pnx~!=kAd14_`}vNqF#;j!Db7rm@f7-cL~V>3~`!F}_(qL(xmf826HO zq4Wpg0?;bIgG+Bn&lj`cJGQ8^es|8Obplx+AE+k7{{R<4J}|PuaK|gg(git;9(efZ zlbz&TeEp)VN)#`E{8NhTY%VH$<$o4~NxyLRrSC*q)X8mc+)VvJZT}7;`s8@4eb~0c z%4F}dL~1N9I($fyt1fO>J7jd5Ud>3+9^eV%P}gvA5xB5O+@r|Ikw245{H}XR|B`l- zc4|A{4X(Eg^582!t2zl3*nU9g(Dj!YvQ9U8z_FRAL0ova@rXbboBs}vzXTo2M&98= zln5Tn#Kdlxgqc$`|3J7?WeDzg>BGYN`FS}M%7cRZ+#I^`D;w-(T#SIjqB31Y0Om@4 zk~>zFy7DCTz4CuGIxf>MA-kJ5f%BY6I@>!m>T>K;+kGldHzc~kTKfpvDE-O7eKBDQ z7DOfn{W=oF0F#~If*R${D4K41b7Vmhgqc!MI|C!pWJ}5&ZaPn#_}L-UrqN+fg)K-a zMA#EcuD*OAUX&5wfo1^Ukw3{U(lj$=U9MO!4i@UzE?{|-WOQnQ_~B|cVB+eRuu|Tn z;xr9t!DS@C1*)4odXY$0&Gjy#ndGPFnX6l-F}O5~{+Zp#DHNP6_Oey)ezzS3l$Put zk>XeiT&cc@s2UQA1X&|Ky{Qe8cMTWly*>bhT1aK^7wg{(x^qO3EdV#gP!$uiI7!S$ zHX+{?BDSf@#>&!8nLNJZb2L!!?U6sB!sy{;1tBWLwbdhBTB3~HV~`nqE%vY~s;*4~ z!G+PBEEA^MxtFZyqLJT3Px5|=N|PejqbFME(0X@nl%bK-C?o5~*TrGFr0nUKil3r= zt7?J+CuvJ`r|+lugwU>>`#YPq7bvGLw8N-k0hNiLWwk_9(>q02Mid1pZJu05;UT(Q z^^R!p1Em>-bR6@BD^WYdaURPO>bBwcU83?%vM?DvU(ts@DV8Cqzzk4ss@Txq0R&E# z@%@x=a0q^At{8@EWmx|F)s*KM83xP^tO>ibbW4VOvO)mS^!bv1i(-^!l!Y(;1Yc;- z+F;<@mBP0F&^inu6;SB6LY&r_jd&>DL^%Hr?^gAZ2aO_Ddsp}N0DGYOQs6*`-!TbD zbUPjn;_W*T8;U$ZBnxFl)S32yIk7sZfsuh6i=K{$W0&)NA2{{_RbblOj zE6lf=b9Km0!q_E{6ZY8tj%y%QuuPn7XIH}RPtAeHV3q?5*l9l8LmDH$|U z6@o%3;2?kUu&_Opl%f(|O?^@g4_!e)1^8&dR%>8HtLj*lZCereMbXns^?nTtKa=g) zEjLJxY(}Jg=(0r>rwH=X>zqCIHqf`I7Lp|k{>y~S_tHQEPhZ{en*VRWj`TG9T3tt5 zz0^{*W=L0ZH>fFO)}A89-WHe526xmtgB=>>jUW8Hj}huY-2rqk4Kt>C&RiQVGr!aH z4t}+3VwI&n@rZJpdFp)Br`qdnh7Au7SHP^WOh<$|H{Dl(IihI9lR9H1#uNEOL~cg8 zyF#$;%4eE-;264rltsq&FMndGA5}`SNFxUKqcvu@4?qII(ZM%Se?Jz(7PH z^Eey=dl;lc625|s?H3h=!O%#%89P>Dior|@+xyp_t7ns5tA26rfOJYyfJlpew4KJK z1|Wx?DQNFsZ|}nXWpUqA(6sa6d82{~JKyGP9)FX|}hVKEe3ZqjLLB0+?SETDvar=7ZB&X<&36l~UUUx+iezO$9lc($AB&DyI zj9QUJ;AJs*vLJjy`SOiN1^wLLnSwwq9vMwcyc~FR^ZO!e!{j3RZHa7-Rt6agKVuo9 zBm?imu)d$w^}x|!NL!;2E!^cKuiss*@L2%_8QXe>G*yyuK>?4aE6~QM0Oc$K&pd z{H`xeUliDk+X+xNSC*uyhF4q>zXH3?K=WXa9d`tx-o`Rm9^$C}hd8f^p?5Ul7}rO( zKaav#(ydYwG`sQQgUhsgof3oJZBL)qK`JB!(gGB%#&2?$C;Nd`VGCIDJ2QD_M5>*3JOy%1K%i4K2|5 zWg>jzO33Djnx6TNcCkit#xb5U^XHG(ahvs@H$2$J?mW*OY)B%c{XTps<35;u*Ihtl z=wm4X#0@Cs9Nb57wwM8^A2#EzjO?r5;f{<)7mSiT&K_^}Kl|OI$s7#oxbf5DgsTE` zwH+tNuWK-i{IT`&7m^B0LMO_8H_6zF?ahc>zPXWnem?mx{qF{LgP;2q1cSoP<{y6^ zd**VOTvohZY&yYMDKwA zi~53tyG`WVxDjXlyxksXNbZxgHixc}BdH13L4SOP1xdqB1EM@9h77#yB(y^rB;YX{ zV6b43Wd9@h&j&(;U_kg2@H@g8P*Y0x zfP{Y9XaCfoL5O+Ak5J(h=v8?SBJ=!1>D#<0!gcyp2QfqU_A-|DcF<|)+Ym<{>et@_ zTB_#DgMLfC zz0qZ(WGJz8U{><&pU?jD#dE{mb|-XB8<#Fc>f+Y41;?p++z=Y}b{*NQ{0*ca0ML1O zCj7$znMv0>&-y~XM2V|M7GQv+D*ITOO4nwcOs4BakMSJAmuO6YKeDY(lE19cxJ~hV zoMC;$0TZD^8E?i#9XA@vAOn|_`%|)~1@_`TUZ`;G=x=hWio=wp-`6MMa_(PXDLuLV zmCQ+VkoooDwuF~z_##EDyu@uWa;+()ua|Y=sMmReO7NhsEy@p^%${&0kHg+22^@cw zpVDaF3Ea;R*h`-tT-f>#I0(m5z!^@b?{o3;7^fI$RO`Utui9p7)3^u|m+F&DVz<-3 zcD~W!RiVTGB0hEd2tyiKstk%#n?jtiHr6aSzib2x)8c9u`Es0g7YY3{sP zHSmsFw`~67#Aa(ya7qy7DR+DX@$r3N$B%97(<1Zs6KJ73YNE5SVP~0R-OH3|5=}7% zO0zeIvLJ6q5{9rL&+ZN$m2t{8xZp)}cQ9CPzR>4N3HB6{V~_rR?%xjzUbmCfkBtI5 zyYVsMmrbePq4d2v`55G8`SV4VfDnIZ)88Af0xE|7JdTC7m-Bsx9xl9g8C6wS&;Xyh zJHE-1!D$cmiZd8bg+?Js5X>$22Nx(JG^of=#R}-F0YtvN)JbBSLs@1Rq#MQp&L^9f z0fN;naB?30rF_?AJkM$hzriO9=IGOkOz|)BBNAK>d{|lfB(4jcAaE3_xL{i^?K%)!O*NTOFX+My-nfh&$ zN-E^-jJ9^#B-9nsdeV#p$|-k|rm?l7DKgYrX$G7e6{}%N0(uqChIlSP1d+ zU2cYr)rOfb4R&qYX+J>sG#aJ2=;o&nBVC4DWJvV}8wcDMw20HE({zrk9*nZ^>lX7j z!EnTYkP>#!iBn<++?k@xhTNNxU%BvR89JzTJ&*G;)kOIy?^gh(dx*lDI7oU>c7(%6 zpIIKZxsdWfk{@VK^b$dd=4DGwH7Pq{9JMU|$s3W7i&b@!PV&6`X~e zz#FL>hDH||_~HrcmA_;DX{fOSO4MU*Eyr+ zJ@(w?AvcgCQOcFjKjNxpgZhXTEvEuThR<@n)&E+Wkq$3;(-Dnlhq`BIa=CJs_(?}` zBxCjk65*?FK!IIH)X)bQ6_)BZe~A0LQiotsX+7?FcT??22PwYF-zCGU;I7vkwLZs6 z?!Sz)x1$!RBp_%%uh$T$XiT8kQ5*gs`Kzv8Z9{pVp8~Udy`DPV@2i$4X}JS{ykHWr z%xVL;JvIRge;#v*H!)3s>#fdOX>i{NhhF0n51kd5XL_=it)4BhM0wVFvt8yzQJotV z0>u%$%~jK31otO*@gE3?c;w>&3T(cQD!4Y^j?PHUxCrlP#c{fDe|@6l z_f=Q#1Tv}1ecl1S;-PWAH0{GTwMx5wh4~f|0l%zVN(}VcKSGs?k;P8>WF*0_T(wO+ z{|{MehxJLe%38R$8j@zYr%8FydqbLpxs>`6*XT8o>sI0?aEE6x_WgX2?zx3LNPpj)Yjgjp@T@%dtUjgvcrsV9 zXgR?0G@SO^!;4xhz8XD|WFLdzSu(r({yqj?#y!e8=2m`zV9?jylZlkR$iB?esBMZ- zv+b-x`aN6kpa?(3l$$4AZ52*ifKqxzueNEF{Szp!!Y>colX zXODI~s<5ZD*62#^jhn}Dh1kEuj!S#yy-Aft6lojbsy&HR&q{@kk!{eWc?r@ZW6{bEBnPLA1KL!pwmp!1WzMAgLei)8e z9m2(i8S5aL$KLhI=8{ylW5CtHFql#}`t*UqBVuAsrV zPB06^2mbCQe7;0cH{!zy{aHDkn@%USt|Y4R=^iucaCIG#w9^O(II z=}fYJQuFUsv+LU6H?_udNQEJ%j}t5|%TY>3*w5?Rt^ zf>yI->iUJCjv^TG-UTEKvT_V4TdUh?o|*RPZKp8LW=QhLozAa4H#>ECr_d0)_klr* zbHoZ)Vv_5pu)`FAnfi5RH%%=vKf%J)6@!&|nhE857e$boeMLTP$4^1AAo~&gD4c*P zk>HA}oQ*-6Hp=-MY?Pgi2Gu#G&HzT=8p*p?*K^VGq~Mx|M`V6p<& zfn1*T39R(ZKy;JxGjEv zRjP=Jq0sBfEpRVRJ6?FI28GqEZ`kFDMPA6`AIW<|Ty-7EiGm$%Uo|?Z0GMnAEnmaVL~<=?btu~<+_}Q@Z{DgCcaMdv~nz2CANJQCSHmI zULjd6A8zo3j)xOt&;PYTAVd#4-c(g|{bUaJEz@Yd(Wvcq-st>=^9AP*x-9nX%paOT zQ^AjJ%KbVNb?EmV`2#FZZsqZ5(w66$RgGZCn$IK4Ei`QDbo2amtAr2tPH(%MOVdXm zX)VH(gs!qZ&Phg0;Blcre_09=5Tfyt7{PdQUY33O7mxpQ*8+VE!^P5tGjD8?*{$b_ zfPl`bt(lnJAjbFp%a$&&MvNxK!A^3&lB}e zTG+dJjWnyZRv~(jw+=ht=a8IK|B50PHTicF=W|pvlI1A^eTuj2v0Uh|z%6RhPh^kK zxmwMkD-e?BQSnTNlU_qmNx8Y^o1Z)q&!r|hre^Ge&TMc&A9MWpbJiU0R-YTx3K+hv@7$8)Dkhe{T6^em?F<#@1uy6L&^HMmy_o z2_n?pzR>S>6#gE&V}msisqj2%y#mmrZkc!6y=H4`Wdt@j8_xSx z^G%gHrRILRG4FSzi7MN!$Q2m~m7f5LIq~f*@7F!Uq!j#!3xzV!RMm4DN43Shu+2`H zi1!sTP~A(kYhhYPCHy@QqQ&D%3IJ)5>@_Gf)dYtCMwf%EM}u>RK$K#z^?eT9X; zqz^62a9sw8b!9Yd*-tfYPcmrb8L$s~qNz za?8NPyHJ+B!nkpL3+vln4mJ=!Wq+jr zrPfogAd~#{Da|F~8ecWS{D3zADL^)D1-JJN5 zi<{SRFk1B2)XRg+zH8$^S^HZ@rqO^apl0*`!`^$xHMMo?!Ye%_kV5Y)dPjN@gwR_= zs-gmhCLlICDhdJtM1r8ASRxS!5+DcyN)QkWN^4z(x4d>zcDpTAmToN@pbz zzirExoi0)~0UP2&g;3tmWWj;ofzqKEVa!<=ic6W2%=l-qS{i^)HxqS+& z-QRc{P+9Ir+@HD6d&9L-l_aQ$s7oG0L#-YX%;uHUZPb&_UewLhu+6V)s28Z!p3Ri> zRVP|HL)}NHG%)li^|X5g@#2PzP%q{&3_%>(p7@?N`?deg7I(d=duw?S?q$K$Cihbl zF7IhszUl8P5nDs;*t`sPPhA7NXhr`0#2wAmzxGNC#97ALhnO%V$>#2>@{~K5S0Ji8 z>&o3;j=SE6o2OFFd7UMr8&ZZ9!J*en~8fdwnT&nGJ;_bE`^E1?+Y`uUXZPRIDuf>!th1@))Yj^|KB!0yRL48i;sswqyyw^gY zs=3A{N7nL)K-fl?G9nFuK+j_KN~1)OC{3XV4vi;KnwqjGlqTW0BJ4z}?9pvpO-unp z^VPc1>^`nSF6k;7kyD(7lfKhUNi_qH^@z@s)RUAaXB&1`90$`^(XRGvq6Mv82c;m{ z7!n%B5_@9rB($7%os~7~g)u)6eu2krgBDF}P%~d17BxynU(oS&NnoQ1Nw?q=U1rakh*^|Ew=O5yzE1Yqkx& zw(^Zm`$q7QPsaL{KHdf?3*Z}vw$u~5fwn^;s1rvpF^?umC!US*`yGbx?)KM_vb;_;T6J?MvMo4a z3co6@x(8N5R6Md(L|*EHob9|r!}+{N0N^`zr=k2JWcD%gkI#V+fBf zh&x%(VJZ2fW|fdQ_jRU3gnhq-n|FV@H<=qc;;!g#&$1a_IK&-(>Z~g&lxe&SHmfn@ z87mB9KMM~rz8Iy>9LgI2OJpk18BbXX;8aXCyhqT4ZAL%3>Y!DMp6jL&F+O%XD&d!^ z9uft9m&CdnZli5v?V%`Wm)f20?Rk3>v1|69_(UY}e99i|8#3>7oGsv8TUi#y8EmNG zV3;iALyf{#Z%iG>_sWo*qxs6_JVTd=I_H|oqdRJ^8_k$(25(1m?;><>3%;xHH&A=G z8I}3dLN;blXSQ|K{%XRsy-iF64Y-GcxDKnW&3IO>ec1Boyt310HF9#7>Kfnfzd2C- zIj_K$5rXPUo|u`-vt?rG>`8zR@*`zt&1p-%l&x=ee!A@z)hNFI6;eQecqo#um28*{ zhhTp*DUYxvo`dT%T%V4rH#u8i)Rx|26VAA_AcEi*2VEVMDKJbTIW?5 z!`5*{y*?3k<7O5ZLgY^)9jc3s+PIKhjQq;YHZ2vib!vEQ$9U`CT(qLJs5{(-fvJ!m zVhmj(4JvT~*ZU$Rq&_~W1W%BQy=tde;(Wx&je$<>#IjJ_z0MhF>v>e`r#-v?7LFBu z@X~hP25Wl7$Z2wCBG>G=xwy)<dQs=B3Y^bmcBb|lSgC`E!$^k|OYz@D>IORD9LaaRB0 z4Co5KcQIBP46@fP_-Ydg@F%t9QAMFg-CJf89#bcBBZW=FeL{8Wvrj<+ zi3U8zPAu!3{ME&)2QG}%TkiMIsp_X14fP16cb$LVYL(`D^5KHOT1jvEA&174*_~rZ zBlj!tjRjI%2@HMdD!lFVrZa8g$OEG9wzO+YsY@%!$f`$*RDIYz)mTD!Syd(!;ehmo z%9T@U+!CZ$6Q1i9$Hv^Bo+}7Q4iV^2hnUjWkDVv%9Y4+Wz&!b2vBEWUlGag?}bvJ{Kuxq+o7z*SD8r6;W0z959n%aR}~t-Oe>oVnWIy%9pWj zL4(t6!pdcoVW`-Z2jA!|p1ot5Fnt==Ez|U(WG|^R7+~7U? z6gf+v?3FO-cN|Vh?~qWhX+j-o{SCO9Vf<@gf?xXKK$jqmvw=-Tt*XPv#xPY2j*Z{U z`~1K7x!>E0i1vK+zyWsQ;UY$iuMFD?i?E0cD0FOqwFFH1XZpY&N9_wOPSW?ioY;QnOm<~-JYz^l86d5lQlol96ANH1LUmIUzjA-k z^-delx5Su8Ub8gG50Dwv4L6Rk!#Y{5r)(J`Q#kd-k0Nb`gZ;0^+%p+L|8V;0q~7ct zbKRT(sA*_HDafR`hql^1<0>^-LtKaJ!o&_q1AH<~P(b=V&BSr{9c7d#RU+N3l+W~& z<}79c7#y;9FZe2|3Ixr(Hsu|+2{kC0lb6^l_{!VvYm=XrU;Q-MK)o|DJpoZ$3Fl2; zz`*({r23Ci>3*soL3CjCy4~Y13AIlzbnciaKRj99Y*)a7JIu8jUl=~BbNH8{)%*3R zyZt)WX~h6QA^~9QuGi+6u2ZE7wY)kHW&whC-lNQ16)LUi%#z2B&j?pt>R2uj7Ahoe z$Bo_>z60O5fFA=net8U24%zkOpm_jEAZ#nkS7s1n0v%;a+r!B3D+{Ci&9mJ!(`GbuEZQDP#=rrL8#lvyb8n=$biU;{@^tbILjw`Ke zC6`u~-Qm9yQv2>zuw!pKyKU3oV%1Vx>QG{$5F^>J<=I;wxP}2}#v5aK`p6Bm*^6+? z5qy{cpARr3y})a3G-|4MUklG`Zg5k&!G|<2hA+lfVV}O=#^(O7JBjev)^4G(M{Ms({lI=F~%e*c%Szk z-UU?Lg8MN^T{3zeTiWuXearINwnaxMZHtw~g>d~#U5aF&>q58bu6I&}TZtBqmF@=vU(2MTaSX`cuy)Y&r zZ5WjWKLZj7j#;$%q`9qtz9C% zgSEb3y*6~wKx3~v~+&GOmg6sS)UZw^1iL*|{S25orYIkj5zC$e3fmEkQH+L++ z%1bm^MmcjL@xxQc>hovR6T?#X zGIBAobkw0r7x(rKnLx|RZ@U~Fb%kY*TD5w}U0p;ZHQj#IfB}c#yiV0{h4{A>!&9Cs zuqz_uE^d<1^(s^5h%isG%u+DagZ5`E%>-f>-mb3{qQ^5-O6|?g9ihoiY!nSu78uDo z9OJLDqOgMe+@p-Q$OJ6~z^B46DXZVkIX|>Tob8 zDxGQ1&&bm3c1A8o8+4i)Rk^?SF+XxsU92u3fXI*t_vT;wK+SXDES5F!lmXozCzKf% z-TJ#8$?q$RdZ@?C2Q+rU%Z@-fo)S~u5K%wFi#6K>Um2a#57FlhR$CWaF}}_9AKl{d zOXG6_Qg&Aw^4vR>g+)?;~Wzp-s3WC7_OjmNd{y7c7W z;j4ZP!*&TF?S3T&A*o%y8@>@XjZeb*_@P+p0lUPaG83_;`y-)+cP!69*$N)S@0A+# zs-y0Fih^Sy<{vVVQHfIGPNe+oZ<8JX*RK^?j+hj$>E`OU-Qm|Y>3rB+*`(Gb)0Dr& zG-yPcVAKME9NwK$09_P33Rq$MrjcZi}Y8?~DHA|d}h(fcr)dMTI zLveRtb!{2~&0}nkmpCd=u=;5s<+mfu6<(&%kT6t3%rJSkH>=MwqW#5aIiLJdq3$DjncDq1(S(uifq*ohHbLd zrn$!<%NQ#no>(UnG1(3E->~bSW7zTcL>ZF1*QZ-^@s0`}-5;mzS+Ye3R&RIBwmM@~ zX7$6$;n5`<_N4xc*p1*<8*q~|L6?YYIVF;^$^E`nbp=U+jnmE26oc|lU?&sCh6d4@ zS}m`7xk#5(Nphs6WK*4w?8nvH*&7k-tGvN9j?TKNf+}YMa^VXAEG==Rk+R#&B1A4A z*{AM7jH|wU;?rSLv@gBQ#IR&U-mu|7t+)0yzxisr{+I0v6B7kO*o1t$?A}jS^gQ;q zy)&ZQ0&aLB80i;VH(DM7m34H)kUMwMN;0mBEPS7bC=Y<~pSoGV;|ZaTEJ^fjxgZ<% zV{Ym6jDU#cdz6UJ&EAVAmG3BK3X17%BT zx;=E9M&o(WH9th@cwMBBz*Z9Aszrt9QnSlrpq~{B#tpn;Ad=0M{PlGVUUUK(e5`sM zWBm&&QBPN}-0W`S(5VNk&EN)_%>zn_wAfjcki@qa?TUYeRfOxlWGFm5Z)m+@esYwVb#6nw2TI# z$Sw0>Kj#*Avy;Z0@MFW>_y;1FE{i$6@g#qx^?=l4Y-e-621jEj+ z?$_6Iu7n-0yy?`xRtSD|0OjpLtR2X1FSHGND9&!Z&C9p<7gHfEjkU6Jxw*Y1Nr4yyF&xViozmG7s}= zHMgfw6Xb?5>rvIA&f&>}Pg+XSlgs6($#T;jRbY|aq?6G(W5f&57bQhpUBgg%eP0%B zx_<{>%BbH<3!)HPiRFtvNa52lodNY^Ke}_Lksu&Ek)t-e%Hn9G zeq$!z`vBmNUa#{d*}t2?3*W;Nu+3=m6~2} zer|`=wapCmCkb+y&BGm@7o%!R5^%xB3zNtqYa&c?!a#h+@n-A@vQ_wKr7GDkjrpF`f!dM|o3 zI>Y};XFG6}3e2q8cx3?Qn>g)bzABVIdV}&%0@gx zI+L7DDHne!C4ECiGEn@Kw9e5X*s7~xPKUNVIxhd~2Uh>^I`MQf(41nsey0w3->} zki}N{NLCD(^m2a`EC(EhW?*Wfs9+%kUBWj2$#c&zb z9cCKc^}3VcKWS@P;!ZEPMD|5AOHR?k*W{~uWF3gyWF75v{*+ruSNbl!Bl$8_k{6tC zhvg`ilD>}F()vd<94||@1J|6dODG(T5x*f7aP_XE_*GpAx{ShMc_;UmyVV`fNf1iU zMY5A0Jcxeob$aq%qti=JYE!{>(m|Q?rWuzEbr&2+gy$aDUauN(+sE~?ov@kV?C~i) zqqLj-;V7A?wMf!A8ZGr+{HLSWu|P_-(3*d4NxgEQmM}UPtSMO*{GY#F00SzM#xT z5Uw>+9z~8vnw_)Kc1GTYjVE>fw09E2g;CnT0jKf&i-9(;eSkPxK8;PgZn9{y?W%?M zr{e;DRU){Z68z-|>^M*{dYn?@c#HC5CL94H5wmgkLJ0Z$;OF2i@JH}bI3`;HZjZJO zZ^W1dirpA=9uj$hf9|vh554tkV}GV!7%n!dJgPQIjJ;A)45mz2@;VyX8hJnRYoz3; z5g`m7Wl@mWO%Ovi!iTVf-Xq@*pkht-;f|SbB5Tba7*E6BMSKlMHe(%J%#@X?P2QRy zuP9y(=taCGAdFz))!pzHXcT-T9voZ*w40+%Q*a5uC5WFvHcA<}&ia8gPNqo~&E?7DNz;Ae6$a~z^Xb=72eVJX>*1I42GI8qwm~C=bHz)##s1_RLY%y} zm_FtjVW4=PFh7#bXceBEFx%=;ziostM<~dvK|h0E)QzYg+VQSuU}$!e!jLyT#SvUbmzZoZ#Kr>QCy7vKos*?B~2vwz+Vwbi({`9=v>#0WsLI!?7X)+vbC-`afq9` zr*fpL3p6HmP_=t>G!FG4CJ=75bd5fZrT4`Zw0V>a{h2vt9coX=<}7{s&Q4-R2x`gb z+U7Up*j)HSQE~DT;TmM2Z7R%*&wc^0%<`Pk_E0VbxFKwxQ%%leoGpC7s-@d-l(2NF zxSufXmn2S;HmhUcc3)G!_s(R6WaH;9r8jZ0`5slG2Z zRUGF9%HK5|+Zs8LqZqrw`dA#PIhENXtC}w55~D+vPQ2*-CM<$%==``t*9^lRH-<;n zuqXOL*=;0=30|dQ$C~qF4u%RSaO$9JwKu6o@rq8JrvGa)34xRl9|!G}6w_os+g6o( zaA|8}&oAj)9MLNBZBlh|w@i=2dWH_Zx#b=VK2~u%Cg#=$zVVK&^cv|uAX1(F|zCJ^h@X zOH(us`V&4{K*7ukVDlsOo5fLE-BRwgp&EV(CQ@0h9YY z#*#S3^!rd|WigmagTgyW!`+cjJ}3p*9Nn7Z;uWOOfW}c8jIUoydp7>@vl7)^8I8gA zk|bYpMVW>|@%0?p=r8-a6ekp&6-<;JmA@$kD2FIt8FEwUQpixsRLWM`pcJpPUFn|E zQza3_4&_G0<4O`LX)b6L-b!78g(`Tr<%u*Pn7uGCh-L?l zs`{-_*rTvj8SD|&+Xo0$NaS+nC0>P?miG^e)rFx{bsymUp@SBv5s#aL6XjjtDJcqWbx*UQ6)z_G_EI@y^```o6>};ZE z5_qIz_py863}}=U?DU0k%;bg53__lk=5zz-i{QOZxb_HB6ZC$SpHFjfb0_Sr@1&&| zF4ws{Q^8%7Xl)fVrEmo$^ zNFUVzFay?*a0zpI|G3kpmgA8f*`vLVp09$#Q={n7M>kii)gb!RhK?d0C?9i@$d-Yh zH~+4>fY!>=(@5RtaA(QFhZS_#;o^GC0kuX|YIcSB0t+!N@o{&&7uS(k^NZw1wS6>s z(+P1H?xZUoDIVbzC&?DCc6uZE+GSSS>gpkD_+_2lvAb(`zuF?)vaR>mVfi7eJ>ynM z9{|xTyA>nb{8Z3Aw~`JrbP{WA``op9^7outaI@|EnLb*jJ`Nwn%&1w7@{V)@vGHs3 zRBO-|HA1p7+^Te6kD$Igj%2lVi0;=;+JI}>oGeCmu(;@GkZnoHAi=qPvr(em&dy=B zSCS~Xlp_+wlorYcYmc`fHfHZ^Z=mW@C9YXTQ#B%iAkUY zU+dfvkv4IuAga^kzUzXCU2}R=kv0CbyqRpcPPh#%)NA@&Uc1s2>X98FlNv+$0b+7x zz%}Mu_F3J6-&4~bwF&1bguJb1Y)!g#GXOmsaV}{gN#g92DCeh%gNfJGZzIy?8{nhz z&G(Qm+Zdy2T3Saq%J6iqc%ls-MPXFOSTK z!TS;w_gg~|&d1HmBdT_R=<8s7FOq}UxAmnV_N6b ztmc!z985m^2zVt`#LJ2Ee0>>0zvtorF^PQpEP>=y}?Hrz8IC1oNp zX6D4Hx8T>rA0{#^Y2(-=olaESsf1k#HLBOq_rMWg0l-vBsBSVX0?K#aihL4|sKlrx zC#IR;Ykh-N4kkTL%xpfMbTO(o`u^t8mgpG9)jL|s!6wRcn=$(>VVeQzxYDyRdq&{p zUmk&0pDWBpv`5yd=d6p|>X#pRnfs;+-J+T{Go$)LPl5#HaM*8y3xOTLHNc+W7T&Ly z&N&CW1l)qX!0q$N*S0pNjgoqpwG7Kx6JD=4$#5vjZ${0;?!2sd&OrNu7EdcBShO~~O}kUO>2iC%xi2$* zsFsa0(t*%_w>tHdDHtQ;@wA&Olr>xeuPduoQz`G%%KWvM0tF1yC|aoc(-4C)MVn#FhY%xv)0m`J$+&&!Gq@r2TVMjW z7&m&r2Oo%&EWCj;FLXb93kQ1z$GPM7(@5wJ(xr{S*#U3VqB-SK-c9tz^W|d#>y5>Q zgqqexMM7`Z46vkp4Twh{%!|B4L?O`XXzxpxfsL2ut!(kTldYEYAB`fe<-I|tva1du z^7Plm>IAPG%W1WjHJ0K_w4zH7)_^j`?G7#-~R!?Y&Rcm;=RDzY)(6? zx>wC?LS6fbhP~!EGyAfYoT8}r&4l}_N>q-{`P{R1%qm+5zn?6`=RU{UzQ}BoF2kk( zrn_`#J9PDa>FXQZd2DECWV9mPICHIurk0krwodBv%hV|)h1+XGrI|OCESY>I|C0@kQR$v`z0tyPnB0 zQDYnUKY$Ty=R)7aP;DLVsq;5n9Q!&=%?IJ zwsDiGHC5T|l6BUC_G?byu*53W`$TZK~s+MQ(^x0^L>aE;lwL2WBrR4)JRwNtN z5OjprGvUD`N4K>kk!F=#bctxIwHMR!mV%sHkwRyKfpVAi7#$rOB!BkD4Ya^ug0m(v z$#;Ua(<57DDAC}^11Cr4jFo*&n2IjTqmOtU3XHQFI<7VgI1hKXw0zHyl6PKbUwa3F zqa`s|voo*JzByz!nZ$F)kYKAyp@-BSlo39IcUR#@8J~?7p1Lz|6P-~u68A_+I_nH8C;<{%uKz=p6sa>cfK3PrlC#h3sBVsH7gGPE5#l!hHj zzz*%kaucw8c+>OBp8hTq0uz9}0tDYU=5$!)IMnX;4JK)6x!oU?p&IPadF&7eJ9Gid znI3Kya)Kr;yVX-#WZ{0fY&3ZsPv7}JgSpo5obn5XmT%;nPS@R-{&+nr2iTtrWYYn7Ai@wCvilYajX~o8 ztjOw3FfpPJ!N+GpJ}+PUZCqU7dRO;5z~PL%sHs5z2>Vc3n4Kq4b_sTcEc!)0Tr)!F zVFksU1^UQYvor>N9p+>esbX;NX2Z}!#+V@!qYb8*2_NzV>6=1j_ z!&+VUrf;Kzv>Nw$JSA}lv*`2i4F`6K`i-qSlMz_bvw;*&4BlCLV)|B};O9=G=gDy* zZ?7D4-I-+WGuX6ei_r=SI48-mW{jda9*j4?WP%y5(GV}@kOcEB+QIe5wA$*R%CjA6 zmU)<0aM&weLVgeJij!3-x&We0`RGrZs9Y?ArL3B#!C_F89eC$~`jb7oZ;7!=M?wZ5 zo|YI+S^p|$#gjFXyctRQJ{?(W9V`HB&GuDMYHAYpCwP={AwR?2 ztt{kvRqm>qrfnbEZVSwh8)wJoOy5Uy$N1>x=ACJ8X)H&dj+He~(x`+OHrOvdJ(zLx z1A+#Hfbh5OlKeEOzz-G@_lp?6JA{D=j#iUd+>s~4QjtA^hKTv z(Q6H-PI*R`2yLQ*bP5!G(k9Ip7pn2agvxxBP@IqReA(im3Y2gE4sXIj8~2?b&^6dD zW&bAGla}9^wzcJxQop(fx>jTgG`eJ9bQE%r#D-|w<&Db8@x0}*m%PA?$=)hx^YVL@ zi@ufJ9ltg?k`bwqOlMpqXNnJ)eeoyNla7-`#Wlq}#cAS0bL=q=;~fX$itWBGTvxeo z;@Dmi*X6bATB(~NiG-$=ejtw&3nz3!6gQtZt_UP+v9GUr9LgrBpv&eH1Yg894}M@P z6g@|lygkngBsKV8x_wB+Nl!A#M6t$&gG`rqX9bi#?kSqkgCom`x6XjHt~qxL=20weu2N>R)AN?Bw?9F%oJ!dE zj4wpEg56JJY`P+|c>ySaN4G;QJl3U{2TIS&mnoVT7Nfz$ua}$^g`m+CTzz zj6qTs`1u)Z>F!&ZlgDNCl*A^czgu_x6l2&-2ytCwF!#!#P)S)D=q8)EElBHY-tVos zu$|Ph?c?Xy?WPpmgPeP(RHyDz`=_G-rL_cEcP7i+|s2uwO=3# ze%jAHw!8YfU|fBomiu^V#Igqnkrc^dq!jhszw>NiPH@w4WeVnk9D8;jL@&(Ug|U3s zkX(qWN)b_JpvO}`9L#J)XEG(h$V3cA5zYY3lQ1lRJ^Bir?AO=bfj2odYlZkEhG5k7 zk;yRZ3sLL?%oz(~a~lg_eAE%ayciGcCeq>q!IzTuad2B;tL8 z*3ecQMd1sZB>AtJPz+UpagQ#hE~bt^#fq#vn%Q+BKTe9(QRr0{OBQeXUdtmPgrewQ z0tC1K*K7K2ECxaQy8z^b01cuM2CSv%dHP&=^aA}Sl%1w|u5=!H{QfA1Zq8GE;hg|7 z_m|eM34zG;B78a(KK&3*dpQqeefpIp^eFTw_kgljE&nF77lhXQi6$Q}FRxnm_Y5ezn>>l=bmgW!}fE+Qb7pG$~JMBXe5(Y3ThZA7qt zczMx(K=c`HUrsD76_7rWCGcz*<2arJTPZ|P5961I%Iy^BW(mKr0o_bG0G`4Z3S`-U zNY)>9q3H5`#t}RRMJ<8aLOQTNbzqRr?>eLd-Cyn%{afcB_o06NslTiPt!PLG1L<&& z;OPMOIR4M}NDh_`=Pc0y=z!5G0gmr)PGpY%#PaoLVI>4kEP+kXprH@`YskO3syQOR zTf%4%VKw6mo}CxGS8wQ~6*tp4&}TWYET766%RkohPt;Jjvt z3!u?U3Fr$DtGKLyqre~wAc}7h1Os@!Y$#FzIQU)!>J83El%SUf56w{?5}HF42S!Ij z1H{lEGmxQ&<4Oq_D{#x5k$|UpDnyn2Dlp)X%4d~1+0R2NT%AiIZ6IE*Qk4I7+ zpAAlFp-x=QUFF88G-X)z4_wu*Iq7ZtuGDq?k``)t#5N1k$Y*?U(Y|%D=lg3b@}0UE zGAH0~cQNrjZ=j?=!bV5lutaB*%!ntiRi=#TISw(dhzY*bdy2ljkKmy=5!8dSyk{~E zpGuuL1$4|ATdsDbYc21k%=s66xqf$cSwob{Xtu8|_PHUe&1=j{!&iu6W1#c_?m}7n zj^hICD?C*ykg_7X0V{Y`?I-9qF!~}3<*jWLug;Csnfrso!u{?Oj9k-0u&vs+6kRSG zN2(3kv7v+vyGdivw{djDL!Q12q?^&(q!~&>B}kFOMd+t0lV_e5Au)|4)2g3VFLDsw z8d5wpDSBR)&cmTD6Dh_GM1z#+PI>OSNOPN=-LpH&?0#ar7;~5#&nkk0Z~J2qwMQ$9 zpH9Pt^he1*SSeHKs~T7iPRHDAIeV)Kw6&Dzotr5>#k3oddn^a*)W!=c7KS!hxZ@oM z)p;jZZn`W@i{7Y2E}e zbf|VmL=Ai`XFA$!%=v3t9z}qCAP^s7nFVwcIRmxF4N05IvVFOxUO!a z2(k&TI}cIS$Kpy5BJe)np(fb#UVNrv%Qx%tXy1cH9sSXMbU%&*Un#J4u#uLSmn79H zsAq^+qh8S%$k=p#t4gq*edR{;jE%cS-WW?~DkwF{op|Kx^kMu_G1Ck-@{{%g;t3TI zj9X9Q7M~rU=1a_iP0DBSER=QEbIhFU`;%TJgo!@!rk>S3&%T}dN<$iZ(9%n4dmc|{ z%r58{$S$b|vvz=kQ++BYnkp*l%)H+k_Ora-4^*n2xH>cE_>;R4)8L;pYR2^oCnE@e z2o6ag05w}NSOgJkM@*f<<3%<#t4V9isu^p`saa`DH^?qb@-ov8m#I%XoT=N5hO>}Y zcQ%g;MxL8aA(jbINPRbbNwfD?Sq1F5!OJHV5e_q|3wVbL*gD7cYhGm1uT}K`v(t(k zlr0l1=z-Ua32x`5%BhZU+IwAvC`N4@qb|5U%&62e^&yiJSLwi;tyE#DbPcqeu>RE# zfv^(;@1A#KZYQ#cUHH}$J@b>cZ~H4{nSKrZF;-oBI+6q&I<;$chb|(ngT9(;(2&aY znUmJ%nF>)2GTS@W7L}Hw%k*1IsX3NE!pw}BH*Ij2!zGfWJ64gAfolnogwq7{7q|lQ zR-XA*7=3}dNBkvACD($zt=HV94noQEX-$ZC7JcR5qB&O{qa}Qp9J~6RIBJ3eivwyw zz8RQo_Rja6g)nBo+cW*RJ6G;Vp)6md$-cp`$9lC0aI3^@rkvVM==e~gS9`xMfHo}I zCm>gCLGn|EMGAV5PgjdTNeBp)0wf2y?{m2aSWz6S*BS#yGJ^IymNN>=ORyh`7-!=+ zB$s1~0EjRQhkQIlbcts+9;odyfbDj_P9vk%?z;+hCxBKSRY{ChG9wtTCQYt8 zMu-|BCJ5vzC5JLGBn*d@kzA?Xm1Rytyx2TZ`0brY4pd=tSI4@L z4L9!TeSREVnM335#PH#5jSJS?#FZZqP!77Zraa`3$?;PQXkF1Dx#Kr=vjp-SeMYZ@ zOKo57&tq;~#ou;-FP`t}1SiD5iM}>9A*f29<{7%ZhQMh_k_fRnD3DO>*QwBpNWN_1 zmecA`5H%>2Z>%J|;bvXDKqfS8pr(`2`&sAROJ&?e4wApsb+mD2>wZ!VMB)fd^G%yn zeePg?+c0atX`+g@p5-3R7go4Fz!l|(DHIH++6}&sc)uVk&?R9xGde;z=LZ9|)$7xf zsWslLnDg<`Rgeu}b&_t4`%Tu7RfDN`p)W)E z0e26cj}(xgAEk<1?!Eo!q2Xy6e=pf>X9{X7rw$&}g%u@LY83Cl7Hz;*Lf{=4T9p7c zQS5=`o~s&wva>e&U<6zAaE*b4G8khI&Punj=2b!snhz_lsjT~afk}RRJe)~-%p`_u zM`|4_6Lv>coqhY2LB`a~_800R_y{41dl6whiG<9iCc)4pgkYdhHV#|&%K5iIHqIOp zlw6vI1Q%#;XyfdC*Cx9IhAR!Pa1;AOjEF2WOMG3Ba205rcpJOWi zc2NCM8N$GaNbn&Xd`JS$#liWTAqSNr1pNHNL6uG=VT%^wMXB(jhj7T~&YfRAEm%Wm z0lEbKZUOzP#9H{71L*x}m6wP>l`qTUkBt4$)cv;35s-CWI^Wj=2!!Rr0oi4Pe7P+L z_K!xA|FG%*apP01kjD57=k)xeUp=yjpmO%NTMRO$AUhT^lHlML9LT_dY#jIv2e#qC zVLaqe`%??D8p#6aBqgA6#RZTxDx5d|u8XMUL&Tf^vQrcPuv1@sDG`O@5&;2{1jq9LJIl<2Vlj3j)F*aX}z5sJH+<``~|CuG7W>uCZXqSg_hy00ns=pxetv zD-Ak-#W5TNARh-=guk!cuQ>k7<;Ui49R~r8C8(r;PjHo4(1~@g5-1wQae^3t;5l$l zfb(492MN9yeZ|paOXg@xY=Ch@9Oei}EiI}1SBLoGJP}%D|Jy>`x`g?+O60|PjKtE? z??ZfP3Gr74d1(puACG__Usr!{wWGi18qmpqO#q8!1X`MdEU5h3?*BilizBniz@Kkw z^!ptlr|&;|?}2LB5@IMsj?!QXbpYodJ@`vKTgi!5I z`ET)`Dt{$6G&D?2HB9~8!C%M?A=$D#by?%D<^NLnck;hq{7;?%aZJ|l^|`#dp!EZl zzg|BexGaat@&f#K6ZS`Y(9p2vkH&v3hh&iaPnG}Ne))};7yt70ulk3ER+Cx-{e_14 z*K$a@Tz-%6Klh*dr+8W6KeYdM%74H3pEd(aS${mAp|t~ozfb>Ref%N+y)Hp$mH+kk zCGh|6e3?Q2=f2FI-@eSUKYf{HIBw5h`7+tdzD)KX zzRdIg*_YY#FJI=SWh6u7pGbzVf58I&iDZcRH%JDk{u{|4A^IPD*(V`ic9$bFI&&Fp z`A6kH`m(8zFFTq={lCta{eOaFkr0EMLVFq4|NpR;0mF{qmyt}S#+D|4N>Vz<0(20A zK&~PuUj6=7h$vJ40C^lo_%5S6M4&w05`=PNqFBu37C#sq!eT=qaUJzzcu^?fF`kG; z;7~{+4vP~d0?Ju91Q7+x#rewLdE^P@qyj->6bc6D_@=Y^gtC;_lJ-|vnX#D;V=bPS<%J9%9K#m}`r+OQ*+RZt$u|%oDiu^n1GaO`;%y{WEtA_vWkwG07jun?1|bf*-Tnzf{Mbow@mgmO5HwPcG7vwv%>}c97PW8DB-_ z(IW?UBt6IQmtu_jW)AWWMGB*NCu~2xxSEqURp>QJfB(Sc`aojtWV4?rj)^1Jyzko8 zUV^EaQgU`FX69U^zniR{Je%Wb%9JM`Xk-2)(LbF2@sXAJYsCkxk1HzXSPsn}Japym z7?5Ls1-9O5L)h7*IwtWCUd{LXw(C5K*FT7VO z<)kPja||PxF2qmI;eYDQ?@tijhz+FcMc?5}N%zGV{M5TRam=t|r}qwi@i$V@4^rZV z>&b7$x4%_mjK77Gc@ySy6HiF^?umO`ea7&FL;J)kJt;{GTs92%YnfpKgt$-+T|{7r zDh`=TjtZVT){k^gAx3CMLSO{qmson{weJGCtj)B&Ch+p@^W@|U?-**j#a%C*jU~t_ z{U$p;$lGWd$C~lZXd=w>Dy;!Cy=~W2aCSYV%`ALhe zy#jFA3g|b-vCTDgT!X#=x`tt5)n0D$!{3cJc2qc-YC`!C>ITlpC)ns$e!cC`xkFl4 z&)N}axh<=kR~ch?xkz7kouZ+-U$Ta-o%Qos74t+wP?o00TR1HA%sQ+8)!uyuHTk{^ z9uK_)5_+#fAOQja0!e^C=%6$y(gl=`^xgyuO({xKdhcD3-fZ+L3JOS(A|NW#L4@UZ z{=2hhXJ=>koEPWKKFP~GGnsrcnYkzT_kJ!@h_t+v4qa2eJWLiIyDsrjTha(9hX6kKhbc_ri2G8tkQTU8#ce)(`J|twS1(%sB zKQ}w|d-Wlbi`k5io5O+6iPjBF!vX~v_CcWvTXo8en!S#a^y)61Yd_ZX9mWj@%1s`d zt0rcN8N|rogsVSdgqvf;Q+Qr^G(N?DD+ATOR4x^pOboh>&ek@U>=bj6N26ePivdYf zZbC+paj`ij&8%Gl@f77v`vQ}1;wKQ@pp0}Fv_<;GV>imQ<8~otf*IS=H@EdmsdNQ5 zkA-q%Wg${uJN+41U_vRd-|Sd)hc1_vmM{h$3YXB5@lVjwtp9wSn1qPxyQrJA_Bc*J zTbKxI`MRLC*B&%)CnmMJU%gWm7GXnMt7V(I z3(33{^`(gs?2^Mjy8F7dIavCgtI{+Q53`q(W~d@a& zhHE}J2HR!E?>dcY;yAxnP8_dD56|Juox zrRFoI=JTfJdqvH656qVXzFbNEFFVE$6>hN&mE*m+LC> zf4k=2TF(D|&A+vu|NWZFmhJw&fEXAod3M`A80u<{^z3Ye{VUv|F13Q zf2L$$B>B&_yng?*y#L3P7xz!fOG5o$+VcKqN)|@ao`%aZG>y1F@lUl)ZuGxDG_)pR z^*@gc6^eH$QC$|0nkWh7yG_r> zL|f}ig{Db-8J$?;M|GKPUnZ_>e7oJE{g;U?L)4x{O;kRpVHd?UXm)d>WY^;H3!)qi z`;t8uP)?Bj`tHQ)`d-}cp+qk#9g#aPJgG)Ks2-;Ab#Ow!e0cCst%uw-k7TvCG&;Pp z({~LiF#D9CQz#=Dm_$5b&~!&rXJ>~ncw=XEFzxC7Fgvl&`tR0JxmD~YkzzpPFNSlZ6n7-IYO^OM-u;=@=J&%?{*N$w`$e#TmT)mY~JvC{O+pox4$l$Lz^RX4Zd zqqqHo=GB#qCcyO{p(jZot3db=m z2X9A%JQ9NurbZ7xyUighEsXH?YQEr-hE?YvP!Ar`p|-_9mSvB5rI2uh6c#Chtat>1 z2@kCd!LUUE$GGeX6C$i`0rDN6QN`f%j9A9CZMepe8{8Sioy}ebL zVEG+6geFr$i#>NY#bXQs^tEt8mUP+-ikp&;GLD|sE*dJtXnIlcuRs1K-jR)w*x~w3 zVIU?af0CRgxR!vya=>y_ICkp72;Gw0<)f3Qve-Fov^=;2ajXj5(!Q zJY*!_T8M|;4>^s~z>_QoJBn z?l0$uR1ee?6nQ!u3CHM8>*C9=vaj+hq-`4WHZ;@VeE1Qiw4;`j8lMqqVGkUPOmu5a zCyPhyBV*{URI(WOFgg*twLF_@q>K76eJfneHyKBpTgpVuDfeY^4O6f-NVg_j9wK|E z3%#DGuH&F-YsxTnbq%X2Iw0j7qpYc6SN>-WJ%?YNQytqJCN#e2z zzBZKk48Ehjx38&=_0G78U6y{Fk`c$~Ke^FjJ*mM2R(~wW?bm121$F<3{#hA(Lx$Kz zVpjnDvf0CmGMq;}i#z1Nt{A-E_@UwfB*B4RCi_Rxrq7R$w+z5-f=~r@wOm`@`0rFf zM4krEuOdHa%ez?kSfzbLSGiz_X(=x8J>8oUgDo{mPP; z;fc?^6Kf)=$=QHEO z5v{4ootI}sbo21ua zw|Ev@I}bW5sz`V-UFV!`7cEW}L>dYX6;;X;IuDjt@b?K`h{$Ad_|2j%;=PNmk7!3+ zMXiG?C2NAEUr0C>XinEb1JVMPRD6S(Xj}T;|7w3m5vt{zq)iy=7;b<*eq|&v!DJ`7 zx%h>d^g%$vsw%gk&#h&&m>(=ui$Ur2<#dj@hw?KmgtoxdE^UoD&GeF0%BOdVH?67= zSqhdV)kA8MISK(Pc5=%yv<6x=+p}s^p(li6Mln%`hP; z>jj7^|D8`!YiEKe#WF0T5j(CLgZnH|acgMBZ+jut@wBiquuQ6^ak zZIX??I1M{HGYhmwJcW&&2dWHW;0Vc_3OD_Lt{kc%e|hMCc=Yg;(o^3zoQ{_E*Ga?H zsrX#6o26EWM!uA8x18UEFWeG?X^E=GlNTv{M$emoTQWBzZGB-0$OR9FM6+%S*2F@ zVV3ij`gP6ann~=ZDp%~8pd9;YHv*OY4fsqmi?uvRS(-18-xyT8t}CC=O9>8e9dLNc zcl_SJk5t|`y%+KD0qeA3Z2_$LsQ_pB{!E=q(T~kNglBD)hS|JNwx&xG1;=8(6+AX! zs_wT`s9{8lpX_XX3RFd$Z&jcFY2CvEXGPjSuOlKJX4}tUMR5UKFZb`QZh|UJ_lD~bLSDT!RN@We zP;)3}_sHkTp_;IiirF$3MKSo%J_k%sMd7j zf~&3SFltIy-#buK>A~`>XyCG&#z@?P-z#MF1FB#@gEtvLyJdM_!)2-AiE7CbSO3WM z>7-oG*!bOSoTnL9%5~VI9`kpMx>P|dnna@ z+19Ivs{}L-(rg_F;}qmP{dZfYm-Vvieu`b$Fwk`C!sR+?4~E%O8FNie-xL-Fi?ShV zj0ZYI;q(%qX{CjJfeE*K%IKo6r$HpfK49OcL%DU|Uk!9gX-nPVv!xv9}@oP1<|u>TAp>edD>;v`;_VOyAM4ST|S1`(o-w_ub8NJZ{b2jEg;FzI(@NBmOQn zMi%w;mYgFK!&F6C?E9#F?0MGL_kQP=-xff-WYNn`hGH(AW~A1R4D9?yCA`xtV1bYD z-Ua)!^GB0Sn9M5?-=BPbaIARG>GXZi)Dx2@O*wiDv2l_sxQeTTH|@zJh5Qw>M=&V( zSj$Y4;Fq7{nvJX>U+nfl742!8ki77 zeE<7P9~Og$8%lX~@?}R#{v7%g$v2SFQ+Jpu7T-wSA1f9;RP?(CF?i;CrJt8PLy_iW z%`5CzwoBWF{B=X)>eZYeluHcHn8qTblEwn5Pme>{>!Ic`%W3>;6@Ak3W5st%_U;N| zLxeEK!6jx;{Ce=*?6abuZt-HGcshFpDZGPmcGIy`n!kK0hr*AQwJPqI5aDYTCWj&{ z+K1hWh3Lk+RS#}F$F6VjoLE1~^hF;2#Lui3sBSRLYE#P`!fp<~{YD>02Ti90*Wb+% zEcU+bfaSaRPA)0NR`>L@Z(O4wH3j+2A2vB(UAfB7Hgi9%g}(V|Soh8AQ;$RptwkB> zZA2y@F#}ezvkr=Lc57Bfe7^2xI5QEmj3u<@-BY4sIp=$$)q1FVfaqeO#l)po~pLlm-#rn0)9l|SlFnZ z$g?%$u3{wua zK+$n*FR!Z#%Dd(@Ecpi%}2dA>Zs(rWK)ZX!8#?&nNh#OW*}SX|WWpiti)^vV5wg=?y6a9sTB; zqH~ZxX2!%M&XBb1tc}_{j5Lfaj64EsN0Yo?PB#o z0V&&#qi7b|FXC^XA`RkfuOzD)lMbc-G@n`z{v!~NDSFRdW1al?dKX+0-hWlHBx7j$ z-d2qX15a7v(DYQ!+pfnS5n7)+6&UCCRb!Z+-h1eyY+9Obfp+=Ow+q+O2E`+Z{1Sa@Glmx5`57OaTP*FLPWrk6EWCAtwoA7 z=^P$gn0cAsf1u(M|3gjZDg-TMWvW_WBT&5gpay9-j)mpx)?!rjgKxZ%40U88;r73Z zro_d@qHsA7KkdTY866oNRyE`MzgXn+Z1q4)ILTl&2x8bb;IF!sF-Z$EA>+3B*FJez zihd=sm9+V6^e$GY;!6|RGgpSeV3TsmBtcG(@vOj zWiVzd%US?zEG<*dV{tIQZB6u!y-bK@PcyYc)jju9i}n9)x+4O}OLWd~mKxscp|FMJ6b5X2!z+W@F|K?1M|^p!z~Z%Q|GW zyM%_9U&+Bt)~w!Np}fZ}$t&2*dUR$f`@zCeb?Y&*Wr1F$c{3naNe+5E#Dj&=GOP60 zioDc%e?G^9s+Y%J>AR^vmUhjT!NOP3R0z?@VOHAl^!DLEek~JOpPt5%o5aqp-c4Q4 zN1){sR#z{#Kk4D->f7$!(E}kGLpYXvq2PmfSyR-3LO5FBo$KB7?^p9}# zE|kypILsz#o(e|21B-jZzx>*e|&B#Hc|?W3%aRycKxhhPkC#IV=tKHp1y!s81%KRfaX1TeL+luXnIDHkFI=ZY z{W}D*mG&c4#vV72KfW&Cs%hRk%qt~RiXDj)w?UP!v~R87$@B1(F5ac&usrSkW3-s6 zyJn6fGXra+w5di3Wtjhx$oM-HktHaoss2c2G*yU+VmQF^?>sK*&H-I*O!3FYd{T91 zSK;A+U(YpjYpJCaFNaTsa#kusuFJmtIvSHKCSPv8T5?X*k}#grbTHG$rpv6{eP70M z>yf6YR&aF2kYqeU(eggQD9!ccb_-G@W$Xj(F8nmX(yLRdvYeAfNF1uW_RG?nm_JxXgO16+<-?~M_uwiGnT(z$QLy+k`#VoUNSG+i*Qf1ArA_t4#-wTHC%%G%%BWZo z9MM{A*C-FwH}9YcxuyZn`kFUR(ki^A_lq&dM?u2DlPz@bLS?wXllZ4BCTO0+74)Bq zE6&G+%Tx1rEnMtENWQ{7e5|1?NQrkcyd;iYa-!Z)9Rtbrv&|aLKYpQiCz)DSjK_KO zl}-44e#x66ECOaB3h9TtpBY6gmK9!1%kmduYdsQ{6*l2;)Eg1NVL>OtHBibl&r%`W=z=LA7ta)*I`c84fs3(K?MKz0$oqH-I`+j`{D8 zpu=jxu20riZ={|bZgA7Gb3q?0AN`rmgE3Kk%q<3a)MCzNW<|W^7!@ZzE@-s1YE+{z z8W824@H_FL@KpG55lHVwXT-p#HEyeT?)_&qQUXuTXV5!r*#bc|f~SfBg@Gl>3N5BX z1E!t4iC+(1@^*D0_vP9S*1jnHTJc<4kOjw=6+TV>P%{dbRY*E<(LSrxzqPC}6>_gy zXR%-2*qY!f#O2>j;n;o1qK^(niFh)8)Q%7xICw$EY?Hfw%{#-TTl;sgHA_~w(1YV^ zS0S(yYj%bBo9yryH~-?mc02k)_>mJ1j}d4K{`ev_YRCwevhk2!A&F#ihMb+$tq0sB zI|n{jP&a-iHhnO!c}*5=(;cVPuE0#a+wvgII}k%I79(1GoWf1FkzK9&B~b%%I`{EQ z-ffx>;oq6MBoGp-I!$e3=eh&zYqIPd`q!wXA`{EHpWPcC5LT?$c4QPW^DKe!u+|bI zJIA%2zQ|5{EVVJyY}w{GBvPUyW<^Bw;-oEegGE>B$4jpAuBnwzZ5n|{*=|GA&|7>B zM!J;u7N!aw+Ui%*8Z$V()@(*KFWjG{*H1Y?_Y62hFvv*=ADp&$o2Lk`j{bEa(4881 z8ZEE?GPBn2=<(S&QqYrLeCH!=Ba1r8#B=68azqxJevii-Sm3GZEYEY zu+3U5PhR@v?~NbH*uoJgtSi9`wlPZjVo1|WReSQ;Nj}AoYh&4tM@ChOCQZF}qZ^Hr z%EQc#v5gu=fu`dRRKmr+*S_C3N)jJA?Te2Pi=Xot)|I`Gpo<<>#ZT0^--MqR3luz^ z2-#IkDY#Y^PAawg!2oM|?3$7$@M(PVONuqnRqNvnvuecXoL4qHVQE@V5U6 zZ>yq}zM)Y=edSOS{@N51Dil8{{8@X^heyY2m?z}>iiBWPt!(2bSI%gDE|;+iW(ly= z#yZAHv}$PK6sG*XIHqA18ty`%kYS~%3sIALFxC-^kIrsScz06ZKK$+7Eft~kd%SXU z5qtMNhla{nA8pMZ9S?>x(ylKbVXeMBbi8-7W*5ExtW31q1`V1 z*r&MXH=M38hAtocKmE#u!I>ZRms6_ z`6;Q;2`m3?6F2{bi`u~9=-adtt%=W)R;dM~YkM)L&(U@f;0LN7t)qysRWDQps~}Z% z7(q_S+;(B?Hzvy*)ztCQILOT}aVYnw=_Fwq6m~m!7GaFV2^nG6lJmYs=-|4a^=JM@ z@ubcaHN{2;Yja4$=_6|)k;6}?ct@?@PpyfBtx$vsKM0Xduaiii(bZnlb~0+hnM1yb zl1s=5uY&EvJ+d~mZ8N=M1~u_DMB#bl^7d&k?`_+57n z_vYY{uCmHthD`h8Z;@$S`ED5&oj>TJXlE<8%!NP5{541<+%Yb1#b_zDsiK)hxeDV~ ztXSt(n`w?yUwm&}iH>*DpL1B7k{NLL&5ZzWR<~i`^5z1`A3%r(Ch}RS(IR$tHG*Gw@ZD00b2};|P8ui2*8!XL3 zf}NZ>;^(Y|eP4Ol<;w4xOO^emb=-rtsOAYHuLK3uyY&S=&(sxiV#O158=Glw&E>eL zR9@ThW`-&qQGFXd8TBaaLKob$z_U|*%FC1IRGs=e92b@taV#Xij+PvsOc>>r={K98 z>tL~Fv|sP_-f)tTLY{VPTJoY1f4wJlA=IYt^lw71XcX&qh`=xs!Ms$DWW6L0-yQb- zwQ(t`eseo4_bDBGGYYHYDbTczRQ<};{&f;2aO~jpIqqYL(6jL~N?3RLJBxC^Ly=5G zz00#D@sFGn)b#J;n=DsFvx0LzuwW$KsN$!jVli-bp@D{AZu*Dgq&`6{nHq%)#_~1} zI#<*J?!F7i$%CoL>ApXRcw%>C!K~{T!}9Ej);$AZ|fY!N4SL1BFmg`lN#&|Mlf1@gWy5SPN8 zk#iav&{^*pdG8wq+tyqX@Oj@3>TBfsdK(A)E;&t5{heRb=WtSAbsEQBUROs2(DBIg z*CWSjy#%n%dE_xjv9o@x&ruQ7xBX--R*wx8#6uovOqHkhY3F!;3}pMe=yu=F^Ydve zE#>;*`NCK%L`;MrS2an}x-b&LI%e+@G}0SprzJ!1=1-4QY2FIM(y2`s*Zpi=W~L{u zJsJ>H;t7q&4ZTwBek+ZiMEv?2 z{0lEO*=Fs(j8MC!I}KXd;r({Z`|FHVQh_Jy4(|+E_1xKuv{*jKtoYu!(jWTJ@!)jl znGeA$$0hVs7=u6K5qslGE93XRKG*^EAA{<_+6ox&NYJ-lqLn3*<(;_}j$?|YFp4Qz zlJ&3nSM z;N|l8`qPVS%ZvJ3J#$&~iD$WxXR65TovwFY(B88;!kG*?^~%9fdN1t8l8__%rHM;9 zv}!}?*RjO2C76i;bB0-3R=$Z@`VF%RGq-75n1e0#qsVB=z`r_FM3EJ=r&4QhqI_|U zB@yC$QO$fgje5wVUiUR{Rq}6R=(ZSYNddJZFI^9n?uD$Ss20B^(1?wQZHQIcM`gyj zK6kCx7U)uGsRH>WR%G3%h@>g)J$~_6N7pSSQpHv8x7l(Df!&YUfgr>Jx)=AlY_}FP zsF8JIf;_OF_}d-Hv+$JUX9iJj21wiz#O(^g4Uz>v8nO^R)Xa6|$Dp}E(yu^_laZQ^ z21FjW?J8Fz#@`i_Rg@FCq>{{KOU{;01XPR*x#>GPkC(3MmzI#0=H9QU&RX8vG698} z5Ji+}V-7yC+C+8sQa@q29M@`GHqBrJ#u4B3UATvqZ7t(rD7pO!OHYW(H%GCocHGiT{v+I7&*=Oe>t!Rwb^u~|@6gU-=*+2i=lW+{ zB`EWRfr1U6IQXO9*y%QrgX{oVou^t!wRGN{s-c_yNDCn?<+R#~xP?1W>ZT)t3U7?^ zC)g3J>?5{s+Hc5a3t51tVu+vV*<8mTtNfs!U82P>t)MJX8jGe!OK$Vm6;zF+KW=X) z=7s!qf!PPsVh>Z8ZE#=Gf_6zxro0I>ei&MBPZ1r2$nQ=otsV@219K1Mw{>_U!JU5Z zuvVf;A`~M=EH$Ebvr7dtC^5VHjltCuCEpXhza!DG&CMszOpG@`V>Gh2wKuywRZVeo zx?_4j%S?*%-9QqB;nzhF^1^3xlIl#nzNNG86!c01HE&6}I@$J=${T8Z`$@-Aqp9%& zbS3*~a7&2vl`tXM3gv{dV_o+Xz3}m@!B0djBdMR(;?_6e^F490KR!v6u1cmLz0t`1 z#T?35s_$gMP?;B*Dvb;cTQLHN)#gw^x1pE)uj0CyRxw8;XV#>XCjHQ$Wv|wtBJ`Kl zRUgw%oN%~76$~p2v(~@*#OB-8%om_M1{NO29r{et&xpr+#w;8df5%BC#TAx zoHlnbbIrXft%n(T!U2={3miP$s)r??a=6q)Pq&EGnMp1#gd58&?!){vGp|f6ic6^q zWu^5DI1i^urRN&!2g{YLD!ZdzKYPuMKENCAvDhCWJ1(d=IX=v?r*yg_l2 zpKqFC-YTk)%OFH=Cn7_XP{I2{a+&^D%wgy6u6j41+h>TE*s~h)VrI-2g{7Qm%@@){L2FR79<h81-NZ&ADnEzy|!wS z!<(yNL}1NvM;v#Rmvsy|fffb7cI#X_{T%2o9;KyYfY+vOiAiaDNu__F)FJql>wOr_ z^DfLBih0{>zKkOc2g&WD7hCTs=J%=eSl35mMeA(rH+>p-Hx`mH+Tpozd3mBqVbL2- z9~g9TyX(p=JH>xLC5d{KjCb7;JO3UYhf?Bs^m#6pN7L`u$2v1^-aTQz-~R;6=9FCQ z){WfLAL0z|aZmD_zU>ef(*P-Xa$$u8naOrt+}~+3pH+y>6n>4>{>V z2JGhKk;eU@>UC+HI4$nYcM%yB+qcBG} zt#neCP?5Kbm2HOGA)9>X0$gOzTE0;_hb}xetH<8-+k2z%-SXx@h$!YXSL}$=tCsa_2JqC-$>xeM3fPxmQyVk~b2f zl;jW(FI(<;FoVQdxjMfAggd$F;j)I7|Kms_7pzt7Lt8Jhb6bh0D1~V)Z5YV1EjD)W zC`{SwGUfk!IiyzyB1cas+?mbC20i4eM8KhvOTBZBTF$81_>(7ecPGMF&Pcia$_Ny}#m&XElC8TLcmg+wp?~kB* zBMe?ez<17B!p_CGnJLdA*(0GTw|h&MmlT7J&w?(FgOq%8ppiirUkAOcHt~5c zZJT&wMK8W>2k*b5~Or*CF6RxM)|)%o8e z_uL3?JZ#^D*3)h+;oEJ7el8JJ9xo~Wh61?Q(ZoF%@TFhl2T$LO zVux~GT4r?)3R zs|aL5Akr5XpSGn+drqBJeqY4LJ}ZGpy)R0$jiiyrNDiaH1)5;0_@X7gYWZ{e#{D}% z_qRG&s7v@M3R$6cJa$|jSXZakqcE9%g>kE>CHW09rE)P&`3u*)EbyP@Q_!Dt(8ZJ_ z!r8ai^u8eTm*@)KeNaeErQH4PT_Ku)6>R<^2_&3NHI+J>Sk&rWBvBMPJLEIPwZMpY z&hTy>xz5p6Q@0%qj`#Q_&$NfR9Ezsq9yLX3-qlK7x95=rT&$K;tKF#_RqA@8fY(H7 z=5#MX|1rdisl$tf55yMaOWWIrwpLKk3UD9c!q$G{p-S%yL1&jIH&7X!nLh$ixBtqQ z?v*c%RD87|=RnDK>YhcEBnaX%Nfk^M3ViH1X-mTB6&AjwCs6C9!TBjN;L1_x0>~Ex zJOBYe01yBK00BS%5cvO1U~~+$HxAl?$~2LfZx#Fco+)L%549v((h(05>AjgIVW_0r zeCFzn59%dQ$7ss6op$imwu4UV2#I=uTUClWaQHL~^uCwy92By^@ten%#k(9FfmW0m zlQk@7BIxNQ+@}DOpm{6B1jSawb`Y>eL|vs~6g2mk_r z03ZMe00MvjAOHve0)PM@00;mAfB+x>2mk_r03ZMe00MvjAOHve0)PM@00;mAfB+x> z2mk_r03ZMe00MvjAOHve0)PM@00;mAfB+x>2mk_r03ZMe00MvjAOHve0)PM@00;mA zfB+x>2mk_r03ZMe00MvjAOHve0)PM@00;mAfB+x>2mk_r03ZMe00MvjAOHve0)PM@ z00;mAfB+x>2mk_r03ZMe00MvjAOHve0)PM@00;mAfB+x>2mk_r03ZMe00MvjAOHve z0)PM@00;mAfB+x>2mk_r03ZMe00MvjAOHve0)PM@00;mAfB+x>2mk_r03ZMe00Mvj zAOHve0)PM@00;mAfB+x>2mk_r03ZMe00MvjAOHve0)PM@00;mAfB+x>2mk_r03ZMe z00MvjAOHve0)PM@00;mAfB+x>2mk_r03ZMe00MvjAOHve0)PM@00;mAfB+x>2mk_r V03ZMe00MvjAOHve0{?Xa{|$X4Ev^6n diff --git a/src/basic/basic_vector_defaults.s b/src/basic/assets/basic_vector_defaults.s similarity index 100% rename from src/basic/basic_vector_defaults.s rename to src/basic/assets/basic_vector_defaults.s diff --git a/src/basic/c000.skip_gap.s b/src/basic/assets/c000.skip_gap.s similarity index 100% rename from src/basic/c000.skip_gap.s rename to src/basic/assets/c000.skip_gap.s diff --git a/src/basic/basic_commands/cmd_list.s b/src/basic/basic_commands/cmd_list.s index d1b8b75b..3da8ca4f 100644 --- a/src/basic/basic_commands/cmd_list.s +++ b/src/basic/basic_commands/cmd_list.s @@ -34,11 +34,11 @@ list_loop: jmp shell_main_loop list_more_lines: + lda STKEY bmi !+ jmp cmd_stop !: jsr list_single_line - // Now link to the next line - jsr basic_find_next_line + jsr follow_link_to_next_line jmp list_loop diff --git a/src/basic/basic_find_next_line.s b/src/basic/basic_find_next_line.s deleted file mode 100644 index cd38025f..00000000 --- a/src/basic/basic_find_next_line.s +++ /dev/null @@ -1,35 +0,0 @@ -// #LAYOUT# STD * #TAKE -// #LAYOUT# * BASIC_0 #TAKE -// #LAYOUT# * * #IGNORE - -// Advance OLDTXT by following the -// link to the next line - -basic_find_next_line: - - ldy #0 - -#if CONFIG_MEMORY_MODEL_60K - ldx # Date: Wed, 1 Jul 2020 15:42:33 +0200 Subject: [PATCH 23/24] fixed broken REM toeknizing, 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 src/basic/editor/tokenise_line.s | 2 +- 7 files changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/basic_generic.rom b/bin/basic_generic.rom index 2d4664acf070770c7ba595b720694e21c4f93e36..dc9dba7bbfb39ebcbaba4cd5b72bacba3350e308 100644 GIT binary patch delta 2260 zcmZ8ieQ*=U6+hicw)`m>3`iiXg<^xjc08fj#tFnw)RDuwfslb|+JqBebB4BQ{^(3g z(%7A08;9B;vcrtcWSAQbEBR!w&mkEbS!a{-Q6GVFC8l(yl*kAO&2;ExN(m&Ls_z6d zA=RvQZ};u)`@Ofn_g-gHXOo&|-^{j=1A*;ie_#jc3AB>#K#2SfkEfXG7&cuI2MWa4 zF!J1GDs*`7(H8qPvVUL841;v{wm7bl159q2H${5jh={$K!XZA122ymZ-B(_sq3ba? zBSv_*M(IT1OoT(1GV0fQky)JD5Ek%Kjmq}=!ukPyt0CYs6X>VYG;LqM;LQn~7(%T{ z*@hO}&^f~<%J%G+nKNnJw~oEw@OK1ak=)}^-sB@WI1m&4(_hUh=KSm4ad7?*9?XQ# zdou^?{amwy%VZQ=)gy2}PNLos)rl@9RROh69Ic8jWBKSx2GEpfzpdU|!}3kR(*7`x zmNUQ*ZM*{u8&$AG;fREM(Maxx+YW6x|CIY7OrXg^g!6p3?H5}PZM)OuzR#rASBbrrBVSo3rwqIDj;vCfvy$(L(JE)T@On(7gSqt{y~c1cm!2`f05I8wU+f1< ze%Md1IhHy72M+%l;u4of}+t&#TWcfgo*%Q*uh!>$H&l1|fq0FmU4wwTjVnwwU02U%6kfFxdc9Qha59X|+2j|WyK?{;uJb-FrR z?UfDkgi?Zcj-v9LtgSgi+VHMX`N#y>r*x}7K0Vg7avei+9Wqo`|0bz2IbU>HP&jVx1~q^be+Wm27{pcqw3 zCux9SsYf^C4XpmwvN&tFRfW#HAF<&8{l2$i!|91rAN~IHnX~6MZ~DWJCiQcALntkm*9*Y4rA>)pw`C6Cz%r?nU5tfY>G{l!w?g21u;{ z0moQQsn%FK3}+R~F{DkANd@d(oDE)9(Qqq7Dpda5VzwBZ2Ae8K2+f{A4@MB(Fwf^$ zlI8L1^Xi|1H$3-wWIlQ>#u_1o6h`b;4QY(71YdwUyef&e55mjK&qtb(7N=L|RV=!f zgawk1W+Y_}Lwsp*{Ptipk#eeh#3^E!LXa%*&7SSmM4*n$MYiCnF^hSoMKIdpTgT7Q zDD{1>?5h~t;b?V)Kmf@Al9=%&5U3OgG|MB3w0F+@oVe*a?_N#U6qM5q1$Nq2Fn3WP zCdC19M95A!sC9rv@8&DX2Ul>UtAFs_32 zz&Yt`5g=HmWqIt?B(hr~yCl+XmVvWfteu3|F0zg7Cfo5VgPzv*uvH6D>ln=70$H%i zLl<;$3EYN0f*eMs9+yBUhWbLIfK36(r#h5{czQfKWo!Y^8}*Lx3;G3PmQ`4EE)Esr ze9ED=qV+NS$+&*;+X7z2Xrm>t_U)_eh^MgHh_=L}en~%I@MLPz2rF*|7frdnl^yyF zb7rMzxTM~o5|E>)Y(VPA!h}=;*>MsqeQjKnB>crV$I%l1i$8dpi V%skkJT%-7X20fkj&*u|E{{wih>~8=7 delta 2304 zcmZ`*eNa@_6@UBQE(^=TE(!_);gSewUD1pap*jRZpPUqv(xk+H5W=t5VQh5Wh7f`gybvl)I5H>F3ag$UvPR&61hYSlB<480&3z3TNb(?Rk&NUofV8|LZZw0;`1RdlhInccpPS}|*# z+2dQM<*~MzF5fCGi+N}E`kvA(pteV>X5PeJ;$>}#F4D$Y6MIN2Yf0=TE%;IZO-xtI zTw)*D$Mz7Jnzx$7S_a8j`=cBLw^>van@q+oFiHgdf+1=H+^OAfPIUv{MdwfZzkUy-j=k+HG7T)AqsOx{c)+rpRfcvd zAXCb6N!hq=6dfNi(6Ulr4HpCR@X^~@C0W}PKn|*mgzC_*7+scK$!}HYmhASD&4EEq z=yBec%#%M33Gkt>oec@St|1qkGeF8R_)&NRsJw|Zy$QXO>W8m!Q& z%(4RyLh5pGPkUHh>vO6bLiXA4e%+-aeFc6kgnki5u_QW|1l+zJMmLk_kD(Db$Xe~E zBPOGH3GWG`%Tbo63;1P)<*MmUOGv=G6cPdJqYIxy(D)w%zXM%(%u3?UZPRnncygWQ zfT)pT4+_rWxloS?Li}9M+6*um`Y3rzy9+{OE)bDK6iI?gG~3>o+jN!r^gn@0Ajb_& z2d+}+Yj&62*A37%;uU;j;hdW$xc9O57Jnr?QL8Y+XAF-q`~|#)y-M0yC-L~XgZt?3 zm)0+3E#yc;D>>ZIM*17Pq_4q4-oaCGdfm36TAG$~@GBFj>^f`T3^4-loAgPCk$`x zITdmmLH8S0gxF*vtK@Xzsz!s!c(*RdnoI5`;MSxHIVP%ERbtgJt4_EKpqual{eD3? z9ay%>`R3$cnyCl=K8xwL*(B0v!DWCWDJK(lEb}?i!{=A ztkLo*Il`pI!jDNmoc9~iSpfU8fwcl2K8u>JqKqMY0UTdn6%7M5d6+l>db;3i+L;QsbRsmK6 zqH^LvOQsP-mFEkKEn8Eb`Fdg1npy>5s2^j-$UWesN2!^3s6!aQ)D9U^;5#vkp`^<+q+`IokAr^C9%%lLSAP zf2QSUO-Ea9^*Hab4(~3~!8$ZZfN0Is4G;4;zra6HXi-`PjX0j#%1x_*kZm}2D(;RQ zin~SiqMof@g4e*GH39!^*hpW-^8f}r6*Vn&qT$$;m^=1S%$-Wb|5*}JOLUd9kl!As zZfE7pKBz=o6v5`jd@Z0NEPMIZ)*OLB{pI4Ei8iFK>msAm{j7YyOv>rm6HCB=N* G)V~4R_zw2~ diff --git a/bin/basic_ultimate64.rom b/bin/basic_ultimate64.rom index 1d45b875eb779a128fe167e9cd828d661a89e4e7..804c370593f56a3fa814dd3d41d52dd600db4a41 100644 GIT binary patch delta 2211 zcmZ`)YitzP6}~g$_1e3BEXKwU{I~{e9)1WxjUA^DnwrLt>x4!Xj;sRXwN2LsDq5*( zWv9heJH>IZy5uSf7BQKweAkR0>zNP)Uc7jvV&tJQnM92oP?|0_8w{!NphO^4iS3y+ zZGTi9?aqCiGv}VicfQ-bvwNqSoKXDM!tVy(V0lA#hW-%vV~}0O#gn)pq9e0JUtV=+GGA_08Vz>(8k#FuRnbAjuB@PKB4c@YNvYY?W9eXcV_i${a49 z*O9@AazcD&Ce9d-ESs;|iqhwp&pzhoP2QJC=9oyAY(L6ZD&!B0Rm!hrX1J7h4ZnT9xBhfJ3?3=VBV{U?WWxe0tGUNXovi#G zlDb6MIgvcrkAxoAV>w|WYp`EHFjYvOD_cHY+|v1NQ3U3hG0g-#&o&F~m*V&87h2LQs%3<`4BR%>()i=6-zO${5F)O-ip+ zrJR$t;jbsWSa}x~Q_G7VD0Q%iEHA!`k4zBfx!!s(l+)e~hVi9&kDhM4FFrurvUT%Y zu(Q%NU_0yj?_HAXVO*7MdHUJ;faOwl5!VBMx*Z~R?K~bD`Yd$LUjXv|7`9+ywGu3%nw}WP&2VTg zR3G{@6fg6?MM7LeQ(UY0rU>2Ws$7Xi^_}q94K3b1H#9JCYQ@J+1=Zuq;Ig)oT7sh* zL?)+}%W34r06sfr9kBayq++ z_N0{nKqL>oAMn{PxZi2K?s@`q_{o9~(8qVXN~Vvp+)^Ryk1Jj`S8fXJtTubNr2 z>mj+VJyY8h*Luu6nYpUp?wwYuLbvX0e8~MUP5ttTlQ>YGp0a!%_=#M>`}pnf2pKQ&yWEla8^Y(Kb*z z5^V*g!_gK{>WI4IN^#J4r5Dq`r@cpi?kqXJr0VM+oq`7ZW3pKSMrKdqggT#AT$#=${A?A74;ft62$ z!WqrNOg5m3rEaz)tXaCq+|p&%B2DJd53@&$(I`1Hju0-n!`jX7v1UUc?E!pdoE_Tr zQ`A>@J%G?Tj z^@xuHdZ#bt-p!K{&Yah=k%(W5kjfz3PKkQ02^g%Qw;XjgQgTNWX=PqE{Zn3k75*l~ zT5WB%W;0%{bUkJ~2EQ}G@2nh=HJj=9epRKOm0vQe8_Z2`X{jguqQci#-xl0 zU;`v40{&nmN#%V>B7r3|dU5`$RWq6hppcQTk^J?t=&xOb1l-VQLw+59O`|mb^_0fj zxG6&BCPgSMt#uZcri82_JM?lhqCaoij5+Yoy6~QnjEuC-o4*WE)t1S_4Smg4oQy_e zquZ*s!L9O}g1u?gBXIb>skXOuOD-CIi^$=S3U-1r$2$g#Z8m delta 2238 zcmZ`)eN0=|6@MQXY=f~OnD38k8Ui$c(oIPyS-Lc%s*_%tbgR;jDatd6Gn98FM$e=%DVqd5>y)eBuz~eh%BIRto z|M_wCfX3t3=TYzbXBkf26!@0aM@MMk4JTjG;*s^&GLw;m> z@)<@z?D-fcCWLmGx!M~+FV5rLSA?NH4Qvh_H`=dy&pJWBm^tY_?S_|6bo#(S3H~Le z8{4n5Vjpd}&WOhaqFdYgUt7EJ$)`6zyY>0L?|kvy+yD4PzLWXEi^mw2+rt0xP>y8E z%`=-V7K?Q*dGA?XPM%996EI$;%Zj3mE6FPgh0dH3i71LdJ$gMo>Zn}tYNacOwBnV6 zTH#8!W|arT?iG*5UGPA@j|wO5`$@gTP_JjWUawEl-r;(BSj(lo&HckLe9mZ&7){SG zY&&t3dIaAaHl4?rFtu&s@oLy79`T7iKGCn&Qjcb*e$hjF#BO>-Jc##CmV5n>hC5;8 zor4jX%-c#9igwjH6<-wDl^_p@p&e>QF9_yjyP*eBDn8R#+`|r|Lh`z$BEKy`J!o5k z`q4IW%~Hd*kzDHmZef~y&$_P$tts@7$!qdJM0pWvS2Nm8+AWsQgQByXxGOtJZGHt0 z1t&MFU1fX5p%=5NEqYqrrkk`&XyHSs8fkYl^fyna>op#4p8!-k)Q(s|3Q*CaBE1Pq z<0v|Tlnh!hAQYTHA7s$lcox9g{ zK+ujZ+%+XJ3w!kvG@JRlW(Ue-&7Wbo6t+(c3g9Hj3~sV042Ry%T+?oV6PXDmBmpHd z5E8K$b(PrSG@!o*A%Pz^ynKLhaP|*JllG zH|woH1(=5)`N&phgIdW;MxJ(}_m)UyVH=HRvP{mos$j=Je){RW5JK(dma8`oW!tmwHNplBV%>)J*2DlBXVWWxW z&vZjOAi!CH5y-{du70SV#2dOe2u;)n_(XG1PjT^{9Dy*Y^;$k%+?5d*<$C-|JhZ4i z1(<$9?GNlx-_o3hpsGw1WZ=!TDdt603O*HAFMf4_i(%w47L0u-oBN|_9P2=hiq{wM zsXx~^aWSO@AZ^Vg^U)JKE8HJ76naY_#+kV|T%CgusLw=jTzd%5PQ`t-d_Gd=d-Qqa_k-xBx%$CWnktuw6 zl3`H8GWF{ZgEsK^^ennONe@5reFxC>ee&b-YJ%ZYYz=TL zZFv1Tyf6(OVh-aT`WL&%x{B7kR6NLn-jhcwJ|M%DWu!ar(GuLSEC~N~g^_S&%{OGW z<;xojBs?3im;gnlR`jQPx59}r&`UcywS-=tG}=>3xaXXJOJn3#W$m+Ug!&=;H)JDr z@vtn38vp=}h9)KGhW4u-aYKx|&`2BMT(D__=s~6Ps4aosi_%`vOP>=D8G2~wA{;4H zmac;!Zf7ZXtZM7mR>Od?U=0Z3|7s!78gEbHi%EmJyMwz>RT%FKlXt7`TYq{M=0qzh zPD%_0MSzu;Cqs#}ImQLe0)`<}!&O~cx*8S$;Sv*k3NOwHp^j_1K?KrO-O2qeOi1<9 zJ8W?@oWPfo!iWFo0aNm~rHEE4e=JeWA^%F6hpVJhN^3cCj}#-Tre^bgB{jV{sz{_Z zx56SN0E+lwMIbNL>@7^i!N9(GZ?bbN5lWE1)O4B~m+)i1Lyb$Msn*54utXlK-Oftn sr?u}oA7B{RefP3GFF-*A;~+28Jzks!iW@A)dY;;)TY$slow}xf0yC@iQ2+n{ diff --git a/bin/kernal_generic.rom b/bin/kernal_generic.rom index cf478edec450357c981dae1d08aa16e0aae23ae5..75684fcc422bb9df7b58d2ea2c882f1b19d72a78 100644 GIT binary patch delta 730 zcmZXPT}V@59LC?XcXPVUuW+E1^`bY0A1uYWC`d@f;zU@~g;1=0Ksg18K#;jB>JsSbT8l;o(&5WZmE-+YLZyiYXd2Vz2M^mGB0}moxRHe$w%2rUyJ*i>w zE&I;w#p#D$zi+m*ZhA5vkET4Sa5NO+W3eczhzUT1w80y!irf!Za@9)y7lP+s*Dpzs4Kp_bbM zfZ~BdDC?D5g-`NT;goy@6^;8TN^ZmVm^vI}jA-RGi|`#{xQuDWjl|4n%tH+6q+ zLN6ETZg-*Ll4{#WN1nSKipRYreBYV;4ZJCk-eCR4)Ff zyu3`8@Tkpe`r>2r1WiyQsAa8? zBbOAL5l))SFhXG>K$Q~o* zgIdxLy$X|077L)WA53G$0W--SG@9DrPM;E=3Yw57${w1m z2OlDa>`w2!D6^uC?QZKo-cY>A)zq@~=bB~&i}{#wS8oB zzxDTA>&!jR1Uq;1%c!3Z}I35rNyd(@q;f{|X&{al_uHm~H z)i4UG8V;SYzmOId-!3h$ylZQH-@f``oB0^+H(ZIu6W`_Mm)DG+);H2Wx3_P839^4p zmRUc`25>GXWQ_4_AkKzx5M()yWx?xB7nxFi3p z6eKZ4b|}X@l6XN-k}ZPW(Jah}d8wTRf;Eqr-$b=uEBH1B7h}Tg{{^)df*+|us&A;o z&PJiP3j7+Q#wp>hs7BJX=wPm!_0oZY61#9HnOkBJbEpwB)9CWxkEh0ATATv&S;};h zgncm!MZqoSLG^j9-Vf`;&R+F>do6dPDQ9KWqKo~^+fV2kZfgnM*+i!cUHncE1K6pWfU%tpP+#zR^-I=h^NwH$?dDbzzDTe6Vu z6mw`B>ZE&67u}1x;l;^(s|~+9%K@!5h*Resvg~+>{kj#25Eftzcn^aI6T3tm9Nme0 zbQcQJ-H6Y(IQuk><~vUGHZI;81{-PxWVl1s*){Va_%VE{7RaDXyw{(2>&ZP5&p_ zUFtE=8DL>g^v$wCBb|Xo*N1`L4=QO)=Be7iz;YN4x^?T#=Tr@iZN?Mj<)-oqx|=TUT!Mw4G}@qD>E%PN z1^U4c7xB4zuOoI5(zc00FYJcmC8w!n?&Uh2K@2MBQ|q}IM2CmN^Z%a%=bWFr-d$h8 z`QZC3cb6G~Wn)8t(Zk&voNY&`b`-;mcq^(;G5{V)SRy#lXDPal)ai0^a@8vBpV*~I zb=iN-H_zH_&)E4x)w4t5EUr2BRdjLb!}7}N$Cl<# zSJyuO;MQYZ1-Ijg+{#VM^7fYy|2JfrpXB)<)^bwDUYHLj_$mAe@q)nf zaAup)DBC^2iKk%A7z}OWaZyH#4G~BxQZz_;DB75%qb|-s$Z<9*T^6&Mi=wNqNt~7T zD0hi~w+vX`#dHBXTtmcCT%7yApbii)sT7pHM@APPBLcNBji^ydd?KmoXhiDc?peyC zMf;2{u{cv=B&9-Xz`}iHrZHY>l*ma?MVNO41Gy6?DT??W2fh+@iyHWSPW7NGBHV8* zTpc2zHmtx?u)zj4pn;BQ?l@aHY=X;K?9K=T@N=pY9DwRD9E(BKOYCk4bPzrrM|!yU zx5+c?IofMr0J3@w8AAkhcn#>Ll!H2qE-#k1l;l)WyBBwPI(5iO0^obBIp`W>QTLg& zita`|X+Zao#1wz!2Fn5xSu+OIS+qZ8mr7G@QgNzPDoEKRJ?ExvDXXM@YsKU{N$O2L zK5|t+`DP6f5h&V8(d`uN$dn(BSv9eDp00op@Y5g_LA9n;oA zQ!tPRUkBj}g~Yl*^#8m0n!?BD)|S@I2)&ga6Vl^pzz@qO;b{czVYYS)8~uL5Gkkcn f>5}GrLyM`(Y_2h%GF>=lssaG-gx~mrw(`Jloo#Ub delta 776 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 F{{|o9$2tH2 diff --git a/bin/mega65_pxlfont.rom b/bin/mega65_pxlfont.rom index 14f258b29df442db69e474046889eeaaad7be062..e496e28528bc5a14aa3afb9c46c7fcc8b568a5a1 100644 GIT binary patch delta 1550 zcmYLI4@?tR7{9yn&w`Xv8CBePMYe!+gg?R<2)JY_x^rxc#U|D86IzZU!yY?pjYl@U{r8d z52{fg%~rtVeYP0=SPW~$@Dk!JzuF|e0lUDKN{Rh!Jq#Brbc0$7P~ndzdRal8)dOy*bu zI?@kfKkHZl8sN>QR66Zgb9VG%gB08D`^);=^-|}`W^WpE0KupIS#&SdqqkE)mK|*i z-yU8qDcJX1NF~nso}jIkMX1J-pyg1PCKY~!vdc8#>|PgG&@WQcJsL5>*{xCH=51s1 znRbn+aJI;q(V(qxYWmPDdeu^d3N0%^rhtmWOQ!eC68p}&;Jff|v^2dJiL0hx)QDTA zfrijh9C$G1hy{!X96%`HO0otm(sCSYbirDGb}Y&$xJO&|BmF(f(!{}r;0rKvas$k^ zEz*jaK9$_E#Au0Q78ToW*K**f9maTx=5Hz8Lq^ zvYYFoH465z$2n|wFpOY>HFzgH8%zxQLoPjzlaff&i2)J#BIL!20g;j-#6r1P0q1;S zpp{`11F(OvPJS&M+OOkjJx>9h2Mi5^)i&oHr9}W6Lr4j(&N&B_Y->OKYUl<%9q=}7WHG06Q#tO|l2!4U<* zTn+^|671L8GUn+U=|eBKW+LSk*L@%cK`sJa0lW?~jECO1jZ1_(*pDai_CNsd zb?tQpaR^h^F<#Bqje^4=RJ(4@Qp@ff{k?j+nBv&TNs5xwJES61J)M>TA}3Mp>Rq{L zIXp1Bgh_b-PmI>a2{xiKk;%bW1P%}dRjyQxV!)vk^^#vKlEQu0fbfv*g=<_hvcRti zK%U$hL6_Bw=1%A5^nzdMV`3BhBEWS9GhCX);l{!RtE+eI88b?QO6w=eR$ zt=*e1#?6qJ+%Vg|l&SH;a(e;%&|9VGMa1-68mh0$!XFvxjE&bFtJ+jG%GJGA$#ER0Dy(8XI({|<>h`wNE%2kgZ|Ol*F?xC`*M*9w zjGzYf&@2bRzNP}MN`%0K#B;XIV2P=Rv1NdSDbZ@HR#BvlQqilnkvTMYh|sH?eZH;BsXy=N|CH6@$1Q_I@um>Y@pEP zFH^V2#sg}ER8CykT7!k6yZ_x`+c{pO-lJ$o^v4v_N6{Cf6|SG6{S;FvKcQ@pe^p+W zS1Hv%x4Dm|6;A9F3dL%n2#i%7PZv1?Omkq3nDjp=0g;^bYDYOqWT>~2#Nf24PS&yk z4(7F_r3N_hict)lrRXk-neG@n`i}v+Ol$z|XnEyHp0h5N1LL|eP=Z|L+~pwSei4{C zYa#(1*#}%f*1a4w!doqw^pX>;`SAvml6ZLhPuqf@%RD8m{wyXR!@umyXbUu=4H2kQ z|2#Z{^2;;J*k&(?wae7ZkY0}Rc=U0u)@>tm9*17mcs^AGW(K+#hi#0%jQGW0ZV7U5_3! z@H|`PwZ(fga2KUHob-n+!n+j1=3qu5$}PS_3;U7r4kfhkFaxh*q9$T>=F%Ifjt9GH=~~2>S`!#%PB_nQ#nGt zo4M3bjCK-pCovmuH}RlbawmgN`p`W6JBg@97(}{a5O4R8c6@}%{)F-*4v?R`7c zWnTaO3=&kYEFfVGBy1d>(&;NAU%G5nsaJ;*Gch zkKtIKj4$KgrP0uL_zLz8I(=Uc2JrXzDo*f@U67= zvCM*I&lVLHQS6a0&!b$S6d8pwo>VX;B!lrNkZ5PSC7Dv9oiez19n z4DwE%y@lEUMNvdDW}75FWVJq!+)M6C^i`p*Ro zH3z}sVZs9p`j#<=`r-WHkU`EH*CMSvtKLVlYS|jUfd_SdSm4ZwNp%tkQk`(SGb5(a zslG4W58rpDz_h9gU zqz3R7-jw^F9Qy}Iq-XhrAc4y8oDi7_Rc@rSJ&#Y2)UZ0dD~9|Pxs|mXycQn37N+x3 F{{|o9$2tH2 diff --git a/src/basic/editor/tokenise_line.s b/src/basic/editor/tokenise_line.s index 7fd6216e..960d5a92 100644 --- a/src/basic/editor/tokenise_line.s +++ b/src/basic/editor/tokenise_line.s @@ -127,7 +127,7 @@ tokenise_line_keyword_V2: pla cmp #$0F // REM token index - jmp tokenise_line_loop + bne tokenise_line_loop // FALLTROUGH From 34b56b1fd58f1a08f93f05e22d5831efaf2735f2 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Wed, 1 Jul 2020 18:43:23 +0200 Subject: [PATCH 24/24] explained all similarities >3 --- strings/0001020304 | 3 +++ strings/008526852785288529 | 3 +++ strings/01020304 | 3 +++ strings/0320FEED | 3 +++ strings/07C922F0 | 3 +++ strings/18A52B69 | 3 +++ strings/20E7FFA537 | 3 +++ strings/2C382099FF | 3 +++ strings/38A52BE901 | 3 +++ strings/60A561F0 | 3 +++ strings/60C922D00B | 3 +++ strings/6902852D | 3 +++ strings/6902852DA52C6900852E20 | 3 +++ strings/A200A000 | 3 +++ strings/A56160A5 | 3 +++ strings/B9903C20 | 3 +++ strings/C901F008C903 | 3 +++ strings/C922D008A5D449 | 3 +++ strings/FFFF0000 | 3 +++ 19 files changed, 57 insertions(+) create mode 100644 strings/0001020304 create mode 100644 strings/008526852785288529 create mode 100644 strings/01020304 create mode 100644 strings/0320FEED create mode 100644 strings/07C922F0 create mode 100644 strings/18A52B69 create mode 100644 strings/20E7FFA537 create mode 100644 strings/2C382099FF create mode 100644 strings/38A52BE901 create mode 100644 strings/60A561F0 create mode 100644 strings/60C922D00B create mode 100644 strings/6902852D create mode 100644 strings/6902852DA52C6900852E20 create mode 100644 strings/A200A000 create mode 100644 strings/A56160A5 create mode 100644 strings/B9903C20 create mode 100644 strings/C901F008C903 create mode 100644 strings/C922D008A5D449 create mode 100644 strings/FFFF0000 diff --git a/strings/0001020304 b/strings/0001020304 new file mode 100644 index 00000000..a295016a --- /dev/null +++ b/strings/0001020304 @@ -0,0 +1,3 @@ +sequence 0, 1, 2, 3, 4 + +Trivial sequence of bytes. Not copyrightable. diff --git a/strings/008526852785288529 b/strings/008526852785288529 new file mode 100644 index 00000000..2eaf0a02 --- /dev/null +++ b/strings/008526852785288529 @@ -0,0 +1,3 @@ +$00 + STA $26 + STA $27 + STA $28 + STA $29 (temporary variables) + +Couple of instructions settin 0 into temporary zeropage variables. Trivial - not copyrightable. diff --git a/strings/01020304 b/strings/01020304 new file mode 100644 index 00000000..8223fcbb --- /dev/null +++ b/strings/01020304 @@ -0,0 +1,3 @@ +sequence 1, 2, 3, 4 + +Trivial sequence of bytes. Not copyrightable. diff --git a/strings/0320FEED b/strings/0320FEED new file mode 100644 index 00000000..add9e8af --- /dev/null +++ b/strings/0320FEED @@ -0,0 +1,3 @@ +BCS (offset matches) + JSR (address only partially matches) + +Instruction + some part. Trivial - not copyrightable. diff --git a/strings/07C922F0 b/strings/07C922F0 new file mode 100644 index 00000000..edabb3cc --- /dev/null +++ b/strings/07C922F0 @@ -0,0 +1,3 @@ +$07 + CMP #$22 + BEQ (offset does not match) + +Instruction + some parts. Trivial - not copyrightable. diff --git a/strings/18A52B69 b/strings/18A52B69 new file mode 100644 index 00000000..f7c7810c --- /dev/null +++ b/strings/18A52B69 @@ -0,0 +1,3 @@ +CLC + LDA $2B + ADC #(value does not match) + +Small part of code performing addition with a given zeropage variable. Trivial - not copyrightable. diff --git a/strings/20E7FFA537 b/strings/20E7FFA537 new file mode 100644 index 00000000..898666f0 --- /dev/null +++ b/strings/20E7FFA537 @@ -0,0 +1,3 @@ +JSR $FFE7 + LDA $37 + +Calling a documented routine (CLALL) and fetching a byte from zeropage variable. Trivial - not copyrightable. diff --git a/strings/2C382099FF b/strings/2C382099FF new file mode 100644 index 00000000..3adeb7a2 --- /dev/null +++ b/strings/2C382099FF @@ -0,0 +1,3 @@ +$2C + SEC + JSR $FF99 (MEMTOP) + +Call of a well-known routine, following operation type set and some part. Trivial - not copyrightable. diff --git a/strings/38A52BE901 b/strings/38A52BE901 new file mode 100644 index 00000000..37a90188 --- /dev/null +++ b/strings/38A52BE901 @@ -0,0 +1,3 @@ +SEC + LDA $2B + SBC #$01 + +Small part of code performing subtraction from a given zeropage variable. Trivial - not copyrightable. diff --git a/strings/60A561F0 b/strings/60A561F0 new file mode 100644 index 00000000..e1c4eb54 --- /dev/null +++ b/strings/60A561F0 @@ -0,0 +1,3 @@ +RTS + LDA $61 + BEQ (offset does not match) + +End of pprevious routine + a new one starting from checking, whether zeropage variable is 0 or not. Trivial - not copyrightable. diff --git a/strings/60C922D00B b/strings/60C922D00B new file mode 100644 index 00000000..ba46a79a --- /dev/null +++ b/strings/60C922D00B @@ -0,0 +1,3 @@ +RTS + CMP #$22 + BNE (offset matches) + +End of the routine + beginning of a new one, which starts by checking for a particular character. Not creative - not copyrightable. diff --git a/strings/6902852D b/strings/6902852D new file mode 100644 index 00000000..db6b0ea3 --- /dev/null +++ b/strings/6902852D @@ -0,0 +1,3 @@ +ADC #$02 + STA $2D + +Add 2, store value in zeropage variable. Trivial - not copyrightable. diff --git a/strings/6902852DA52C6900852E20 b/strings/6902852DA52C6900852E20 new file mode 100644 index 00000000..4e0943b8 --- /dev/null +++ b/strings/6902852DA52C6900852E20 @@ -0,0 +1,3 @@ +ADC #$02 + STA $2D + LDA $2C + ADC #$00 + STA $2E + JSR (address does not match) + +Code calculatin VARTAB value from TXTTAB - by adding 2. Trivial - not copyrightable. diff --git a/strings/A200A000 b/strings/A200A000 new file mode 100644 index 00000000..c840f00c --- /dev/null +++ b/strings/A200A000 @@ -0,0 +1,3 @@ +LDX #$00 + LDY #$00 + +Load $00 into both index registers. Trivial - not copyrightable. diff --git a/strings/A56160A5 b/strings/A56160A5 new file mode 100644 index 00000000..0e9cf4a5 --- /dev/null +++ b/strings/A56160A5 @@ -0,0 +1,3 @@ +LDA $61 + RTS + LDA (zeropage address does not match) + +One routine ending with returning a zeropage variable, another one starting with fetching data to acccumulator (not even the same address). Trivial - not copyrightable. diff --git a/strings/B9903C20 b/strings/B9903C20 new file mode 100644 index 00000000..2bb1fa38 --- /dev/null +++ b/strings/B9903C20 @@ -0,0 +1,3 @@ +$B9 + BCC (offset matches) + JSR (addres does not match) + +Instruction + some parts. Trivial - not copyrightable. diff --git a/strings/C901F008C903 b/strings/C901F008C903 new file mode 100644 index 00000000..ff92a76f --- /dev/null +++ b/strings/C901F008C903 @@ -0,0 +1,3 @@ +CMP #$01 + BEQ (offset matches) + CMP #$03 + +Two decisions based on accumulator value (second not even the same one). Trivial - not copyrightable. diff --git a/strings/C922D008A5D449 b/strings/C922D008A5D449 new file mode 100644 index 00000000..e175dea4 --- /dev/null +++ b/strings/C922D008A5D449 @@ -0,0 +1,3 @@ +CMP #$22 + BNE (offset matches) + LDA $D4 (QTSW) + EOR #(value does not match) + +Small piece of code handling QTSW flag - telling whether we are in the quote mode. Nothing complicated here - not creative, not copyrightable. diff --git a/strings/FFFF0000 b/strings/FFFF0000 new file mode 100644 index 00000000..893fe180 --- /dev/null +++ b/strings/FFFF0000 @@ -0,0 +1,3 @@ +$FF, $FF, $00, $00 + +Sequence of bytes being similar most likely fue to ROM not being filled in completely. Trivial - not copyrightable.