Z-System Corneò (c) by Jay Sage The Computer Journal, Issue 39 Reproduced with permission of author and publisher For this issue I will discuss some unique new capabilities made possible by NZCOM that have already proved their value and that I hope will be exploited to a much greater extent in the future. I originally had several other issues on my agenda, but Lee A. Hart sent me such an interesting article that I wanted to leave plenty of room for it. System Enhancements Using NZCOM I'm afraid that many people think of NZCOM as just a way for unskilled users to get Z-System running on their computers. It's true that NZCOM accomplishes that, but, as I have asserted often before, NZCOM does much more than that. It offers possibilities that a manually installed Z-System cannot achieve. I would like to describe one of them here and will do so first in the context of a problem that arose with the new ZSDOS and ZDDOS disk operating systems on some computers. Because CP/M was created originally for the 8080 microprocessor, a number of BIOS implementors (the BIOS, or Basic Input/Output System, is the hardware-dependent part of CP/M) felt that they could make free use of the additional registers introduced with the Z80 chip. These registers included two index registers, called IX and IY, and a duplicate set of the standard registers denoted with primes on the names (e.g., B' or HL'). This was perhaps excusable at the time, but it is poor programming practice for an operating system to change anything other than what is explicitly indicated in the specifications. Most BIOS writers who have used the Zilog registers have been careful to restore the original values before exit from the BIOS routines. Unfortunately, a few BIOSes fail to do that.  Among them are the following: Epson QX10, Zorba, Televideo 803 and TPC-1, Oneac On, and the Osborne Executive. The Bondwell is on the suspect list, and there are probably others we don't know about yet. The (mis)use of these registers poses no problem for programs written to run on the 8080, but today we are rapidly moving beyond the limitations of the 8080 and making extensive use of the Z80 registers to pack more power into operating system components and application programs. Today, the Z­ System, true to its name, is intended to run only on the Z80 or upwardly compatible processors like the HD64180, Z180, or Z280. Several users who purchased ZDOS (that is ZSDOS and ZDDOS) found that it would not work properly on their computers. An investigation turned up the fact that the BIOSes in those computers were modifying the index registers.  This also explained why those same users had been experiencing strange problems with JetLDR, Bridger Mitchell's superb Z-System module loader. ItŠalso explained some mysterious problems I was having with a number of programs (for example, EDITNDR) on my Televideo 803! The question was what to do about the problem. In the ancient days, when computers always came with the source to their BIOS and their owners were always intimately familiar with the procedures for rebuilding their operating systems, the solution would have been to rewrite the BIOS with the proper PUSH IX and POP IX instructions to preserve the index register values. But what could we do today for nonprogrammers and those without BIOS source code? NZCOM provided the answer quite nicely! As I explained in a column long ago, NZCOM works by creating what I call a virtual BIOS (I'll call it VBIOS) lower in memory in order to open up space for the Z-System modules between it and the real BIOS (often called the custom BIOS or CBIOS). The source for this virtual BIOS is available.  Except for the warmboot code and some minor complications for IOP (input/output processor) support, the standard NZCOM VBIOS module just vectors calls that come to it up to the real BIOS. But no one says this is all it is allowed to do. ZDOS authors Cam Cotrill and Hal Bower found it quite easy to surround the vectors with code to save and restore registers. First they released ZSNZBI11.LBR, which contained the source and ZRL file (loadable by NZCOM) for a VBIOS that preserved the IX and IY registers for all disk function calls. Later they discovered that some of the machines changed the index registers even for console I/O function calls, and others changed the alternate registers.  They then wrote ZSNZBI12.LBR, whose VBIOS preserves all the registers for all BIOS functions. Instead of having the virtual BIOS routines jump directly to the real BIOS, they jump to an intermediate entry point. For example, the list­ status vector in the jump table has a JP ILSTST (intermediate list status), and the code at ILSTST is ILSTST: LD A,45 JR DOBIOS The offset for the BIOS function is placed in the A register and then control is transferred to a general BIOS-calling routine shown in Table 1 that implements the register protection. The routine JPHL referenced there contains only the code line JP (HL), which vectors the CPU off to the BIOS with a return to the DOBIOS code. ----------------------------------------------------------------------------- DOBIOS: LD HL,CBIOS ; Start with address of real BIOS ADD A,L ; Add offset in A (never a LD L,A ; ..carry since on page boundary) EXX ; Swap to alternate registers LD (HLP),HL ; Save them all in memory LD (DEP),DE LD (BCP),BC Š LD (IXREG),IX ; Save index registers, too LD (IYREG),IY EXX ; Back to regular registers EX AF,AF' ; Swap to alternate PSW PUSH AF ; Save it on stack EX AF,AF' ; Back to original PSW CALL JPHL ; Actually call the BIOS! EXX ; Restore alternate and index LD HL,(HLP) ; ..registers LD DE,(DEP) LD BC,(BCP) LD IX,(IXREG) EX AF,AF' ; Alternate PSW, too POP AF EX AF,AF' RET ; Register save area BCP: DEFS 2 ; BC' DEP: DEFS 2 ; DE' HLP: DEFS 2 ; HL' IXREG: DEFS 2 ; IX IYREG: DEFS 2 ; IY END Table 1. Code from ZSNZBI12.Z80 that preserves all index and alternate registers across BIOS calls in NZCOM. ----------------------------------------------------------------------------- To use this replacement VBIOS, you have to run MKZCM and create an NZCOM system with 4 records allocated for the BIOS instead of the standard 2.  Because the BIOS must start on a page rather than just a record boundary, MKZCM will sometimes make automatic adjustments to the BIOS size.  Therefore, you should specify changes in MKZCM starting with the higher­ numbered modules; the adjustment in the BIOS allocation should be made last.  If an attempt to enter a value of 4 results in MKZCM using 5, then you could go back (if you don't like wasting memory) and make one of the other modules (such as the NDR) one record larger and then respecify a 4-record BIOS. There are many other ways that NZCOM can be used to introduce system enhancements without having to make changes in the real BIOS. As an example, we will show how to add support for the drive vector in environment descriptors of type 80H and above (implemented with NZCOM and Z3PLUS). The drive vector is a 16-bit value stored as a word beginning at offset 34H in the environment descriptor. It specifies which disk drives are actually implemented on a system. The lowest order bit in the word is for drive A and the highest for drive P. A zero in a bit position indicates that the corresponding drive is not available. For example, on my SB180 the bytes at addresses ENV+34H and ENV+35H were 7FH and 00H, respectively. Thus the wordŠvalue is 007FH or 0000,0000,0111,1111 binary, indicating that I had drives A, B, C, D, E, F, and G. When the hard disk E partition developed a problem that made it unusable, I changed the 7FH value to 6FH, thereby disabling drive E. You can display the drive vector using menu selection 3 in the SHOW program (ZSHOW for Z3PLUS). The ZCPR34 command processor knows about the drive vector and will not allow command references to unsupported drives. But what about programs that you run? Unfortunately, the BIOS generally knows only which drives are potentially implemented, and it may try to access a nonexistent drive. When 'smart' BIOSes encounter this problem, they often prompt the user as to what to do next. This is fine if you are sitting at the console and can take appropriate action to recover, but if the system is being run remotely, there is generally no way for the remote user to recover. In fact, because the 'smart' BIOS uses direct hardware calls to display the "Abort, Retry, Ignore?" message rather than calls through the BIOS vector table, the remote user does not even see the message and just thinks the system has crashed.  My Z-Node got hung once that way when I forgot to put a diskette back into a floppy drive. A caller attempted to access it, and when I got home, the BIOS was dutifully beeping at me and waiting for me to tell it what to do. My first stab at writing a VBIOS that observes the drive vector restrictions is shown in Table 2. Now that I have read Lee Hart's column, I am sure that this code can be made shorter, faster, or both! But I will leave that as an exercise for the reader. (I already see one place where I could save a byte.) The listing assumes you are starting with the ZSNZBIO described earlier.  Just add the extra equate for DRVEC under the /_ENV_/ common block and replace the simple ISELDK (intermediate select disk) code with the slightly more complex version shown in the Table. I put this on my Televideo, and the results were most pleasant. Now when I attempt to access a nonexistent drive, the system does not force a direct-CBIOS warmboot that drops me out of NZCOM. ----------------------------------------------------------------------------- ; Add DRVEC definition in the ENV common COMMON /_ENV_/ Z3ENV: DRVEC EQU Z3ENV+34H ; Drive vector CCP EQU Z3ENV+3FH DOS EQU Z3ENV+42H ; Modify ISELDK as follows and place it after the DOBIOS code and before ; the data area for register storage. ISELDK: LD HL,(DRVEC) ; Get drive vector LD A,16 ; Subtract requested drive SUB C ; .. from 16 Š LD B,A ; .. and put into B ISELDK1: ADD HL,HL ; Move bits left into carry DJNZ ISELDK1 ; Loop 16- times LD HL,0 ; BIOS return code for invalid drive RET NC ; Return if drive vector bit not set LD A,27 ; Otherwise, use CBIOS function JR DOBIOS ; .. at offset 27 Table 2. Code added to virtual BIOS to support the environment drive vector at the BIOS level. ----------------------------------------------------------------------------- These two examples of system enhancements by no means exhaust the possibilities. One can implement all kinds of additional features and drivers right in the NZCOM VBIOS. Joe Wright suggested early during NZCOM development that one should create an absolutely stripped down CBIOS, one that contains only the functions that are absolutely necessary to get the system running and then implement all the bells and whistles in the VBIOS.  These extra features would include things like RAM-disk drivers, keyboard type-ahead buffers, logical drive swapping facilities, and disk error recovery management routines. With this strategy, one can actually achieve a larger TPA with an NZCOM system than one had under the standard CP/M system, since the CBIOS can be made smaller and the fancy features dropped when a larger TPA is more important. For example, the "Abort, Retry, Ignore" message should be implemented in the VBIOS, with the CBIOS returning from disk errors with standard error codes. With the normal VBIOS, the error will simply be passed back to the DOS, which will report the error in its usual way ("BDOS ERROR on..." in the case of the Digital Research BDOS). A more elaborate VBIOS can detect the error, report it to the user, and allow the operation to be retried. When the system is running in remote mode, either the simpler VBIOS can be used or the prompt can be vectored properly through the jump table so that the remote user will be able to deal with the problem. Similarly, one should be able to handle the swapping of logical drive names in the VBIOS. There are a couple of pitfalls to watch out for, however. If you change logical names, you better make sure that the disk system is reset, probably both before and after the swap. You also better make sure that NZCOM can still find its CCP file, which is normally kept in directory A15:. If you swap the A drive without providing a copy of this CCP in the new A drive, you'll be in serious trouble. Of course, the swapping would be handled by a utility program, and it would worry about these requirements. The VBIOS would simply have the code for translating references to a logical drive value in register C into a possibly different physical drive value. I hope that this short discussion has given some of you ideas for imaginative applications of the new capability offered by the NZCOM virtual BIOS. If so, I would love to hear about them and to see sample code. Š [This article was originally published in issue 39 of The Computer Journal, P.O. Box 12, South Plainfield, NJ 07080-0012 and is reproduced with the permission of the author and the publisher. Further reproduction for non- commercial purposes is authorized. This copyright notice must be retained. (c) Copyright 1989, 1991 Socrates Press and respective authors]