Nice fixes!

 

This jogged my memory about a bug on the M100 version of TS-DOS is that it will 
let you try to LOAD a directory which of course promptly locks up the computer. 
I have not tested this on an 8201 to see if it acts the same.

 

Jeff

 

From: M100 <[email protected]> On Behalf Of Gary Weber
Sent: Wednesday, October 14, 2026 10:45 PM
To: [email protected]
Subject: [M100] The Story of 40 year old bugs in TS-DOS

 

Believe it or not, there are some TS-DOS NEC-specific bugs from 1986.  These 
have been there since the original NEC port that Traveling Software did of 
their Model 100 TS-DOS.

They relate to how DOS-ON LOAD"0:PROG.BA <http://PROG.BA> " works from BASIC.
1) If you have "DOS-ON" and do a LOAD"0:PROG.BA <http://PROG.BA> ", its line 
pointers are messed up and you have to return to the main menu and then back to 
BASIC to fix.
2) If you're in any other bank other than bank #1, LOAD"0:PROG.BA 
<http://PROG.BA> " simply hangs.  You always have to be in RAM bank #1 with 
TS-DOS 4.10 or earlier.

Both of these bugs are in the TS-DOS 4.10 stand-alone option ROM, as well as 
the one embedded in SARDOS.   I'm putting out a new TS-DOS 4.20 option ROM 
image as well as SARDOS 1.80 with fixes, and they're available here 
<https://www.web8201.net/default.asp?content=/Files/body.asp%3Fname=NEC%20Option%20ROM%20Images%26bknm=Back%20to%20Web8201%20Files%26bk=NEC-filedirlist.asp%26url=ROMS>
 .

If you want the nitty-gritty details, keep reading!

Bug #1: Any .BA that gets loaded from disk with LOAD"0:PROG.BA <http://PROG.BA> 
" keeps stale line links

Symptom: Wwith DOS-ON, LOAD"0:PROG.BA <http://PROG.BA> " followed by LIST shows 
only the first line and then garbage, or RUN fails. Going to the MENU and back 
into BASIC "fixes" it.

Why: Every line of tokenized BASIC starts with a 2-byte link, the absolute RAM 
address of the next line. A .BA file keeps the links from the address it was 
saved at. If it loads anywhere else, BASIC must rebuild them with the system 
ROM's LINKER routine. The BASIC program area starts right after the RAM files, 
so any difference in the files present moves it. The normal native ROM LOAD 
calls LINKER, and so does entering BASIC from the MENU, which is why the round 
trip hides the problem.

Now, if it just so happens that the .BA you are loading was the *first* .BA in 
RAM when it was saved to disk, and you're reloading it as the very first .BA in 
a freshly cleared RAM bank, the pointers will still be correct and you won't 
experience the problem.  But if you already have some .BA programs in memory 
when you do this LOAD, the pointers will be off and you will see this issue.  
(Want to try reproduce it?  Use TS-DOS 4.00 or 4.10, clear your RAM bank, 
create a small .BA program, SAVE"0:PROG.BA <http://PROG.BA> " to your TPDD 
drive or server, clear RAM again and then load up another program, i.e. 
LOAD"0:HELLO.BA <http://HELLO.BA> " and SAVE"HELLO.BA <http://HELLO.BA> " to 
your RAM directory, go back to BASIC and LOAD"0:PROG.BA <http://PROG.BA> " from 
your TPDD device that you had created earlier.  Then do a LIST.  Kaboom!)

Okay, so what's going on here?  In the original code, TS-DOS receives the file 
straight into the program area. Then it hands back to the system ROM's own LOAD 
code to finish:

44E8  CALL 4B1Bh       ; restore the serial settings
44EB  XRA  A
44EC  LXI  H,27B8h     ; system ROM LOAD tail...
44EF  PUSH H
44F0  JMP  00A5h       ; bank out and "return" into the system ROM at 27B8h

The NEC system ROM's LOAD tail code in ROM:

27AC  CALL 0714h       ; LINKER  <- skipped
  ...
27B5  CALL 280Bh       ; NEC only: give back the extra space reserved for the 
load
27B8  XRA  A           ; <- TS-DOS comes back in here

TS-DOS re-enters at 27B8h, past both LINKER and the space-trimming call. 
Skipping the trim is on purpose, because TS-DOS has already fixed the 
end-of-program pointer itself (44DA–44E5h), and doing it twice would corrupt 
it. Skipping LINKER is the side effect: nothing ever rebuilds the links.

My fix is in TS-DOS 4.20 stand-alone, and SARDOS 1.80: the call to restore the 
serial settings now goes through a 6-byte stub in unused option ROM space, and 
the stub runs LINKER too:

44E8  CALL 4CCEh       ; was CALL 4B1Bh
  ...
4CCE  CALL 4B1Bh       ; restore the serial settings, like it was already doing
4CD1  JMP  4CB6h       ; TS-DOS's existing system call: RST 1 / DW 0714h / RET 
= LINKER

LINKER runs on the new program, then control returns to 44EBh and the original 
hand-back carries on unchanged.

And so....  Why didn't the Model 100 TS-DOS code have this bug?? The Model 
100's TS-DOS ends its loader the same way (XRA A / LXI H,23F5h / PUSH H / JMP 
00A6h), but the Model 100 ROM's LOAD tail is in a different order:

23F5  JNZ  CLOADERR    ; <- TS-DOS returns here (A = 0, so no error)
  ...
2403  CALL 05F0h       ; LINKER: still ahead, so it runs

On the Model 100, LINKER comes after the point where TS-DOS returns, so the 
program is always relinked.

The NEC ROM loads differently, it first reserves extra space for the incoming 
program and gives back the excess afterwards (27B5h). It calls LINKER before 
that trim. When Traveling Software ported TS-DOS, the return point had to come 
after the trim, to avoid fixing the end pointer twice. On the NEC, that spot is 
also past LINKER.

It stayed hidden for years because on a freshly set-up machine the program area 
usually starts at the same address (8017h, after the TS-DOS menu entry). Most 
.BA files were saved from there, so their links happened to be right.

Bug #2: Disk LOAD"0:FILE.BA <http://FILE.BA> " hangs from RAM bank #2 or #3 on 
the NEC PC-8201A

On the PC-8201A, port A1h is one latch for two things: bits 0–1 select the ROM 
at 0000–7FFFh (system or option ROM), and bits 2–3 select which RAM bank 
appears at 8000–FFFFh.

After a disk .BA LOAD (LOAD"0:FILE.BA <http://FILE.BA> " with DOS-ON), TS-DOS 
has to call the system ROM's CLRPTR routine (22EEh) to reset BASIC's pointers. 
CLRPTR can't go through TS-DOS's normal bank-call path, so TS-DOS copies a 
small helper into RAM at FC8Ah and runs it there:

44FF  LXI  H,44F3h     ; copy the 12-byte helper...
      LXI  D,FC8Ah     ; ...into RAM
      LXI  B,000Ch
      CALL MOVE
      JMP  FC8Ah       ; and run it

FC8A  XRA  A           ; A = 00
      OUT  A1h         ; system ROM in -- but RAM bank bits = 00 too!
      CALL 22EEh       ; CLRPTR
      CALL F991h       ; bank TS-DOS back in (restores the right RAM bank)
      JMP  44CCh

The bug: XRA A / OUT A1h doesn't only switch to the system ROM. It also selects 
RAM bank #1. From bank #1 nothing goes wrong. But this helper runs from RAM, in 
the very area the bank switch replaces. From bank #2 or #3, the CPU's next 
instruction fetch, its stack, and CLRPTR itself all suddenly act on bank #1's 
memory. Bank #1's BASIC pointers get reset, the return address comes from the 
wrong bank, and the machine crashes into bank #1.

The same 12 bytes are in TS-DOS 4.0 (1986), 4.1 and 4.2, and in every SARDOS. 
It went unnoticed for about 40 years because almost everyone works in bank #1.

The fix: switch only the ROM and keep the current RAM bank, the same way 
TS-DOS's own bank-out routine does it:

FC8A  IN   A0h         ; read the current bank latch
      ANI  0Ch         ; keep the RAM-bank bits; ROM bits 00 = system ROM
      OUT  A1h         ; switch the ROM, stay in our RAM bank
      CALL 22EEh       ; CLRPTR
      CALL F991h       ; bank TS-DOS back in
      JMP  44CCh

The helper grew from 12 to 15 bytes, so it moved to free TS-DOS/SARDOS ROM 
space at 4FF0h, and the copy at 44FFh now copies 15 bytes from there.

The usual option-ROM trick won't work here: write the latch, read bank #1's 
saved bank number at F3DBh, then write the latch again. That only works in code 
running from ROM. In this helper, which runs from RAM, the instruction after 
the first OUT would already be fetched from bank #1.

--- 

Bottom line:  On your NEC, if you're using the TS-DOS 4.10 or earlier option 
ROM, you should switch to using TS-DOS 4.20.  Same for SARDOS 1.73 or earlier: 
switch to 1.80.

Both are available in the ROMs download area 
<https://www.web8201.net/default.asp?content=/Files/body.asp%3Fname=NEC%20Option%20ROM%20Images%26bknm=Back%20to%20Web8201%20Files%26bk=NEC-filedirlist.asp%26url=ROMS>
  up on Web8201.

-- 

Gary Weber
[email protected] <mailto:[email protected]> 

Reply via email to