Skip to content

LOAD: do not mistake a line number for the end of file marker - #6

Open
stefanobaldo wants to merge 1 commit into
dimitrit:mainfrom
stefanobaldo:fix/load-line-number-eof
Open

LOAD: do not mistake a line number for the end of file marker#6
stefanobaldo wants to merge 1 commit into
dimitrit:mainfrom
stefanobaldo:fix/load-line-number-eof

Conversation

@stefanobaldo

Copy link
Copy Markdown

Closes #5.

The change

LOAD tested every byte it copied for 1ah, including the two bytes of each
line number, so a line whose number's low byte is 1ah ended the load and
everything after it was lost with no error reported.

The copy loop no longer tests for the marker. It cannot usefully do so: at the
moment it sees 1ah it has no idea whether that byte is a line number's low
half or the terminator, and telling those apart needs the previous line
number, which the loop cannot carry — the BDOS call between records destroys
the registers.

The end of the program is found afterwards, by walking the lines that were
read. Only at a line's first byte can 1ah be the marker, and even there it
is only the marker when the two bytes do not read as a line number greater
than the one before it: line numbers ascend, and the NUL padding that follows
a saved program's marker does not.

+50 −2 in src/cpmio.asm, and the two deleted lines are the cp 1ah and
its jr. Nothing else was restructured.

Measured

Before and after, on the CP/M build, counting the lines a LIST shows after
a LOAD:

file before after expected
100 / 1050 / 1100, the case in #5 1 3 3
10 / 26 / 30, the other degenerate number 1 3 3
examples/TICTAC.BAS, assembled to .TBA 94 117 117
examples/tictac.tba, exactly as shipped 94 117 117
a line 1050 placed inside the file's last record 13 15 15
a program with no such line number 3 3 3

examples/tictac.tba is worth a word: the file is complete, all 117 lines of
it. It only ever loaded as 94, which is why the game fails at line 1020 with
HOW? — its GOTO 1050 targets a line that was never brought into memory.
With this change it loads whole and the game plays. Nothing needs regenerating.

The ROMWBW build assembles byte for byte identical, as it must: this file is
only included for CP/M.

The residual

One case remains, and it is in the format rather than in this code: if the
bytes after the marker happen to read as an ascending line number followed by
a carriage return, the walk takes them for a line. A file saved by Tasty Basic
pads with NUL and cannot do that. Saying so rather than claiming the hole is
closed.

How it was tested

Under an emulated Z80 with a host-side BDOS, assembled with uz80as 2.02 using
the version string the Makefile passes. The counts above come from running the
patched and unpatched binaries over the same files.

LOAD tested every byte it copied for 1ah, including the two bytes of each
line number, so a line whose number's low byte is 1ah ended the load and
everything after it was lost without an error. Line numbers congruent to 26
modulo 256 are affected: 26, 282, 538, 794, 1050, and so on. This is issue dimitrit#5.

The copy loop no longer tests for the marker. It cannot usefully do so: at
the moment it sees 1ah it has no idea whether that byte is a line number's
low half or the terminator, and telling those apart needs the previous line
number, which the loop cannot carry because the BDOS call between records
destroys the registers.

The end of the program is found afterwards instead, by walking the lines that
were read. Only at a line's first byte can 1ah be the marker, and even there
it is only the marker when the two bytes do not read as a line number greater
than the one before it: line numbers ascend, and the NUL padding that follows
a saved program's marker does not.

One residual remains, and it is in the format rather than in this code: if the
bytes after the marker happen to read as an ascending line number followed by
a carriage return, the walk takes them for a line. A file saved by Tasty Basic
pads with NUL and cannot do that.

Measured before and after, on the CP/M build, with these files:

  file                                  before   after   expected
  100 / 1050 / 1100, as issue dimitrit#5           1       3        3
  10 / 26 / 30, the other degenerate       1       3        3
  examples/TICTAC.BAS, assembled          94     117      117
  examples/tictac.tba, as shipped         94     117      117
  a line 1050 inside the last record      13      15       15
  a program with no such number            3       3        3

The shipped tictac.tba is worth a word: the file is complete, all 117 lines of
it. It only ever loaded as 94, which is why the game fails at line 1020 on a
GOTO 1050 that was never brought into memory. Nothing needs regenerating.

The ROMWBW build is unaffected and assembles byte for byte identical; this
file is only included for CP/M.
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.

LOAD does not load complete program

1 participant