Posted By
 SukkoPera on 2025-04-06 04:09:02
| Another RS232 KERNAL Bug
I think I've found another bug in the RS-232 KERNAL routines, I would like to hear your thoughts.
The bug happens when software flow control is enabled and we hit the low watermark, meaning that a XON should be sent so that the sender will resume sending data. The code goes like this:
; get a char out of the input buffer
agetch lda inqcnt ; got any? beq bukbuk ; nope, inqcnt=0 then return a $00
; not empty
php ; save int enb bit
; { mut-ex begin
sei ldx inqrpt ; do: inqrpt <- inqrpt+1 mod 64 inx txa and #$3f sta inqrpt plp
; mut-ex end }
tax lda inpque,x ; get char from queue pha ; save it dec inqcnt ; one less lda inqcnt cmp #lowatr ; low watermark? bne notlow ; nope
; hit low water mark
bit arstop ; is remote ~s'ed bpl notlow ; nope, then don't ~q lda xon beq notlow ; x-sw is off sta soutq ; send a ~q sec ror soutfg ; flag it lsr arstop ; remote now not ~s'ed (msb cleared)
aready ; entry for chkin & chkout bit apres ; is he there? bpl anrdy ; no, don't even bother to look bukbuk ; i'll just be jumping in here pha notlow ; here too lda astat ; get status definition and #$4f ; use bits 0..3, and 6 eor #$40 ; invert dsr sta status pla anrdy clc rts
The code is correct just until the aready label: I assume that the developers wanted to recycle some code from the aready routine (which has a further bug!) in order to update the in-memory copy of the ACIA status, but this won't work:
- The received character is stored on the stack and needs to be pulled out just before returning. - If there is no character in the incoming buffer, the code jumps to bukbuk right at the beginning. There they had to push a dummy byte to the stack just so that the pla before returning has something to pull out of it. Fair enough. - When we don't hit the low watermark, the code jumps to notlow, skipping bukbuk and its pha. So far, so good. - Although, when we DO hit the low watermark, the code sends the XON and then falls through to aready (which can be ignored) and bukbuk, resulting in two chars being pushed to the stack but only one pulled out, which causes the stack to get exhausted if enough data is sent.
The fix is to add a jmp notlow right before aready.
This is what was causing the +4 to hang while I was trying to add flow control to George's Tie Fighter demo.
I think there is yet another bug at the end: the current code will ALWAYS return with the carry cleared, but other parts of the code expect it to return with the carry set in case the ACIA was not ready. This also means that if this function gets called while the incoming buffer is empty, it will return bogus data and there is no way of knowing that!
What a mess! |