A curious bug in EhBasic
Posted: Sat Jun 21, 2025 10:20 pm
Hi everyone,
I recently encountered an issue with EhBasic, and I would like to hear opinions on this; in particular, do you agree that this is a bug in EhBasic, and if so, how can it best be fixed?
The issue is with the following code:
I posit that this cannot work on a system where interrupts are being handled. If the stack pointer is $FF going into this code (or $FE, but $FF actually seems to be typical), and an interrupt occurs somewhere after STX $1FE and before TXS, then the interrupt sequence will overwrite the return address that is being put on the stack here. It does not matter what the interrupt service routine does or does not do; the issue would exist even if it is nothing more than an RTI, as the problem already happens during the hardware controlled modification of the stack. Nothing terrible will happen immediately after the ISR returns, but the moment the RTS is executed, things will go awry.
(Background story: I discovered this after implementing RTS/CTS flow control for the serial port on my self-designed system, with the RTS/CTS lines controlled by software, and this required going from polled serial input to an interrupt-driven mechanism with a small ring buffer. EhBasic was actually a very good use case for this new code, because this would allow me to paste BASIC programs for my 6502 computer directly into the PuTTY window on my PC. Without flow control, EhBasic is too slow to process the input even at 19200 baud, and characters will be lost. Unfortunately, as soon as I started testing my fancy new IRQ code, I began experiencing very disconcerting behaviour: I would paste a program, and suddenly EhBasic would start new at the memory prompt, or I would find myself at the monitor prompt, and similar things. I took me a while to nail it down to this piece of code.)
To test my theory, I fixed the issue very simply like this:
And with this, my problems did indeed go away. A more sophisticated solution is not so easy to find. It seems like the right return address is already on the stack, just unfortunately in the wrong byte order. (Why this would be so, I have no idea. Incidentally I also have no idea why EhBasic goes through this kind of code when all I'm doing is entering a program.)
Now, if this were 65C02 code, you could simply do:
But EhBasic is not 65C02 code, and I'd like to keep it that way. It's not clear to me if I'm allowed to modify Y at this point in the code; that would also make things easier.
What are your thoughts?
I recently encountered an issue with EhBasic, and I would like to hear opinions on this; in particular, do you agree that this is a bug in EhBasic, and if so, how can it best be fixed?
The issue is with the following code:
Code: Select all
; flush stack and clear continue flag
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 $1FE ; save to cleared stack
STA $1FF ; save to cleared stack
LDX #$FD ; new stack pointer
TXS ; reset stack
LDA #$00 ; clear byte
.
.
RTS
(Background story: I discovered this after implementing RTS/CTS flow control for the serial port on my self-designed system, with the RTS/CTS lines controlled by software, and this required going from polled serial input to an interrupt-driven mechanism with a small ring buffer. EhBasic was actually a very good use case for this new code, because this would allow me to paste BASIC programs for my 6502 computer directly into the PuTTY window on my PC. Without flow control, EhBasic is too slow to process the input even at 19200 baud, and characters will be lost. Unfortunately, as soon as I started testing my fancy new IRQ code, I began experiencing very disconcerting behaviour: I would paste a program, and suddenly EhBasic would start new at the memory prompt, or I would find myself at the monitor prompt, and similar things. I took me a while to nail it down to this piece of code.)
To test my theory, I fixed the issue very simply like this:
Code: Select all
SEI
STX LAB_SKFE ; save to cleared stack
STA LAB_SKFF ; save to cleared stack
LDX #$FD ; new stack pointer
TXS ; reset stack
CLI
Now, if this were 65C02 code, you could simply do:
Code: Select all
PLX
PLA
PHX
PHA
What are your thoughts?