accumulated fixes
Fixing string compare issues, stack floor protection and conditional NEXT.
This commit is contained in:
parent
241c4dc247
commit
d9f570859a
220
bugsnquirks.txt
220
bugsnquirks.txt
|
@ -23,6 +23,7 @@ filled/emptied or a count is reached.
|
|||
|
||||
|
||||
2. String handling when the string is in the input buffer.
|
||||
fixed in 2.22p3
|
||||
|
||||
When a string is entered via the input buffer (Ibuffs - Ibuffe) in Ehbasic it
|
||||
is transient because it gets overwritten by the next input. In this case it
|
||||
|
@ -87,6 +88,7 @@ evaluate -1 correctly.
|
|||
|
||||
|
||||
4. Use of decimal mode and invalid BCD
|
||||
fixed in 2.22p
|
||||
|
||||
There is only one place in EhBASIC where decimal mode is used. HEX$() uses
|
||||
invalid BCD to convert a number to a hexadecimal string. Some processors do not
|
||||
|
@ -140,6 +142,7 @@ LAB_HEXS
|
|||
|
||||
|
||||
5. Ibuffs located at $xx00
|
||||
fixed in 2.22p
|
||||
|
||||
If the input buffer is located at the beginning of a page then any direct
|
||||
statement (RUN, LIST, ...) is read from Ibuffs-$100 resulting in unexpected
|
||||
|
@ -183,6 +186,7 @@ Ibuffe = Ibuffs+$47; end of input buffer
|
|||
|
||||
|
||||
6. First statement after direct mode does not set the continue pointer
|
||||
fixed in 2.22p2
|
||||
|
||||
After a RUN or GOTO in direct mode CONT does not work for the first statement in
|
||||
run mode. It throws a "Can't continue error". If that first statement is INPUT
|
||||
|
@ -195,4 +199,218 @@ only cleared later in the same loop.
|
|||
The fix is in the patched folder (version 2.22p2). The continue counter is now
|
||||
always saved and the decision to continue is postponed until the CONT statement
|
||||
is executed and based on the fact that the continue pointer must not point to
|
||||
the input buffer in run mode.
|
||||
the input buffer in run mode.
|
||||
|
||||
LAB_1491
|
||||
LDX #des_sk ; set descriptor stack pointer
|
||||
STX next_s ; save descriptor stack pointer
|
||||
PLA ; pull return address low byte
|
||||
TAX ; copy return address low byte
|
||||
PLA ; pull return address high byte
|
||||
STX LAB_SKFE ; save to cleared stack
|
||||
STA LAB_SKFF ; save to cleared stack
|
||||
LDX #$FD ; new stack pointer
|
||||
TXS ; reset stack
|
||||
LDA #$00 ; clear byte
|
||||
;*** fix p2: no longer necessary as the continue pointer is saved anyway
|
||||
; STA Cpntrh ; clear continue pointer high byte
|
||||
STA Sufnxf ; clear subscript/FNX flag
|
||||
.........................................................................
|
||||
LAB_15C2
|
||||
JSR LAB_1629 ; do CRTL-C check vector
|
||||
LDA Bpntrl ; get BASIC execute pointer low byte
|
||||
LDY Bpntrh ; get BASIC execute pointer high byte
|
||||
|
||||
LDX Clineh ; continue line is $FFxx for immediate mode
|
||||
; ($00xx for RUN from immediate mode)
|
||||
INX ; increment it (now $00 if immediate mode)
|
||||
;*** fix p2: skip no longer necessary as the continue pointer is saved anyway
|
||||
; BEQ LAB_15D1 ; branch if null (immediate mode)
|
||||
|
||||
STA Cpntrl ; save continue pointer low byte
|
||||
STY Cpntrh ; save continue pointer high byte
|
||||
.........................................................................
|
||||
LAB_163B
|
||||
BNE LAB_167A ; if wasn't CTRL-C or there is a following byte return
|
||||
|
||||
LDA Bpntrh ; get the BASIC execute pointer high byte
|
||||
;*** fix p2: skip no longer necessary as the continue pointer is saved anyway
|
||||
; EOR #>Ibuffs ; compare with buffer address high byte (Cb unchanged)
|
||||
; BEQ LAB_164F ; branch if the BASIC pointer is in the input buffer
|
||||
; ; (can't continue in immediate mode)
|
||||
; ; else ..
|
||||
; EOR #>Ibuffs ; correct the bits
|
||||
LDY Bpntrl ; get BASIC execute pointer low byte
|
||||
.........................................................................
|
||||
LAB_CONT
|
||||
BNE LAB_167A ; if following byte exit to do syntax error
|
||||
|
||||
LDY Cpntrh ; get continue pointer high byte
|
||||
CPY #>Ibuffs ; *** fix p2: test direct mode
|
||||
BNE LAB_166C ; go do continue if we can
|
||||
.........................................................................
|
||||
LAB_1934
|
||||
JSR LAB_CKRN ; check not Direct, back here if ok
|
||||
JSR LAB_INLN ; print "? " and get BASIC input
|
||||
LDA #$00 ; set mode = INPUT
|
||||
CMP Ibuffs ; test first byte in buffer
|
||||
BNE LAB_1953 ; branch if not null input
|
||||
|
||||
; *** change p2: keep carry set to throw break message
|
||||
; CLC ; was null input so clear carry to exit program
|
||||
JMP LAB_1647 ; go do BREAK exit
|
||||
|
||||
|
||||
7. String compare of equal strings in direct mode returns FALSE
|
||||
fixed in 2.22p4
|
||||
|
||||
The string descriptor pointer of the 1st string is loaded to FAC1 mantissa
|
||||
bytes 2 & 3 and is later tranferred to FAC2 via the stack. The subroutine to put
|
||||
FAC1 on the stack is rounding up if FAC1_r is > $7F. In string operations FAC1_r
|
||||
is not initialized and rounding up may offset the string pointer high byte.
|
||||
|
||||
A patch is available to initialize FAC1_r to < $80 if the variable type is
|
||||
string.
|
||||
|
||||
LAB_1C25
|
||||
; *** begin patch string pointer high byte trashed when moved to stack
|
||||
; *** add
|
||||
LSR FAC1_r ; clear bit 7 (<$80) = do not round up
|
||||
; *** end patch
|
||||
RTS
|
||||
|
||||
|
||||
8. FALSE value stored to a variable after string compare is not exactly zero
|
||||
fixed in 2.22p4
|
||||
|
||||
When strings are compared and the result is stored to a variable (x=a$=b$) a
|
||||
FALSE result is not exactly 0 but only less than 1-E16. So IF var evaluates as
|
||||
true and falsely executes the statements after THEN.
|
||||
|
||||
After a compare FAC1 contains the result. The LET command should store FAC1 into
|
||||
the variable but actually stores a string pointer.
|
||||
|
||||
A patch is available to fix the LET command.
|
||||
|
||||
LAB_LET
|
||||
JSR LAB_GVAR ; get var address
|
||||
STA Lvarpl ; save var address low byte
|
||||
STY Lvarph ; save var address high byte
|
||||
LDA #TK_EQUAL ; get = token
|
||||
JSR LAB_SCCA ; scan for CHR$(A), else do syntax error then warm start
|
||||
LDA Dtypef ; get data type flag, $FF=string, $00=numeric
|
||||
PHA ; push data type flag
|
||||
JSR LAB_EVEX ; evaluate expression
|
||||
PLA ; pop data type flag
|
||||
ROL ; set carry if type = string
|
||||
; *** begin patch result of a string compare stores string pointer to variable
|
||||
; but should store FAC1 (true/false value)
|
||||
; *** replace
|
||||
; JSR LAB_CKTM ; type match check, set C for string
|
||||
; BNE LAB_17D5 ; branch if string
|
||||
; *** with
|
||||
JSR LAB_CKTM ; type match check, keep C (expected type)
|
||||
BCS LAB_17D5 ; branch if string
|
||||
; *** end patch
|
||||
|
||||
JMP LAB_PFAC ; pack FAC1 into variable (Lvarpl) and return
|
||||
|
||||
|
||||
9. The stack floor protection does not cater for background interrupts
|
||||
fixed in 2.22p4
|
||||
|
||||
EhBASIC makes heavy use of the stack. FOR, DO and GOSUB put their data
|
||||
structures on the stack and can be nested only limited by the stack size. The
|
||||
remaining free bytes on the stack are checked everytime a data structure is to
|
||||
be stored on the stack. However, this check is not catering for the additional
|
||||
stack space required by background interrupts of a monitor or operating system.
|
||||
|
||||
A patch is available to configure a value to raise the protected stack floor.
|
||||
|
||||
LAB_1212
|
||||
; *** patch - additional stack floor protection for background interrupts
|
||||
; *** add
|
||||
.IF Stack_floor
|
||||
CLC ; prep ADC
|
||||
ADC #Stack_floor ; stack pointer lower limit before interrupts
|
||||
.ENDIF
|
||||
; *** end patch
|
||||
STA TempB ; save result in temp byte
|
||||
TSX ; copy stack
|
||||
CPX TempB ; compare new "limit" with stack
|
||||
BCC LAB_OMER ; if stack < limit do "Out of memory" error then warm start
|
||||
|
||||
RTS
|
||||
|
||||
You should also define Stack_floor with other configuation items. I put it just
|
||||
after RAM_top.
|
||||
|
||||
Stack_floor = 16 ; bytes left free on stack for background interrupts
|
||||
|
||||
|
||||
10. Conditional NEXT throws a "NEXT without FOR Error"
|
||||
fixed in 2.22p4
|
||||
|
||||
If a NEXT statement is executed after IF THEN the FOR structure cannot be found.
|
||||
The NEXT expects the FOR structure at a fixed offset on the stack but the
|
||||
IF THEN puts an additional address on the stack. The additional address is
|
||||
required as EhBASIC allows an ELSE statement on the same line and the statement
|
||||
after the ELSE needs to be skipped.
|
||||
|
||||
The same is also true for other commands that need to find a data structure on
|
||||
the stack. The code already contained a fix for a conditional RETURN but it
|
||||
could not be used for LOOP (UNTIL/WHILE) or NEXT as it does not allow resuming
|
||||
execution after falling through.
|
||||
|
||||
I have a fix that simply discards the original call to the "interpret statement"
|
||||
routine (The one that executed the IF) and replaces the final RTS with a JMP to
|
||||
the interpreter loop. This also eliminates the need to have a separate fix for
|
||||
RETURN. To my big surprise even nested IFs work correctly.
|
||||
|
||||
LAB_174D
|
||||
; *** patch allow NEXT, LOOP & RETURN to find FOR, DO or GOSUB structure on stack
|
||||
; *** replace
|
||||
; CMP #TK_RETURN ; compare the byte with the token for RETURN
|
||||
; BNE LAB_174G ; if it wasn't RETURN go interpret BASIC code from (Bpntrl)
|
||||
; ; and return to this code to process any following code
|
||||
;
|
||||
; JMP LAB_1602 ; else it was RETURN so interpret BASIC code from (Bpntrl)
|
||||
; ; but don't return here
|
||||
;
|
||||
;LAB_174G
|
||||
; JSR LAB_15FF ; interpret BASIC code from (Bpntrl)
|
||||
;
|
||||
;; the IF was executed and there may be a following ELSE so the code needs to return
|
||||
;; here to check and ignore the ELSE if present
|
||||
;
|
||||
; LDY #$00 ; clear the index
|
||||
; LDA (Bpntrl),Y ; get the next BASIC byte
|
||||
; CMP #TK_ELSE ; compare it with the token for ELSE
|
||||
; BEQ LAB_DATA ; if ELSE ignore the following statement
|
||||
;
|
||||
;; there was no ELSE so continue execution of IF <expr> THEN <stat> [: <stat>]. any
|
||||
;; following ELSE will, correctly, cause a syntax error
|
||||
;
|
||||
; RTS ; else return to the interpreter inner loop
|
||||
;
|
||||
; *** with
|
||||
PLA ; discard interpreter loop return address
|
||||
PLA ; so data structures are at the correct stack offset
|
||||
JSR LAB_GBYT ; restore token or variable
|
||||
JSR LAB_15FF ; interpret BASIC code from (Bpntrl)
|
||||
|
||||
; the IF was executed and there may be a following ELSE so the code needs to return
|
||||
; here to check and ignore the ELSE if present
|
||||
|
||||
LDY #$00 ; clear the index
|
||||
LDA (Bpntrl),Y ; get the next BASIC byte
|
||||
CMP #TK_ELSE ; compare it with the token for ELSE
|
||||
BNE LAB_no_ELSE ; no - continue on this line
|
||||
JSR LAB_DATA ; yes - skip the rest of the line
|
||||
|
||||
; there was no ELSE so continue execution of IF <expr> THEN <stat> [: <stat>]. any
|
||||
; following ELSE will, correctly, cause a syntax error
|
||||
|
||||
LAB_no_ELSE
|
||||
JMP LAB_15C2 ; return to the interpreter inner loop
|
||||
; *** end patch allow NEXT, LOOP & RETURN to find FOR, DO or GOSUB structure on stack
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
; Enhanced BASIC to assemble under 6502 simulator, $ver 2.22p3
|
||||
; Enhanced BASIC to assemble under 6502 simulator, $ver 2.22p4
|
||||
|
||||
; $E7E1 $E7CF $E7C6 $E7D3 $E7D1 $E7D5 $E7CF $E81E $E825
|
||||
|
||||
|
@ -24,9 +24,15 @@
|
|||
; changed INPUT to throw "break in line ##" on empty line input
|
||||
; 2.22p3 fixed RAM above code / Ibuff above EhBASIC patch breaks STR$()
|
||||
; fix provided by github user mgcaret
|
||||
; 2.22p4 fixed string compare of equal strings in direct mode returns FALSE
|
||||
; fixed FALSE stored to a variable after a string compare
|
||||
; is > 0 and < 1E-16
|
||||
; added additional stack floor protection for background interrupts
|
||||
; fixed conditional LOOP & NEXT cannot find their data strucure on stack
|
||||
|
||||
; zero page use ..
|
||||
|
||||
; the following locations are bulk initialized from StrTab at LAB_GMEM
|
||||
LAB_WARM = $00 ; BASIC warm start entry point
|
||||
Wrmjpl = LAB_WARM+1; BASIC warm start vector jump low byte
|
||||
Wrmjph = LAB_WARM+2; BASIC warm start vector jump high byte
|
||||
|
@ -40,6 +46,7 @@ TWidth = $0F ; BASIC terminal width byte
|
|||
Iclim = $10 ; input column limit
|
||||
Itempl = $11 ; temporary integer low byte
|
||||
Itemph = Itempl+1 ; temporary integer high byte
|
||||
; end bulk initialize from StrTab at LAB_GMEM
|
||||
|
||||
nums_1 = Itempl ; number to bin/hex string convert MSB
|
||||
nums_2 = nums_1+1 ; number to bin/hex string convert
|
||||
|
@ -248,6 +255,7 @@ Cptrh = Aspth ; BASIC pointer temp low byte
|
|||
Sendl = Asptl ; BASIC pointer temp low byte
|
||||
Sendh = Aspth ; BASIC pointer temp low byte
|
||||
|
||||
; the following locations are bulk initialized from LAB_2CEE at LAB_2D4E
|
||||
LAB_IGBY = $BC ; get next BASIC byte subroutine
|
||||
|
||||
LAB_GBYT = $C2 ; get current BASIC byte subroutine
|
||||
|
@ -255,6 +263,7 @@ Bpntrl = $C3 ; BASIC execute (get byte) pointer low byte
|
|||
Bpntrh = Bpntrl+1 ; BASIC execute (get byte) pointer high byte
|
||||
|
||||
; = $D7 ; end of get BASIC char subroutine
|
||||
; end bulk initialize from LAB_2CEE at LAB_2D4E
|
||||
|
||||
Rbyte4 = $D8 ; extra PRNG byte
|
||||
Rbyte1 = Rbyte4+1 ; most significant PRNG byte
|
||||
|
@ -273,10 +282,8 @@ IrqBase = $DF ; IRQ handler enabled/setup/triggered flags
|
|||
; = $E0 ; IRQ handler addr low byte
|
||||
; = $E1 ; IRQ handler addr high byte
|
||||
|
||||
; = $DE ; unused
|
||||
; = $DF ; unused
|
||||
; = $E0 ; unused
|
||||
; = $E1 ; unused
|
||||
; *** removed unused comments for $DE-$E1
|
||||
|
||||
; = $E2 ; unused
|
||||
; = $E3 ; unused
|
||||
; = $E4 ; unused
|
||||
|
@ -426,16 +433,20 @@ LAB_SKFE = LAB_STAK+$FE
|
|||
LAB_SKFF = LAB_STAK+$FF
|
||||
; flushed stack address
|
||||
|
||||
; the following locations are bulk initialized from PG2_TABS at LAB_COLD
|
||||
ccflag = $0200 ; BASIC CTRL-C flag, 00 = enabled, 01 = dis
|
||||
ccbyte = ccflag+1 ; BASIC CTRL-C byte
|
||||
ccnull = ccbyte+1 ; BASIC CTRL-C byte timeout
|
||||
|
||||
VEC_CC = ccnull+1 ; ctrl c check vector
|
||||
; end bulk initialize from PG2_TABS at LAB_COLD
|
||||
|
||||
; the following locations are bulk initialized by min_mon.asm from LAB_vec at LAB_stlp
|
||||
VEC_IN = VEC_CC+2 ; input vector
|
||||
VEC_OUT = VEC_IN+2 ; output vector
|
||||
VEC_LD = VEC_OUT+2 ; load vector
|
||||
VEC_SV = VEC_LD+2 ; save vector
|
||||
; end bulk initialize by min_mon.asm from LAB_vec at LAB_stlp
|
||||
|
||||
; Ibuffs can now be anywhere in RAM, ensure that the max length is < $80,
|
||||
; the input buffer must not cross a page boundary and must not overlap with
|
||||
|
@ -449,6 +460,8 @@ Ibuffe = Ibuffs+$47; end of input buffer
|
|||
Ram_base = $0300 ; start of user RAM (set as needed, should be page aligned)
|
||||
Ram_top = $C000 ; end of user RAM+1 (set as needed, should be page aligned)
|
||||
|
||||
Stack_floor = 16 ; bytes left free on stack for background interrupts
|
||||
|
||||
; This start can be changed to suit your system
|
||||
|
||||
*= $C000
|
||||
|
@ -473,7 +486,7 @@ LAB_2D13
|
|||
LDA #$4C ; code for JMP
|
||||
STA Fnxjmp ; save for jump vector for functions
|
||||
|
||||
; copy block from LAB_2CEE to $00BC - $00D3
|
||||
; copy block from LAB_2CEE to $00BC - $00D7
|
||||
|
||||
LDX #StrTab-LAB_2CEE ; set byte count
|
||||
LAB_2D4E
|
||||
|
@ -695,6 +708,13 @@ LAB_120A
|
|||
; stack too deep? do OM error
|
||||
|
||||
LAB_1212
|
||||
; *** patch - additional stack floor protection for background interrupts
|
||||
; *** add
|
||||
.IF Stack_floor
|
||||
CLC ; prep ADC
|
||||
ADC #Stack_floor ; stack pointer lower limit before interrupts
|
||||
.ENDIF
|
||||
; *** end patch
|
||||
STA TempB ; save result in temp byte
|
||||
TSX ; copy stack
|
||||
CPX TempB ; compare new "limit" with stack
|
||||
|
@ -2021,14 +2041,35 @@ LAB_174C
|
|||
|
||||
; is var or keyword
|
||||
LAB_174D
|
||||
CMP #TK_RETURN ; compare the byte with the token for RETURN
|
||||
BNE LAB_174G ; if it wasn't RETURN go interpret BASIC code from (Bpntrl)
|
||||
; and return to this code to process any following code
|
||||
|
||||
JMP LAB_1602 ; else it was RETURN so interpret BASIC code from (Bpntrl)
|
||||
; but don't return here
|
||||
|
||||
LAB_174G
|
||||
; *** patch allow NEXT, LOOP & RETURN to find FOR, DO or GOSUB structure on stack
|
||||
; *** replace
|
||||
; CMP #TK_RETURN ; compare the byte with the token for RETURN
|
||||
; BNE LAB_174G ; if it wasn't RETURN go interpret BASIC code from (Bpntrl)
|
||||
; ; and return to this code to process any following code
|
||||
;
|
||||
; JMP LAB_1602 ; else it was RETURN so interpret BASIC code from (Bpntrl)
|
||||
; ; but don't return here
|
||||
;
|
||||
;LAB_174G
|
||||
; JSR LAB_15FF ; interpret BASIC code from (Bpntrl)
|
||||
;
|
||||
;; the IF was executed and there may be a following ELSE so the code needs to return
|
||||
;; here to check and ignore the ELSE if present
|
||||
;
|
||||
; LDY #$00 ; clear the index
|
||||
; LDA (Bpntrl),Y ; get the next BASIC byte
|
||||
; CMP #TK_ELSE ; compare it with the token for ELSE
|
||||
; BEQ LAB_DATA ; if ELSE ignore the following statement
|
||||
;
|
||||
;; there was no ELSE so continue execution of IF <expr> THEN <stat> [: <stat>]. any
|
||||
;; following ELSE will, correctly, cause a syntax error
|
||||
;
|
||||
; RTS ; else return to the interpreter inner loop
|
||||
;
|
||||
; *** with
|
||||
PLA ; discard interpreter loop return address
|
||||
PLA ; so data structures are at the correct stack offset
|
||||
JSR LAB_GBYT ; restore token or variable
|
||||
JSR LAB_15FF ; interpret BASIC code from (Bpntrl)
|
||||
|
||||
; the IF was executed and there may be a following ELSE so the code needs to return
|
||||
|
@ -2037,12 +2078,15 @@ LAB_174G
|
|||
LDY #$00 ; clear the index
|
||||
LDA (Bpntrl),Y ; get the next BASIC byte
|
||||
CMP #TK_ELSE ; compare it with the token for ELSE
|
||||
BEQ LAB_DATA ; if ELSE ignore the following statement
|
||||
BNE LAB_no_ELSE ; no - continue on this line
|
||||
JSR LAB_DATA ; yes - skip the rest of the line
|
||||
|
||||
; there was no ELSE so continue execution of IF <expr> THEN <stat> [: <stat>]. any
|
||||
; following ELSE will, correctly, cause a syntax error
|
||||
|
||||
RTS ; else return to the interpreter inner loop
|
||||
LAB_no_ELSE
|
||||
JMP LAB_15C2 ; return to the interpreter inner loop
|
||||
; *** end patch allow NEXT, LOOP & RETURN to find FOR, DO or GOSUB structure on stack
|
||||
|
||||
; perform ELSE after IF
|
||||
|
||||
|
@ -2239,8 +2283,15 @@ LAB_LET
|
|||
JSR LAB_EVEX ; evaluate expression
|
||||
PLA ; pop data type flag
|
||||
ROL ; set carry if type = string
|
||||
JSR LAB_CKTM ; type match check, set C for string
|
||||
BNE LAB_17D5 ; branch if string
|
||||
; *** begin patch result of a string compare stores string pointer to variable
|
||||
; but should store FAC1 (true/false value)
|
||||
; *** replace
|
||||
; JSR LAB_CKTM ; type match check, set C for string
|
||||
; BNE LAB_17D5 ; branch if string
|
||||
; *** with
|
||||
JSR LAB_CKTM ; type match check, keep C (expected type)
|
||||
BCS LAB_17D5 ; branch if string
|
||||
; *** end patch
|
||||
|
||||
JMP LAB_PFAC ; pack FAC1 into variable (Lvarpl) and return
|
||||
|
||||
|
@ -3259,6 +3310,10 @@ LAB_1C24
|
|||
JMP LAB_UFAC ; unpack memory (AY) into FAC1
|
||||
|
||||
LAB_1C25
|
||||
; *** begin patch string pointer high byte trashed when moved to stack
|
||||
; *** add
|
||||
LSR FAC1_r ; clear bit 7 (<$80) = do not round up
|
||||
; *** end patch
|
||||
RTS
|
||||
|
||||
; get value from line .. continued
|
||||
|
@ -7842,7 +7897,7 @@ LAB_MSZM
|
|||
|
||||
LAB_SMSG
|
||||
.byte " Bytes free",$0D,$0A,$0A
|
||||
.byte "Enhanced BASIC 2.22p3",$0A,$00
|
||||
.byte "Enhanced BASIC 2.22p4",$0A,$00
|
||||
|
||||
; numeric constants and series
|
||||
|
||||
|
|
Loading…
Reference in New Issue