From 27b33c2b2657ab8a3d43085b13386d6db203f6e1 Mon Sep 17 00:00:00 2001 From: Paul Gardner-Stephen Date: Wed, 1 May 2019 07:37:52 +0930 Subject: [PATCH] use more space efficient calling convention for calling errors --- c64/basic/basic_delete_line.s | 3 +- c64/basic/basic_execute_line.s | 3 +- c64/basic/basic_parse_line_number.s | 4 +- c64/basic/cmd_run.s | 5 +- c64/basic/cmd_sys.s | 3 +- c64/basic/cmd_unimplemented.s | 3 +- c64/basic/do_basic_error.s | 129 +++++++++++++++++++++++++++- c64/basic/fac1_mul.s | 3 +- c64/basic/tokenise_line.s | 3 +- 9 files changed, 137 insertions(+), 19 deletions(-) diff --git a/c64/basic/basic_delete_line.s b/c64/basic/basic_delete_line.s index b4712df3..4e317f8d 100644 --- a/c64/basic/basic_delete_line.s +++ b/c64/basic/basic_delete_line.s @@ -42,8 +42,7 @@ basic_delete_line: beq + ;; Line length is <0 or >255 bytes. ;; Either way, things are bad, so abort. - ldx #35 - jmp do_basic_error + jmp do_MEMORY_CORRUPT_error * ;; Length can now be safely assumed to be in the low ;; byte only, i.e., stored in tokenise_work3 diff --git a/c64/basic/basic_execute_line.s b/c64/basic/basic_execute_line.s index f3ab8659..494a82c6 100644 --- a/c64/basic/basic_execute_line.s +++ b/c64/basic/basic_execute_line.s @@ -86,8 +86,7 @@ not_a_token: beq basic_skip_char ;; If all else fails, it's a syntax error - ldx #10 - jmp do_basic_error + jmp do_SYNTAX_error jmp basic_main_loop diff --git a/c64/basic/basic_parse_line_number.s b/c64/basic/basic_parse_line_number.s index 083cdf61..50991ff3 100644 --- a/c64/basic/basic_parse_line_number.s +++ b/c64/basic/basic_parse_line_number.s @@ -10,8 +10,8 @@ basic_parse_line_number: ora basic_fac1_exponent beq + ml_bad_line_number: - ldx #10 - jmp do_basic_error + ;; Invalid line number + jmp do_ILLEGAL_QUANTITY_error * ;; Line number are not allowed to have decimal points in them lda tokenise_work4 diff --git a/c64/basic/cmd_run.s b/c64/basic/cmd_run.s index c372a8fa..fc03a8da 100644 --- a/c64/basic/cmd_run.s +++ b/c64/basic/cmd_run.s @@ -14,9 +14,8 @@ cmd_run: jsr basic_parse_line_number jsr basic_find_line bcc + - ;; Undefined Statement Error - ldx #16 - jmp do_basic_error + ;; Line doesn't exist, so report error + jmp do_UNDEFD_STATEMENT_error * ;; Run it! jmp basic_execute_from_current_line diff --git a/c64/basic/cmd_sys.s b/c64/basic/cmd_sys.s index e628fa81..979c1457 100644 --- a/c64/basic/cmd_sys.s +++ b/c64/basic/cmd_sys.s @@ -4,8 +4,7 @@ cmd_sys: bcc + ;; SYS requires an argument - ldx #10 - jmp do_basic_error + jmp do_SYNTAX_ERROR * jsr basic_parse_line_number diff --git a/c64/basic/cmd_unimplemented.s b/c64/basic/cmd_unimplemented.s index bdb846d5..2133a60b 100644 --- a/c64/basic/cmd_unimplemented.s +++ b/c64/basic/cmd_unimplemented.s @@ -82,5 +82,4 @@ cmd_go: ;; Undefined tokens cmd_unimplemented: - ldx #36 - jmp do_basic_error + jmp do_NOT_IMPLEMENTED_error diff --git a/c64/basic/do_basic_error.s b/c64/basic/do_basic_error.s index 60be41e1..cadbe691 100644 --- a/c64/basic/do_basic_error.s +++ b/c64/basic/do_basic_error.s @@ -1,6 +1,131 @@ - ;; Error # in X + ;; As many errors are triggered from many places in the BASIC + ;; interprettor, it is important to have an efficicent means of + ;; calling them. + ;; LDX #$nn / jmp do_basic_error + ;; is the simplest, but takes 5 bytes. + ;; Having a direct JMP address for each error is preferable, as + ;; it reduces the overhead to 3 bytes, but at the cost of having + ;; a jump table of some sort. The .byte $2C method can be used + ;; to have a set of addresses that each execute a different + ;; LDX #$nn command, reducing the cost of the jump table to 3 + ;; bytes per error number. + ;; But we can do better with a bit of scullduggery and carnal + ;; knowledge of ZP usage. + ;; The INC $nn opcode is $E6. ZP location $E6 is one of the screen + ;; link addresses. In the original KERNAL, the lower bits of those + ;; addresses have meaning, but in our KERNAL, we ignore them, and just + ;; have them all zeroes. So.... We can have a sequence of $E6 bytes, + ;; and know exactly how many of them have been executed, by checking + ;; the value of $E6. Then all we need to worry about is if an odd + ;; number is required, then we have to have an exit that has a $E6 + ;; opcode with some other address as target, but where the byte value + ;; of that argument can be safely executed as a CPU instruction. + ;; NOP = $EA is the obvious choice, as if used as an argument to + ;; $E6 will increment location $EA, which is another of the screen + ;; link addresses. -do_basic_error: + ;; This gives a total overhead of 18 bytes + 1 byte per error + ;; message. This compares favourably to the 3 bytes per error + ;; message that the $2C method would result in. + +do_NOT_IMPLEMENTED_error: + .byte $E6 +do_MEMORY_CORRUPT_error: + .byte $E6 + ;; the message "BYTES FREE" + .byte $E6 + ;; the word ERROR + .byte $E6 + ;; The word "SAVING" + .byte $E6 + ;; The word "VERIFYING" + .byte $E6 + ;; The word "LOADING" + .byte $E6 + ;; The word "READY." + .byte $E6 +do_LOAD_error: + .byte $E6 +do_VERIFY_error: + .byte $E6 +do_UNDEFD_FUNCTION_error: + .byte $E6 +do_CANT_CONTINUE_error: + .byte $E6 +do_FORMULA_TOO_COMPLEX_error: + .byte $E6 +do_FILE_DATA_error: + .byte $E6 +do_STRING_TOO_LONG_error: + .byte $E6 +do_TYPE_MISMATCH_error: + .byte $E6 +do_ILLEGAL_DIRECT_error: + .byte $E6 +do_DIVISION_BY_ZERO_error: + .byte $E6 +do_REDIMD_ARRAY_error: + .byte $E6 +do_BAD_SUBSCRIPT_error: + .byte $E6 +do_UNDEFD_STATEMENT_error: + .byte $E6 +do_OUT_OF_MEMORY_error: + .byte $E6 +do_OVERFLOW_error: + .byte $E6 +do_ILLEGAL_QUANTITY_error: + .byte $E6 +do_OUT_OF_DATA_error: + .byte $E6 +do_RETURN_WITHOUT_GOSUB_error: + .byte $E6 +do_SYNTAX_error: + .byte $E6 +do_NEXT_WITHOUT_FOR_error: + .byte $E6 +do_ILLEGAL_DEVICE_NUMBER_error: + .byte $E6 +do_MISSING_FILENAME_error: + .byte $E6 +do_NOT_OUTPUT_FILE_error: + .byte $E6 +do_NOT_INPUT_FILE_error: + .byte $E6 +do_DEVICE_NOT_PRESENT_error: + .byte $E6 +do_FILE_NOT_FOUND_error: + .byte $E6 +do_FILE_NOT_OPEN_error: + .byte $E6 +do_FILE_OPEN_error: + .byte $E6 +do_TO_MANY_FILES_error: + .byte $EA + + ;; Now get the error # and restore $E6 to its correct value + lda $E6 + pha + and #$80 + sta $E6 + pla + ;; $E6 has even part + asl + ora $EA + and #$7f + tax + + ;; Restore $EA to correct value in case the NOP above is used + ;; as an argument to the preceeding INC $nn (opcode $E6). + LDA $EA + and #$80 + sta $EA + + ;; FALL THROUGH + + ;; Error # in X + +;; do_basic_error: ;; "?" txa pha diff --git a/c64/basic/fac1_mul.s b/c64/basic/fac1_mul.s index 89425ea1..0b559669 100644 --- a/c64/basic/fac1_mul.s +++ b/c64/basic/fac1_mul.s @@ -60,8 +60,7 @@ f1m10_l3: bpl f1m10_l3 ;; Exponent has bit 7 set, so has wrapped. ;; = OVERFLOW ERROR - lda #14 - jmp do_basic_error + jmp do_OVERFLOW_error fac1_mantissa_mul2: ldy #3 diff --git a/c64/basic/tokenise_line.s b/c64/basic/tokenise_line.s index 259ee946..dc4aea50 100644 --- a/c64/basic/tokenise_line.s +++ b/c64/basic/tokenise_line.s @@ -101,8 +101,7 @@ tk_might_be_keyword: cmp #$10 bcc + ;; Packed string too long - ldx #16 - jmp do_basic_error + jmp do_STRING_TOO_LONG_error * ;; Search for it in keywords