Skip to content

Fix for mos_fgetc setting carry at every byte read with value >= 128 - #205

Open
envenomator wants to merge 1 commit into
AgonPlatform:mainfrom
envenomator:mos_fgetc_fix
Open

envenomator wants to merge 1 commit into
AgonPlatform:mainfrom
envenomator:mos_fgetc_fix

Conversation

@envenomator

Copy link
Copy Markdown
Contributor

MOS API call mos_fgetc (0x0C) incorrectly sets the carry flag after a byte is read with values >= 128.
This happens because in src/mos.c, the following code

char c;
...
return c | (fat_EOF(fo) << 8);

An UINT24 type is returned to the caller, which the compiler handles transfers using the HL register.

for c = 0x80 or higher, signed char becomes 0xFFFF80, so the returned H byte becomes 0xFF.

The high byte is shifted in the upstream caller to the carry bit (in mos_api.asm):

LD A,L
SRL H        ; carry = bit 0 of H

A is returned as the character read, any carry set is indicating end-of-file, which is incorrectly set using above code for values read larger than 127.

This issue can be easily reproduced using the following BBC Basic V code (either z80 or ez80 versions):

   10 F$ = "TEST.$$$"
   20 F% = OPENOUT(F$)
   30 BPUT#F%, STRING$(128, CHR$(128))
   40 CLOSE #F%
   50 F% = OPENIN(F$)
   60 A$ = GET$#F% BY 128
   65 PRINT "Expecting 128, got ";LEN(A$)
   70 IF LEN(A$)<>128 PRINT "Failed" : STOP
   80 CLOSE #F%

@envenomator

Copy link
Copy Markdown
Contributor Author

Summary for the release notes:
Fixed mos_fgetc incorrectly signalling EOF when reading bytes with bit 7 set (0x80–0xFF).
A signed char was sign-extended into the status byte returned to the MOS API layer, causing the EOF carry flag to be set for non-EOF data. This affected binary file reads and BBC BASIC GET$# operations on files containing bytes ≥ 128.

@stevesims stevesims left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice work

such a subtle bug that's been in there since Dean first wrote this function nearly 4 years ago - hidden in plain sight 😁

I question the sanity of whoever it was that decided that char should be a signed 8-bit integer 😉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants