December 30, 1985 Re: locating M/L utilities One of the first activities I had planned for my new Model 100 was to logon to C'Serve and join the "M100SIG". Having been a member of the LDOS, Heath and IBM Sig's for quite some time, I was certain I would meet new friends and just as certain that I would find a printer "filter" program to save me from the dread of "DIPswitchitis", brought on by having one MSDOS computer, one CP/M machine and two TRS-80's (4P and 100) sharing 2 printers. I was not disappointed, the needed programs (and friends) were there. Suddenly though, shadows of my old Model III days appeared. The "filter" programs for the 100 loaded M/L routines into high RAM, just below the system "housekeeping" memory. This method results in a real possibility of conflict between these routines and other machine language programs attempting to use the same memory addresses. Corruption of the filter program will cause any attempted printer output to crash the system, a disasterous occurance in the Model 100's RAM file system. One program minimized the chances of this happening by "stuffing" the filter routine into the function key definition buffer for . This protects it from being overlayed by other M/L programs, but leaves it open to discombobulation by programs which redefine the function keys. These concerns prompted me to search for a more secure memory location for the filter routine, one in which it would be safe from the intrusion of other programs. An old BASIC trick is to load such routines into "REM" statements in the first line of a BASIC source code, and I thought that perhaps this sort of approach would work on the 100. As I set out to examine the pointers used by BASIC to locate source code (aided by Robert Covington's splendid disassembly of the M100 system), I found that the first BASIC program saved to RAM is always located at an address corresponding to the beginning of RAM memory +1. This is location 32769 in my 32K machine, and would be at 57345 (8K), 49153 (16K) or 40961 (24K). Eureka!!! Although other files are constantly being shuffled about in RAM (as programs and documents are saved and killed), the first BASIC program saved will always stay in this same location. So, by creating and saving a "dummy" program, then POKEing the appropriate bytes into it, you can have a machine language routine permanently resident in memory, and completely protected from invasion by alien programs. There are two caveats to this technique (aren't there always!). First, is that your M/L routine cannot be longer than 254 bytes, the maximum length of a BASIC program line minus one byte for the REM token. Secondly, the routine cannot have any null bytes ("0" data bytes or NOP instructions). This restriction is due to what seems to be a "re-packing" of saved BASIC sources done by the ROM file managment routines. Apparently, the ROM code maintaining the file structure rescans BASIC source files during the restructuring of RAM as files are saved and deleted. This is done to reset the "nextline" pointers of BASIC's linked list format so that they represent a file's new RAM location. As you may know, the end of a BASIC line is indicated by a single null byte. If your M/L routine contains a zero byte, the ROM "re-pack" routine will assume that byte to be the "end of line", and set the next two bytes as a pointer to the next line of code or end of program. This of course corrupts the M/L routine. The code length restriction (254 bytes) could be circumvented if necessary, by using a jump instruction at the end of one "line" which would transfer control to M/L code in the next BASIC line. The null byte problem cannot be overcome, and must be programmed around. The "dummy" program can be further protected by setting bit 3 of the file's directory header byte making the file "invisable" on the MENU directory screen. The short BASIC program found in the file "MLPFLT.BA" must be loaded and executed with no other BASIC programs saved in memory. When run, it will poke a machine language printer linefeed filter into it's own line 10, and then reset the "LPT:" handler's RAM vector so hat a C/R (chr$(13)) sent to the printer will be followed by a linefeed (chr$(10)). It is absolutely necessary that this program be run with no other BASIC (".BA") programs saved in RAM. After the program has run, delete lines 20-130 and then save the remaining, altered line 10 as "LPTLF.BA". See the comments of line 120 for RAMsize specific changes. The filter can be disabled in either of two ways. The first would be to reset the RAM vector pointer to it's original contents ("POKE 64228,243:POKE 64229,127"). The second (and my favorite) is to simply "POKE SA,201", using the value of SA corresponding to your RAMsize. Re-enable the filter via "POKE SA,254". This second procedure simply replaces the "CPI" instruction of the first M/L line with a "RET" opcode, effectively disabling the filter. That's it, I hope that you find the info presented here to be of use, and hope that I haven't bored you to death with my long winded explanations. If you have any questions, give a yell here or via E-mail. Cliff Knight 71106,1153