TCJ #49 R60 The Z-System Corner Putting the NZCOM Virtual BIOS to Work Jay Sage For this issue we are going to look once more at ways to¨ use the NZCOM virtual BIOS. Ten issues back, in TCJ #39, I¨ talked about how one can take advantage of NZCOM's¨ incredible ability to change the BIOS, statically and¨ dynamically, without requiring any source code for the¨ computer's real BIOS. In that column I described how Cam¨ Cotrill, one of the authors of the Z-System DOS (ZDOS), used¨ the NZCOM virtual BIOS to overcome problems experienced with¨ ZDOS on computers whose real BIOS failed to preserve the Z80¨ index and/or alternate registers across BIOS function calls,¨ as is required for ZDOS. To Cam's code, I added my own¨ enhancement to implement the Z-System environment's drive¨ vector. I had hoped that those two examples would inspire others¨ to apply this technique to a wide range of problems, but so¨ far nothing has appeared. It's not for lack of a need,¨ however, for I have seen on Z-Nodes quite a few discussions¨ of issues that could be handled quite nicely in this way.¨ Ever the optimist, I will try a few more examples. Two of¨ the examples will essentially be the solutions to problems¨ asked about recently in messages posted on Z-Nodes. The starting point will be the modified NZCOM BIOS that I¨ discussed in the earlier TCJ column. The main parts of the¨ code are shown in Listing 1. Several interesting features¨ are worth pointing out before we proceed to our new¨ modifications. The beginning of the code has the material required for¨ the generalized loading concept developed by Bridger¨ Mitchell and described in detail in TCJ issue #33 (if you¨ don't have all these back issues, you would do well to pick¨ them up). The NAME statement embeds an ID into the REL¨ object code. The NZCOM.COM and JETLDR.COM loaders use this¨ ID to recognize the function of a module they have been¨ asked to load so they can figure out its proper load¨ address. The COMMON statements allow any addresses in the Z­ System to be installed into the code by the loader at load¨ time. This is the beauty of Bridger's concept: a single¨ binary file can be used in many different systems. The next section of the code must adhere to a rigidly¨ defined format. First comes the table of jump vectors as¨ required in the CP/M-2.2 specifications. With the exception¨ of the cold and warm boot routines, these jumps would¨ normally go directly to the real BIOS. Since we want to¨ intercept this code and enhance its functions, we vector to¨ other locations in the virtual BIOS code. Note that the jump¨ vector table has room for 13 extra custom BIOS functions¨ that might be implemented in the user's system. The block of jump vectors is followed by some special¨ data for NZCOM. First there is an ID string that can be used¨ by programs to determine if an NZCOM version of Z-System is¨ currently running. Then there is a data byte with the number¨ of the user area where the command processor file is stored.¨ In an NZCOM system, the command processor is loaded from a¨ file and not from the system tracks of the disk. Finally,¨ there is the space for the file control block for the CCP¨ file. Then comes the replacement warm boot code that loads¨ this file. This is an area where changes would be made in a¨ multiuser system (a number of such systems are around,¨ including some manufactured by Televideo). Imagine that¨ there are two terminals running on the system and each user¨ wants to run a different configuration of NZCOM. Clearly,¨ they can't both use the same NZCOM.CCP file. Therefore, each¨ user has to be set up with a different name or user area for¨ the CCP file. One place this change would have to be made is¨ in the virtual BIOS code. I am not going to say any more on¨ this subject, but I hope that some day we will get a TCJ¨ submission dealing with the issues of implementing Z-System¨ on a multiuser system. Now we finally come to the internal BIOS function¨ routines, such as ICONST and ICONIN. All of these entry¨ points have code that loads the A register with the address¨ offset in the jump table of the real BIOS and then calls the¨ routine DOBIOS, whose function was described in detail in my¨ column in issue #39. Briefly, DOBIOS saves all the alternate¨ and index registers, calls the real BIOS function, restores¨ the registers, and then returns to the calling program. If we want to incorporate additional functionality, this¨ is the place for it. The code in Listing 1 includes the¨ enhancement to the select-disk code to make it check the¨ drive vector and return an error code if the drive is not¨ enabled. This code, too, was discussed in detail in issue¨ #39. Changing the Logical Drive Assignments There are times when you may not like the way the¨ manufacturer of your computer has assigned the logical¨ drives (those things you know as A:, B:, and so on). On my¨ Televideo 803H, the hard drive has the two partitions A: and¨ B:, while the floppy is C:. As an example, I have¨ implemented a special NZCOM BIOS that swaps drives B: and¨ C:, so that the floppy can be referenced as B: and the¨ second hard disk partition as C:. I'm not sure why one would¨ want to do this, but there might be reasons. The ISELDK routine with the additional code is shown in¨ Listing 2. The code is pretty simple. When the SELDSK BIOS¨ function is invoked, the requested drive is passed in the C¨ register. The code checks sequentially for values of 2 (C:)¨ and 1 (B:), and it changes the value in C to 1 and 2¨ respectively. If the value is neither 1 nor 2, then the¨ value is left unchanged. Finally, the BIOS routine is¨ called. Thus, virtual BIOS tricks the real BIOS, which still¨ knows the drives by their original names. Once this code has been entered, say under the name¨ SWAPBC.Z80, then it is assembled to a REL file (Z80ASM¨ SWAPBC/R in the case of the SLR assembler). If you wish, the¨ file can be renamed from SWAPBC.REL to SWAPBC.ZRL just to¨ make it clear that it adheres to the ZRL standard. The¨ loaders don't care which name is used. Now you just enter¨ the command JETLDR SWAPBC.ZRL and, presto, you have a new¨ BIOS with the drive designations reversed. Some cautions are in order. Drive references that occur¨ within the real BIOS will still use the same physical units¨ and will not know about the swap. External routines that¨ call the BIOS or DOS will see the drives as swapped. Thus¨ swapping the A: drive (assuming that is where NZCOM.CCP is¨ loaded from) will cause the CCP file not to be found. I just¨ tried modifying the code in the listing so that it swapped¨ A: and B:. I also changed the number 1 in the first byte of¨ the NZCOM.CCP file control block to a 2. Now the CCP file¨ will be loaded from the B: drive, which used to be the A:¨ drive. It worked just fine! In this example, the drives are relogged automatically by¨ the loader. If you try writing a more sophisticated BIOS¨ that has a swap table in it that you intend to change later¨ using a utility, just make sure that the utility forces a¨ relogging of the swapped drives (or all drives) after the¨ swap has been implemented. Disabling the LIST Device I think it was our editor Chris McEwen who raised this¨ issue with me. As I recall, he was unable to use a¨ particular utility on his Z-Node because it had a function¨ -- not disabled when the wheel byte was off -- that engaged¨ the printer. I had faced a similar problem myself. I have no printer¨ attached to most of my computers, and occasionally I would¨ accidentally hit a key that would initiate a printing¨ operation. On some of the computers this meant instant¨ crash! The BIOS would wait forever for the printer to signal¨ that it was ready, and if I didn't want to wait that long, I¨ had to hit the little red button, losing all my work. My simple solution to this was to go into the BIOS and¨ replace the jump instruction for the LIST function with a¨ simple RET. Boy could that printer print fast! A little POKE¨ instruction in my startup alias could handle this for me¨ very nicely. When Chris presented his problem, I told him he could use¨ the BIOS in his NZCOM to take care of things. Just make up¨ two versions of the BIOS, one normal version and one with¨ the list routine RET'd out. Then just use NZCOM or JETLDR to¨ install the one needed. The code shown in Listing 3 is a more elegant solution.¨ It looks at the printer configuration data stored in the¨ environment. If the width is set to zero, then the print¨ output is disabled. Otherwise it functions normally. As you¨ see, the code is short and sweet. Console Input/Output Enhancements George Worley asked on Z-Node Central for a suggestion as¨ to how he could get his system to send some escape sequences¨ to his terminal whenever he pressed certain keys. Again, the¨ NZCOM BIOS can solve the problem. I originally wrote a virtual BIOS that would remap some¨ keys on the keyboard. I make it interchange the 'a' and 'b'¨ keys -- not likely to be very useful, but it illustrated the¨ point. I'm not going to show you that code; it is quite¨ similar to the code for swapping drives except for one¨ detail that will be covered in the example I will present. The interesting thing about George's problem is that¨ something going on in the console input routine is supposed¨ to initiate an activity with the console output routine. The¨ notion of mixing up the BIOS functions caught my interest. I¨ decided to write a BIOS that would change the cursor on my¨ Televideo terminal to a blinking block when I typed a tilde¨ and back to a blinking underline when I typed a back¨ apostrophe. See Listing 4 for the result. The thing that is different here from the earlier¨ examples with the SELDSK function is that in those cases the¨ action was taken with input data, before the function was¨ called. Here we must take action on data returned by the¨ function, after the function has executed. Instead of¨ jumping to DOBIOS, we call it and then continue with our¨ code on return from it. Once we have the character returned by CONIN, we check to¨ see if it is either of our trigger characters. If not, we¨ just return to the calling program with the character. If we¨ do detect one of the trigger characters, then we send a¨ string of characters to the screen using the CONOUT¨ function. When that operation is complete, we then get the¨ typed character back into its proper register and return. I hope these examples will get you thinking about new¨ ways to use the virtual BIOS. I have shown only very simple¨ code. NZCOM allows one to declare as much space as one wants¨ for a virtual BIOS, and someday I would like to see someone¨ write a version of BYE that can be loaded as a virtual BIOS. Z-System for MS-DOS I'd like to finish with a brief announcement. I had¨ originally hoped to discuss this in more detail, but there¨ just is not time or space, so I will leave it for the next¨ issue. But I do want you to know about it now. I'm sure I'm not the only Z-System user who also uses MS­ DOS computers and finds DOS's primitiveness annoying and¨ frustrating. Well, the new version 2 release of PCED¨ (Professional Command line EDitor) is a DOS enhancement¨ product that comes as close as any I have yet found to¨ bringing the features we love in Z-System to MS-DOS. This is¨ not entirely accidental, as I made the author aware of our¨ Z-System work. As a result, PCED gives one most of the¨ functionality of LSH and ARUNZ: full command history, both¨ line and screen oriented, with editing and searching;¨ multiple commands on a line; command scripts with advanced¨ parameter parsing. There are some Z-System features that¨ PCED does not add to DOS, but there are also many very¨ powerful features it does bring that are probably only¨ possible with the larger memory available on a DOS machine. As is my wont with products like this that I use myself¨ and really like, I got Sage Microsystems East to add it to¨ the product line. PCED is now available at a very attractive¨ price of only $50. I'll try to tell you more about it next¨ time.