home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 1994-09-02 | 53.9 KB | 1,133 lines
The ZCPR3 Corner Jay Sage One of the problems with writing a column for a magazine that onlyì appears every two months or so is that so many things can happen betweenì when one column is written and the next one is published. (Of course, thereì would be other, insurmountable problems if I had to turn out these columnsì every month, so I am not complaining.) At the end of the last article, Iì mentioned that ZCPR33 would probably be out by the time that issue appeared. ì Indeed, that was true. What I did not write, because no public announcementì had been made yet, was that I had joined the Echelon team and would be theì author of that version. So I am now wearing two hats, one as ZSIG softwareì librarian and one as the Echelon team member in charge of command processorì development. Richard Conn has gone off to do more esoteric things. Inì recognition of this change, I have broadened the title of this column. ZCPR Version 3.3 Since ZCPR33, or Z33 as I will call it for short, is too exciting aì subject to pass up, I will say a few words about it before continuing theì discussion we began last time of techniques for customizing Z-COM. I willì not say too much, however, since a lot of effort already went into preparingì the 60-page "ZCPR33 User Guide." It has all the details and is availableì from either Echelon or Sage Microsystems East for $15 plus shipping ($3 fromì SME). Since the code, as in the past, is still available free of charge forì personal, noncommercial use, sale of the manual is the only way other thanì OEM sales that we get any compensation for the enormous amount of effortì that went into Z33. I will talk this time only about the design goals forì Z33, and perhaps in future columns I will talk about some of the newì features and capabilities. Design Goals ------------ In developing Z33, I tried to achieve five things (the number keepsì growing every time it think about it). (1) I have tried to maintain a veryì high level of compatibility; (2) I have tried to increase flexibility,ì control, and speed; (3) I have tried to make the code rigorous and reliable;ì (4) I have tried to make more information about the internal state of theì command processor accessible to user programs; and (5) I have tried to makeì the code readable and educational. To the greatest extent reasonable, I have maintained compatibilityì between Z30 and Z33. No change need be made to any part of the operatingì system other than the command processor; the Z33 command processor, as Iì hinted at in the last column, can simply be dropped in wherever the oldì command processor was, either on the system tracks of the boot disk or inì the appropriate places in a Z-COM system. No changes need be made in theì memory allocations, and the officially released system modules that workedì with Z30 will work with Z33 as well, though new, more powerful RCP and FCPì modules were released with Z33 (the 'H' command in the unofficialì experimental RCP145, because it made direct references to internal addressesì in the CPR, will not work). All application programs and almost all utilityì programs will work unchanged with Z33. New utility programs have beenì written to take advantage of some of the new features in Z33. Many features of ZCPR3 -- such as automatic path searching for COMì files, extended command processing, and error handling -- are veryì convenient but can significantly slow system response. With Z33, the userì is given greater control over these features from the command line so thatì unnecessary operations can be bypassed to save disk activity and time. Noì longer does the path automatically include the current directory first. Theì user can now, at his option, omit the current directory or include it in anyì position in the path. This has a dramatic effect on system speed. Aì command entered with a leading slash ("/") is handled directly by theì extended command processor without wasting time searching the path for a COMì file. For systems that take increasing advantage of ARUNZ or other extendedì command processing, speed is, again, greatly improved. Programs with whatì is called a type-3 environment are automatically loaded and executed atì addresses other than 100H. By loading error handlers, shells, and extendedì command processors high in memory, user programs at 100H are left intact andì can be reinvoked using the GO command. The code in Z33 was almost totally rewritten, taking only the basicì functions from Z30. Quite a few bugs, some very serious, were corrected,ì and new algorithms were used for many of the functions. A great deal ofì effort was devoted to making the code rigorous. No longer can a commandì tail longer than 128 bytes overwrite the program code and crash the system. ì No longer can command lines in SUBMIT files write beyond the end of theì command line buffer. The root path and minimum path features now workì correctly, so that duplicated elements in the search path do not have to beì searched more than once. Extended command processing functions reliably andì in combination with error handling. The Z33 command processor makes much more information available aboutì its operation. In Z30, only COM files that could not be found would invokeì error handling. Z33 traps many different kinds of errors, and it can reportì the nature of the error to the user. Some examples are TPA overflow, diskì full, bad numerical expression, incorrect password, bad directoryì specification, or ambiguous file specification. Z33 even makes it possibleì for user programs and routines in the resident command package to invokeì error handling and to report the type of error. When Z30 parsed a fileì expression that specified an invalid directory, it simply substituted theì current directory, but the program had no way to tell that this had beenì done. Z33 sets a flag to indicate the error. With Z33, a program can tellì where on the search path it was actually found. This can be valuable forì shells and error handlers that install themselves into the system. They canì operate faster if they know where they are located. Finally, the source code has been completely reorganized and veryì extensively commented. I did this not only to make it easier for me toì maintain it but also so that others could read it to learn how the commandì processor works. One of the main reasons why many of us hobbyists remainì involved in the 8-bit world is that a Z80 can be comprehended fairly easilyì and can thus be used to learn deeply about the operation of a computer. Z33ì is designed to contribute to this. Advanced Z-COM Customization In our discussion last time we described what Z-COM is and how itì works, and we presented a number of techniques for carrying out simpleì modifications that did not alter the basic structure of the Z-COM system. ì This time we will examine some much more far-reaching modifications,ì including those that involve changing the way Z-COM operates. The goal isì to develop techniques that will permit us to use the basic principles behindì Z-COM to build arbitrary systems of our choice. I do want to warn you: aì good part of this discussion will be at an advanced technical level. Even Iì feel rather mentally exhausted after going through the process of developingì it and writing it down. If any one section is getting too technical forì you, please do not give up completely. Skip ahead to each new section andì read the introductory philosophical comments. There is material there thatì I would really like everyone to see. When Z-COM Will Not Work ------------------------ Before launching into the heavy code patching, I would like to cover aì topic that probably should have been included last time: why Z-COM will notì work in all systems or will not work fully. There are two circumstances that I have experienced in which Z-COMì interferes with the proper operation of a system. One class of difficultiesì arises when the system uses utilities that make modifications to theì operating system image in memory. Such utilities always invite disaster,ì but they are nevertheless quite common (partly because they are so useful). ì If the utilities calculate the addresses to change from the BIOS warmbootì address at location 0001, then there will be trouble, because that addressì points to the virtual BIOS set up by Z-COM and not to the real BIOS. The Ampro BIOS, for example, has a number of special structures inì defined locations with respect to the beginning of the BIOS. Some of these,ì for example, support the various configuration options. Since these optionsì are rarely changed except when the system is first assembled or when newì hardware is added, one can overcome any problem by running the utilitiesì when Z-COM is not in operation. Other BIOS structures are used to defineì the alternative disk formats. These one might want to change during aì session at the computer. Although it is inconvenient, one could again exitì from Z-COM using ZCX, change the disk format, and then reenter Z-COM. Ofì course, a conventionally installed ZCPR system is available for the Ampro soì that Z-COM is not necessary. However, a number of other computers runningì standard CP/M 2.2 use similar techniques and have similar utilities. The second class of difficulties arises when the BIOS warmboot codeì performs some indispensable function. Remember that when Z-COM is running,ì the warm boot is intercepted, and the warmboot code in the original BIOSì does not run. My BigBoard I with the double-density upgrade automaticallyì selects from a large number of disk formats. One simply puts the disketteì with the new format into the drive and presses control-c. The warmboot codeì in the BIOS includes code for determining the format of the diskette. Whenì Z-COM is running, I often experience problems when I try to log in a newì drive for the first time or when I try changing disk formats. The troubleì seems to have to do with the way the BIOS keeps track of what drives areì logged in, and by using disk resets or control-c's from Z-COM, I can oftenì get the system to work. But clearly there can be problems when the BIOSì warmboot code is completely by-passed. More Named Directories ---------------------- To get our feet wet again with Z-COM patching, let's start with aì relatively simple but very practical example. The most frequent request Iì get from users of Z-COM, especially those using it to make a remote accessì system, is for a way to increase the number of named directories. To refresh our memories, I have reproduced in Fig. 1 the memory map ofì our unmodified Z-COM system. Those of you who are really sharp (or haveì photographic memories or are cheating by actually looking at the last issue)ì will notice that this is not exactly the same as the map presented last timeì as Fig. 2. The reason for this is that I recently was offered a deal that Iì simply could not refuse on a hard-disk Televideo 803H system (everyì household needs four complete computer systems, no?). Since I cannot bearì to operate a computer without Z-System, I immediately implemented Z-COM onì it and have been using it as the testbed for the techniques described here. ì It's BIOS is obviously even less compact than the one on my BigBoard andì starts 200H lower in memory. I hope this address switch does not confuseì you too much, but since your system probably does not match mine anyway, youì have to get used to translating addresses. The addresses in the ZC.COMì image, of course, do not change. ----------------------------------------------------------------------------- System Component ZC.COM Address System Address ---------------- -------------- -------------- CPR 0200 - 09FF BA00 - C1FF ZRDOS 0A00 - 17FF C200 - EFFF Virtual BIOS 1800 - 19FF D000 - D1FF Named Directory Register 1A00 - 1AFF D200 - D2FF Shell Stack 1B00 - 1B7F D300 - D47F Z3 Message Buffer 1B80 - 1BCF D380 - D4CF External FCB 1BD0 - 1BF3 D3D0 - D4F3 PATH 1BF4 - 1BFE D3F4 - D4FE Wheel Byte 1BFF - 1BFF D3FF - D4FF Environment Descriptor 1C00 - 1C7F D400 - D47F TCAP 1C80 - 1CFF D480 - D4FF Multiple Command Line 1D00 - 1DCF D500 - D5CF External Stack 1DD0 - 1DFF D5D0 - D5FF Resident Command Package 1E00 - 25FF D600 - DDFF Flow Control Package 2600 - 27FF DE00 - DFFF I/O Package 2800 - 2DFF E000 - E5FF Fig. 1. Addresses of system components in the ZC.COM file and in theì example system for which it was generated (Televideo 803H). ----------------------------------------------------------------------------- Now, if we want to have room for more directory names, we have to findì a way to allocate more memory to the NDR module. Where can we steal someì memory? Unfortunately, the memory cannot be taken from either of theì neighbors of the NDR. The virtual BIOS and shell stack are indispensable. ì That means that we will have to move the NDR or something else from itsì present position. The best target for our memory raid is that hulkingì 6-page, 1.5K IOP that often goes unused, especially on remote accessì systems. We will cut it down to 3 pages and use the top 3 pages for our newì NDR, which will have a capacity for 42 names [ (3 * 256 - 1 ) div 18 = 42 ]. ì The resulting memory map is shown in Fig. 2. ----------------------------------------------------------------------------- System Component ZC.COM Address System Address ---------------- -------------- -------------- CPR 0200 - 09FF BA00 - C1FF ZRDOS 0A00 - 17FF C200 - EFFF Virtual BIOS 1800 - 19FF D000 - D1FF ( unused space ) 1A00 - 1AFF D200 - D2FF Shell Stack 1B00 - 1B7F D300 - D47F Z3 Message Buffer 1B80 - 1BCF D380 - D4CF External FCB 1BD0 - 1BF3 D3D0 - D4F3 PATH 1BF4 - 1BFE D3F4 - D4FE Wheel Byte 1BFF - 1BFF D3FF - D4FF Environment Descriptor 1C00 - 1C7F D400 - D47F TCAP 1C80 - 1CFF D480 - D4FF Multiple Command Line 1D00 - 1DCF D500 - D5CF External Stack 1DD0 - 1DFF D5D0 - D5FF Resident Command Package 1E00 - 25FF D600 - DDFF Flow Control Package 2600 - 27FF DE00 - DFFF I/O Package 2800 - 2AFF E000 - E2FF Named Directory Register 2B00 - 2DFF E300 - E5FF Fig. 2. Addresses of system components in the ZC.COM file and in the targetì system as modified to support 42 named directories. ----------------------------------------------------------------------------- To implement this change in our Z-COM file we have to change only theì ENV and CPR modules. The ENV has to know about the new memory map, and theì CPR code has to know where the NDR module is located. Although the NDRì module will be placed in a new location in the ZC.COM file, the NDR data areì position-independent, so the module itself need not be changed (though weì will presumably be adding many new names). The FCP and RCP are still in theì same place doing the same thing. One of the new features of Z33, by the way, is the ability to determineì the locations of the NDR, FCP, and RCP from the environment descriptor. ì Thus if we are using ZCPR33 with this feature enabled, no change in the CPRì code is required. Only three changes in the Z3BASE.LIB file are required to reflect theì new memory map. These are the definitions for the symbols IOPS (the numberì of 128-byte records allocated to the IOP), Z3NDIR (the address of the NDR),ì and Z3NDIRS (the number of names in the NDR). These changes are as follows: symbol old expression new expression ------ -------------- -------------- IOPS 12 (0CH) 6 (06H) Z3NDIR z3env - 200H z3env + 0E00H or iop + 300H Z3NDIRS 18 (12H) 42 (2AH) The new SYS.ENV file can be made either by assembling SYSENV.ASM withì the modified Z3BASE.LIB, or it can be done by patching (either to the imageì imbedded in ZC.COM or to the standalone ENV file). I didn't have a copy ofì SYSENV handy, so I have been using ZPATCH (which is much more fun anyway). ì I find that I am constantly in need of the addresses of various items in theì environment descriptor, so to make them easier to find, I took my copies ofì Richard Conn's "ZCPR3, The Manual" and put a 3M Post-It (one of thoseì wonderful little yellow semi-stick note sheets) on page 300 where the SYSENVì module is described. Then I wrote the offsets shown in Fig. 3 into theì margin next to the symbols. It was thus very easy to determine that theì addresses to patch in the ZC.COM image are 1C11H (IOPS), 1C15H (Z3NDIR), andì 1C17H (Z3NDIRS). ----------------------------------------------------------------------------- offset SYSENV code line ------ ---------------- 09 dw expath 0B db expaths 0C dw rcp 0E db rcps 0F dw iop 11 db iops 12 dw fcp 14 db fcps 15 dw z3ndir 17 db z3ndirs 18 dw z3cl 1A db z3cls 1B dw z3env 1D db z3envs 1E dw shstk 20 db shstks 21 db shsize 22 dw z3msg 24 dw extfcb 26 dw extstk 28 db [quiet flag -- no symbol] 29 dw z3whl 2B db [cpu speed -- no symbol] 2C db [max drive (A=1) -- no symbol] 2D db [max user] Fig. 3. Offsets to various symbols and information in SYSENV.ASM, theì environment descriptor module (see "ZCPR3, The Manual" p. 300ff). ----------------------------------------------------------------------------- The next steps were to assemble up a new version of the commandì processor, create the desired NDR file, and then put all the pieces into theì ZC.COM file as described last time. While I was at it, I decided that itì would be nice if this new version could co-exist on the system with theì previous version, in case I ever wanted the full IOP space back temporarily. ì To achieve this, I made two additional changes in the image and saved it toì a file called ZC1.COM instead of ZC.COM. These two changes were to the nameì of the startup alias and the name of the CPR file to be loaded from A15 byì the warmboot code. The startup command is stored in the multiple command line buffer,ì whose image begins at 1D00H. The standard ZC.COM has the following dataì there for my Televideo 803H with its real MCL at D500H: <04> <D5> <CC> <04> S T R T <00> The first two bytes are a pointer to the address D504, where the nextì command (in this case the only command) to be executed is stored. They doì not have to be changed. The third byte, CCH, is the maximum number ofì characters that the command line can contain. It should not have to beì changed, but in fact the value is wrong. Fortunately, this mistake can onlyì cause trouble in highly exceptional circumstances, but while we are at it weì can put in the correct value of CBH = 203. The value of the symbol Z3CLS inì Z3BASE.LIB should also be changed. The correct value is the maximum numberì of actual characters in the command line. As can be seen above, there areì four bytes before the command string and one byte (the terminating null)ì after it. Hence the proper value for Z3CLS is five less than the totalì amount of memory allocated to the multiple command line buffer module. The fourth byte is the number of text characters in the command line. ì This value is never used by the operating system, but the DOS line inputì function writes the count to that position, so we have to provide space forì it. If you put a wrong value there, it will not make any difference, atì least not for the operations performed here. I have heard that there was atì least one utility program that used this value for some purpose. I do notì recommend this practice, since some command-line-generator programs, Iì believe, and do not update the value after they produce their command lines. ì I am also not sure whether or not the Z3LIB routines APPCL and PUTCL updateì the character count. To make ZC1.COM use a startup alias called START1 (6 characters), weì would change the MCL buffer to <04> <D5> <CB> <06> S T A R T 1 <00> This can be done either with ZPATCH or a debugger. If there is a lot ofì garbage in the rest of the command line buffer, you can fill it with zerosì out through address 1DCFh to make things look neater. The file control block for the ZC.CP command processor image that isì loaded from directory A15 starts at address 1944H. By changing the spaceì character at address 1947H from 20H to 31H ('1' ASCII), the CPR image ZC1.CPì will be loaded instead. You can also change the message at address 1901H toì reflect the name of the CPR image file. There is room to squeeze two extraì characters into that message, one by eliminating the leading space and oneì by omitting the ending period. After you're done with these changes, don'tì forget to put the CPR image file ZC1.CP in A15. It seems wasteful with this configuration to leave unused the block ofì memory where the NDR used to be. When I implemented this version, I movedì the multiple command line buffer there so that I could increase its sizeì from 208 to a full 256. One might not enter such long commands by hand, butì aliases and other command line generators occasionally overflow the 203ì character limit in the usual configuration. For ZCPR34 I am consideringì some techniques for extending the length to a two-byte value so that theì command line can be as large as one would like. I will not describe theì extra changes required to move the command line buffer, since the nextì example will cover that and more. Completely Revamping the Memory Model ------------------------------------- We will now consider how we go about completely revamping the memoryì model, including moving the IOP. Moving any module except for the IOP canì be accomplished using a straightforward extension of what we have alreadyì described. The IOP poses some special problems that we will now deal with. Before turning to that subject, I would like to make some generalì comments about the memory allocation in a ZCPR3 system. With a fixed systemì -- that is, any particular system that one will use at all times -- it doesì not really matter how the modules are distributed in memory, just so long asì they all fit somewhere. As soon as one wants to be able to change from one system configurationì to another, not all memory models are as good as others. I first noticedì this when I wanted to run both Z3-DOT-COM and Z-COM on my system. I usuallyì used Z3-DOT-COM because it left a larger TPA, but occasionally I wanted toì make use of the IOP for redirecting console output to a disk file. At thatì point I discovered that Joe Wright's choice of memory models was a poor one. ì By adding the IOP at the top in Z-COM rather than at the bottom, theì environment descriptor moved down to a lower address, and that meant that Iì either had to have two sets of utility programs or had to reinstall all theì utilities every time I changed from one system to the other. This providedì a powerful incentive to discover methods for modifying the memory maps. Ofì course, with ZCPR33 and its automatic installation of utilities, this is noì longer a concern. Even with ZCPR33 there are compelling reasons to choose some memoryì configurations over others. The addresses of most system components areì hard-coded into even the ZCPR33 command processor. However, as we mentionedì earlier, the addresses of the largest memory buffers -- the NDR, FCP, andì RCP -- can determined dynamically from the environment descriptor in memory. ì As a result, if these buffers are placed adjacent to one another, the singleì block of memory allocated to the set of them can be reconfigured simply byì loading a new environment descriptor. Since the command processor does notì directly refer to the IOP, the IOP can also be included at the bottom ofì this single buffer space. The tradeoffs that become possible areì illustrated in Fig. 4, where a single memory block of 4.25K (the standardì amount in Z-COM for these modules) is allocated in two different ways. ----------------------------------------------------------------------------- total space standard configuration alternate configuration --- --- --- | | NDR (2) | | --- | NDR (6) | | FCP (4) | | | --- | all --- | | buffers | | FCP (7) | 4.25K | | | 34 records | --- | | RCP (16) | | | | | | | | | | | | | RCP (20) | --- | | | | | | | | | IOP (12) | | | | | | --- | | | IOP (1) --- --- --- Fig. 4. One illustration of how a single block of memory can be dynamicallyì allocated among the IOP, RCP, FCP, and NDR buffers in a ZCPR33 system. ----------------------------------------------------------------------------- In the alternative memory map in Fig. 4 the IOP buffer has been shrunkì to a single record, a space just large enough to hold the dummy IOP that Z-COM comes with (we can't shrink it to zero without changing the VBIOS). Theì extra 11 records of memory are then distributed to the other modules. Theì NDR increases to 6 records, enough for 42 named directories. The FCP picksì up 3 more records. At 7 records, it has enough space to implement a veryì large number of resident test options. The remaining 4 records go to theì RCP, which can probably now include all options in Z33RCP. Suppose the standard configuration is described by SYS.ENV and uses theì modules SYS.NDR, SYS.FCP, and SYS.RCP, and that the alternativeì configuration is described by ALT.ENV with modules ALT.NDR, ALT.FCP, andì ALT.RCP. Then we would change from the standard to the alternateì configuration by entering the command LDR ALT.ENV,ALT.NDR,ALT.FCP,ALT.RCP Note that it is essential that the ENV module be listed, and thereforeì loaded, first. If it is not, LDR will not know the correct addresses forì the other modules. Similarly, to change back to the standard configuration,ì one would use the command LDR SYS.ENV,SYS.NDR,SYS.FCP,SYS.RCP If one were switching back, for example, to use the NuKey IOP to provideì keyboard macro capability, the line could read LDR SYS.ENV,SYS.NDR,SYS.FCP,SYS.RCP,NUKEY.IOP In this way one can make much more flexible use of system resources. Oneì might choose to reduce the size of the overall buffer space to only 35ì records, keeping only the IOP stub in the standard configuration. Then whenì an IOP like IOR (I/O recorder) or BPRINT (print spooler) is needed, the RCPì and/or FCP would be contracted temporarily. Either one or both could evenì be eliminated (reduced to zero size). Aliases can be used to automate theì process of switching configurations. Moving the IOP -------------- We will now build a Z-COM system of the form described above. Theì memory map for the new configuration is shown in Fig. 5. Since the ENVì (including TCAP) is a fixture in any system, I would have preferred to putì it in the invariant position at the very top of memory. However, ZRDOS hasì to know where the ENV is in order to support wheel-locking of files. If youì have purchased ZRDOS separately, you can generate a version to run at anyì address and to reference an ENV at any address. If you only have Z-COM,ì however, you do not have this freedom. Therefore, I have left theì environment where it was. ----------------------------------------------------------------------------- System Component ZC.COM Address System Address ---------------- -------------- -------------- operating system modules CPR 0200 - 09FF BA00 - C1FF ZRDOS 0A00 - 17FF C200 - EFFF Virtual BIOS 1800 - 19FF D000 - D1FF large, variable buffers I/O Package 1A00 - 1FFF D200 - D7FF Resident Command Package 2000 - 25FF D800 - DFFF Flow Control Package 2800 - 27FF E000 - E1FF Named Directory Register 2A00 - 1AFF E200 - E2FF third page of buffers Shell Stack 2B00 - 1B7F E300 - E47F Z3 Message Buffer 2B80 - 1BCF E380 - E4CF External FCB 2BD0 - 1BF3 E3D0 - E4F3 PATH 2BF4 - 1BFE E3F4 - E4FE Wheel Byte 2BFF - 1BFF E3FF - E3FF second page of buffers Environment Descriptor 2C00 - 1C7F E400 - E47F TCAP 2C80 - 2DFF E480 - E4FF top page of buffers Multiple Command Line 2D00 - 1DCF E500 - E5CF External Stack 2DD0 - 1DFF E5D0 - E5FF Fig. 5. Memory map for a system designed for dynamic buffer reallocationì under ZCPR33. ----------------------------------------------------------------------------- The first step, as usual, in making a new configuration is to prepare aì new Z3BASE.LIB file. The important addresses in that file are shown in Fig.ì 6. I have considered each page of memory to be a unit. The bottom of theì page is referenced to the real BIOS address, and the other modules in theì page are referenced to the base module for that page. Of course, you canì express these addresses in many other equivalent ways, and you may wellì prefer to do it differently. In any case, with Z3BASE.LIB in hand, you canì assemble up the CPR, RCP, FCP, and ENV modules (or you can make the latterì by patching). ----------------------------------------------------------------------------- ; Z3BASE.LIB rbios equ 0e600h ; First page under BIOS z3cl equ rbios - 100h z3cls equ 203 extstk equ z3cl + 0d0h ; Second page under BIOS z3env equ rbios - 200h z3envs equ 2 ; Third page under BIOS shstk equ rbios - 300h shstks equ 4 shsize equ 32 z3msg equ shstk + 080h extfcb equ shstk + 0d0h expath equ shstk + 0f4h expaths equ 5 z3whl equ shstk + 0ffh ; Variable modules z3ndirs equ 14 z3ndir equ rbios - 0400h fcps equ 4 fcp equ z3ndir - fcps*80h rcps equ 16 rcp equ fcp - rcps*80h iops equ 12 iop equ rcp - iops*80h ; Operating system components vbios equ iop - 0200h dos equ vbios - 0e00h ccp equ dos - 0800h Fig. 6. Address equates for the Z3BASE.LIB file corresponding to the memoryì configuration shown in Fig. 5. ----------------------------------------------------------------------------- We would be able to implement this configuration without any problemì using the techniques we have already seen were it not for the IOP module. ì The IOP is really an extension of the BIOS, and the problem is that theì virtual BIOS has vectors (jump instructions) going to the IOP. When the Z-COM system is built by the loader program ZCLD.COM, the addresses areì calculated based on the assumed relative positions of the VBIOS and IOP. ì Since we are now going to change the spacing between them, we will have toì perform some patching on the VBIOS module. The table of jump vectors in the virtual BIOS is shown in Fig. 7. ì There are two jumps (warm and cold boot) that are internal to the VBIOS, 7ì jumps to addresses in the IOP (6 in one group and one extra), and 10 jumpsì to the real BIOS. Only the jumps to the IOP have to be changed. ----------------------------------------------------------------------------- (00) VBIOS: JP VBIOS + 67H ; coldboot (03) JP VBIOS + 67H ; warmboot (06) JP IOP + 0CH ; console status (09) JP IOP + 0FH ; console input (0C) JP IOP + 12H ; console out (0F) JP IOP + 15H ; list out (12) JP IOP + 18H ; punch out (15) JP IOP + 1BH ; reader in (18) JP BIOS + 18H ; home disk (1B) JP BIOS + 1BH ; select disk (1E) JP BIOS + 1EH ; set track (21) JP BIOS + 21H ; set sector (24) JP BIOS + 24H ; set DMA (27) JP BIOS + 27H ; read sector (2A) JP BIOS + 2AH ; write sector (2D) JP IOP + 1EH ; list status (30) JP BIOS + 30H ; sector translation Fig. 7. Structure of the jump table in the virtual BIOS. ----------------------------------------------------------------------------- You should begin by making a copy of ZC1.COM, which we generatedì earlier, giving it the name ZC2.COM. Then determine the absolute address ofì the IOP in your system. Next, go into ZC2.COM with ZPATCH or with aì debugger and change the addresses. For my Televideo 803H system the IOP hadì been at E000H and is now at D200H. I would look for the seven jumps of theì form "C3 ?? E0" and change them to "C3 ?? D2". We also have to make some changes to the code in the dummy IOP. It hasì a total of 16 jump instructions, 7 of which refer to the real BIOS and 9 ofì which refer to internal addresses. The former need not be changed, but,ì since we are changing the address at which the IOP will execute, we have toì change the latter addresses. The source code for the dummy IOP is shown inì Fig. 8. ----------------------------------------------------------------------------- (00) IOP: JP IOP + 3DH ; status (03) JP IOP + 3DH ; device select (06) JP IOP + 3DH ; device name (09) JP IOP + 3DH ; initialization (0C) JP BIOS + 06H ; console status (0F) JP BIOS + 09H ; console input (12) JP BIOS + 0CH ; console output (15) JP BIOS + 0FH ; list output (18) JP BIOS + 12H ; punch output (15) JP BIOS + 15H ; reader input (18) JP BIOS + 2DH ; list status (1B) JP IOP + 3DG ; new I/O routine (1E) JP IOP + 3DH (21) JP IOP + 3DH (24) JP IOP + 3DH (27) JP IOP + 3DH (30) DB 'Z3IOPDUMMY ' ; ID string (3D) XOR A ; set zero value and flag (3E) RET ; return Fig. 8. Source code for the dummy IOP in Z-COM. All the internal routinesì simply return with the zero flag set, while the substantive functions areì vectored off to the real BIOS. ----------------------------------------------------------------------------- The garbage that appears from address IOP+3FH to the end of the IOP atì IOP+5FFH can be filled with zeros to make things look neater. Then the 9ì internal vectors have to be modified in the same way those in the BIOS wereì to point to the new address of the IOP. Finally, the reconfigured IOP hasì to be moved from its present position at 2800H to its new place in ZC2.COMì at 1A00H. While we are in the debugger doing that, we can also change (1) theì file control block to load the command processor image ZC2.CP (and also theì 'not found' message) and (2) the multiple command line buffer to run START2. ì This initial multiple command line must also be moved from its old addressì at 1D00H to its new position at 2D00H. Make sure that the second byte inì the command line buffer points to the page where the real multiple commandì line buffer will be. You should then fill all the other buffers with zeros. The CPR, RCP,ì FCP, and ENV modules can be loaded into the image. Then the initial pathì should be set up at address 2BF4H, and the wheel byte at address 2BFFHì should be set to FFH if you want it on. Finally, if you want an errorì handler to be loaded when Z-COM is booted, then patch in the error commandì line (for example, "A0:Z33VERR<0>") at Z3MSG+10H (2B90H in ZC2.COM). If everything has gone right, and I have not left something out orì written something wrong, you should be ready to test it out. Don't forgetì to put the command processor image files in A15. I know I keep harping onì this, but while working on this article, I forgot to do that on oneì occasion, and there are now a few dents in the table from my fist! A Minimum System ---------------- If you ever meet me and feel like having a little fun at my expense,ì just casually make some comment like, "Oh, yeah, I hear ZCPR3 has some niceì features but that it uses up much too much memory." It is a subject thatì has become a sore point for me lately and one that is almost guaranteed toì provoke me. To be honest, however, the persistance of this false impressionì is to a large degree the result of poor education on our part. No one everì talks about minimum ZCPR3 systems; we only describe full-blown ones. It is true that a full-blown ZCPR3 system uses quite a bit of memory. ì Z-COM takes 1600H = 5.5K bytes of memory out of your TPA, a pretty heftyì chunk. I like the features that this big Z-System gives me, and for theì kind of work I do, the smaller TPA almost never causes any problem. For me,ì the benefits far outweigh the cost. For some people, however, especially those working with voraciousì memory hogs like database managers and C compilers, this is not the case. ì (It seems to me that someone like Steve Russell of SLR should write a good,ì virtual-memory C compiler like his virtual-memory assemblers to prevent thisì problem.) But the real answer is that a ZCPR3 system does not have to haveì every feature implemented. As with most things in this world, the 20/80ì rule applies: for less than 20% of the cost, you can buy more than 80% ofì the features. If we eliminate all the variable buffers in the last example,ì we end up with a system that uses only 5 pages (1.25K) of memory, a veryì modest amount. The same system installed in the conventional way, with noì space required for the virtual BIOS of Z-COM, would take only 0.75K awayì from the TPA, yet all of the following features would still be there: automatic command search path flexible access to user areas multiple commands on a line aliases shells (including history shell and filer shells) extended command processing (including ARUNZ command generator) powerful error handlers (with command editing) terminal-independent operation (TCAP) flexible program loading (type-3 environment) interprogram communication The only things missing are named directories and flow control. Some simpleì flow-control-like features could be implemented even without the FCP. Withì all the security features and named-directory support removed from theì command processor, there is room for many more CPR-resident commands, andì the ones that won't fit can be implemented as virtual residents using theì new type-3 environment. In summary, a very powerful system can be builtì with a very small cost in TPA. To prove this point (and because it will be useful on those rareì occasions when I run my database manager), I decided to develop a version ofì Z-COM that would have only the three pages of core modules. The memory mapì is shown in Fig. 9. It differs in two fundamental ways from all the otherì maps we have seen: (1) it is shorter and (2) the real VBIOS and ZRDOS run atì different addresses than usual. These differences will require some newì techniques, and we will cover them shortly. ----------------------------------------------------------------------------- System Component ZC.COM Address System Address ---------------- -------------- -------------- CPR 0200 - 09FF CB00 - D1FF ZRDOS 0A00 - 17FF D300 - E0FF Virtual BIOS 1800 - 19FF E100 - E2FF Shell Stack 1A00 - 1A7F E300 - E47F Z3 Message Buffer 1A80 - 1ACF E380 - E4CF External FCB 1AD0 - 1AF3 E3D0 - E4F3 PATH 1AF4 - 1AFE E3F4 - E4FE Wheel Byte 1AFF - 1AFF E3FF - E4FF Environment Descriptor 1B00 - 1B7F E400 - E47F TCAP 1B80 - 1BFF E480 - E4FF Multiple Command Line 1C00 - 1CCF E500 - E5CF External Stack 1CD0 - 1CFF E5D0 - E5FF Fig. 9. Addresses of system components in the ZC3.COM file and in theì target system for a minimum configuration with no IOP, RCP, FCP, or NDR. ì The file is 2E00H - 1D00H = 1100H = 4.25K shorter than the other versions. ----------------------------------------------------------------------------- First we have to make Z3BASE.LIB, the equates for which are shown inì Fig. 10. The only subtle change is in the way the VBIOS address is defined. ì Make sure you do not define it in terms of any of the modules whoseì addresses have been set to zero to disable them or you will get extremelyì strange results. ----------------------------------------------------------------------------- ; Z3BASE.LIB rbios equ 0e600h ; First page under BIOS z3cl equ rbios - 100h z3cls equ 203 extstk equ z3cl + 0d0h ; Second page under BIOS z3env equ rbios - 200h z3envs equ 2 ; Third page under BIOS shstk equ rbios - 300h shstks equ 4 shsize equ 32 z3msg equ shstk + 080h extfcb equ shstk + 0d0h expath equ shstk + 0f4h expaths equ 5 z3whl equ shstk + 0ffh ; Variable modules -- all disabled z3ndirs equ 0 z3ndir equ 0 fcps equ 0 fcp equ 0 rcps equ 0 rcp equ 0 iops equ 0 iop equ 0 ; Operating system components vbios equ shstk - 0200h dos equ vbios - 0e00h ccp equ dos - 0800h Fig. 10. The Z3BASE.LIB equates for a minimum system that takes only 0.75Kì for the ZCPR3 buffers and 0.5K for the virtual BIOS required for automaticì installation. ----------------------------------------------------------------------------- The basic procedure for creating this system is very much like what weì have done before. We edit the Z3BASE.LIB file and assemble up the CPR andì ENV modules (or make the latter by patching). There are no FCP, NDR, or IOPì modules to worry about. We set up the path, the wheel, and the errorì handler; we change the VBIOS file control block to load ZC3.CP for the CPRì image file and change the 'not found' message to match; and we put in theì ENV and CPR modules. Now we have to face the new complications that arise because of theì change in size of the file. First we will take up the simpler problem --ì changing the loader code in the first page of the file. It normally copiesì 2C00H bytes (from 200H to 2E00H) up to the run-time location in memory. Nowì the image part of the file is only 1B00H bytes long. If you follow throughì the loader code in a debugger, you should not have too much difficultlyì figuring out what is going on. The hardest parts to trace through are theì places where the code prints out in-line strings. You will typically see aì call instruction followed by very strange code. That strange code is theì text to be printed. That coding technique is very convenient for theì programmer (and I use it all the time), but it makes disassembly and single-stepping in a debugger much more difficult. When you encounter code likeì this, you have to use the dump ('D') display to locate the null (binary 0)ì that marks the end of the string. Then you can continue running using theì command "G,addr", where 'addr' is the address just after the null. Anyway, at address 181H you will find the key instruction: LDì B.C.,2C00H. This must simply be changed to LD B.C.,1B00H. That's all thereì is to it -- as far as the loader code is concerned. You might wonder why weì don't have to change the starting address for the load, since it is not theì same as before. The answer is that Z-COM derives it from the initial jumpì instruction in the CPR image. My first versions of Z33 used a relativeì jump, and I had to put the absolute jump back after one of my beta-testersì pointed out that it would not work with Z-COM. Now we have to face two much more difficult problems: both the VBIOSì and the ZRDOS modules have to be relocated to a new address. How can weì possibly do this without source code? Well, if you purchased a separateì copy of ZRDOS, you have a file with a name like ZRDINS.COM with which youì can create a binary image of ZRDOS that will run at any address and with anyì ENV address. But what if you don't have it? And what about the VBIOS part? ì The latter could conceivably be disassembled, since the code is not veryì long or very complex, but there is a better way, one that makes use of theì built-in capabilities of the auto-install package. If you had two computers with different BIOS entry addresses, you couldì perform a standard installation of Z-COM on each system. By taking the twoì ZC.COM files and subtracting them in a debugger, you could derive theì relocation map. Now the question is how we can make two ZC.COMs using aì single computer. If you examine the beginning of the code in ZCLD.COM, you will see thatì ZCLD keys its system generation to the address of the BIOS warmboot vectorì at address 0001, and that is what we will base our strategy on. We willì fool ZCLD into making us two versions of ZC.COM one page apart that we canì subtract. With my standard Z-COM system running on the Televideo 803H, the CPR isì at BA00H and the virtual BIOS at D000H. Thus the vector at address 0001ì points to D003H. By entering the following commands, we can make the BIOSì look as though it were at B900: POKE B903 C3 03 D0 ; Set up JP D003H at address B903H POKE 2 B9 ; Change bios vector from D003 to B903 Of course, you must use addresses appropriate to your system. Any addressì below the CPR but above the memory used by ZCLD should work. With this patch in place, everything will be fine so long as we do notì try to run a program that does direct BIOS calls based on the address atì 0001. (If we do? -- the system will simply go up in flames!) In caseì you're worried, the next warmboot will delete our patch and restore thingsì to normal. Fortunately, ZCLD does not mind being fooled this way. All in all, theì following sequence of commands will result in two files, ZCB8.COM andì ZCB9.COM. POKE B903 CE 03 D0;POKE 2 B9;ZCLD;REN ZCB9.COM=ZC.COM POKE B803 CE 03 D0;POKE 2 B8;ZCLD;REN ZCB8.COM=ZC.COM We can then load both files into a debugger using the commands IZCB8.COM ; set file to ZCB8.COM R ; read in at 100H (100H-2DFFH) IZCB9.COM ; set file to ZCB9.COM R3000 ; read in at 3100H (3100H-5DFFH) Now from right in the debugger we can assemble a little program atì 3000H to subtract the ZRDOS and VBIOS images in memory block 0A00H-19FFHì from the images in memory block 3A00H-49ffH to give us the relocation map weì need. Here is how the entry of the assembly code proceeds: -A3000 3000 LD DE,3A00 ; set up pointers to two files 3003 LD HL,A00 3006 LD B.C.,1000 ; number of bytes to subtract 3009 LD A,(DE) ; get byte from higher image 300A SUB (HL) ; subtract byte from lower image 300B LD (DE),A ; put result (0 or 1) back 300C INC HL ; increment the pointers 300D INC DE 300E DEC B.C. ; check count 300F LD A,B 3010 OR C 3011 JR NZ,3009 ; loop through 1000H bytes 3013 Enter the command "G3000,3013" to run this routine with a breakpoint atì 3013. If you look at memory from 3A00H TO 49FFH you will see a pattern ofì 1s and 0s. This is the relocation map. It indicates which bytes must beì changed to shift the execution address of the code. Now we have to relocate the ZRDOS to run at D300H and the VBIOS to runì at E100H instead of the values 9400H and A200H as they are in the image inì ZCB8.COM (determined by inspection with a debugger). Thus we have to add anì offset of 3FH (E1-A2) to all bytes where the relocation map has a one in it. ì So we assemble up another little program at 3000H as follows: -A3000 3000 LD HL,3A00 ; point to relocation byte 3003 LD DE,1A00 ; point to ZRDOS/VBIOS we are creating 3006 LD B.C.,1000 ; number of bytes to cover 3009 LD A,(DE) ; get current value of byte 300A BIT 0,(HL) ; see if relocation map has a 1 in it 300C JR Z,3011 ; if not, skip the offset addition 300E ADD A,3F ; add the offset 3010 LD (DE),A ; put back the corrected byte 3011 INC HL ; increment the pointers 3012 INC DE 3013 DEC B.C. ; check the count 3014 LD A,B 3015 OR C 3016 JR NZ,3009 ; loop through 1000h bytes 3018 Run this program with "G3000,3018" and you will have a ZRDOS and VBIOS thatì will run at the required address. Put them in a safe place temporarilyì while you load in ZC3.COM and then move them into the proper place in theì image. This completes the generation of the minimum system except for oneì step described a little later. Although all that work with the debugger took quite a lot of space toì describe, it is really not that difficult to do. I particularly wanted toì show it to you because it is a technique that is useful in many otherì circumstances as well (like using MOVCPM to relocate your system in one-pageì rather than 1K increments). Now, however, I will show you a much easier wayì to accomplish the same thing in the case of Z-COM. If you load ZCLD.COM into the debugger and trace through the code withì the 'L' command, you will see how it works. Before one gets to the mainì code, there are two places where checks are made. One is to see if theì command was invoked as "ZCLD //" to request the built-in help screen. Theì second test is to make sure that you are not trying to run ZCLD from insideì a running Z-COM system. We could drop out of Z-COM after making the changesì I am about to describe, but why put up with that trouble. The code isì testing for the presence of the letter 'Z' in the copyright notice insideì the VBIOS at offset 42H. At address 249H there is a "JP NZ,29D" instructionì that takes one to the system-building code if no 'Z' is detected. If weì change this to an unconditional jump, we will effectively disable the test. At 29DH, the code loads the address of the BIOS with the instructionì "LD HL,(1)". We know that we want the system to be generated at an addressì 1100H higher than it would be normally because of all the modules weì removed. Since the normal BIOS address was E600H, we want ZCLD to see aì value of F700H. To accomplish this, we assemble in the instruction "LDì HL,F700", a direct load instead of an indirect load to HL. We can then saveì away this modified version as ZCLD1.COM. When we run it, it very nicelyì produces a system with a ZRDOS and VBIOS at just the addresses we wanted. There is one other change I have forgotten to mention. The jumps inì the VBIOS that go to the IOP have to be replaced by jumps to the real BIOSì at the very same offset as in the VBIOS. Thus the jump at offset 06, whichì was "JP IOP+0CH", would become "JP BIOS+06H". Switching from One Version to Another ------------------------------------- What if we are running one of our versions of Z-COM and want to changeì to another one. We can always run the ZCX command to get back to CP/M andì then load the new Z-COM system. This seems unnecessarily tedious. Whyì can't we just run ZC2.COM from the ZC1 system? The answer is that Joeì Wright did not want us to do this. Of course, he was thinking in terms ofì only single configurations, and then there would be no reason to run ZC.COMì when Z-COM was already running. So, he put in some code to protect us fromì this mistake. Now we want to do that very thing! How can we disable the safety code? ì Very simply. It is based on the same check we described with the ZCLDì program. It looks for a 'Z' at byte 42H of the BIOS or VBIOS. If it is aì VBIOS, the 'Z' will be there; if it is a real BIOS, it would be veryì unlikely that a 'Z' would be there. We could go into the code itself as Iì described with ZCLD and disable the test. Alternatively, we could doì something much simpler (and reversible): go into the VBIOS and remove theì 'Z' by changing it to something else. A third possibility, one Iì implemented for the fun of it, is to write a little utility program thatì finds that byte of the BIOS. If it is not a 'Z', it simply returns; if itì is a 'Z', it sets it to zero. Then the next ZCx can load over it. If theì utility is not run, then the system cannot be overlaid. I will suggest one last modification to Z-COM to enhance it evenì further. That is a change to allow alternative versions of Z-COM to beì loaded without interrupting the flow of commands. Thus your memory-hungry Cì compiler would be invoked with an alias the reads something like: RUNC zc3;c $*;zc2 This alias would load the minimum Z-COM system to give the C compiler theì most room to work, and then once the compilation was finished it wouldì reload the full Z-COM configuration. I did this with my Z3-DOT-COM/Z-COMì combination. The I/O Recorder IOP was invoked using an alias. The aliasì would first check to see which Z-System was running (that is what I put theì $M parameter into ARUNZ for). If it was Z3-DOT-COM, then alias would loadì Z-COM before proceeding to load the IOP. I will not go through the methodì for accomplishing this, but I will give you a hint. You have to change theì loader code in the first page of ZCx.COM so that the multiple command lineì buffer and some other system information is not overwritten by the load. Plans for Next Time ------------------- Whew! That was quite a session of heavy technical material. I don'tì know yet exactly what I will do next time, but I certainly I will find aì less technical subject. You need a rest, and I need a rest. If you haveì any questions or suggestions, please write or call. See the ad for Sageì Microsystems East for the address and phone numbers.