variable support cleanup
This commit is contained in:
1 parent
51aec45c8d
commit
09f85cea8a
64 files changed
+266
-87
No files matched your search
@@ -0,0 +1,283 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
|
||||
assign_variable:
|
||||
|
||||
// Fetch variable name, should be followed by assign operator
|
||||
|
||||
jsr fetch_variable
|
||||
|
||||
#if HAS_OPCODES_65CE02
|
||||
|
||||
bcs_16 do_SYNTAX_error
|
||||
jsr injest_assign
|
||||
bcs_16 do_SYNTAX_error
|
||||
|
||||
#else
|
||||
|
||||
bcs !+
|
||||
jsr injest_assign
|
||||
bcc !++
|
||||
!:
|
||||
jmp do_SYNTAX_error
|
||||
!:
|
||||
|
||||
#endif
|
||||
|
||||
// Determine variable type and push it to the stack
|
||||
|
||||
lda #$00
|
||||
clc
|
||||
bit VARNAM+0
|
||||
bpl !+
|
||||
adc #$01
|
||||
!:
|
||||
bit VARNAM+1
|
||||
bpl !+
|
||||
adc #$80
|
||||
!:
|
||||
pha
|
||||
|
||||
// Push the VARPNT to the stack - it might get overridden
|
||||
|
||||
lda VARPNT+0
|
||||
pha
|
||||
lda VARPNT+1
|
||||
pha
|
||||
|
||||
// Evaluate the expression
|
||||
|
||||
jsr FRMEVL
|
||||
|
||||
// Restore VARPNT
|
||||
|
||||
pla
|
||||
sta VARPNT+1
|
||||
pla
|
||||
sta VARPNT+0
|
||||
|
||||
// Determine what to assign
|
||||
|
||||
pla
|
||||
bmi assign_string
|
||||
beq assign_float
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
// XXX integer and float probably have much in common
|
||||
|
||||
assign_integer:
|
||||
|
||||
lda VALTYP
|
||||
bmi_16 do_TYPE_MISMATCH_error
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
|
||||
// XXX
|
||||
// XXX: implement this
|
||||
// XXX
|
||||
|
||||
#elif CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
// XXX consider optimized version without multiple JSRs
|
||||
|
||||
// XXX
|
||||
// XXX: implement this
|
||||
// XXX
|
||||
|
||||
#else // CONFIG_MEMORY_MODEL_38K
|
||||
|
||||
// XXX
|
||||
// XXX: implement this
|
||||
// XXX
|
||||
|
||||
#endif
|
||||
|
||||
jmp do_NOT_IMPLEMENTED_error
|
||||
|
||||
assign_float:
|
||||
|
||||
lda VALTYP
|
||||
bmi_16 do_TYPE_MISMATCH_error
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
|
||||
// XXX
|
||||
// XXX: implement this
|
||||
// XXX
|
||||
|
||||
#elif CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
// XXX consider optimized version without multiple JSRs
|
||||
|
||||
// XXX
|
||||
// XXX: implement this
|
||||
// XXX
|
||||
|
||||
#else // CONFIG_MEMORY_MODEL_38K
|
||||
|
||||
// XXX
|
||||
// XXX: implement this
|
||||
// XXX
|
||||
|
||||
#endif
|
||||
|
||||
jmp do_NOT_IMPLEMENTED_error
|
||||
|
||||
assign_string:
|
||||
|
||||
// Check if value type matches
|
||||
|
||||
lda VALTYP
|
||||
bpl_16 do_TYPE_MISMATCH_error
|
||||
|
||||
// Copy the string descriptor to DSCPNT
|
||||
|
||||
jsr helper_strdesccpy
|
||||
|
||||
// First special case - check if the new string has size 0
|
||||
|
||||
lda __FAC1+0
|
||||
bne assign_string_not_empty
|
||||
|
||||
// Yes, it is empty - free the old one
|
||||
|
||||
jsr varstr_free
|
||||
|
||||
// Set the new variable as empty string
|
||||
|
||||
ldy #$00
|
||||
lda #$00
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
ldx #<VARPNT
|
||||
jsr poke_under_roms
|
||||
#else // CONFIG_MEMORY_MODEL_38K || CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
sta (VARPNT), y
|
||||
#endif
|
||||
|
||||
rts
|
||||
|
||||
assign_string_not_empty:
|
||||
|
||||
// Check if the source and destination strings are the same
|
||||
|
||||
lda DSCPNT+1
|
||||
cmp __FAC1+1
|
||||
bne assign_string_not_same
|
||||
iny
|
||||
lda DSCPNT+2
|
||||
cmp __FAC1+2
|
||||
bne assign_string_not_same
|
||||
|
||||
// If we are here, than both source and destination strings are the same - nothing more to be done
|
||||
|
||||
rts
|
||||
|
||||
assign_string_not_same:
|
||||
|
||||
// Strings are not the same - check if the new one is located within the text area, between TXTTAB and VARTAB
|
||||
|
||||
lda VARTAB+1
|
||||
cmp __FAC1+2
|
||||
bcc assign_string_not_text_area
|
||||
bne !+
|
||||
lda VARTAB+0
|
||||
cmp __FAC1+1
|
||||
bcc assign_string_not_text_area
|
||||
!:
|
||||
lda __FAC1+2
|
||||
cmp TXTTAB+1
|
||||
bcc assign_string_not_text_area
|
||||
bne !+
|
||||
lda __FAC1+1
|
||||
cmp TXTTAB+0
|
||||
bcc assign_string_not_text_area
|
||||
!:
|
||||
// String is located within text area - great, just copy the descriptor
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
|
||||
// .X already contains #<VARPNT
|
||||
|
||||
ldy #$00
|
||||
lda __FAC1+0
|
||||
jsr poke_under_roms
|
||||
iny
|
||||
lda __FAC1+1
|
||||
jsr poke_under_roms
|
||||
iny
|
||||
lda __FAC1+2
|
||||
jsr poke_under_roms
|
||||
|
||||
#else // CONFIG_MEMORY_MODEL_38K || CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
|
||||
ldy #$00
|
||||
lda __FAC1+0
|
||||
sta (VARPNT), y
|
||||
iny
|
||||
lda __FAC1+1
|
||||
sta (VARPNT), y
|
||||
iny
|
||||
lda __FAC1+2
|
||||
sta (VARPNT), y
|
||||
|
||||
#endif
|
||||
|
||||
rts
|
||||
|
||||
assign_string_not_text_area:
|
||||
|
||||
// Check if the new string is a temporary one - if so, reuse alocation
|
||||
|
||||
// XXX
|
||||
|
||||
// Check if the old string belongs to the string area (is above FRETOP)
|
||||
|
||||
jsr helper_cmp_fretop
|
||||
bcc assign_string_no_optimizations
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
assign_string_try_reuse:
|
||||
|
||||
// Check if we can reuse old string memory
|
||||
|
||||
lda DSCPNT+0
|
||||
cmp __FAC1+0
|
||||
|
||||
// If size of both string equals - simply reuse it
|
||||
|
||||
beq_16 helper_strvarcpy
|
||||
|
||||
assign_string_try_reuse_unsuccesful:
|
||||
|
||||
// No special case optimization is possible - but first get rid of the old string
|
||||
|
||||
jsr varstr_free
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
assign_string_no_optimizations:
|
||||
|
||||
// Allocate memory for the new string
|
||||
|
||||
lda __FAC1+0
|
||||
ldy #$00
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
|
||||
ldx #<VARPNT
|
||||
jsr poke_under_roms
|
||||
|
||||
#else // CONFIG_MEMORY_MODEL_38K || CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
|
||||
sta (VARPNT), y
|
||||
|
||||
#endif
|
||||
|
||||
jsr varstr_alloc
|
||||
|
||||
// Copy the string and quit
|
||||
|
||||
jmp helper_strvarcpy
|
||||
@@ -0,0 +1,320 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Carry set = failure, not recognized variable name
|
||||
//
|
||||
|
||||
|
||||
fetch_variable:
|
||||
|
||||
// Set default second character and variable type
|
||||
|
||||
lda #$00
|
||||
sta VARNAM+1
|
||||
|
||||
// Fetch the first character of variable name
|
||||
|
||||
jsr fetch_character_skip_spaces
|
||||
jsr is_AZ
|
||||
bcc !+
|
||||
|
||||
#if !HAS_OPCODES_65CE02
|
||||
jsr unconsume_character
|
||||
#else
|
||||
dew TXTPTR
|
||||
#endif
|
||||
|
||||
sec
|
||||
rts
|
||||
!:
|
||||
sta VARNAM+0
|
||||
|
||||
// Fetch the (optional) second character
|
||||
|
||||
jsr fetch_character
|
||||
jsr is_09_AZ
|
||||
bcs fetch_variable_check_type
|
||||
|
||||
sta VARNAM+1
|
||||
|
||||
// Fetch the remaining variable characters - ignore them
|
||||
!:
|
||||
jsr fetch_character
|
||||
jsr is_09_AZ
|
||||
bcc !-
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
fetch_variable_check_type:
|
||||
|
||||
// Encode variable type within name, as documented in:
|
||||
// - https://sites.google.com/site/h2obsession/CBM/basic/variable-format
|
||||
|
||||
cmp #$24 // '$'
|
||||
beq fetch_variable_type_string
|
||||
cmp #$25 // '%'
|
||||
beq fetch_variable_type_integer
|
||||
|
||||
// FALLTORUGH
|
||||
|
||||
fetch_variable_type_float:
|
||||
|
||||
#if !HAS_OPCODES_65CE02
|
||||
jsr unconsume_character
|
||||
#else
|
||||
dew TXTPTR
|
||||
#endif
|
||||
|
||||
#if HAS_OPCODES_65C02
|
||||
bra fetch_variable_special
|
||||
#else
|
||||
jmp fetch_variable_special
|
||||
#endif
|
||||
|
||||
fetch_variable_type_integer:
|
||||
|
||||
lda VARNAM+0
|
||||
ora #$80
|
||||
sta VARNAM+0
|
||||
|
||||
lda #$00
|
||||
skip_2_bytes_trash_nvz
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
fetch_variable_type_string:
|
||||
|
||||
lda #$80
|
||||
sta VALTYP
|
||||
|
||||
lda VARNAM+1
|
||||
ora #$80
|
||||
sta VARNAM+1
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
fetch_variable_special:
|
||||
|
||||
lda VARNAM+0
|
||||
cmp #$54 // 'T'
|
||||
beq !+
|
||||
cmp #$53 // 'S'
|
||||
bne fetch_variable_find_addr
|
||||
|
||||
// First character is 'S', check the second one
|
||||
|
||||
lda VARNAM+1
|
||||
cmp #$54 // 'T'
|
||||
bne fetch_variable_find_addr
|
||||
|
||||
jmp fetch_variable_ST
|
||||
!:
|
||||
// First character is 'T', check the second one
|
||||
|
||||
lda VARNAM+1
|
||||
cmp #$49
|
||||
beq_16 fetch_variable_TI
|
||||
cmp #$C9
|
||||
beq_16 fetch_variable_TI_string
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
fetch_variable_find_addr:
|
||||
|
||||
// Now try to find variable address between VARTAB and ARYTAB, see
|
||||
// - https://www.c64-wiki.com/wiki/Memory_(BASIC)
|
||||
|
||||
lda VARTAB+0
|
||||
sta VARPNT+0
|
||||
lda VARTAB+1
|
||||
sta VARPNT+1
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
fetch_variable_find_addr_loop:
|
||||
|
||||
// Check if end of search loop
|
||||
|
||||
lda VARPNT+1
|
||||
cmp ARYTAB+1
|
||||
bne !+
|
||||
lda VARPNT+0
|
||||
cmp ARYTAB+0
|
||||
beq fetch_variable_alocate
|
||||
!:
|
||||
// Compare current variable name with searched one
|
||||
// XXX consider creating optimized version for 46K/50K memory models
|
||||
|
||||
ldy #$00
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
ldx #<VARPNT
|
||||
jsr peek_under_roms
|
||||
#elif CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
jsr peek_under_roms_via_VARPNT
|
||||
#else // CONFIG_MEMORY_MODEL_38K
|
||||
lda (VARPNT),y
|
||||
#endif
|
||||
|
||||
cmp VARNAM+0
|
||||
bne fetch_variable_find_addr_next
|
||||
|
||||
iny
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
jsr peek_under_roms
|
||||
#elif CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
jsr peek_under_roms_via_VARPNT
|
||||
#else // CONFIG_MEMORY_MODEL_38K
|
||||
lda (VARPNT),y
|
||||
#endif
|
||||
|
||||
cmp VARNAM+1
|
||||
bne fetch_variable_find_addr_next
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
fetch_variable_adjust_VARPNT:
|
||||
|
||||
// Adjust VARPNT to point just after variable name and quit
|
||||
|
||||
#if !HAS_OPCODES_65CE02
|
||||
|
||||
clc
|
||||
lda VARPNT+0
|
||||
adc #$02
|
||||
sta VARPNT+0
|
||||
bcc !+
|
||||
inc VARPNT+1
|
||||
!:
|
||||
#else // HAS_OPCODES_65CE02
|
||||
|
||||
inw VARPNT
|
||||
inw VARPNT
|
||||
|
||||
#endif
|
||||
|
||||
clc
|
||||
rts
|
||||
|
||||
fetch_variable_find_addr_next:
|
||||
|
||||
// Increase VARPNT by 7 - constant value, each variable uses 7 bytes, see:
|
||||
// - https://sites.google.com/site/h2obsession/CBM/basic/variable-format
|
||||
|
||||
clc
|
||||
lda VARPNT+0
|
||||
adc #$07
|
||||
sta VARPNT+0
|
||||
bcc fetch_variable_find_addr_loop
|
||||
inc VARPNT+1
|
||||
bne fetch_variable_find_addr_loop // branch always
|
||||
|
||||
fetch_variable_alocate:
|
||||
|
||||
// First check if we have enough space for a new descriptor (if FRETOP - STREND >= 7)
|
||||
|
||||
sec
|
||||
lda FRETOP+0
|
||||
sbc STREND+0
|
||||
pha
|
||||
lda FRETOP+1
|
||||
sbc STREND+1
|
||||
bne !+ // branch if high byte of result > 0
|
||||
|
||||
pla
|
||||
cmp #$07
|
||||
bcs fetch_variable_alocate_space_OK
|
||||
|
||||
jmp do_OUT_OF_MEMORY_error
|
||||
!:
|
||||
pla
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
fetch_variable_alocate_space_OK:
|
||||
|
||||
// If needed, move all the arrays up
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
|
||||
// XXX
|
||||
// XXX: implement this for arrays
|
||||
// XXX
|
||||
|
||||
#elif CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
// XXX consider optimized version without multiple JSRs
|
||||
|
||||
// XXX
|
||||
// XXX: implement this for arrays
|
||||
// XXX
|
||||
|
||||
#else // CONFIG_MEMORY_MODEL_38K
|
||||
|
||||
// XXX
|
||||
// XXX: implement this for arrays
|
||||
// XXX
|
||||
|
||||
#endif
|
||||
|
||||
// Adjust ARYTAB and STREND
|
||||
|
||||
clc
|
||||
lda STREND+0
|
||||
adc #$07
|
||||
sta STREND+0
|
||||
bcc !+
|
||||
inc STREND+1
|
||||
!:
|
||||
|
||||
clc
|
||||
lda ARYTAB+0
|
||||
adc #$07
|
||||
sta ARYTAB+0
|
||||
bcc !+
|
||||
inc ARYTAB+1
|
||||
!:
|
||||
// VARPNT already points to the start of the variable descriptor
|
||||
|
||||
// Fill-in the new variable name, descriptor (it is enough to zero first 2 bytes of content)
|
||||
|
||||
ldy #$00
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
|
||||
ldx #<VARPNT
|
||||
lda VARNAM+0
|
||||
jsr poke_under_roms
|
||||
iny
|
||||
lda VARNAM+1
|
||||
jsr poke_under_roms
|
||||
iny
|
||||
lda #$00
|
||||
jsr poke_under_roms
|
||||
iny
|
||||
jsr poke_under_roms
|
||||
|
||||
#else // CONFIG_MEMORY_MODEL_38K || CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
|
||||
lda VARNAM+0
|
||||
sta (VARPNT),y
|
||||
iny
|
||||
lda VARNAM+1
|
||||
sta (VARPNT),y
|
||||
iny
|
||||
lda #$00
|
||||
sta (VARPNT),y
|
||||
iny
|
||||
sta (VARPNT),y
|
||||
|
||||
#endif
|
||||
|
||||
// Adjust variable pointer and quit
|
||||
|
||||
#if HAS_OPCODES_65C02
|
||||
bra fetch_variable_adjust_VARPNT
|
||||
#else
|
||||
jmp fetch_variable_adjust_VARPNT
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
|
||||
fetch_variable_ST:
|
||||
|
||||
// XXX implement this
|
||||
|
||||
jmp do_NOT_IMPLEMENTED_error
|
||||
@@ -0,0 +1,10 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
|
||||
fetch_variable_TI:
|
||||
|
||||
// XXX implement this
|
||||
|
||||
jmp do_NOT_IMPLEMENTED_error
|
||||
@@ -0,0 +1,95 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
|
||||
// XXX does not fully work
|
||||
|
||||
fetch_variable_TI_string:
|
||||
|
||||
// Alocate memory for 6-byte temporary string, copy the string descriptor
|
||||
|
||||
lda #$06
|
||||
jsr tmpstr_alloc
|
||||
jsr helper_strdesccpy
|
||||
|
||||
// Fetch the time in a safe way, store it in temporary area
|
||||
|
||||
jsr JRDTIM
|
||||
|
||||
sty INDEX+0
|
||||
stx INDEX+1
|
||||
sta INDEX+2
|
||||
|
||||
// Now calculate the digits, starting from the most important one
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
ldx #<DSCPNT+1
|
||||
#endif
|
||||
|
||||
ldy #$00
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
fetch_variable_TI_string_loop:
|
||||
|
||||
// Set the initial digit value ('0')
|
||||
|
||||
lda #$30
|
||||
sta INDEX+3
|
||||
|
||||
// Compare the counter with value from table
|
||||
!:
|
||||
lda INDEX+2
|
||||
cmp table_TI_hi, y
|
||||
bcc fetch_variable_TI_string_got_digit
|
||||
bne fetch_variable_TI_string_inc_digit
|
||||
lda INDEX+1
|
||||
cmp table_TI_mid, y
|
||||
bcc fetch_variable_TI_string_got_digit
|
||||
bne fetch_variable_TI_string_inc_digit
|
||||
lda INDEX+0
|
||||
cmp table_TI_lo, y
|
||||
bcc fetch_variable_TI_string_got_digit
|
||||
|
||||
fetch_variable_TI_string_inc_digit:
|
||||
|
||||
// Increment digit and subtract the table value from the counter
|
||||
|
||||
inc INDEX+3
|
||||
|
||||
sec
|
||||
lda INDEX+0
|
||||
sbc table_TI_lo, y
|
||||
sta INDEX+0
|
||||
lda INDEX+1
|
||||
sbc table_TI_mid, y
|
||||
sta INDEX+1
|
||||
lda INDEX+2
|
||||
sbc table_TI_hi, y
|
||||
sta INDEX+2
|
||||
|
||||
bcs !- // branch always
|
||||
|
||||
fetch_variable_TI_string_got_digit:
|
||||
|
||||
// Copy digit to the string
|
||||
|
||||
lda INDEX+3
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
jsr poke_under_roms
|
||||
#else // CONFIG_MEMORY_MODEL_38K || CONFIG_MEMORY_MODEL_50K || CONFIG_MEMORY_MODEL_60K
|
||||
sta (DSCPNT+1), y
|
||||
#endif
|
||||
|
||||
// Next iteration
|
||||
|
||||
iny
|
||||
cpy #$06
|
||||
bne fetch_variable_TI_string_loop
|
||||
|
||||
// Return success
|
||||
|
||||
clc
|
||||
rts
|
||||
@@ -0,0 +1,22 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Check string address (DSCPNT+1/+2) vs FRETOP
|
||||
//
|
||||
// Output:
|
||||
// - Zero flag set - this is the first variable of the string area
|
||||
// - Carry flag set - this string belongs to the string area
|
||||
|
||||
|
||||
helper_cmp_fretop:
|
||||
|
||||
lda DSCPNT+2
|
||||
cmp FRETOP+1
|
||||
beq !+
|
||||
rts
|
||||
!:
|
||||
lda DSCPNT+1
|
||||
cmp FRETOP+0
|
||||
rts
|
||||
@@ -0,0 +1,31 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Helper routines for FRETOP handling
|
||||
//
|
||||
|
||||
helper_FRETOP_down_A: // .A - bytes to lower FRETOP, uses DSCPNT+0
|
||||
|
||||
sta DSCPNT+0
|
||||
|
||||
sec
|
||||
lda FRETOP+0
|
||||
sbc DSCPNT+0
|
||||
sta FRETOP+0
|
||||
bcs !+
|
||||
dec FRETOP+1
|
||||
!:
|
||||
// FALLTROUGH
|
||||
|
||||
helper_FRETOP_check: // check if FRETOP > STREND, Carry set if not
|
||||
|
||||
lda STREND+1
|
||||
cmp FRETOP+1
|
||||
beq !+
|
||||
rts
|
||||
!:
|
||||
lda STREND+0
|
||||
cmp FRETOP+0
|
||||
rts
|
||||
@@ -0,0 +1,19 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Helper routine for FRETOP handling
|
||||
//
|
||||
|
||||
|
||||
helper_FRETOP_up: // DSCPNT+0 - bytes to increment FRETO
|
||||
|
||||
clc
|
||||
lda FRETOP+0
|
||||
adc DSCPNT+0
|
||||
sta FRETOP+0
|
||||
bcc !+
|
||||
inc FRETOP+1
|
||||
!:
|
||||
rts
|
||||
@@ -0,0 +1,24 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Helper routine, used by garbage collector and string concatenation
|
||||
//
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_38K || CONFIG_MEMORY_MODEL_60K
|
||||
|
||||
helper_INDEX_up_A: // .A - bytes to increase TXTPTR, uses DSCPNT+0
|
||||
|
||||
sta DSCPNT+0
|
||||
|
||||
clc
|
||||
lda INDEX+0
|
||||
adc DSCPNT+0
|
||||
sta INDEX+0
|
||||
bcc !+
|
||||
dec INDEX+1
|
||||
!:
|
||||
rts
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
// #LAYOUT# STD * #TAKE-HIGH
|
||||
// #LAYOUT# * BASIC_0 #TAKE-HIGH
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
// This has to go $E000 or above - it can be used by routines which bank out the main BASIC ROM!
|
||||
|
||||
//
|
||||
// Helper routine, used by garbage collector and string concatenation
|
||||
//
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
|
||||
helper_INDEX_up_A: // .A - bytes to increase TXTPTR, uses DSCPNT+0
|
||||
|
||||
sta DSCPNT+0
|
||||
|
||||
clc
|
||||
lda INDEX+0
|
||||
adc DSCPNT+0
|
||||
sta INDEX+0
|
||||
bcc !+
|
||||
dec INDEX+1
|
||||
!:
|
||||
rts
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
// #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 for string concatenation
|
||||
//
|
||||
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
|
||||
helper_strconcat:
|
||||
|
||||
// Unmap BASIC lower ROM
|
||||
|
||||
lda #$26
|
||||
sta CPU_R6510
|
||||
|
||||
// Copy data from the first string
|
||||
|
||||
ldy #$00
|
||||
!:
|
||||
lda (__FAC2+1),y
|
||||
sta (INDEX),y
|
||||
iny
|
||||
cpy __FAC2+0
|
||||
bne !-
|
||||
|
||||
// Increase INDEX pointer by the size of the 1st string
|
||||
|
||||
tya
|
||||
jsr helper_INDEX_up_A
|
||||
|
||||
// Copy data from the second string
|
||||
|
||||
ldy #$00
|
||||
!:
|
||||
lda (__FAC1+1),y
|
||||
sta (INDEX),y
|
||||
iny
|
||||
cpy __FAC1+0
|
||||
bne !-
|
||||
|
||||
// Restore default memory mapping
|
||||
|
||||
lda #$27
|
||||
sta CPU_R6510
|
||||
|
||||
rts
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Helper routine to copy string descriptor
|
||||
//
|
||||
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_38K
|
||||
|
||||
helper_strdesccpy:
|
||||
|
||||
ldy #$00
|
||||
lda (VARPNT), y
|
||||
sta DSCPNT+0
|
||||
iny
|
||||
lda (VARPNT), y
|
||||
sta DSCPNT+1
|
||||
iny
|
||||
lda (VARPNT), y
|
||||
sta DSCPNT+2
|
||||
|
||||
rts
|
||||
|
||||
#endif
|
||||
@@ -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
|
||||
//
|
||||
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
|
||||
helper_strdesccpy:
|
||||
|
||||
// Unmap BASIC lower ROM
|
||||
|
||||
lda #$26
|
||||
sta CPU_R6510
|
||||
|
||||
// Retrieve pointer to destination
|
||||
|
||||
ldy #$00
|
||||
lda (VARPNT), y
|
||||
sta DSCPNT+0
|
||||
iny
|
||||
lda (VARPNT), y
|
||||
sta DSCPNT+1
|
||||
iny
|
||||
lda (VARPNT), y
|
||||
sta DSCPNT+2
|
||||
|
||||
// Restore default memory mapping
|
||||
|
||||
lda #$27
|
||||
sta CPU_R6510
|
||||
|
||||
rts
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Helper routine to copy string descriptor
|
||||
//
|
||||
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
|
||||
helper_strdesccpy:
|
||||
|
||||
ldx #<VARPNT
|
||||
|
||||
ldy #$00
|
||||
jsr peek_under_roms
|
||||
sta DSCPNT+0
|
||||
iny
|
||||
jsr peek_under_roms
|
||||
sta DSCPNT+1
|
||||
iny
|
||||
jsr peek_under_roms
|
||||
sta DSCPNT+2
|
||||
|
||||
rts
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Helper routine to copy string descriptor
|
||||
//
|
||||
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_38K
|
||||
|
||||
helper_strvarcpy:
|
||||
|
||||
// Retrieve pointer to destination
|
||||
|
||||
ldy #$02
|
||||
lda (VARPNT), y
|
||||
sta DSCPNT+2
|
||||
dey
|
||||
lda (VARPNT), y
|
||||
sta DSCPNT+1
|
||||
dey
|
||||
|
||||
// .Y is now 0 - copy the content
|
||||
!:
|
||||
lda (__FAC1+1),y
|
||||
sta (DSCPNT+1),y
|
||||
iny
|
||||
cpy __FAC1+0
|
||||
bne !-
|
||||
|
||||
rts
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
// #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 variable content
|
||||
//
|
||||
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
|
||||
helper_strvarcpy:
|
||||
|
||||
// Unmap BASIC lower ROM
|
||||
|
||||
lda #$26
|
||||
sta CPU_R6510
|
||||
|
||||
// Retrieve pointer to destination
|
||||
|
||||
ldy #$02
|
||||
lda (VARPNT), y
|
||||
sta DSCPNT+2
|
||||
dey
|
||||
lda (VARPNT), y
|
||||
sta DSCPNT+1
|
||||
dey
|
||||
|
||||
// Copy the string content
|
||||
!:
|
||||
lda (__FAC1+1),y
|
||||
sta (DSCPNT+1),y
|
||||
iny
|
||||
cpy __FAC1+0
|
||||
bne !-
|
||||
|
||||
// Restore default memory mapping
|
||||
|
||||
lda #$27
|
||||
sta CPU_R6510
|
||||
|
||||
rts
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Helper routine to copy string descriptor
|
||||
//
|
||||
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
|
||||
helper_strvarcpy:
|
||||
|
||||
ldx #<VARPNT
|
||||
|
||||
// Retrieve pointer to destination
|
||||
|
||||
ldy #$02
|
||||
jsr peek_under_roms
|
||||
sta DSCPNT+2
|
||||
dey
|
||||
jsr peek_under_roms
|
||||
sta DSCPNT+1
|
||||
dey
|
||||
|
||||
// .Y is now 0 - copy the content
|
||||
!:
|
||||
|
||||
ldx #<__FAC1+1
|
||||
jsr peek_under_roms
|
||||
ldx #<DSCPNT+1
|
||||
jsr poke_under_roms
|
||||
iny
|
||||
cpy __FAC1+0
|
||||
bne !-
|
||||
|
||||
rts
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Helper routine, used by garbage collector
|
||||
//
|
||||
|
||||
|
||||
helper_TXTPTR_down_A: // .A - bytes to decrease TXTPTR, uses DSCPNT+0
|
||||
|
||||
sta DSCPNT+0
|
||||
|
||||
sec
|
||||
lda TXTPTR+0
|
||||
sbc DSCPNT+0
|
||||
sta TXTPTR+0
|
||||
bcs !+
|
||||
dec TXTPTR+1
|
||||
!:
|
||||
rts
|
||||
@@ -0,0 +1,70 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Allocates memory for a temporary string
|
||||
//
|
||||
// Input:
|
||||
// -.A desired string length, has to be > 0
|
||||
//
|
||||
// Output:
|
||||
// - VARPNT points to the newly alocated descriptor
|
||||
//
|
||||
|
||||
tmpstr_alloc:
|
||||
|
||||
tax
|
||||
|
||||
// First we need to find a free temporary string descriptor
|
||||
|
||||
lda TEMPPT
|
||||
cmp #$22
|
||||
bcs tmpstr_alloc_try_reuse
|
||||
|
||||
tay
|
||||
sta LASTPT
|
||||
clc
|
||||
adc #$03
|
||||
sta TEMPPT
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
tmpstr_alloc_found:
|
||||
|
||||
// Store desired string length
|
||||
|
||||
stx $00, y
|
||||
|
||||
// Store descriptor address
|
||||
|
||||
sty VARPNT+0
|
||||
lda #$00
|
||||
sta VARPNT+1
|
||||
|
||||
// Jump to alocation routine
|
||||
|
||||
jmp varstr_alloc
|
||||
|
||||
tmpstr_alloc_try_reuse:
|
||||
|
||||
// It seems there is no space left - try to find empty entry
|
||||
|
||||
ldy #$19
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
tmpstr_alloc_try_reuse_loop:
|
||||
|
||||
lda $00, y
|
||||
beq tmpstr_alloc_found // branch if free entry found
|
||||
|
||||
iny
|
||||
iny
|
||||
iny
|
||||
cpy #$22
|
||||
bne tmpstr_alloc_try_reuse_loop
|
||||
|
||||
// Everything failed - give up
|
||||
|
||||
jmp do_FORMULA_TOO_COMPLEX_error
|
||||
@@ -0,0 +1,97 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Frees the string if it belongs to temporary string stack
|
||||
//
|
||||
// Input:
|
||||
// - DSCPNT+1/+2 - pointer to string (depending on the call addres, can fetch from FAC1/FAC2)
|
||||
//
|
||||
|
||||
|
||||
tmpstr_free_FAC1:
|
||||
|
||||
lda __FAC1+1
|
||||
sta DSCPNT+1
|
||||
lda __FAC1+2
|
||||
|
||||
#if HAS_OPCODES_65C02
|
||||
bra !+
|
||||
#else
|
||||
jmp !+
|
||||
#endif
|
||||
|
||||
tmpstr_free_FAC2:
|
||||
|
||||
lda __FAC2+1
|
||||
sta DSCPNT+1
|
||||
lda __FAC2+2
|
||||
!:
|
||||
sta DSCPNT+2
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
tmpstr_free:
|
||||
|
||||
// First find the descriptor matching the given string
|
||||
|
||||
ldx #$19
|
||||
|
||||
//FALLTROUGH
|
||||
|
||||
tmpstr_free_loop:
|
||||
|
||||
cpx TEMPPT
|
||||
bne !+
|
||||
rts // quit if not found
|
||||
!:
|
||||
// First fetch the string size - if 0, do not even try to compare
|
||||
|
||||
ldy $00, x
|
||||
beq tmpstr_free_next_3
|
||||
|
||||
// Check if current string
|
||||
|
||||
inx
|
||||
lda $00, x
|
||||
cmp DSCPNT+1
|
||||
bne tmpstr_free_next_2
|
||||
|
||||
inx
|
||||
lda $00, x
|
||||
cmp DSCPNT+2
|
||||
bne tmpstr_free_next_1
|
||||
|
||||
// This is the string we need to free
|
||||
|
||||
sty DSCPNT+0
|
||||
phx_trash_a
|
||||
jsr varstr_free
|
||||
plx_trash_a
|
||||
|
||||
// Mark empty string as free and quit
|
||||
|
||||
dex
|
||||
dex
|
||||
lda #$00
|
||||
sta $00, x
|
||||
|
||||
rts
|
||||
|
||||
tmpstr_free_next_3:
|
||||
|
||||
inx
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
tmpstr_free_next_2:
|
||||
|
||||
inx
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
tmpstr_free_next_1:
|
||||
|
||||
inx
|
||||
bne tmpstr_free_loop
|
||||
@@ -0,0 +1,20 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
|
||||
tmpstr_free_all:
|
||||
|
||||
// Go through all the temporary descriptors and free everything
|
||||
|
||||
ldx #$19
|
||||
|
||||
// XXX implement this
|
||||
|
||||
//FALLTROUGH
|
||||
|
||||
tmpstr_free_all_loop:
|
||||
|
||||
// XXX finish, deduplicate part with CLR
|
||||
|
||||
rts
|
||||
@@ -0,0 +1,145 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Allocates memory for string - lowers FRETOP (but not below STREND)
|
||||
//
|
||||
// Note: We are not going to use the C64-style memory management here, as it implies
|
||||
// a very slow garbage collector. Instead, we are using a scheme similar to used in
|
||||
// BASIC V3.5 and later, with 'back-pointers' after each string, telling about the
|
||||
// location of the string descriptor.
|
||||
//
|
||||
// See:
|
||||
// - https://www.c64-wiki.com/wiki/Memory_(BASIC)
|
||||
// - https://sites.google.com/site/h2obsession/CBM/basic/variable-format
|
||||
//
|
||||
// Input:
|
||||
// - VARPNT - pointer to string descriptor, first pointed byte should contain desired length
|
||||
// Output:
|
||||
// - fills-in pointer in the string descriptor
|
||||
//
|
||||
|
||||
// NOTE: if FAC1 or FAC2 contains a value (not a string descriptor - these are going to be updated
|
||||
// if garbage collector starts), then preserve __FAC1+1/+2 and __FAC2+1/+2 somewhere, as there
|
||||
// is a small chance they'll get damaged!
|
||||
|
||||
varstr_alloc:
|
||||
|
||||
// Mark garbage collector as not run yet
|
||||
|
||||
lda #$00
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
varstr_alloc_retry:
|
||||
|
||||
sta GARBFL // Computes Mapping the Commodore 64, page 10
|
||||
|
||||
// Backup FRETOP in case of alocation problems
|
||||
|
||||
lda FRETOP+0
|
||||
sta INDEX+0
|
||||
lda FRETOP+1
|
||||
sta INDEX+1
|
||||
|
||||
// Lower FRETOP to make space for the back-pointer
|
||||
|
||||
#if !HAS_OPCODES_65CE02
|
||||
|
||||
lda #$02
|
||||
jsr helper_FRETOP_down_A
|
||||
|
||||
#else // HAS_OPCODES_65CE02 - this time code is slightly longer, but faster
|
||||
|
||||
dew FRETOP
|
||||
dew FRETOP
|
||||
|
||||
jsr helper_FRETOP_check
|
||||
|
||||
#endif
|
||||
|
||||
bcs varstr_alloc_fail
|
||||
|
||||
// Create the back-pointer to the string descriptor
|
||||
|
||||
ldy #$00
|
||||
lda VARPNT+0
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
ldx #<FRETOP
|
||||
jsr poke_under_roms
|
||||
#else // CONFIG_MEMORY_MODEL_38K || CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
sta (FRETOP), y
|
||||
#endif
|
||||
|
||||
iny
|
||||
lda VARPNT+1
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
jsr poke_under_roms
|
||||
#else // CONFIG_MEMORY_MODEL_38K || CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
sta (FRETOP), y
|
||||
#endif
|
||||
|
||||
// Now lower FRETOP again to make space for the string content
|
||||
|
||||
ldy #$00
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
ldx #<VARPNT
|
||||
jsr peek_under_roms
|
||||
#elif CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
jsr peek_under_roms_via_VARPNT
|
||||
#else // CONFIG_MEMORY_MODEL_38K
|
||||
lda (VARPNT),y
|
||||
#endif
|
||||
|
||||
jsr helper_FRETOP_down_A
|
||||
bcs varstr_alloc_fail
|
||||
|
||||
// Success - fill in the string descriptor
|
||||
|
||||
ldy #$01
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
ldx #<VARPNT
|
||||
lda FRETOP+0
|
||||
jsr poke_under_roms
|
||||
iny
|
||||
lda FRETOP+1
|
||||
jsr poke_under_roms
|
||||
#else // CONFIG_MEMORY_MODEL_38K || CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
lda FRETOP+0
|
||||
sta (VARPNT), y
|
||||
iny
|
||||
lda FRETOP+1
|
||||
sta (VARPNT), y
|
||||
#endif
|
||||
|
||||
// The end
|
||||
|
||||
rts
|
||||
|
||||
varstr_alloc_fail:
|
||||
|
||||
// Unable to alocate memory - restore FRETOP value
|
||||
|
||||
lda INDEX+0
|
||||
sta FRETOP+0
|
||||
lda INDEX+1
|
||||
sta FRETOP+1
|
||||
|
||||
// Check if it is worth to perform garbage collection and retry
|
||||
|
||||
bit GARBFL
|
||||
bpl_16 do_OUT_OF_MEMORY_error
|
||||
|
||||
dec GARBFL // $00 -> $FF
|
||||
jsr varstr_garbage_collect
|
||||
|
||||
#if HAS_OPCODES_65C02
|
||||
bra varstr_alloc_retry
|
||||
#else
|
||||
jmp varstr_alloc_retry
|
||||
#endif
|
||||
@@ -0,0 +1,102 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
//
|
||||
// Releases back memory used by string
|
||||
//
|
||||
// Input:
|
||||
// - DSCPNT+0 - string size
|
||||
// - DSCPNT+1, DSCPNT+2 - pointer to string
|
||||
//
|
||||
|
||||
|
||||
varstr_free:
|
||||
|
||||
// Check the string size - do not do anything if 0
|
||||
|
||||
lda DSCPNT+0
|
||||
bne !+
|
||||
rts
|
||||
!:
|
||||
// Check if string is above FRETOP (in string area)
|
||||
// XXX move this check out of the routine
|
||||
|
||||
jsr helper_cmp_fretop
|
||||
bcs !+
|
||||
|
||||
// No, it does not belong to string area - quit
|
||||
|
||||
rts
|
||||
!:
|
||||
// Check if this is the lowest string
|
||||
|
||||
bne varstr_free_inside
|
||||
|
||||
// This is the lowest string - so just increase FRETOP, this way
|
||||
// the garbage collector will not be needed that quickly
|
||||
|
||||
jsr helper_FRETOP_up // free the string data
|
||||
|
||||
#if !HAS_OPCODES_65CE02
|
||||
|
||||
lda #$02 // free the back-pointer
|
||||
sta DSCPNT+0
|
||||
jmp helper_FRETOP_up
|
||||
|
||||
#else // HAS_OPCODES_65CE02
|
||||
|
||||
inw FRETOP // free the back-pointer
|
||||
inw FRETOP
|
||||
|
||||
rts
|
||||
|
||||
#endif
|
||||
|
||||
varstr_free_inside:
|
||||
|
||||
// This is not the lowest string; mark it as free
|
||||
// First preserve the string size, it will make it easier for the garbage collector
|
||||
|
||||
// Increase DSCPNT+1/+2 to point to the back-pointer minus 1
|
||||
|
||||
dec DSCPNT+0
|
||||
|
||||
clc
|
||||
lda DSCPNT+1
|
||||
adc DSCPNT+0
|
||||
sta DSCPNT+1
|
||||
bcc !+
|
||||
inc DSCPNT+2
|
||||
!:
|
||||
// Put the size-1, garbage collector will make use of this value
|
||||
|
||||
lda DSCPNT+0
|
||||
ldy #$00
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
ldx #<DSCPNT+1
|
||||
jsr poke_under_roms
|
||||
#else // CONFIG_MEMORY_MODEL_38K || CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
sta (DSCPNT+1), y
|
||||
#endif
|
||||
|
||||
// Now fill-in the back-pointer with 0's
|
||||
|
||||
tya
|
||||
iny
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
jsr poke_under_roms
|
||||
#else // CONFIG_MEMORY_MODEL_38K || CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
sta (DSCPNT+1), y
|
||||
#endif
|
||||
|
||||
iny
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
jmp poke_under_roms
|
||||
#else // CONFIG_MEMORY_MODEL_38K || CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
sta (DSCPNT+1), y
|
||||
rts
|
||||
#endif
|
||||
@@ -0,0 +1,352 @@
|
||||
// #LAYOUT# STD * #TAKE
|
||||
// #LAYOUT# * BASIC_0 #TAKE
|
||||
// #LAYOUT# * * #IGNORE
|
||||
|
||||
|
||||
varstr_garbage_collect:
|
||||
|
||||
// The routine utilizes the 'shift_mem_up' - which leaves INDEX+0 and INDEX+1
|
||||
// free to be used, but INDEX+2 and beyond would be overwritten
|
||||
|
||||
// We will reuse TXTPTR as the moving pointer, so store it on the stack
|
||||
|
||||
lda TXTPTR+0
|
||||
pha
|
||||
lda TXTPTR+1
|
||||
pha
|
||||
|
||||
// Similarly, we will reuse OLDTXT as the pointer to string descriptor
|
||||
|
||||
lda OLDTXT+0
|
||||
pha
|
||||
lda OLDTXT+1
|
||||
pha
|
||||
|
||||
// INDEX+0 and INDEX+1 will be our cumulative shift counter
|
||||
|
||||
lda #$00
|
||||
sta INDEX+0
|
||||
sta INDEX+1
|
||||
|
||||
// Start from the highest string and go downwards
|
||||
|
||||
lda MEMSIZ+0
|
||||
sta TXTPTR+0
|
||||
lda MEMSIZ+1
|
||||
sta TXTPTR+1
|
||||
|
||||
varstr_garbage_collect_loop:
|
||||
|
||||
// Check if this was the last (lowest) string (if FRETOP == TXTPTR)
|
||||
|
||||
lda FRETOP+1
|
||||
cmp TXTPTR+1
|
||||
bne varstr_garbage_collect_check_bptr
|
||||
lda FRETOP+0
|
||||
cmp TXTPTR+0
|
||||
bne varstr_garbage_collect_check_bptr
|
||||
|
||||
// End of strings - adapt FRETOP
|
||||
|
||||
clc
|
||||
lda INDEX+0
|
||||
adc FRETOP+0
|
||||
sta FRETOP+0
|
||||
lda INDEX+1
|
||||
adc FRETOP+1
|
||||
sta FRETOP+1
|
||||
|
||||
// FALLTROUGH
|
||||
|
||||
varstr_garbage_collect_end:
|
||||
|
||||
// Restore OLDTXT and TXTPTR, and quit
|
||||
|
||||
pla
|
||||
sta OLDTXT+1
|
||||
pla
|
||||
sta OLDTXT+0
|
||||
pla
|
||||
sta TXTPTR+1
|
||||
pla
|
||||
sta TXTPTR+0
|
||||
|
||||
rts
|
||||
|
||||
varstr_garbage_collect_check_bptr:
|
||||
|
||||
// Decrement TXTPTR by 2, so that it points to the back-pointer
|
||||
|
||||
#if !HAS_OPCODES_65CE02
|
||||
lda #$02
|
||||
jsr helper_TXTPTR_down_A
|
||||
#else // HAS_OPCODES_65CE02
|
||||
dew TXTPTR
|
||||
dew TXTPTR
|
||||
#endif
|
||||
|
||||
// Copy the back-pointer to OLDTXT, check if it is NULL
|
||||
|
||||
ldy #$00
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
ldx #<TXTPTR
|
||||
jsr peek_under_roms
|
||||
sta OLDTXT+0
|
||||
iny
|
||||
jsr peek_under_roms
|
||||
sta OLDTXT+1
|
||||
#elif CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
// XXX consider optimized version without multiple JSRs
|
||||
jsr peek_under_roms_via_TXTPTR
|
||||
sta OLDTXT+0
|
||||
iny
|
||||
jsr peek_under_roms_via_TXTPTR
|
||||
sta OLDTXT+1
|
||||
#else // CONFIG_MEMORY_MODEL_38K
|
||||
lda (TXTPTR),y
|
||||
sta OLDTXT+0
|
||||
iny
|
||||
lda (TXTPTR),y
|
||||
sta OLDTXT+1
|
||||
#endif
|
||||
|
||||
ora OLDTXT+0
|
||||
beq_16 varstr_garbage_collect_unused
|
||||
|
||||
// The back-pointer is not NULL - string is used
|
||||
|
||||
// Setup 'memmove__size' - number of bytes to copy
|
||||
|
||||
ldy #$00
|
||||
|
||||
#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 memmove__size+0
|
||||
lda #$00
|
||||
sta memmove__size+1
|
||||
|
||||
// The 'memmove__size' contains string length - add back-pointer size
|
||||
|
||||
#if !HAS_OPCODES_65CE02
|
||||
clc
|
||||
lda memmove__size+0
|
||||
adc #$02
|
||||
sta memmove__size+0
|
||||
bcc !+
|
||||
inc memmove__size+1
|
||||
!:
|
||||
#else // HAS_OPCODES_65CE02
|
||||
inw memmove__size
|
||||
inw memmove__size
|
||||
#endif
|
||||
|
||||
// Setup 'memmove__src' - last byte of source
|
||||
|
||||
iny
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
jsr peek_under_roms
|
||||
sta memmove__src+0
|
||||
iny
|
||||
jsr peek_under_roms
|
||||
sta memmove__src+1
|
||||
#elif CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
// XXX consider optimized version without multiple JSRs
|
||||
jsr peek_under_roms_via_OLDTXT
|
||||
sta memmove__src+0
|
||||
iny
|
||||
jsr peek_under_roms_via_OLDTXT
|
||||
sta memmove__src+1
|
||||
#else // CONFIG_MEMORY_MODEL_38K
|
||||
lda (OLDTXT),y
|
||||
sta memmove__src+0
|
||||
iny
|
||||
lda (OLDTXT),y
|
||||
sta memmove__src+1
|
||||
#endif
|
||||
|
||||
// The 'memmove__src' contains the first byte of source - add 'memmove__size' to it
|
||||
|
||||
clc
|
||||
lda memmove__src+0
|
||||
adc memmove__size+0
|
||||
sta memmove__src+0
|
||||
lda memmove__src+1
|
||||
adc memmove__size+1
|
||||
sta memmove__src+1
|
||||
|
||||
// Shift 'memmove__src' to point last byte of source
|
||||
|
||||
#if !HAS_OPCODES_65CE02
|
||||
sec
|
||||
lda memmove__src+0
|
||||
sbc #$01
|
||||
sta memmove__src+0
|
||||
bcs !+
|
||||
dec memmove__src+1
|
||||
!:
|
||||
#else // HAS_OPCODES_65CE02
|
||||
dew memmove__src
|
||||
#endif
|
||||
|
||||
// Setup 'memmove__dst' - last byte of destination
|
||||
|
||||
clc
|
||||
lda memmove__src+0
|
||||
adc INDEX+0
|
||||
sta memmove__dst+0
|
||||
lda memmove__src+1
|
||||
adc INDEX+1
|
||||
sta memmove__dst+1
|
||||
|
||||
// Increase the string descriptor pointer by INDEX, so that it will point to the new position
|
||||
|
||||
ldy #$01
|
||||
|
||||
#if CONFIG_MEMORY_MODEL_60K
|
||||
|
||||
ldx #<OLDTXT
|
||||
jsr peek_under_roms
|
||||
clc
|
||||
adc INDEX+0
|
||||
php
|
||||
jsr poke_under_roms
|
||||
|
||||
iny
|
||||
jsr peek_under_roms
|
||||
plp
|
||||
adc INDEX+1
|
||||
jsr poke_under_roms
|
||||
|
||||
#elif CONFIG_MEMORY_MODEL_46K || CONFIG_MEMORY_MODEL_50K
|
||||
// XXX consider optimized version without multiple JSRs
|
||||
|
||||
jsr peek_under_roms_via_OLDTXT
|
||||
clc
|
||||
adc INDEX+0
|
||||
sta (OLDTXT),y
|
||||
iny
|
||||
|
||||
php
|
||||
jsr peek_under_roms_via_OLDTXT
|
||||
plp
|
||||
adc INDEX+1
|
||||
sta (OLDTXT),y
|
||||
|
||||
#else // CONFIG_MEMORY_MODEL_38K
|
||||
|
||||
lda (OLDTXT),y
|
||||
clc
|
||||
adc INDEX+0
|
||||
sta (OLDTXT),y
|
||||
iny
|
||||
lda (OLDTXT),y
|
||||
adc INDEX+1
|
||||
sta (OLDTXT),y
|
||||
|
||||
#endif
|
||||
|
||||
// Move string memory up
|
||||
|
||||
jsr shift_mem_up
|
||||
|
||||
// Update TXTPTR
|
||||
|
||||
ldy #$00
|
||||
|
||||
#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
|
||||
|
||||
jsr helper_TXTPTR_down_A
|
||||
|
||||
// Check if variable descriptor in __FAC1 matches the previously moved string;
|
||||
// if so - adapt it too
|
||||
|
||||
lda __FAC1+2
|
||||
cmp TXTPTR+1
|
||||
bne !+
|
||||
lda __FAC1+1
|
||||
cmp TXTPTR+0
|
||||
bne !+
|
||||
|
||||
clc
|
||||
adc INDEX+0
|
||||
sta __FAC1+1
|
||||
lda __FAC1+2
|
||||
adc INDEX+1
|
||||
sta __FAC1+2
|
||||
!:
|
||||
// Same for __FAC2
|
||||
|
||||
lda __FAC2+2
|
||||
cmp TXTPTR+1
|
||||
bne !+
|
||||
lda __FAC2+1
|
||||
cmp TXTPTR+0
|
||||
bne !+
|
||||
|
||||
clc
|
||||
adc INDEX+0
|
||||
sta __FAC2+1
|
||||
lda __FAC2+2
|
||||
adc INDEX+1
|
||||
sta __FAC2+2
|
||||
!:
|
||||
// Next iteration
|
||||
|
||||
jmp varstr_garbage_collect_loop
|
||||
|
||||
varstr_garbage_collect_unused:
|
||||
|
||||
// The back-pointer is NULL - string is a garbage to collect
|
||||
// Fetch the string length
|
||||
|
||||
#if !HAS_OPCODES_65CE02
|
||||
lda #$01
|
||||
jsr helper_TXTPTR_down_A
|
||||
#else // HAS_OPCODES_65CE02
|
||||
dew TXTPTR
|
||||
#endif
|
||||
|
||||
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
|
||||
|
||||
tax
|
||||
|
||||
// Increase INDEX (shift offset) by string length + back-pointer length
|
||||
|
||||
lda #$03
|
||||
jsr helper_INDEX_up_A
|
||||
txa
|
||||
jsr helper_INDEX_up_A
|
||||
|
||||
// Decrease TXTPTR by unused string length-1
|
||||
|
||||
txa
|
||||
jsr helper_TXTPTR_down_A
|
||||
|
||||
// Next iteration
|
||||
|
||||
jmp varstr_garbage_collect_loop
|
||||
Reference in new issue
Block a user