variable support cleanup

This commit is contained in:
FeralChild64 committed 2020-07-19 08:54:53 +02:00
1 parent 51aec45c8d
commit 09f85cea8a
64 files changed
+266 -87

No files matched your search

+379
View File
@@ -0,0 +1,379 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# X16 BASIC_0 #TAKE-OFFSET 2000
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
// Well-known BASIC routine, described in:
//
// - [CM64] Computes Mapping the Commodore 64 - page 102
// - https://sta.c64.org/cbm64basconv.html
//
// Output:
// - VALTYP - $00 = floating number, $FF = string
// - for float: FAC1
// - for string: __FAC1 + 0 = length, __FAC1 + 1 = pointer to string
//
// Idea:
// - use a stack to reorder operations, so that they can be executed
// in a correct order
//
// XXX finish the implementation: invoking functions, fetcching PI, fetching float, fetching variables
FRMEVL:
// Push the sentinel to the stack
lda #$00
pha
// FALLTROUGH
FRMEVL_loop:
// At this point there are 4 valid possibilities:
// - a string, a float, pi, or a variable (in short: a value to fetch)
// - a token (whichj means function to execute)
// - an unary operator
// - an opening bracket
// Check if end of statement, fetch the character
jsr is_end_of_statement
bcs_16 do_SYNTAX_error
jsr fetch_character
// Check for a string or opening bracket
cmp #$22 // check for opening quote
beq FRMEVL_fetch_string
cmp #$28 // check for opening bracket
beq FRMEVL_handle_bracket
// Check for unary operators
cmp #$AB // check for unary minus
beq_16 FRMEVL_unary_minus
cmp #$A8 // check for NOT
beq_16 FRMEVL_unary_not
// Check for the PI
cmp #$FF // check for PI
beq_16 FRMEVL_fetch_PI
// If not a PI and not an unary operator, than everything above
// $7F has to be a function
cmp #$80 // check for a token
bcs FRMEVL_execute_function
// Check for a variable
#if !HAS_OPCODES_65CE02
jsr unconsume_character
#else
dew TXTPTR
#endif
jsr fetch_variable
bcs !+
// Found the variable - copy descriptor to FAC1
#if CONFIG_MEMORY_MODEL_60K
ldx #<VARPNT
ldy #$00
jsr peek_under_roms
sta __FAC1+0
iny
jsr peek_under_roms
sta __FAC1+1
iny
jsr peek_under_roms
sta __FAC1+2
#elif CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
jsr helper_frmevl_strdesccpy
#else // CONFIG_MEMORY_MODEL_38K
ldy #$00
lda (VARPNT),y
sta __FAC1+0
iny
lda (VARPNT),y
sta __FAC1+1
iny
lda (VARPNT),y
sta __FAC1+2
#endif
#if HAS_OPCODES_65C02
bra FRMEVL_got_value
#else
jmp FRMEVL_got_value
#endif
!:
// There is one possibility left - a floating point value
// XXX implement this part
// Nothing recognized
jmp do_SYNTAX_error
//
// This subroutine handles the situation when we have to execute a BASIC function
// in place when parser normally expects a value
//
FRMEVL_execute_function:
// XXX implement this - use function_jumptable*
jmp do_NOT_IMPLEMENTED_error
//
// These two subroutines handles the situation when we got an unary operator
// in place when parser normally expects a value
//
FRMEVL_unary_not:
ldy #$0D // our code for unary NOT
skip_2_bytes_trash_nvz
// FALLTROUGH
FRMEVL_unary_minus:
ldy #$0E // our code for unary NOT
jmp FRMEVL_push_operator_address
//
// This subroutine handle brackets - it just calls FRMEVL recursively
// and consumes the closing bracket afterwards
//
FRMEVL_handle_bracket:
jsr FRMEVL
jsr fetch_character
cmp #$29 // closing bracket
beq FRMEVL_got_value
jmp do_SYNTAX_error
//
// This subroutine handles the situation when our value to fetch is PI
//
FRMEVL_fetch_PI:
// XXX implement this
jmp do_NOT_IMPLEMENTED_error
//
// This subroutine fetches the floating point value from the 'outside world'
//
FRMEVL_fetch_float:
// XXX implement this
jmp do_NOT_IMPLEMENTED_error
//
// This subroutine fetches the string value from the 'outside world'
//
FRMEVL_fetch_string:
// Mark return value as a string, set initial length as 0
ldx #$FF
stx VALTYP
inx
stx __FAC1 + 0
// Set pointer to start of the string
ldx TXTPTR + 0
stx __FAC1 + 1
ldx TXTPTR + 1
stx __FAC1 + 2
!:
// Search for closing quote
jsr fetch_character
cmp #$22
beq FRMEVL_got_value
cmp #$00
beq !+
inc __FAC1 + 0
bne !-
jmp do_STRING_TOO_LONG_error
!:
// No closing quote, but end of the data
#if !HAS_OPCODES_65CE02
jsr unconsume_character
#else
dew TXTPTR
#endif
// FALLTROUGH
//
// This subroutine handles the situation after fetching the value from 'outside world':
// - either there is nothing sane remaining there; if so, this value is or final result
// - or there is an operator following the value; in such case we have much more work to do;
// we push the current value and the operator to the stack and we proceed to fetch the next
// value (which is mandatory)
// small catch: if the priority of the new operator is not higher than priority of the last
// operator on the stack (sentinel is considered as the lowest priority operator) we first
// compute what currently is present on the stack - this enforces proper operator precedence
//
FRMEVL_got_value:
jsr is_end_of_statement
bcs FRMEVL_compute_all // compute the stack if expression ended
// FALLTROUGH
FRMEVL_fetch_operator:
// We have a value, but this is not the end of expression. Check if
// there is an operator waiting to be served
jsr fetch_operator
bcs FRMEVL_compute_all // if operator not recognized, compute what we have
// on stack and quit
// Move the new operator ID to .Y
tay
// Compare the priority of the last operator with the new one
pla
pha
cmp operator_priorities, y
bcc FRMEVL_push_value_operator
// Here the priority is not higher - so compute what we already have on stack
// but do not finish proccessing
sty OPPTR+1 // store .Y, we want to preserve it
lda #$FF // mark that we want to return here
sta OPPTR+0
!:
jmp FRMEVL_compute_partial
FRMEVL_compute_partial_return:
pla
pha
bne !-
ldy OPPTR+1
// FALLTROUGH
FRMEVL_push_value_operator:
// Push the value from FAC1
ldx VALTYP
bmi FRMEVL_push_string
// Push float
// XXX implement this
FRMEVL_push_string:
// Push string - length, address, type
lda __FAC1+0
pha
lda __FAC1+1
pha
lda __FAC1+2
pha
txa
pha
// FALLTROUGH
FRMEVL_push_operator_address:
// Check if there is enough stack space; this could not have been done earlier,
// as this is the place where unary operator support calls
tsx
cpx #$60 // XXX is this a safe threshold?
bcc_16 do_FORMULA_TOO_COMPLEX_error
// Push the operator address to stack, in a form
// suitable for RTS
lda operator_jumptable_hi, y
pha
lda operator_jumptable_lo, y
pha
// Push operator priority
lda operator_priorities, y
pha
// Continue
jmp FRMEVL_loop
//
// This part serves two purposes:
// - it is an exit point for the concrete operator implementations
// - it causes computation of everything which is stored on the stack
//
FRMEVL_compute_all:
lda #$00
sta OPPTR+0
// FALLTROUGH
FRMEVL_continue:
lda OPPTR+0
bne FRMEVL_compute_partial_return
// FALLTROUGH
FRMEVL_compute_partial:
// Now, we have to compute operation; at this point we should have a value
// in FAC1 and (most likely) operator on a stack
pla // priority does not matter here, get rid of it
rts // this either jumps to operator, or quits FRMEVL
+3
View File
@@ -0,0 +1,3 @@
This routine is desribed in Mapping the C64, page 102, and used at least by CCGMS terminal software - see here:
- https://raw.githubusercontent.com/spathiwa/ccgmsterm/master/original/5a.gs
@@ -0,0 +1,21 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tries to convert PETSCII in .A to a digit (0-9 values), sets Carry to indicate failure
//
convert_PETSCII_to_digit:
sec
sbc #$30
bcc convert_PETSCII_to_digit_fail
cmp #$0A
rts
convert_PETSCII_to_digit_fail:
sec
rts
+221
View File
@@ -0,0 +1,221 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 BASIC_1 #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
// 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.
// 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.
// Error messages reported by KERNAL
do_kernal_error: // .A = KERNAL error code, also almost matches BASIC error codes
// Convert to BASIC error code
tax
beq do_BREAK_error // XXX is 0 really a proper error code?
dex
#if (ROM_LAYOUT_M65 && SEGMENT_BASIC_1)
jmp do_basic_error
#else
bpl do_basic_error // branch always
#endif
// Error messages specific to OpenROMs BASIC dialect
do_MEMORY_CORRUPT_error:
.byte $E6
// Error messages compatible with CBM BASIC V7 dialect
do_FILE_READ_error:
.byte $E6
do_NOT_IMPLEMENTED_error:
.byte $E6
do_UNRESOLVED_REFERENCE_error:
.byte $E6
do_LINE_NUMBER_TOO_LARGE_error:
.byte $E6
do_BEND_NOT_FOUND_error:
.byte $E6
do_BAD_DISK_error:
.byte $E6
do_NO_GRAPHICS_AREA_error:
.byte $E6
do_DIRECT_MODE_ONLY_error:
.byte $E6
do_LOOP_WITHOUT_DO_error:
.byte $E6
do_LOOP_NOT_FOUND_error:
.byte $E6
do_CANT_RESUME_error:
.byte $E6
// Error messages compatible with CBM BASIC V2 dialect
do_BREAK_error:
.byte $E6
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
#if (ROM_LAYOUT_M65 && SEGMENT_BASIC_1)
jmp do_error_fetch
#else
// FALLTROUGH
do_error_fetch:
// Now get the error id 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
// FALLTHROUGH
do_basic_error: // error code in .X
#if ROM_LAYOUT_M65
// Make sure we are back with normal memory map
jsr map_NORMAL
#endif
// "?"
phx_trash_a
ldx #IDX__STR_RET_QM
jsr print_packed_misc_str
plx_trash_a
// Error message text + " ERROR"
jsr print_packed_error
ldx #IDX__STR_ERROR
jsr print_packed_misc_str
// Check if direct mode
lda CURLIN+1
cmp #$FF
beq !+
// We were in a program, so show IN <line>
ldx #IDX__STR_IN
jsr print_packed_misc_str
lda CURLIN+1
ldx CURLIN+0
jsr print_integer
!:
// Reset stack, and go back to main loop
ldx #$FE
txs
jmp shell_main_loop
#endif // ROM layout
@@ -0,0 +1,110 @@
// #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 if original ROM does this too
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
// This is a good place to reset the temporary string stack
lda #$19
sta TEMPPT
lda #$16
sta LASTPT
// 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
@@ -0,0 +1,23 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
//
// Executes the next command - after previous got finished
//
end_of_statement:
jsr tmpstr_free_all
jsr fetch_character_skip_spaces
cmp #$3A // check for colon
beq_16 execute_statements
cmp #$00 // check for end of the line
beq_16 execute_statements_end_of_line
// Unexpected character
jmp do_SYNTAX_error
@@ -0,0 +1,253 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tries to execute the statement, and all the subsequent ones
//
execute_statements:
// Check for RUN/STOP
lda STKEY
bpl_16 cmd_stop
// Skip over any white spaces and colons (':')
!:
jsr fetch_character_skip_spaces
cmp #$3A // colon, can be skipped
beq !-
// Check if end of the line
cmp #$00
beq execute_statements_end_of_line
// Not end of the line - it seems we actually have something to execute
// Move token code to .X
tax
// Push the 'end_of_statement' address for RTS
lda #>(end_of_statement - 1)
pha
lda #<(end_of_statement - 1)
pha
// Check if token is valid for execution
cpx #$7F
bcc_16 execute_statements_var_assign // not a token - try variable assign
cpx #$A6
bcs execute_statements_extended
#if !HAS_OPCODES_65C02
// Get the jump table entry for it, push it on the stack, and then RTS to start it.
lda command_jumptable_hi - $80, x
pha
lda command_jumptable_lo - $80, x
pha
rts
#else // HAS_OPCODES_65C02
// Use jumptable to go to the command routine
txa
asl
tax
jmp (command_jumptable, x)
#endif
execute_statements_extended:
// Support for extended BASIC commands
cpx #$CC
beq execute_statements_CC
cpx #$CD
beq execute_statements_CD
// 'GO' command has a strange token, it is placed after function tokens
cpx #$CB
beq_16 cmd_go
jmp do_SYNTAX_error
execute_statements_CC:
// Get the sub-token, check that it is valid
jsr fetch_character
cmp #$00
beq_16 do_SYNTAX_error
cmp #(TK__MAXTOKEN_keywords_CC+1)
bcs_16 do_SYNTAX_error
// Execute command
#if !HAS_OPCODES_65C02
// Get the jump table entry for it, push it on the stack, and then RTS to start it.
tax
lda command_CC_jumptable_hi - 1, x
pha
lda command_CC_jumptable_lo - 1, x
pha
rts
#else // HAS_OPCODES_65C02
// Use jumptable to go to the command routine
asl
tax
jmp (command_CC_jumptable - 2, x)
#endif
execute_statements_CD:
// Get the sub-token, check that it is valid
jsr fetch_character
cmp #$00
beq_16 do_SYNTAX_error
cmp #(TK__MAXTOKEN_keywords_CD+1)
bcs_16 do_SYNTAX_error
// Execute command
#if !HAS_OPCODES_65C02
// Get the jump table entry for it, push it on the stack, and then RTS to start it.
tax
lda command_CD_jumptable_hi - 1, x
pha
lda command_CD_jumptable_lo - 1, x
pha
rts
#else // HAS_OPCODES_65C02
// Use jumptable to go to the command routine
asl
tax
jmp (command_CD_jumptable - 2, x)
#endif
execute_statements_end_of_line:
// First check, if we are in direct mode - if so,
// end the execution and go to main loop
ldx CURLIN+1
inx
beq_16 shell_main_loop
// Advance to the next line - first copy the line number
// to previous line number
lda CURLIN+0
sta OLDLIN+0
lda CURLIN+1
sta OLDLIN+1
// Advance the basic line pointer to the next line; if end,
// go to the main loop
jsr follow_link_to_next_line
lda OLDTXT+0
ora OLDTXT+1
beq_16 shell_main_loop
// FALLTROUGH
execute_line:
// Check if pointer is null, if so, we are at the end of the program
ldy #0
jsr peek_line_pointer_null_check
bcc_16 shell_main_loop // branch if end of program reached
// Skip pointer and line number to get address of first statement
lda OLDTXT+0
clc
adc #$04
sta TXTPTR+0
lda OLDTXT+1
adc #$00
sta TXTPTR+1
ldy #$02
#if CONFIG_MEMORY_MODEL_60K
ldx #<OLDTXT
jsr peek_under_roms
#elif CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
jsr peek_under_roms_via_OLDTXT
#else // CONFIG_MEMORY_MODEL_38K
lda (OLDTXT),y
#endif
sta CURLIN+0
iny
#if CONFIG_MEMORY_MODEL_60K
jsr peek_under_roms
#elif CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
jsr peek_under_roms_via_OLDTXT
#else // CONFIG_MEMORY_MODEL_38K
lda (OLDTXT),y
#endif
sta CURLIN+1
jmp execute_statements
execute_statements_var_assign:
// Prevent wedges from being executed within a program
#if CONFIG_TAPE_WEDGE
cpx #$40
beq_16 do_DIRECT_MODE_ONLY_error
#endif
#if CONFIG_DOS_WEDGE
cpx #$5F
beq_16 do_DIRECT_MODE_ONLY_error
#endif
// Try variable assignment - execute as LET command
#if !HAS_OPCODES_65CE02
jsr unconsume_character
#else
dew TXTPTR
#endif
jmp assign_variable
@@ -0,0 +1,21 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
//
// Fetches line number, stores it in LINNUM, sets Carry to indicate failure (not a number)
//
// Preserves both .X and .Y
//
fetch_line_number:
lda #IDX__EV7_26 // 'LINE NUMBER TOO LARGE'
jsr fetch_uint16
bcs_16 do_SYNTAX_error
lda LINNUM+1
cmp #$FF
beq_16 do_LINE_NUMBER_TOO_LARGE_error
rts
+106
View File
@@ -0,0 +1,106 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
//
// Fetches an operator - for the expression parser
//
// Note: does not recognize unary operators
//
fetch_operator: // XXX change the operator code to start from 0
// Retrieve the next character
jsr fetch_character
// Check if within range
sec
sbc #$AA
bcc fetch_operator_failed // branch if below 0
cmp #$0A
bcs fetch_operator_failed // branch if $0A or greater
// Now we have to recognize '>=', '<=' and '<>' operators
cmp #$07
beq fetch_operator_try_gteq
cmp #$09
beq fetch_operator_try_lteq_neq
// FALLTROUGH
fetch_operator_success:
clc
rts
fetch_operator_failed:
#if !HAS_OPCODES_65CE02
jsr unconsume_character
#else
dew TXTPTR
#endif
sec
rts
fetch_operator_try_gteq:
// Here we distinguish between '>' and '>='
jsr fetch_character
cmp #$B2 // '='
beq !+
// This is a '>'
#if !HAS_OPCODES_65CE02
jsr unconsume_character
#else
dew TXTPTR
#endif
lda #$07
bne fetch_operator_success // branch always
!:
// This is a '>='
lda #$0A
bne fetch_operator_success // branch always
fetch_operator_try_lteq_neq:
// Here we distinguish between '<', '<=', and '<>'
jsr fetch_character
cmp #$B2 // '='
beq !+
cmp #$B1 // '>'
beq !++
// This is a '<'
#if !HAS_OPCODES_65CE02
jsr unconsume_character
#else
dew TXTPTR
#endif
lda #$09
bne fetch_operator_success // branch always
!:
// This is a '<='
lda #$0B
bne fetch_operator_success // branch always
!:
// This is a '<>'
lda #$0C
bne fetch_operator_success // branch always
+128
View File
@@ -0,0 +1,128 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
//
// Fetches unsigned 16-bit integer, stores it in LINNUM, sets Carry to indicate failure (not a number)
//
// If value above 65535, error depends on .A opn entry
//
// Preserves both .X and .Y
//
fetch_uint16:
// Push the error code to stack
pha
// Fetch the first character (skip spaces), check if 0-9
jsr fetch_character_skip_spaces
jsr convert_PETSCII_to_digit
bcs fetch_uint16_rts
// First character seems to be correct - store it
sta LINNUM+0
lda #$00
sta LINNUM+1
// FALLTROUGH
fetch_uint16_loop:
// Try to fetch another digit
jsr fetch_character
jsr convert_PETSCII_to_digit
bcs fetch_uint16_end
// We got another digit - store it
pha
// Multiply current LINNUM by 10 (x * 10 = (x * 2) + (x * 2) * 4)
jsr fetch_uint16_mul_LINNUM_2
bcs fetch_uint16_1PLA_error
lda LINNUM+1
pha
lda LINNUM+0
pha
jsr fetch_uint16_mul_LINNUM_2
bcs fetch_uint16_3PLA_error
jsr fetch_uint16_mul_LINNUM_2
bcs fetch_uint16_3PLA_error
clc
pla
adc LINNUM+0
sta LINNUM+0
pla
adc LINNUM+1
sta LINNUM+1
bcs fetch_uint16_1PLA_error
// Add the new digit to LINNUM
pla
clc
adc LINNUM+0
sta LINNUM+0
lda LINNUM+1
adc #$00
sta LINNUM+1
bcs fetch_uint16_error
// Next iteration
#if HAS_OPCODES_65C02
bra fetch_uint16_loop
#else
jmp fetch_uint16_loop
#endif
fetch_uint16_end:
#if !HAS_OPCODES_65CE02
jsr unconsume_character
#else
dew TXTPTR
#endif
clc
// FALLTROUGH
fetch_uint16_rts:
pla
rts
fetch_uint16_mul_LINNUM_2:
asl LINNUM+0
rol LINNUM+1
rts
fetch_uint16_3PLA_error:
pla
pla
// FALLTROUGH
fetch_uint16_1PLA_error:
pla
// FALLTROUGH
fetch_uint16_error:
plx_trash_a
jmp do_basic_error
+27
View File
@@ -0,0 +1,27 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
//
// Fetches 8-bit unsigned integer
//
fetch_coma_uint8:
jsr injest_comma
bcs !+
// FALLTROUGH
fetch_uint8:
lda #IDX__EV2_0E // 'ILLEGAL QUANTITY ERROR'
jsr fetch_uint16
bcs !+
lda LINNUM+1
bne_16 do_ILLEGAL_QUANTITY_error
lda LINNUM+0
clc
!:
rts
@@ -0,0 +1,33 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
follow_link_to_next_line:
ldy #0
#if CONFIG_MEMORY_MODEL_60K
ldx #<OLDTXT+0
jsr peek_under_roms
#elif CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
jsr peek_under_roms_via_OLDTXT
#else // CONFIG_MEMORY_MODEL_38K
lda (OLDTXT),y
#endif
pha
iny
#if CONFIG_MEMORY_MODEL_60K
jsr peek_under_roms
#elif CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
jsr peek_under_roms_via_OLDTXT
#else // CONFIG_MEMORY_MODEL_38K
lda (OLDTXT),y
#endif
sta OLDTXT+1
pla
sta OLDTXT+0
rts
@@ -0,0 +1,40 @@
// #LAYOUT# STD * #TAKE-HIGH
// #LAYOUT# * BASIC_0 #TAKE-HIGH
// #LAYOUT# * * #IGNORE
// This has to go $E000 or above - routines below banks out the main BASIC ROM!
//
// Helper routine to copy string descriptor, for expression evaluator
//
#if CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
helper_frmevl_strdesccpy:
// Unmap BASIC lower ROM
lda #$26
sta CPU_R6510
// Copy string descriptor
ldy #$00
lda (VARPNT),y
sta __FAC1+0
iny
lda (VARPNT),y
sta __FAC1+1
iny
lda (VARPNT),y
sta __FAC1+2
// Restore default memory mapping
lda #$27
sta CPU_R6510
rts
#endif
+13
View File
@@ -0,0 +1,13 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
init_oldtxt:
lda TXTTAB+0
sta OLDTXT+0
lda TXTTAB+1
sta OLDTXT+1
rts
+29
View File
@@ -0,0 +1,29 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
//
// Consummes assign operator in a BASIC code, Carry set if not found. Injests all spaces.
//
injest_assign:
jsr fetch_character_skip_spaces
cmp #$B2 // assign operator character
beq injest_assign_found
// Not found
#if !HAS_OPCODES_65CE02
jsr unconsume_character
#else
dew TXTPTR
#endif
sec
rts
injest_assign_found:
clc
rts
+30
View File
@@ -0,0 +1,30 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
//
// Consummes a comma in a BASIC code, Carry set if not found. Injests all spaces.
//
injest_comma:
jsr fetch_character_skip_spaces
cmp #$2C // comma character
beq injest_comma_found
// Not found
#if !HAS_OPCODES_65CE02
jsr unconsume_character
#else
dew TXTPTR
#endif
sec
rts
injest_comma_found:
clc
rts
@@ -0,0 +1,39 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 BASIC_1 #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
//
// Check .A content, if within 0-9, A-Z ranges, sets Carry if check fails
//
is_09_AZ:
jsr is_AZ
bcs is_09
rts
is_09:
cmp #$30 // if below '0' - check failed
bcc is_alphanumeric_fail
cmp #$3A // if above '9' - check failed
rts
is_AZ:
cmp #$41 // if below 'A' - check failed
bcc is_alphanumeric_fail
cmp #$7B // if above 'Z' - check failed
rts
is_alphanumeric_fail:
sec
rts
@@ -0,0 +1,39 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
//
// Check for end of statement, sets Carry if so. Injests all spaces.
//
is_end_of_statement:
jsr fetch_character_skip_spaces
cmp #$00
beq !+
cmp #$3A
beq !+
// Not end of statement
#if !HAS_OPCODES_65CE02
jsr unconsume_character
#else
dew TXTPTR
#endif
clc
rts
!:
// End of statement
#if !HAS_OPCODES_65CE02
jsr unconsume_character
#else
dew TXTPTR
#endif
sec
rts
@@ -0,0 +1,38 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 BASIC_1 #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
//
// Prepare interpreter to execute commands in direct mode
//
prepare_direct_execution:
#if (ROM_LAYOUT_M65 && SEGMENT_BASIC_0)
jsr map_BASIC_1
jsr_ind VB1__prepare_direct_execution
jmp map_NORMAL
#else
// Setup pointer to the statement
lda #<BUF
sta TXTPTR+0
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
#endif // ROM layout
+23
View File
@@ -0,0 +1,23 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 BASIC_1 #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
// XXX for Mega65, it should be available in BASIC_1 segment only
select_device:
// Take last device number, make sure it is a drive - 8 or above. Above 30,
// although illegal for IEC we also consider a drive, as they exists
// drivers assigning these numbers to CBM-DOS capable devices - like some
// IEEE-488 carts.
//
// If current device is not a drive, set device to 8 (first drive number)
// Device number is left in X, for SETFLS Kernal routine
ldx FA
cpx #$08
bcs !+
ldx #$08
!:
rts
@@ -0,0 +1,23 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# * BASIC_0 #TAKE
// #LAYOUT# * * #IGNORE
//
// Reverses character fetch
//
#if !HAS_OPCODES_65CE02
unconsume_character:
lda TXTPTR+0
sec
sbc #$01
sta TXTPTR+0
lda TXTPTR+1
sbc #$00
sta TXTPTR+1
rts
#endif