Okay, I've written a program which uses the method I proposed above for first allocating space for a .CO file via *SAVEM* and then POKEing directly into it. (As opposed to what I believe is the usual method of clearing space in RAM, poking memory to the RAM buffer, and then saving a copy to a new .CO file.)
Surprisingly, it works! Or rather, I *think* it works. I haven't blown up anything on my Tandy 200 (yet). Can people check my work and tell me if I'm doing something silly before I release a program that ends up POKEing bytes into the wrong places? On the Bitchin100 wiki, John mentioned sometimes needing to call the *LNKFIL <https://bitchin100.com/wiki/index.php?title=Low_Level_Filesystem_Access#LNKFIL>* ROM routine at 2146H in order to fix up the links to the files in the RAM Directory. I'm imagining one might have an existing .CO file which has to be resized during *SAVEM*, causing its address in RAM to change. If that happened and the RAM Directory wasn't updated, it would be disastrous. However, I believe (and correct me if I'm wrong) that *SAVEM* itself calls *LNKFIL* on all the different Model T / NEC / Kyocera / Olivetti platforms. I can see that is true for the Model 100 by looking at Ken Petit's ROM disassembly <http://www.club100.org/memfiles/index.php?action=downloadfile&filename=m100_dis_2013.txt&directory=Ken+Pettit%2FM100+ROM+Disassembly>. (Although, oddly, the comment only mentions line addresses in BASIC programs.) For the other variants, I looked to Z88dk's disassembly, although I do not know how trustworth it is. In particular, I checked the unified disassembly for the Kyotronic K-85, Olivetti M10, and TRS-80 Model 100 <https://github.com/z88dk/techdocs/blob/master/targets/m100/m100.asm>. While it uses different nomenclature — *RESFPT <https://github.com/z88dk/techdocs/blob/master/targets/m100/m100.asm#L8230>* ("reset file pointers") instead of *LNKFIL* — it seems to indicate that, just like in Ken Petit's M100 disassembly, the K-85 and M10 also reset the file pointers after saving a .CO file to RAM. For the NEC PC-8201 <https://github.com/z88dk/techdocs/blob/master/targets/m100/pc8201.asm>, Z88dk has a disassembly that is not as polished (many of the routines are named things like "GETWORD_294"), but, again, appears to have *__BSAVE* <https://github.com/z88dk/techdocs/blob/master/targets/m100/pc8201.asm#L6902> calling *RESFPT_0*. So, at least on the Model 100, K-85, M10, and PC-8201 this method should be safe. I have not checked the disassembly for the Tandy 102, Tandy 102 UK, Tandy 200, M10 US, PC-8201A, or PC-8300 — or any of the other Kyocera Sisters I may have forgotten — but I feel reasonably confident that they will be derivatives of the source I have already looked at. What do you all think? This method lets programmers create binary files without duplicating them first in RAM which means the files can be almost twice as large. Have I done due diligence in ensuring the technique is safe? Is there something important I'm missing? (There often is.) Please let me know. Thanks, —b9 On Tue, Aug 16, 2022 at 12:34 AM B 9 <hacke...@gmail.com> wrote: > On Mon, Aug 15, 2022 at 2:04 PM John R. Hogerhuis <jho...@pobox.com> > wrote: > >> In fact if you don't CLEAR before load or launch the CO it will fail no >> matter what, error BEEP and show the Load, Length and EXE address. >> > > The hint about the error BEEP was exactly right. > > I just tried SAVEM "FOO.CO", 0, 0 on my Tandy 200 and it created a seven > byte file which gives an Out of Memory error when LOADMed. Presuming the > error behaviour is the same on the other platforms, I think setting the > Load Address to 0 is perfect for preventing people from accidentally > running a data file as code. > > > >> I'm trying to avoid duplicating the file in memory. Has anybody ever >>> tried first creating a .DO file of the correct size in BASIC and then >>> twiddling the RAM Directory's attribute byte so that it is a binary file? >>> >> >> You cannot do that. The BA, DO and CO regions are separate contiguous >> blocks. You'd have to move the file bytes if you changed its type. Which is >> a whole thing. >> > > Thanks for explaining that to me. I'll start with a .CO file. > > > >> To create a CO file: >> First, CLEAR space at some location. [...] >> After you have a safe area, you can poke your data to it. >> Then you can SAVE it as a file. This command is different on different >> BASICs. >> > > Wouldn't clearing space and poking data before creating the file require > twice as much RAM? Couldn't I do it in reverse? > > 1. SAVEM "FOO", 0, 16383 > 2. Get address of "FOO.CO" from Ram Directory > 3. POKE data directly into RAM > > I'm guessing there's a reason people don't do it that way that I'm just > not seeing. > > > As to having one program run on M100, T200 and NEC... be advised that is >> tricky if it's even possible. Their BASICs are different, and there ROMs >> are different and their RAM offsets are different. >> > > Thanks for the warning. I'm hopeful this program will be the exception. I > solved the PRINT@ / LOCATE problem using Esc Y, the program doesn't use > ROM calls, and I've found the Ram Directory offsets for all Tandys and > NECs. > > My current cross-platform problem is the seemingly simple question of how > to find the year from BASIC in a way that works with both American > (MM/DD/YY) and European (YY/MM/DD) style DATE$. If anybody happens to > know the standard best practice for that, I'd love to hear it. I had been > trying to associate the value from PEEK(1) with the YEAR location in RAM, > but the NEC 8300 has foiled that as it is not the same address as the > 8201/8201A. If nobody knows a better solution, I'll probably switch back to > LEFT$/RIGHT$ based on PEEK(1), but that might cause problems with the > Tandy 102 UK. > > >> >> In particular the SAVE/LOAD commands are different between NEC and Tandy. >> > > It looks like the NEC uses BSAVE instead of SAVEM which might be a > problem, but — on my Tandy 200 at least — BASIC doesn't complain about > unrecognized commands if they are never run. For example, this doesn't give > any errors: > > 10 ID=PEEK(1) > 20 IF (ID=148) THEN BSAVE "FOO.CO", 0, 16383: ELSE SAVEM "FOO.CO", 0, > 16383 > > Was there another issue with the SAVE/LOAD commands? For example, if NEC's > .CO files are in a different format, that would certainly throw a monkey > wrench in the works. > > Thanks for all the help! > > —b9 >