durgadas311 / cosmac-elf

COS/MAC ELF Simulator
4 stars 1 forks source link

Tiny BASIC crashes when writing replacement statement #2

Open durgadas311 opened 3 years ago

durgadas311 commented 3 years ago

This was observed with the default sample program compiled-in. Once Tiny BASIC starts and completes running the sample program, entering the line "10 LET N=10" (CR) causes the crash. If the "NEW" command is used first, then the crash is avoided.

durgadas311 commented 3 years ago

The immediate cause of the crash is that memory at 8000h gets overwritten, and some critical LBR vectors there get corrupted and result in the crash/hang. The corruption occurs at instruction 0616H, where Tiny BASIC is copying a chunk of memory. The computation of the size of that chunk of memory was wrong, producing a large value (08BDFH) and the copy operation ends up trashing memory that it shouldn't. Need to back-track from this point and determine why the length is computed wrong.

durgadas311 commented 3 years ago

Some more about the symptoms. After starting Tiny BASIC and entering "NEW" to clear out the test program, I can re-enter the test program (e.g. paper tape) and then enter the replace for line 10 ("10 LET N=10") and it works fine (does not crash).

Digging a bit into the inner-workings of BASIC, there appears to be a "end of memory" pointer ("MEND") at 0x8024 which is supposed to point "a few" bytes past the end of the current program. At the time of entering the new statement, location 0x802e seems to hold the pointer to the current program memory ("SP"). These values are normally subtracted (SP-MEND) to compute the length of the memory copy, to make space for the replacement statement. Under normal (working) conditions, at this point, MEND=0x0d2c and SP=0x0d00 so the length value is reasonable. However, after startup with the test program, the values end up being MEND=0x8121 and SP=0x0d00, so the length value is 0x8bdf - much too large.

What I can't tell is whether this behavior is seen on real hardware or only my simulator. Perhaps no one has tried to overwrite the test program without first typing "NEW". However, based on traces before and after "NEW", it appears that the pointers are not setup correctly when BASIC contains an embedded test program.

durgadas311 commented 3 years ago

Interestingly, if I compile BASIC without the test program, it seems to run using memory at 0x8100 for program(s), not the location of the embedded program - 0x0d00. The AUTORUN feature may have bugs, although I don't have proof of that yet.

I'm not clear on whether Tiny BASIC is intended to run from ROM, but I did try loading it (w/embedded test program) as ROM (both 4K and 32K) and did not see a change to the crash.

So, one issue with the version that has no embedded test program (no AUTORUN) is that it seems to throw away a lot of memory (0xd00 - 0x7fff). The version with AUTORUN seems to use all of that memory, but has a flaw if "NEW" is not used to clear the test program.

durgadas311 commented 3 years ago

Reading more of the comments, it seems that this embedded "autostart" program is expected to be in "ROM", with the rest of Tiny BASIC. Some internal pointers are changed to point to the ROM area in order to run that program. If this were all in ROM, the program would not be alterable anyway, so perhaps this behavior does not indicate something broken as much as a situation that isn't "supported" and thus not handled well. Since giving the "NEW" command appears to make things work, perhaps it is enough to just be aware of this and leave it as-is.

However, if running as ROM (4K image), typing the "NEW" command allows statements to be entered without crashing but does not actually store the new statements as the pointer(s) still point to the area inside the ROM, which cannot be altered. It would appear that one cannot use Tiny BASIC for new programs if it was compiled with a test program (and is run from ROM).

durgadas311 commented 3 years ago

So, what's happening is that Tiny BASIC initializes the "BASIC" pointer from a constant of 0x8100, then (after discovering the AUTORUN program at 0x0d00) in COLD/CLEAR it computes MEND to be BASIC + 32. But after this call to COLD is when it then sets BASIC to 0x0d00 - where the program actually is. This leaves MEND set to 0x8121 but BASIC set to 0x0d00. When these two values are later used to compute the length of a memory move, it ends up trashing most of memory - more importantly, it overwrites critical data in 0x8000-0x8030 and causes the crash/hang.

So, I'm inclined to call this a Tiny BASIC bug that was introduced when adding the feature to AUTORUN an embedded (ROM) program.