more sane directory name, updated binaries
This commit is contained in:
1 parent
d4d32095d1
commit
76aaf298b8
697 files changed
+56
-56
No files matched your search
@@ -0,0 +1,324 @@
|
||||
// #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 end_of_statement_check
|
||||
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
|
||||
bcc FRMEVL_execute_function
|
||||
|
||||
// There are 2 possibilities left - a floating point value or a variable
|
||||
|
||||
|
||||
// XXX implement this part
|
||||
|
||||
|
||||
// Nothing recognized
|
||||
|
||||
jmp do_SYNTAX_error
|
||||
|
||||
//
|
||||
// This subroutine handles the situation when we have to execute a BASIC function
|
||||
// in place when parser normally expects a value
|
||||
//
|
||||
|
||||
FRMEVL_execute_function:
|
||||
|
||||
// XXX implement this - 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
|
||||
|
||||
jsr unconsume_character
|
||||
|
||||
// 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 end_of_statement_check
|
||||
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 #$40 // XXX is this a safe threshold?
|
||||
bcc_16 do_FORMULA_TOO_COMPLEX_error
|
||||
|
||||
// Push the operator address to stack, in a form
|
||||
// suitable for RTS
|
||||
|
||||
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
|
||||
@@ -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,26 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Allocates area for a temporary string
|
||||
//
|
||||
// Input:
|
||||
// - .A - string length
|
||||
//
|
||||
|
||||
|
||||
// XXX - finish the implementation once string memory handling is done
|
||||
|
||||
|
||||
alloc_temp_string:
|
||||
|
||||
// Check if temporary descriptor stack has a free slot
|
||||
|
||||
ldx LASTPT
|
||||
cpx #$1F
|
||||
bcs_16 do_FORMULA_TOO_COMPLEX_error
|
||||
|
||||
// XXX
|
||||
|
||||
jmp do_NOT_IMPLEMENTED_error
|
||||
@@ -0,0 +1,199 @@
|
||||
// #LAYOUT# STD * #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
|
||||
bpl do_basic_error // branch always
|
||||
|
||||
// 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
|
||||
|
||||
// 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
|
||||
|
||||
// "?"
|
||||
|
||||
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 basic_main_loop
|
||||
@@ -0,0 +1,45 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Check for end of statement, sets Carry if so. Injests all spaces.
|
||||
//
|
||||
|
||||
|
||||
end_of_statement_check:
|
||||
|
||||
// XXX this can probably be size-optimized
|
||||
|
||||
ldy #$00
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
ldx #<TXTPTR
|
||||
jsr peek_under_roms
|
||||
#elif CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
jsr peek_under_roms_via_TXTPTR
|
||||
#else // CONFIG_MEMORY_MODEL_38K
|
||||
lda (TXTPTR),y
|
||||
#endif
|
||||
|
||||
// Injest any spaces
|
||||
|
||||
cmp #$20
|
||||
bne !+
|
||||
jsr consume_character
|
||||
jmp end_of_statement_check
|
||||
!:
|
||||
cmp #$00
|
||||
beq !+
|
||||
cmp #$3A
|
||||
beq !+
|
||||
|
||||
// Not end of statement
|
||||
|
||||
clc
|
||||
rts
|
||||
!:
|
||||
// End of statement
|
||||
|
||||
sec
|
||||
rts
|
||||
@@ -0,0 +1,248 @@
|
||||
// #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
|
||||
cmp #$20 // space, can be skipped
|
||||
beq !-
|
||||
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
|
||||
|
||||
// Initialize temporary string stack - just about any statement might need it
|
||||
// XXX original C64 ROM initializes this during the startup too - not sure where to put this
|
||||
|
||||
ldx #$16
|
||||
stx LASTPT
|
||||
ldx #$19
|
||||
stx TEMPPT
|
||||
|
||||
// Check if token is valid for execution
|
||||
|
||||
cmp #$7F
|
||||
bcc_16 execute_statements_var_assign // not a token - try variable assign
|
||||
|
||||
cmp #$A6
|
||||
bcs execute_statements_extended
|
||||
|
||||
#if !HAS_OPCODES_65C02
|
||||
|
||||
// Get the jump table entry for it, push it on the stack, and then RTS to start it.
|
||||
|
||||
tax
|
||||
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
|
||||
|
||||
asl
|
||||
tax
|
||||
jmp (command_jumptable, x)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
execute_statements_extended:
|
||||
|
||||
// Support for extended BASIC commands
|
||||
|
||||
cmp #$CC
|
||||
beq execute_statements_CC
|
||||
cmp #$CD
|
||||
beq execute_statements_CD
|
||||
|
||||
// 'GO' command has a strange token, it is placed after function tokens
|
||||
|
||||
cmp #$CB
|
||||
beq_16 cmd_go
|
||||
|
||||
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 basic_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 basic_follow_link_to_next_line
|
||||
|
||||
lda OLDTXT+0
|
||||
ora OLDTXT+1
|
||||
beq_16 basic_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 basic_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:
|
||||
|
||||
// XXX here we should handle variable assignments, probably in a separate file
|
||||
|
||||
// Prevent wedges from being executed within a program
|
||||
|
||||
#if CONFIG_TAPE_WEDGE
|
||||
cmp #$40
|
||||
beq_16 do_DIRECT_MODE_ONLY_error
|
||||
#endif
|
||||
#if CONFIG_DOS_WEDGE
|
||||
cmp #$5F
|
||||
beq_16 do_DIRECT_MODE_ONLY_error
|
||||
#endif
|
||||
|
||||
jmp do_SYNTAX_error
|
||||
@@ -0,0 +1,48 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Fetches a single character
|
||||
//
|
||||
|
||||
|
||||
fetch_character:
|
||||
|
||||
ldy #0
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
|
||||
ldx #<TXTPTR
|
||||
jsr peek_under_roms
|
||||
|
||||
#elif CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
|
||||
jsr peek_under_roms_via_TXTPTR
|
||||
|
||||
#else // CONFIG_MEMORY_MODEL_38K
|
||||
|
||||
lda (TXTPTR),y
|
||||
|
||||
#endif
|
||||
|
||||
// FALLTHROUGH
|
||||
|
||||
consume_character:
|
||||
|
||||
// Advance basic text pointer
|
||||
|
||||
#if !HAS_OPCODES_65CE02
|
||||
|
||||
inc TXTPTR+0
|
||||
bne !+
|
||||
inc TXTPTR+1
|
||||
!:
|
||||
|
||||
#else // HAS_OPCODES_65CE02
|
||||
|
||||
inw TXTPTR
|
||||
|
||||
#endif
|
||||
|
||||
rts
|
||||
@@ -0,0 +1,94 @@
|
||||
// #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:
|
||||
|
||||
jsr unconsume_character
|
||||
|
||||
sec
|
||||
rts
|
||||
|
||||
|
||||
fetch_operator_try_gteq:
|
||||
|
||||
// Here we distinguish between '>' and '>='
|
||||
|
||||
jsr fetch_character
|
||||
cmp #$B2 // '='
|
||||
beq !+
|
||||
|
||||
// This is a '>'
|
||||
|
||||
jsr unconsume_character
|
||||
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 '<'
|
||||
|
||||
jsr unconsume_character
|
||||
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
|
||||
@@ -0,0 +1,26 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Fetches 8-bit unsigned integer
|
||||
//
|
||||
|
||||
|
||||
fetch_coma_uint8:
|
||||
|
||||
jsr injest_comma
|
||||
bcs !+
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
fetch_uint8:
|
||||
|
||||
jsr injest_spaces
|
||||
jsr basic_parse_line_number // XXX detect errors here
|
||||
lda LINNUM+1
|
||||
bne_16 do_ILLEGAL_QUANTITY_error
|
||||
lda LINNUM+0
|
||||
clc
|
||||
!:
|
||||
rts
|
||||
@@ -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
|
||||
@@ -0,0 +1,27 @@
|
||||
// #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
|
||||
cmp #$2C // comma character
|
||||
beq injest_comma_found
|
||||
cmp #$20 // space, can always be skipped
|
||||
beq injest_comma
|
||||
|
||||
// Not found
|
||||
jsr unconsume_character
|
||||
|
||||
sec
|
||||
rts
|
||||
|
||||
injest_comma_found:
|
||||
|
||||
clc
|
||||
rts
|
||||
@@ -0,0 +1,18 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Injests all spaces
|
||||
//
|
||||
|
||||
// XXX get rid of this when proper number parsing is implemented
|
||||
|
||||
|
||||
injest_spaces:
|
||||
|
||||
jsr fetch_character
|
||||
cmp #$20 // space, can be skipped
|
||||
beq injest_spaces
|
||||
|
||||
jmp unconsume_character
|
||||
@@ -0,0 +1,20 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Reverses character fetch
|
||||
//
|
||||
|
||||
|
||||
unconsume_character:
|
||||
|
||||
lda TXTPTR+0
|
||||
sec
|
||||
sbc #$01
|
||||
sta TXTPTR+0
|
||||
lda TXTPTR+1
|
||||
sbc #$00
|
||||
sta TXTPTR+1
|
||||
|
||||
rts
|
||||
Reference in new issue
Block a user