diff --git a/Doc/CPM/BPBIOS/BPBIOS_1_Introduction.md b/Doc/CPM/BPBIOS/BPBIOS_1_Introduction.md new file mode 100644 index 00000000..611ffe0f --- /dev/null +++ b/Doc/CPM/BPBIOS/BPBIOS_1_Introduction.md @@ -0,0 +1,81 @@ +# B/P Bios +# Banked and Portable Basic IO System + +# 1 Introduction + +The Banked and Portable (B/P) Basic I/O System (BIOS) is an effort to standardize many of the logical to physical mapping mechanisms on Microcomputers running Z-Systems with ZSDOS. In expanding the capabilities of such systems, it became apparent that standard BIOSes do not contain the functionality necessary, adequate standardization in extended BIOS calls, nor an internal structure to fully support external determination of system parameters. B/P Bios provides a method of achieving these goals, while also possessing the flexibility to operate on a wide range of hardware systems with a much smaller level of systems programming than previously required. + + +## 1.1 About This Manual + +Documentation on B/P Bios consists of this manual plus the latest addendum on the distribution disk in the file README.2ND. This manual is divided into the following sections: + +* The Features of B/P Bios summarizes the significant features of B/P Bios in general, highlighting advantages and the few limitations in the system. + +* Tailoring B/P Bios contains details on altering the many options to generate a customized `.REL` file tailored to your system. + +* Installing a B/P Bios details the installation of B/P Bios in both Unbanked and Banked configurations in a "how to" fashion. + +* Programming for B/P Bios describes the interfaces, data structures and recommended programming practices to insure the maximum benefit and performance from systems with B/P Bios. + +* The B/P Bios Utilities describes the purpose, operation, and customization of all supplied B/P Bios utilities and support routines. + +* Appendices which summarize various technical information. + +* A glossary defining many technical terms used in this Manual. + +* An index of key words and phrases used in this Manual. + +For those not interested in the technical details, or who want to bring the system up with a pre-configured version as quickly as possible, Section 4, Installing a B/P Bios, will lead you through the installation steps needed to perform the final tailoring to your specific computer. Other chapters cover details of the individual software modules comprising the B/P Bios, and specifics on the utilities provided to ease you use of this product. + + +## 1.2 Notational Conventions + +Various shorthand terms and notations are used throughout this manual. Terms are listed in the Glossary at the end of this manual. + +Though the symbols seem cryptic at first, they are a consistent way of briefly summarizing program syntax. Once you learn to read them you can tell at a glance how to enter even the most complicated commands. + +Several special symbols are used in program syntax descriptions. By convention, square brackets (\[\]) indicate optional command line items. You may or may not include items shown between brackets in your command, but if you do not, programs usually substitute a default value of their own. If items between brackets are used in a command, all other items between the brackets must also be used, unless these items are themselves bracketed. + +All of the support utilities developed to support the B/P Bios system contain built-in help screens which use the above conventions to display helpful syntax summaries. Help is always invoked by following the command with two slashes (`//`). So for example, + +`ZXD //` + +invokes help for ZXD, the ZSDOS extended directory program. Interactive ZSDOS programs such as BPCNFG2 also contain more detailed help messages which appear as a session progresses. + +Many utilities may be invoked from the command line with options which command the programs to behave in slightly different ways. By convention, options are given after other command parameters. For example, the `P` option in the command + +`ZXD *.* P` + +causes the ZXD directory utility to list all files (*.*) and send its output to the printer (P). For convenience, a single slash character (/) can often be used in place of leading parameters to signify that the rest of the command line consists of option characters. Therefore, the command + +`ZXD /P` + +is identical in meaning to the previous example (see 6.23 for more on ZXD). + + +## 1.3 What is B/P Bios? + +B/P Bios is a set of software subroutines which directly control the chips and other hardware in your computer and present a standard software interface to the Operating System such as our ZSDOS/ZDDOS, Echelon's ZRDOS, or even Digital Research's CP/M 2.2. These routines comply with the CP/M 2.2 standards for a Basic IO System (BIOS) with many extensions; some based on CP/M 3.x (aka CP/M Plus), and others developed to provide necessary capabilities of modern software. When properly coded, the modules comprising a B/P Bios perform with all the standard support utilities, nearly all Z-System utilities, and most application programs without alteration. + +The ability to operate Banked, Non-banked and Boot System versions of the Bios with a single suite of software, across a number of different hardware machines, plus the maximization of Transient Program Area for application programs in banked systems are features which are offered by no other system of which we are aware. + + +## 1.4 The History of B/P Bios + +Our earlier work developing ZSDOS convinced us that we needed to attack the machine-dependent software in Z80-compatible computers and develop some standard enhancements in order to exercise the full potential of our machines. This premise is even more true today with large Hard Disks (over 100 Megabytes) being very common, needs for large RAM Drives, and an ever shrinking Transient Program Area. Attempts to gain flexibility with normal operating systems were constrained by the 64k addressable memory range in Z80-compatible systems, and forced frequent operating system changes exemplified by NZCOM and NZBLITZ where different operating configurations could be quickly changed to accommodate application program needs. + +In the mid to late 1980's, several efforts had been made to bank portions of CP/M 2.2 "type" systems. XBIOS was a banked Bios for only the HD64180-based MicroMint SB-180 family. While it displayed an excellent and flexible interface and the ability to operate with a variety of peripherals, it had several quirks and noticeably degraded the computer performance. A banked Bios was also produced for the XLM-180 single board S-100 computer, but required special versions of many Z-System utilities, and was not produced in any significant quantity. Other spinoffs, such as the Epson portable, attempted banking of the Bios, but most failed to achieve our comprehensive goals of compatibility with the existing software base, high performance, and portability. + +In 1989, Cam developed the first prototype of B/P Bios in a Non-banked mode on his TeleTek while Hal concentrated on extending ZSDOS and the Command Processor. As of 1997, B/P Bios has been installed on: + +| Computer | Features | +| :--- | :--- | +| YASBEC | Z180 CPU, FD1772 FDC, DP8490 SCSI, 1MB RAM | +| Ampro LB w/MDISK | Z80 CPU, FD1770 FDC, MDISK 1MB RAM | +| MicroMint SB-180 | HD64180 CPU, SMS9266 FDC, 256KB RAM | +| MicroMint SB180FX | HD64180Z CPU, SMS9266 FDC, 512KB RAM | +| Compu/Time S-100 | Z80 CPU, FD1795 FDC, 1 MB RAM | +| Teletek | Z80 CPU, NEC765 FDC, 64KB RAM | +| D-X Designs P112 | Z182 CPU, SMC FDC37C665 FDC, Flash ROM, 512KB RAM (mods for 5380 SCSI and GIDE) | + diff --git a/Doc/CPM/BPBIOS/BPBIOS_2_Features.md b/Doc/CPM/BPBIOS/BPBIOS_2_Features.md new file mode 100644 index 00000000..308b3f3f --- /dev/null +++ b/Doc/CPM/BPBIOS/BPBIOS_2_Features.md @@ -0,0 +1,36 @@ +# 2 Features of B/P Bios + +B/P BIOS is designed to be completely compatible with the CP/M 2.2 standards for a Basic IO System, as well as to provide many extensions needed for banked memory which is becoming so prevalent with newer systems and processors. Additionally, strict coding standards used in the various modules forming the BIOS ease interface problems with applications programs and provide a more robust framework for future development. The extensions added to the basic CP/M 2.2 foundation include many elements from Digital Research's CP/M 3 (aka CP/M Plus), but in a more logically consistent manner. Also included in banked versions are provisions for managing up to 8 MB of extended memory for banked applications, RAM Drives and potentially multitasking in future versions. To provide insight into the methodology used, let us now examine some of the features in a generic B/P Bios. + + +## 2.1 Character IO + +As defined by Digital Research in their CP/M 2.2 standards, character IO consisted of logical devices referred to as TTY, CRT, UC1, CON, etc. B/P Bios extends and generalizes these interfaces using the IOBYTE to define four physical devices called COM1, COM2, PIO and NUL. The first two, COM1 and COM2, are serial ports; PIO is a Parallel port, while NUL is a "bit-bucket" which can be replaced by a customized driver, or used in lieu of an actual device. Digital Research provided only a limited interface capability to the character devices in CP/M 2.2, consisting of a Console (CON), an auxiliary Input and Output (RDR/PUN), and a Printer (LST). The ability to sense Input and Output Status with these devices was extremely limited and was enhanced in CP/M 3. These enhanced capabilities are completely incorporated into B/P Bios with the addition of strict register usage so that only relevant registers may be altered in the respective routines. By manipulating the IOBYTE, any of the four physical devices may be used in the three logical devices of CONsole, AUXiliary, and Printer (LST). + +Also featured in B/P Bios are modifications of CP/M 3 functions to initialize (or re-initialize) all devices and parameters, and return the address of a table which contains names and parameters of the defined character devices. While not totally compatible with CP/M 3 equivalents, these functions are consistent with the spirit and functionality needed with this advanced system. Included in the device table are; flags defining whether the device is capable of Input, Output or Both, Data rates for serial devices (Maximum and Set), Serial data format where applicable, and Handshaking method (CTS/RTS, XON/XOFF or None), as well as Input and Output Data masks for stripping unneeded bits from characters during IO. + + +## 2.2 Mass Storage IO + +All versions of Digital Research's CP/M BIOSes define only a generic Disk driver with implementations of Floppy, Hard, RAM and Tape drives left to the user or developer. In B/P Bios, we went several steps further to ease many problems. First, we retained all standard CP/M 2.2 functions and parameters, added CP/M 3 features for returning the Disk Parameter Header (DPH) table address, and flushing of the software deblocking code segment, and added a new vector to the BIOS jump table to provide a standard method of directly addressing low-level device functions. Several standard low-level Floppy Disk functions are supported and used by the standard utilities, including a function to return the type of Disk Controller in use which permits a single support utility to adapt to a wide variety of hardware platforms. In a like manner, low-level functions are provided for SCSI/SASI Hard Disk drives, and provisions for RAM Disk drives in the event special hardware is implemented. The methods used to implement these access mechanisms may be logically extended to handle Tape Drives or Network Interfaces. + + +## 2.3 Clock Support for Time and Date + +Many Hardware vendors have added provisions for Time and Date as non-standard extensions to CP/M 2.2 BIOSes, and more have incorporated such support into CP/M 3 BIOSes. We opted to define the CP/M 3 clock vector as a ZSDOS-standard clock building on our previous Operating System work. This entry point into the Bios completely complies with our ZSDOS standards and can completely replace the separate clock driver when used with ZSDOS. For systems capable of returning tenths-of-seconds, such as the YASBEC and SB-180, the standard has been enhanced to support this capability as well. + + +## 2.4 Banked Memory Support + +While Digital Research added banked memory support to their CP/M 3, it was in a manner incompatible with Bios interface standards defined for earlier CP/M standards. The method used in B/P Bios is compliant with CP/M 2.2 in direct accessing of Bios functions with only one minor exception when using the Banked ZSDOS2, and contains many of the CP/M 3 extensions added for banked memory support, with some being modified to be consistent with standards adopted for Z-System software. The exception to CP/M 2.2 accesses occurs when the Operating System can access certain buffers in the System Memory Bank. With ZSDOS 2, Allocation Bit Buffers (ALV), Check Buffers (CSV), and the Disk Host Buffer are all contained in the System Bank and not directly accessible from Transient Programs. To compensate for this, we have added a command to ZSDOS 2 to return the free space on disks (the most common reason for accessing these buffers) and tailored several utilities to adapt to banked and non-banked systems. + +In addition to the primitives initiated by Digital Research, we added functions to directly access Words and Bytes in extended banks of memory, Directly accessing software routines contained in alternate memory banks, and properly managing the system when errors occur. These features make B/P Bios much more robust and resilient than other products. These features are implemented by methods transparent to the system utilities so that the same functions are available in both banked and non-banked versions. + + +## 2.5 Other Features + +B/P Bios contains a standardized identification method which may be used to determine the hardware on which the software is operating. This allows applications to "adapt" to the environment in a manner similar to that used in the rest of the Z-System community. It also minimizes system "crashes" by executing programs which assume certain hardware features which may be detrimental if executed on other systems. The effects of identification of physical system parameters is most readily noticed by virtue of a single suite of support programs performing low-level functions such as formatting and diagnostics which function across widely differing hardware platforms. Portability on this scale can rarely be seen in other computer systems. + +The ZCPR 3.4 Environment with extensions is mandatory in a B/P Bios system. Beginning with the addition of System Segment address and size information for CPR, DOS and BIOS which were added in the ZCPR 3.4 Environment, B/P Bios also adds a Resident User Space which may be used to locate unique routines for custom applications in a manner similar to, but more consistent than NZ-COM. An Environment Version number of 90H identifies the Z3 Environment as being compliant with B/P definitions. + +In Banked systems, application programs may also be placed in alternate memory banks using location and sizing information contained at standard positions within the Bios Header Structure. This feature permits significantly greater functionality without sacrificing precious Transient Program Area. While the scheme employed in the initial distribution is subject to minor adjustments as the banked ZSDOS2 becomes more firmly developed, experimentation and suggestions into this realm are encouraged. diff --git a/Doc/CPM/BPBIOS/BPBIOS_3_Tailoring.md b/Doc/CPM/BPBIOS/BPBIOS_3_Tailoring.md new file mode 100644 index 00000000..af1bb0f7 --- /dev/null +++ b/Doc/CPM/BPBIOS/BPBIOS_3_Tailoring.md @@ -0,0 +1,232 @@ +# 3 Tailoring a B/P Bios + +To customize a B/P Bios for your use, or adapt it to a new hardware set, you will need an editor and an assembler capable of producing standard Microsoft Relocatable files. Systems using the Hitachi HD64180 or Zilog Z180 must be assembled with either ZMAC or SLR180 which recognize the extended mnemonic set, or with a Z80 assembler and MACRO file which permits assembly of the extended instructions. For Z80 and compatible processors, suitable assemblers include ZMAC and Z80ASM. For any assembler, failure to produce standard Microsoft Relocatable code will preclude the ability of our Standard utilities to properly install B/P Bios systems. + + +## 3.1 Theory of Operation + +In order to understand the need for, and principles behind B/P Bios, you must understand the way in which CP/M 2.2, as modified by the Z-System, uses the available memory address space of a Z80 microprocessor. For standard versions of CP/M and compatible systems, the only absolute memory addresses are contained in the Base Page which is the range of 0 to 100H. All addresses above this point are variable (within certain limits). User programs are normally run from the Transient Program Area (TPA) which is the remaining space after all Operating System components have been allocated. The following depicts the assigned areas pictorially along with some common elements assigned to each memory area: + +```generic +FFFFH /------------------\ + | Z-System Buffers | ENV, TCAP, IOP, FCP, RCP + |------------------| + | Bios | Code + ALV, CSV, Sector Buffers + |------------------| + | Operating System | CP/M 2.2, ZRDOS, ZSDOS1 + |------------------| + | Command Processor| CCP, ZCPR3.x + |------------------| + | Transient | + | | + | Program | + | | + | Area | +0100H |------------------| + | Base Page | IOBYTE, Jmp WB, Jmp Dos, FCB, Buffer +0000H \------------------/ +``` + +As more and more functionality was added to the Z-System Buffers, bigger drives were added using more ALV space, and additional functionality was added to Bios code in recent systems, the available TPA space has become increasingly scarce. + +B/P Bios attacks this problem at the source in a manner which is easily adaptable to different hardware platforms. It uses additional memory for more than the traditional role of simple RAM Disks, it moves much of the added overhead to alternate memory banks. The generic scheme appears pictorially as: + +```generic +FFFFH /----------\ + | | + | BNK1 | + | | +8000H |----------| /----------\ /----------\ /----------\ + | | | |\ | |\ | |\ + | BNK0 | | BNK2 | | BNKU | | BNK3 ||\ + | | | || | || | ||| +0000H \----------/ \----------/ \----------/ \----------/ + \- - - - - / \- - - - - / \- - - - - /| + | BNKM | + \----------/ + TPA SYSTEM USER RAM DISK +``` + +As can be seen from the above diagram, multiple banks of memory may be assigned to different functional regions of memory, with each 32k bank (except for the one defined as BNK1) being switched in and out of the lower 32k of the processor's memory map. The bank defined as BNK1 is ALWAYS present and is referred to as the Common Bank. This bank holds the portions of the Operating System (Command Processor, Operating System, BIOS, and Z-System tables) which may be accessed from other areas, and which therefore must always be "visible" in the processor's memory. It also contains the code to control the Bank switching mechanisms within the B/P Bios. + +To illustrate this functional division, the memory map of a basic B/P Bios system is divided as: + +```generic +FFFFH /------------------\ + | Z-System Buffers | + |------------------| + | User Space | + |------------------| + | Bios | + |------------------| + | Operating System | + |------------------| + | Command Processor| /------------------\ 8000H + |------------------| / | Bios Buffers | +8000H | Transient | | Banked Bios Part | + | | |------------------| + | | | Banked Dos Part | + | Program | |------------------| + | | | Banked CCP Part | + | | |------------------| + | Area | | CCP Restoral | +0100H |------------------| |------------------| 0100H + | Base Page | | Base Page Copy | +0000H \------------------/ \------------------/ 0000H + TPA (BNK0/BNK1) System Bank (BNK2) +``` + +The B/P Bios banking concept defines a one byte Bank Number permitting up to 8 Megabytes to be directly controlled. Certain assumptions are made in the numbering scheme, the foremost of which is that BNK0 is the lowest physical RAM bank, BNK1 is the next incremental RAM bank, with others follow in incrementing sequential order. A couple of examples may serve to illustrate this process. The YASBEC is offered with a couple of options in the Memory Map. Units with the MEM-1, 2 or 3 decoder PALs assign the first 128k bytes of physical memory to the Boot ROM, so BNK0 is set to 4 (Banks 0-3 are the ROM). The MEM-4 PAL only uses the first 32k (Physical Bank 0) for the ROM which means that BNK0 is assigned to 1, BNK1 to 2 and so on up to the 1 Megabyte maximum where BNKM is 31. + +The Ampro Little Board equipped with MDISK, on the other hand, completely removes the Boot ROM from the memory map leaving a maximum of 1 MB of contiguous RAM space. In this system, BNK0 is set to 0 and BNKM to 31 of a fully equipped 1 MB MDISK board. + +The region beginning after BNK1 is referred to as the System Bank. It begins at the bank number assigned to BNK2 and ends at the bank number immediately before that assigned to the User Bank, BNKU if present, or BNK3 if no User Bank area is defined. + +If present, one or more 32k banks of memory may be defined with the BNKU equate for unique user programs or storage areas. This area begins with the bank number set to the label and ends at the bank number immediately before the BNK3 label. BNK3 defines a high area of physical memory which is most often used for a RAM Disk providing fast temporary workspace in the form of an emulated disk drive. + +B/P Bios contains protection mechanisms in the form of software checks to insure that critical portions of the memory map are enforced. In the case of Non-banked systems, a check is made to insure that the system size is not so great that the Bios may overwrite reserved Z-System areas in high memory (RCP, IOP, etc). If a possible overflow condition is detected, the message + +`++ mem ovfl ++` + +will be issued when the system is started. In Banked Bios systems, this message will be displayed if the top of the system portions in the SYStem Bank exceeds the 32k bank size. For most systems, this space still permits drives of several hundred megabytes to be accommodated. + +Since the Common portions of the operating system components must remain visible to applications, a similar check is made to insure that the lowest address used by the Command Processor is equal to or greater than 8000H. This factor is checked both in both MOVxSYS and BPBUILD with either a warning issued in the case of the former, or validity checks on entry in the case of the latter. + + +## 3.2 B/P Bios Files + +This BIOS is divided into a number of files, some of which depend highly on the specific hardware used on the computer, and some of which are generic and need not be edited to assemble a working system. Much use is made of conditional assembly to tailor the resulting Bios file to the desired configuration. The Basic file, `BPBIO-xx.Z80`, specifies which files are used to assemble the Bios image under the direction of an included file, `DEF-xx.LIB`. It is this file which selects features and contains the Hardware-dependent mnemonic equates. By maintaining the maximum possible code in common modules which require no alterations, versions of B/P Bios are relatively easy to convert to different machines. The independent modules used in the B/P Bios system are: + +| Filename | Description | +| :--- | :--- | +| `BOOTRAM.Z80` | (only needed in BOOT ROM applications) | +| `BOOTROM.Z80` | (only needed in BOOT ROM applications) | +| `BYTEIO.Z80` | Character IO per IOBYTE using IIO-xx routines | +| `DEBLOCK.Z80` | Disk Deblocking routines | +| `DPB.LIB` | 3.5/5.25" Floppy Format Definitions (if AutoSelect) | +| `DPB8.LIB` | 8"/Hi-Density Floppy Format Definitions (if AutoSelect) | +| `DPB2.LIB` | Additional Floppy Definitions (optional if AutoSelect) | +| `DPBRAM.LIB` | Fixed Floppy Format Definitions (if Not AutoSelect) | +| `DPH.LIB` | Disk Parameter Header Table & Floppy definitions | +| `FLOPPY.Z80` | Floppy Disk High-Level Control | +| `SECTRAN.Z80` | Sector Translate routines | +| `SELFLP1.Z80` | Floppy Select routine (if Not auto selecting) | +| `SELFLP2.Z80` | Floppy Select routine (if auto selecting) | +| `SELRWD.Z80` | Generic Read/Write routines | +| `Z3BASE.LIB` | ZCPR 3.x file equate for Environment settings | + +Other files are hardware version dependent to varying extents. These modules requiring customization for different hardware systems are given names which end with a generic "-xx" designator to identify specific versions. Tailoring these modules ranges from simple prompt line customization to complete re-writes. Versions of B/P Bios generated to date are identified as: + +| ID | Computer system | +| :---: | :--- | +| `-18` | MicroMint SB-180 | (64180 CPU, 9266 FDC, 5380 SCSI) | +| `-YS` | YASBEC | (Z180 CPU, 1772 FDC, DP8490 SCSI) | +| `-AM` | Ampro Little Board | (Z80 CPU, 1770 FDC, 1MB MDISK) | +| `-CT` | Compu/Time S-100 board set | (Z80 CPU, 1795 FDC, 1MB Memory) | +| `-TT` | Teletek | (Z80 CPU, 765 FDC) | + +Files associated with specific hardware versions or require tailoring are: + +| Filename | Description | +| :--- | :--- | +| `BPBIO-xx.Z80` | Basic file, tailored for included file names | +| `CBOOT-xx.Z80` | Cold Boot routines, Sign-on prompts | +| `DEF-xx.LIB` | Equates for option settings, mode, speed, etc. | +| `DPBHD-xx.LIB` | Hard Drive Partition Definitions (optional) | +| `DPBM-xx.LIB` | Ram Drive Definition (optional) | +| `DPHHD-xx.LIB` | Hard Drive DPH definitions (optional) | +| `DPHM-xx.LIB` | Ram Drive DPH Definition (optional) | +| `FDC-xx.Z80` | Floppy Disk Low-Level interface/driver routines | +| `HARD-xx.Z80` | Hard Drive Low-Level interface/driver routines (optional) | +| `IBMV-xx.Z80` | Banking Support Routines (if banked) | +| `ICFG-xx.Z80` | Configuration file for speed, Physical Disks, etc. | +| `IIO-xx.Z80` | Character IO definitions and routines | +| `RAMD-xx.Z80` | Ram Drive interface/driver routines (optional) | +| `TIM-xx.Z80` | Counter/Timer routines and ZSDOS Clock Driver | +| `WBOOT-xx.Z80` | Warm Boot and re-initialization routines | + + +## 3.3 B/P Bios Options + +The most logical starting point in beginning a configuration is to edit the `DEF-xx.LIB` file to select your desired options. This file is the basic guide to choosing the options for your system, and some careful choices here will minimize the Bios size and maximize your functionality. Some of the more important options and a brief description of them are: + +**MOVCPM** - Integrate into MOVCPM "type" loader? If the system is to be integrated into a MOVCPM system, the Environment descriptor contained in the CBOOT routine is always moved into position as part of the Cold Start process. If set to NO, a check will be made to see if an Environment Descriptor is already loaded, and the Bios copy will not be loaded if one is present. + +NOTE: When assembling a Bios for Boot Track Installation (MOVCPM set to YES), many options are deleted to conserve space and the Bios Version Number is forced to 1.1. + +**BANKED** - Is this a banked BIOS? If set to YES, the Bank control module, IBMV, is included in the assembly, and much of the code is relocated to the system bank. Note that a Banked system CANNOT be placed on the System Tracks, or integrated into a MOVCPM image. + +**IBMOVS** - Are Direct Inter-Bank Moves possible? If set to YES, direct transfer of data between banks is possible such as with the Zilog Z180/Hitachi 64180. If NO, a 256-byte transfer buffer is included in high Common Memory and Interbank moves require transfer of bytes through this buffer. + +**ZSDOS2** - Assemble this for a Banked ZSDOS2 system? If YES, the ALV and CSV buffers will be placed in the System bank invisible to normal programs. This has the side effect that many CP/M programs which perform sizing of files (Directory Listers, DATSWEEP, MEX, etc) which do not know about this function will report erroneous sizes. The advantage is that no sacrifice in TPA is required for large Hard Disks. Set this to NO if you want strict CP/M 2.2 compatibility. + +**FASTWB** - Restore the Command Processor from the System Bank RAM? If set to YES, Warm Boots will restore the Command Processor from a reserved area in the System RAM bank rather than from the boot tracks. For the maximum benefit of B/P Bios, always attempt to set this to YES. In systems without extended memory, it MUST be set to NO. + +**MHZ** - Set to Processor Speed in closest even Megahertz (e.g. for a 9.216 MHz clock rate, set to 9). The value entered here is used in many systems to compute Timing values and/or serial data rate parameters. + +**CALCSK** - Calculate Diskette Skew Table? If NO, a Skew table is used for each floppy format included in the image. Calculating Skew is generally more efficient from a size perspective, although slightly slower by factors which are so small as to be practically unmeasurable. + +**HAVIOP** - Include IOP code into Jump table? If the IOPINIT routine satisfies your IOP initialization requirements, you may turn this off by setting to NO and save a little space. This typically will be turned off when generating a system for MOVCPM integration to conserve space. + +**INROM** - Is the Alternate Bank in ROM? Set to NO for Normal Disk-based systems. Please contact the authors if you need additional information concerning ROM-based system components. + +**BIOERM** - Print BIOS error messages? Set this to YES if you desire direct BIOS printing of Floppy Disk Error Messages. If you are building a BIOS for placement on Boot Tracks, however, you will probably not have room and must turn this Off. Set to NO to simply return the normal Success/Fail error flag with no Message printout. + +**FLOPY8** - Include 8"/Hi-Density Floppy Formats? Some systems (SB-180, Compu/Time) can handle both 5.25" and 8" disks. If your hardware supports the capability and you want use 8" disks as well as the normal 3.5 and 5.25" diskettes, setting this to YES will add formats contained in `DPB8.LIB` and control logic to the assembly. Future systems may take advantage of the "High-Density" 3.5 and 5.25" Floppy Disks which use higher data rates. Their definitions will be controlled by this flag as well. + +NOTE: If AUTOSL is set to NO, this option will probably cause the BIOS to be larger than necessary since these additional formats may not be accessible. + +**MORDPB** - Use more Floppy DPB's (in addition to normal 4-5.25" and optional 8")? If YES, the file `DPB2.LIB` is included. Many of the formats are Dummies and may be filled with any non-conflicting formats you desire. + +NOTE: If AUTOSL if set to NO, this option will probably cause the BIOS to be larger than necessary since these additional formats may not be accessible. + +**MORDEV** - Include Additional Character Device Drivers? Is set to YES, user-defined drivers are added to the Character IO table, and associated driver code is assembled. Systems featuring expansion board such as the SB-180 and YASBEC may now take advantage of additional serial and parallel interfaces within the basic Bios. Set to NO to limit code to the basic 4 drivers. + +NOTE: When assembling a Bios for Boot Track Installation (MOVCPM set to YES), MORDEV is overridden to conserve space, and the Bios Version Number is forced to 1.1 in the distribution files. + +**BUFCON** - Use type ahead buffer for the Console? If set to YES, code is added to create and manage a type-ahead buffer for the driver assembled as the console. This device will be controlled by either interrupts (in systems such as the YASBEC and SB-180) or background polling (in Ampro and Compu/Time). This means that characters typed while the computer is doing something else will not be lost, but will be held until requested. + +**BUFAUX** - Use type ahead buffer on Auxiliary Port? As with BUFCON above, setting to YES will add code to create and manage a type ahead buffer for the auxiliary device. Since the AUX port typically is used for Modem connections, buffering the input will minimize the loss of characters from the remote end. + +**AUTOSL** - Auto-select floppy formats? If set to YES, selection of Floppy disks will use an algorithm in `SELFLP2.Z80` to identify the format of the disk from the DPB files included (`DPB.LIB`, optional `DPB8.LIB`, and optional `DPB2.LIB`) and log the disk if a match is found. There must be NO conflicting definitions included in the various files for this to function properly. See the notes in the various files to clarify the restrictions. If set to NO, the single file `DPBRAM.LIB` is included which may be tailored to contain only the fixed format or formats desired per disk drive. This results in the smallest code requirement, but least flexibility. + +**RAMDSK** - Include code for a RAM-Disk? If set to YES, any memory above the System or User bank may be used for a RAM Drive (default is drive M:) by including the file `RAMD-xx.Z80`. Parameters to determine the size and configuration are also included in the files `DPHM-xx.LIB` and `DPBM-xx.LIB`. In systems without extended memory, or to conserve space such as when building a system for the boot tracks, this may be disabled by setting to NO. + +**HARDDSK** - Include SCSI Hard Disk Driver? Set to YES if you wish to include the ability to access Hard Disk Drives. In a floppy-only system, a NO entry will minimize BIOS code. + +**HDINTS** - (System Dependent) In some systems such as the YASBEC, Interrupt-driven Hard Disk Controllers using DMA transfer capabilities may be used. If you wish to use this type of driver specified in the file `HARDI-xx.Z80` instead of the normal polled routines included in `HARD-xx.Z80`, set this option to TRUE. In most cases, this driver will require more Transient Program Area since the Interrupt Handling routine must be in Common Memory. + +**CLOCK** - Include ZSDOS Clock Driver Code? If set to YES, the vector at BIOS+4EH will contain a ZSDOS-compatible clock driver with the physical code contained in the `TIM-xx.Z80` module. If set to NO, calls to BIOS+4EH return an error code. + +**TICTOC** - (System Dependent) Use pseudo heartbeat counter? This feature is used in systems such as the Ampro Little Board and Compu/Time SBC880 which do not have an Interrupt scheme to control a Real Time Clock. Instead, a series of traps are included in the code (Character IO Status polls, Floppy Disk Status polls) to check for overflow of a 1-Second Counter. It is less desirable than an Interrupt based system, but suffices when no other method is available. Set to NO if not needed. + +**QSIZE** - Size in bytes of type ahead buffers controlled by BUFCON and BUFAUX. + +**REFRSH** - Activate Dynamic Refresh features of Z180/HD64180 processors? In some computers using these processors such as the YASBEC, refresh is not needed and merely slows down processing. Set to NO if you do not need this feature. If your processor uses dynamic memory, or needs the signal for other purposes (e.g. The SB180 uses Refresh for Floppy Disk DMA), Set this to YES. + +**Z3** - Include ZCPR init code? Since a Z3 Environment is mandatory in a B/P Bios (which now "owns" the Environment), this option has little effect. + +For assembly of a Banked version of B/P Bios, the identification of various banks of memory must be made so that the various system components "know" where things are located. Refer to Section 3.1 above for a description of these areas. The BNK0 value should be the first bank of RAM in the System unless other decoding is done. The following equates must be set: + +| Equate | Description | +| :--- | :--- | +| BNK0 | First 32k TPA Bank (switched in/out) | +| BNK1 | Second 32k TPA Bank (Common Bank) | +| BNK2 | Beginning of System Bank (BIOS, DOS, CPR) area | +| BNKU | Beginning of Bank sequence for User Applications | +| BNK3 | Beginning of Extra Banks (first bank to use for RAM Disk) | +| BNKM | Maximum Bank Number assigned | + + +## 3.4 Configuration Considerations + +When assembling a version of B/P Bios for integration into an IMG file, size of the resulting image is not much of a concern, so you need not worry about minor issues of size. For integration into a system for loading onto diskette boot tracks, however, the limitation is very real in order to insure that the CPR/DOS/BIOS and Boot Sector(s) can fit on the reserved system tracks. Typically, a limit of slightly under 4.5k exists for the Bios component. When the MOVCPM flag is set to YES for this type of assembly, warnings will be issued when the image exceeds 4352 bytes (the maximum for systems with 2 boot records), and 4480 bytes (the maximum for systems with a single boot record). Achieving these limits often requires disabling many of the features. + +The first thing you should do before assembling the BIOS is to back up the entire disk, then copy only the necessary files onto a work disk for any editing. After setting the options as desired, edit the hardware definitions in `ICFG-xx.Z80` to reflect the physical characteristics of your floppy and hard drives, as well as any other pertinent items. Then edit the logical characteristics for your Hard and Ram Drives (if any) in `DPBHD-xx.LIB` and `DPBM-xx.LIB`. If you do not desire any of the standard floppy formats or want to change them, edit `DPB.LIB` and/or `DPB2.LIB` (if using auto selection) or `DPBRAM.LIB` if you are using fixed floppy formats. Finally edit the DPH files to place the logical drives where desired in the range A..P. + +Decide whether you want to generate a system using the Image file construct developed in support of B/P Bios (BPBUILD/LDSYS), or for integration on a floppy disk's boot tracks. If the latter, you probably will not be able to have all options turned on. For example, with the MicroMint SB-180, the following options must be turned Off: BANKED, ZSDOS2, BIOERM, FLOPY8, MORDPB, BUFAUX and usually either CLOCK or RAMDSK. As an aid to space reduction, conditional assembly based on the MOVCPM flag automatically inhibits all but double-sided Floppy formats from `DPB.LIB`. If configuring for Floppy Boot tracks (MOVCPM flag set to TRUE), a warning will be printed during assembly if the size exceeds that available for a One or Two-sector boot record. Using the BPBUILD/LDSYS method, you may vary nearly all system parameters, even making different systems for later dynamic loading. + +If you are using a version of the B/P Bios already set for your type of computer, you are now ready to assemble, build a system and execute it. The only remaining task would be an optional tailoring of the sign on banner in the file `CBOOT-xx.Z80` and reassembly to a `.REL` file. + +For those converting a standard version of the B/P Bios to a new hardware system, we recommend that you begin with a Floppy-only system in Non-Banked mode then expand from there. The easiest way to test out new versions is to use the System Image (IMG file) mode, then advance to boot track installations if that is desired. Enhancements that can be added after testing previous versions may be to add Hard Drives, RAM Drive, and finally Banking. + diff --git a/Doc/CPM/BPBIOS/BPBIOS_4_Installation.md b/Doc/CPM/BPBIOS/BPBIOS_4_Installation.md new file mode 100644 index 00000000..b2b55a0a --- /dev/null +++ b/Doc/CPM/BPBIOS/BPBIOS_4_Installation.md @@ -0,0 +1,200 @@ +# 4 Installing a B/P Bios + +The Distribution diskette(s) on which B/P Bios is furnished are configured for booting from the vanilla hardware for the version ordered. A 9600 bps serial terminal is standard, and will allow you to immediately bring up a minimal Non-Banked Floppy Disk system. Due to the variety of different system configurations and size restrictions in some versions, only the Floppy Disk Mass Storage capability can be assured on the initial boot disk. Where space remained on the boot tracks, limited Hard Drive support is also provided, and in some configurations, even RAM Drive support exists. + +After booting from either an established system, or the boot tracks of the distribution disk, format one or more fresh diskettes and copy the distribution diskette(s) contents to the backup diskette(s). Copy the boot tracks from the master to the copies using BPSYSGEN (see 6.6). Remove the master diskette(s) for safekeeping and work only with the copies you just made. + +Using the backup diskette with the B/P utilities on it, execute BPCNFG in the Boot Track configuration mode (see 6.2), adjusting all the options to your specific operating environment. When you have completed tailoring the system, it is ready for booting by placing the diskette in drive A: and resetting the system. + +The sample `STARTUP.COM` file on the distribution disk will automatically execute a sequence of instructions when the system is booted. It contains various instructions which further tailor the system and load portions of the operating system which are too big to fit on the boot tracks. The default instruction sequence is: + +| Command | Explanation | +| :--- | :--- | +| `LDDS` | Load the DateStamper style File Stamp routine and clock | +| `LDR SYS.RCP,SYS.FCP,SYS.NDR` | Load ZCPR 3 Environment segments for Resident Command Processor, Flow Control Pkg and Named Dirs | +| `IOPINIT` | Initialize the IO Processor Pkg | +| `TD S` | Prompt for Date and Time, Set Clk / Alternatives are to use `TDD` (6.21) or `SETCLOK` (6.18) | +| `IF ~EX MYTERM.Z3T` | If the file `MYTERM.Z3T` does Not exist... | +| `TCSELECT MYTERM.Z3T` | ..select which terminal you have creating a `MYTERM.Z3T` file | +| `FI` | ...end of the `IF` | +| `LDR MYTERM.Z3T` | Load the Terminal Definition data | + +If you wish to alter any of these initial instructions to, for example, initialize the RAM drive using INIRAMD, add File Time Stamp capabilities to it with INITDIR or PUTDS and copy some files there with COPY, these may be added with ALIAS, VALIAS, SALIAS or other compatible files available from the ZSYSTEM or ZCPR33 areas on Z-Nodes. + +After the initial system is up and running from the Default Boot Track system, you may expand the operation by generating systems for different purposes in order to gain the most advantage from your system. Many types of installation are possible, the simplest of which is a Non-Banked system using only 64k of the systems memory, all of which is in primary memory. Such a system uses a normal Command Processor such as the ZCPR3.x family, and a Non-Banked Operating System such as our ZSDOS Version 1. Non-Banked systems may be installed on a Disk's Boot Tracks, or created as an Image File for dynamic loading using the LDSYS Utility (see 6.15). + +Banked systems MUST be created with the BPBUILD Utility (see 6.1) and loaded with LDSYS (see 6.15). The techniques to manage different memory banks to form a complete Operating Environment are rather intricate and are best handled by our utilities. Many Image files may be created and loaded as needed to tailor your system for optimum performance. The following sections describe these various types of installations in detail. + + +## 4.1 Boot Track Installation + +For most of the existing CP/M compatible computers to begin executing a Disk Operating System, a program must be placed on a specified area of a Floppy or Hard Disk Drive. Normally, the first two or three tracks on the disk are reserved for this purpose and are referred to as the "Boot Tracks". Since the space so defined is generally restricted, neither a complete B/P Bios nor a Banked installation is possible. Instead, a scaled-down system roughly equivalent to those currently in use is used to start the computer and serve as the Operating System, with larger systems loaded later as needed. + +If you are using a pre-configured version of B/P Bios for your hardware, you may simply continue to use the Boot Track system from the distribution disk(s) by copying the system as described in Section 4 above using BPSYSGEN (see 6.6). If you elect to alter or otherwise customize the Boot Track system, you must assemble the B/P Bios source setting certain of the equates in the `DEF-xx.LIB` file to insure a correct type of system. To assemble a Boot Track system, the most important equates are: + +| Equate | | +| :---: | :--- | +| `MOVCPM` | Set to `YES` | +| `BANKED` | Set to `NO` | +| `ZSDOS2` | Set to `NO` | + +One element of Banked Systems is available in a Boot Track installation if additional memory is available, and your B/P Bios routines support such a feature. This feature reloads the Command Processor from Banked memory instead of from the Boot Tracks of a disk, and generally produces less code (taking less space on the Boot Tracks) and executes faster. It is set with: + +| Equate | | +| :---: | :--- | +| `FASTWB` | Set to `YES` if desired, `NO` if Warm Boot from disk | + +Some of the features that generally need to be disabled to scale a smaller system are set as: + +| Equate | | +| :---: | :--- | +| `MORDPB` | Set to `NO` | +| `DPB8` | Set to `NO` | +| `MORDEV` | Set to `NO` | + +When at least these equates and any others you desire to change (see section 4) have been made to the component files of the system, assemble your `BPBIO-xx` file to a Microsoft standard `.REL` file. This output file may be used to overlay the Bios portion of the `MOVxSYS.COM` system generation utility (see 6.16) furnished with your distribution disk, or an equivalent program provided with your computer. MOVxSYS or its equivalent (MOVCPM, MOVZSYS, etc) is a special program customized for your particular hardware containing all the Operating System components which will be placed on the Boot Tracks, along with a routine to alter the internal addresses to correspond to a specified memory size. + +To Add the new Bios you just assembled, execute INSTAL12 (see procedures in 6.13) specifying your computer's MOVxSYS or equivalent program and follow the prompts to overlay the new Bios. Once INSTAL12 has saved a relocatable or absolute file, you are ready to create a boot disk containing the modified system. + +If you used the command INSTAL12 to install system segments on MOVxSYS or equivalent program, you must first create an Absolute System Model file. Since the functional portion of your new program is identical to the original MOVxSYS or equivalent, use the method explained in your original documentation to generate a new system. With MOVxSYS, the command is: + +| Command | | +| :---: | :--- | +| `MOVxSYS nn *` | replace MOVxSYS with your version | + +Where `nn` is the size of the system (typically 51 for a moderate boot system). The asterisk tells the program to retain the image in memory and not write it to a disk file. You may now use BPSYSGEN to write the new image to the system tracks of your boot diskette. Do this by executing BPSYSGEN with no arguments and issue a single Carriage Return when asked for the source of the Image. + +If you used the command `INSTAL12 /A` to install replacement system segments over a System Image file, or used a utility which wrote the new image to a disk file, use BPSYSGEN to write the image file to the system tracks of your boot disk. The proper command is + +`BPSYSGEN filename` + +where filename is the name of the disk file you just created by executing MOVxSYS or equivalent with output to a disk file, or with INSTAL12 on an existing image file. + +If the system is written to a Hard Disk, and your system supports booting from a Hard Disk such as the YASBEC, you normally must alter the default Boot Sector from the default Floppy Disk Boot Sector contained in MOVxSYS or equivalent. This alteration is accomplished by HDBOOT (see 6.9) which must be customized to the specific Hardware System used. + +After the above actions have been completed as appropriate, tailor the Boot Track system to reflect the desired starting configurations with BPCNFG (see 6.2). Such items as the desired Startup file name, Bank Numbers (critical if FASTWB is used), and drive types and assignments are routinely tailored at this point. When the you have finished this step, test your new system by resetting the system, or cycling the power and you should be up and running! + + +## 4.2 Non-Banked Image Installation + +A Non-Banked system may be installed as an Image File as opposed to the basic Boot Track installation covered in 4.1 above. To create an Image File, you must have `.REL` or `.ZRL` versions of a Command Processor (ZCPR3.x or equivalent recommended), an Operating (`ZSDOS.ZRL` recommended), and a REL version of B/P Bios for your system assembled with the MOVCPM equate in `DEF-xx.LIB` set to NO. Other equates in this file may be set as described above for the Boot Track system. Since Image Files are not as constrained in size as is installation for Boot Tracks, more features may generally be activated such as Error Messages, RAM Drive, additional Hard Drive partitions, and complete Floppy Format suites. The main precaution here is that large Hard Drives will rapidly cause significant loss of Transient Program Area since all Drive parameters must be in protected high memory above the Bios. + +After the Bios has been assembled, an Image file must be produced. This is accomplished with the BPBUILD Utility (see 6.1). Set the File names in Menu 1 to reflect only Non-Banked files (or minimally banked Bios if FASTWB is set to YES), and let BPBUILD do the work. Since the standard Non-Banked System segments are normally set to the "standard" CP/M 2.2 sizes, you may answer the "autosize" query with a Y to obtain the maximum Transient Program Area in the resulting system. When BPBUILD completes its work, a file, normally with the default type of `.IMG`, will have been placed in the currently logged Drive/User area and you are ready to perform the next step in preparation of the Non-Banked Image. + +As with the Boot Track installation covered above, several system items must be tailored before the Image may be safely loaded and executed. This is done by calling BPCNFG with the Image file name as an argument, or specify Image configuration from the interactive menu (see 6.2). Set all items as you desire them in the operating system, particularly the Bank Numbers (if FASTWB is active), and the Disk Drive characteristics and assignments. When this has been satisfactorily completed, you are ready to load and execute the newly-created system. + +Installing an Image File (default file type of `.IMG`) is extremely easy. Only the utility `LDSYS.COM` (see 6.15) is needed. If the file type has not been changed from the default `.IMG`, only the basic name of the Image File need be passed to LDSYS when executed as: + +| Command | | +| :---: | :--- | +| `LDSYS IMGFILE` | where IMGFILE.IMG is your Image file name | + +The operating parameters of the currently-executing system are first examined for suitability of loading the Image File. If it is possible to proceed, the Image File is loaded, placed in the proper memory locations, and commanded to begin execution by calling the B/P Bios Cold Boot Vector. The Cold Boot (Bios Function 0) performs final installation, displays any desired opening prompt and transfers control to the Command Processor with any specified Startup file for use by a ZCPR3.x Command Processor Replacement. + +Since a non-banked Image File will probably closely resemble that contained on the Boot Tracks, the same STARTUP file may generally be used to complete the initial tailoring sequence. If a different file is desired, the Image File may be altered to specify a different file using BPCNFG. + + +## 4.3 Banked Bios, Non-banked System Installation + +With the B/P Bios system, an Image system may be created and loaded which places portions of the Bios Only in the System bank, retaining a non-banked Operating System and therefore maximum compatibility with existing applications software. A few thousand bytes can normally be reclaimed for Transient Programs in this manner, although large and/or increasing numbers of logical drives will still reduce TPA space because of the need to store Allocation Vector information in Common Memory. + +To prepare such a system, simply edit the needed Bios files if necessary with particular emphasis on the `DEF-xx.LIB` file where the following equates must be set as: + +| Equate | | +| :---: | :--- | +| `MOVCPM` | Set to `NO` | +| `BANKED` | Set to `YES` | +| `ZSDOS2` | Set to `NO` | + +Since banked memory MUST be available for this type of installation, you will probably want the Fast Warm Boot feature available to maximize system performance. To activate this option, set the following equate as: + +| Equate | | +| :---: | :--- | +| `FASTWB` | Set to `YES` | + +When the editing is complete, assemble the Bios to a Microoft `.REL` file with an appropriate assembler such as ZMAC and build an Image system with BPBUILD (see 6.1) changing the Bios file name in menu 1 to the name of the newly created Bios file. Next, configure the default conditions if necessary with BPCNFG (see 6.2) and you are ready to activate the new system in the same manner as all Image files by calling LDSYS with the Image file argument as: + +| Command | | +| :---: | :--- | +| `LDSYS BBSYS` | where BBSYS.IMG is your Image File Name | + +As with the completely Non-Banked system described above in Section 4.2, no new requirements are established for a Startup file over that used for the initial Boot System, since both the Command Processor and Disk Operating System are unbanked, and no data areas needed by application programs are placed in the System Bank. As with all Image Files, additional features such as full Bios Error Messages, more extensive Floppy Disk Formats and RAM drive may generally be included in the System definition prior to assembly since the size constraints of Boot Track systems do not apply. + + +## 4.4 Fully Banked Image Installation + +To create a system taking maximum advantage of banked memory, a special banked Operating System and Command Processor are needed. These have been furnished in initial form with this package as `ZSDOS20.ZRL` and `Z40.ZRL` respectively. They use the Banking features of B/P Bios and locate the maximum practicable amount of executable code and data in the System Bank. Of significant importance to maximizing the Transient Program Area is that the Drive Allocation Bit maps are placed in the System Bank meaning that adding large hard drives, or multiple drives produce only minimal expansion to the resident portion of the Bios. + +NOTE: The latest versions are `ZS203.ZRL`, `ZS227G.ZRL`, and `Z41.ZRL` as included in the public release of B/P Bios. See also sections 7 and 8. + +A Fully banked Bios is created by editing the B/P Bios files as needed to customize the system to your desires. Insure that the following `DEF-xx.LIB` equates are set as: + +| Equate | | +| :---: | :--- | +| `MOVCPM` | Set to `NO` | +| `BANKED` | Set to `YES` | +| `ZSDOS2` | Set to `YES` | + +Assemble the resultant B/P Bios to a Microsoft `.REL` file, Build an Image file with BPBUILD (see 6.1) and configure the produced Image file with BPCNFG (see 6.2). When you are confident that all default settings have been made, activate the file by entering: + +| Command | | +| :---: | :--- | +| `LDSYS FBANKSYS` | where FBANKSYS.IMG is your Image File Name | + +Several differences may exist in the Startup file used for a Fully banked system. Generally the changes amount to deleting items such as a File Stamp module for the Non-banked ZSDOS1 which is not necessary with the fully-banked ZSDOS 2 and Z40. Only the type of clock need be specified for ZSDOS2. Furthermore, since the Z40 Command Processor Replacement contains most commonly-used commands gathered from a number of Resident Command Processor (RCP) packages, there is normally no need to load an RCP. A simple Startup file found adequate during development of the fully-banked B/P system is: + +| Command | Explanation | +| :--- | :--- | +| `ZSCFG2 CB` | Set ZSDOS 2 clock to Bios+4EH | +| `LDR SYS.FCP,SYS.NDR` | Load ZCPR 3 Environment segments for Flow Control and Named Dirs | +| `IOPINIT` | Initialize the IO Processor Pkg | +| `TD S` | Prompt for Date and Time, Set Clk / Alternatives are to use `TDD` (6.21) or `SETCLOK` (6.18) | +| `IF ~EX MYTERM.Z3T` | If the file `MYTERM.Z3T` does Not exist... | +| `TCSELECT MYTERM.Z3T` | ..select which terminal you have creating a `MYTERM.Z3T` file | +| `FI` | ...end if the `IF` | +| `LDR MYTERM.Z3T` | Load the Terminal Definition data | + +Since the requirements for a fully-banked system differ significantly from a non-banked one, we recommend that you use a different name for the Startup file. For example, `STARTUP.COM` is the default name used with Boot Track systems for initial operation, and with Non-banked Image Files, while STARTB may be a suitable name for the script to be executed upon loading a fully-banked system. The name of the desired Startup file may be easily altered in either Boot Track or Image systems from Option 1 in BPCNFG (see 6.2). + +An option available to start from a large Image File is to configure a Startup file for execution by the Boot Track system containing a single command. The command would simply invoke LDSYS with the desired Banked Image File as an argument such as: + +| Command | | +| :---: | :--- | +| `LDSYS BANKSYS` | where BANKSYS.IMG is your Image file | + +In this case, none of the normal initialization sequences cited above would be executed by the Boot Track system, and only those contained in the Startup for `BANKSYS.IMG` would occur. Other options abound and are left to the community to invent new combinations and sequences. + + +## 4.5 In Case of Problems... + +While We attempted to outline procedures for the majority of installations we considered feasible, there may be occasions where you inadvertently find yourself in a position where you seem to have lost the ability to get your system up and running. + +**PROBLEM:** When loading an `.IMG` file with LDSYS, the screen displays the LDSYS banner, system addresses, and halts with the last screen displaying: "...loading banked system". + +_SOLUTION:_ Something is not set correctly in the Bios, since all lines after the last one displayed are printed from the newly-loaded Bios. One of the most common causes for this problem is incorrect bank number settings. Use the hidden selection in Menu 1 of BPCNFG (see 6.2) to verify that the correct bank numbers have been set for TPA and SYStem banks. Another common cause of this problem is incorrect settings for the Console port, or a setting in the IOBYTE which directs Console data to a device other than the one intended. Use Menu 2 BPCNFG to properly set the IOBYTE and the console parameters. + +**PROBLEM:** You boot from or load a B/P Bios system from a Hard Drive, and immediately after starting, the system attempts to log onto Floppy Drive 0. + +_SOLUTION:_ The most common cause for this symptom is that the desired Hard Drive and Floppy Drive definitions were not swapped to define a Hard Drive Partition as the A: drive. Use BPCNFG (see 6.2), Menu 5 to exchange drives to the desired configuration. A similar situation may exist where a Hard Drive is activated immediately after booting when a Floppy drive is desired as the A: Drive. + +**PROBLEM:** The computer seems to boot satisfactorily, but after a few programs or any program which executes a Warm Boot (or entering Control-C), the system goes into "Never-never Land" and must be reset. + +_SOLUTION:_ This symptom is most often caused by an inability to access and load the Command Processor. This is most probably caused by assembling B/P Bios with the FASTWB equate in `DEF-xx.LIB` set to YES when the system contains no extended memory, or incorrect settings of the Bank Numbers. To check Bank Number settings, use the hidden function in BPCNFG, Menu 1 (see 6.2). + +**PROBLEM:** When doing a Cold Boot from a Hard Drive (from Power up or Reset), the system goes to a Floppy Drive before displaying the initial sign on messages, and remains logged on the Floppy. + +_SOLUTION:_ This is most often due to your forgetting to run the HDBOOT utility on the Hard Drive Boot system after applying it with BPSYSGEN. Normally, systems created with MOVxSYS contain a Floppy Disk Boot sector which will load the initial Operating System from a Floppy. HDBOOT (see 6.9) modifies this record on a specified Hard Drive Unit so that the Operating System is loaded from a Hard Drive. Run HDBOOT on the Desired Hard Drive, then use BPCNFG (see 6.2) to insure that the logical drives are positioned as desired (Menu 5). + +**PROBLEM:** When Booting, the system console either doesn't display anything, or prints strange characters. + +_SOLUTION:_ This is most often due to incorrect settings for the current Console, most probably the Data rate, or CPU Clock Frequency. Boot from a good system, then use BPCNFG (see 6.2) to adjust the settings on the problem system. Pay particular attention to Menu 1 (CPU Clock Rate) and Menu 2 (IOBYTE and Serial Port Data Rates). + +**PROBLEM:** When running a fully-banked system with ZSDOS 2, some programs seem to "hang" or "lock up" the system on exit. + +_SOLUTION:_ One of the most common sources of this symptom is with the application program where the author used code which assumes that the BDOS and Command Processor are of a certain size, or bear a fixed relationship to the addresses in page 0. You may experience this most often when using an IMG system built by answering YES to the Autosizing query in BPBUILD (see 6.1). To compensate for such ill-behaved programs, you may use a two-step build process as: + +1. Use BPBUILD to create an IMG file answering YES to Autosizing on exit. This maximizes TPA placing the Resident Bios as high as possible in memory. + +2. Execute BPBUILD again with an argument of the name you gave to the file just created above. This loads the definition from the IMG file. Immediately exit with a Carriage Return, and answer NO to Autosizing, and YES to placing system segments at standard locations. This procedure keeps the Bios address constant, but will move the starting addresses of BDOS and Command Processor down, if possible, to simulate "standard" sizes used in CP/M 2.2. + + diff --git a/Doc/CPM/BPBIOS/BPBIOS_5_Programming.md b/Doc/CPM/BPBIOS/BPBIOS_5_Programming.md new file mode 100644 index 00000000..de4808c6 --- /dev/null +++ b/Doc/CPM/BPBIOS/BPBIOS_5_Programming.md @@ -0,0 +1,1364 @@ +# 5. Programming for B/P Bios + +For most existing purposes, programming for B/P Bios is no different than for standard CP/M 2.2 BIOSes. Even adapting CP/M 3 programs for a B/P Bios should present no great hurdle due to the close similarity retained with the corresponding extended functions. The power of a B/P Bios interface, however, is in using the combined features to produce portable software across a wide variety of hardware platforms by exercising all of the B/P Bios features in concert. This section describes the interfaces available to the programmer of a system using the B/P Bios, and the functions available to ease direct floppy and hard drive accesses for specialized programming in a consistent manner. + +One of the architectural flaws which we considered in CP/M Plus was the odd way in which direct BIOS access was handled. We designed B/P Bios to be as compatible with CP/M 2.2 as possible, yet provide the expanded functionality needed in Banked applications. To that end, direct interface with BIOS calls follows CP/M 2.2 conventions as much as possible. + +The following pages on programming assume some familiarity with the basic CP/M fundamentals, and with Z80/Z180 assembly language, since it is beyond the intent of this manual, and our literary writing skills, to present an assembly programming tutorial. Should you need additional assistance in this area, please refer to the annotated bibliography for reference material. + + +## 5.1 Bios Jump Table + +The BIOS Jump table consists of 40 Jumps to various functions within the BIOS and provides the basic functionality. It includes the complete CP/M 2.2 sequence, most of the CP/M 3 (aka CP/M Plus) entry points (although some differ in parameter ordering and/or register usage), and new entry points needed to handle banking in a consistent and logical manner. + +Bios entry points consist of a Table of Absolute 3-byte jumps placed at the beginning of the executable Image. Parameters are passed to the Bios in registers as needed for the specific operation. To avoid future compatibility problems, some of the ground rules for Bios construction include; No alteration of Alternate or Index registers as a result of Bios calls, and all registers listed in the documentation as being Preserved/Unaffected MUST be returned to the calling program in their entry state. + + +## 5.2 Bios Reference Card + +| Number | Fcn Name | Input Parameters | Returned Values | Uses | +|:------:|:---------|:---------------------|:------------------------ |:------| +| 0 | CBOOT | None | None | All | +| 1 | WBOOT | None | None | All | +| 2 | CONST | None | A= FFH Ready, 0 No Char | AF | +| 3 | CONIN | None | A= Char from CON: (masked) | AF | +| 4 | CONOUT | C= Char to send (masked) | None | AF | +| 5 | LIST | C= Char to send (masked) | None | AF | +| 6 | AUXOUT | C= Char to Send (masked) | None | AF | +| 7 | AUXIN | None | A= Char from AUX: (masked) | AF | +| 8 | HOME | None | _[Status Code]_ | All | +| 9 | SELDSK | C= Drive (0=A .. 15=P) | HL= DPH addr, 0 No Drive | All | +| 10 | SETTRK | BC= Track Number | None | None | +| 11 | SETSEC | BC= Sector Number | None | None | +| 12 | SETDMA | BC= DMA Address | None | None | +| 13 | READ | None | _Status Code_ | All | +| 14 | WRITE | C= Write Type (0= Unalloc, 1= Dir, Force) | __ | All | +| 15 | LISTST | None | A= FFH Ready, 0 Busy | AF | +| 16 | SECTRN | BC= Logical Sect # | HL= Physical Sect # | All | +| **----** | **----** | **----------** |**<<< End of CP/M 2.2 Vectors >>>** | **----** | +| 17 | CONOST | None | A= 0FFH Ready, 0 Busy | AF | +| 18 | AUXIST | None | A= FFH Ready, 0 No Char | AF | +| 19 | AUXOST | None | A= 0FFH Ready, 0 Busy | AF | +| 20 | DEVTBL | None | HL-> Char IO Table | HL | +| 21 | DEVINI | None | None | All | +| 22 | DRVTBL | None | HL-> DPH Table if Ok, 0 No Drive | HL | +| 23 | | ***Reserved for MULTIO*** | | | +| 24 | FLUSH | None | _[Status Code]_ | All | +| 25 | MOVE | HL= Source adr, DE= Dest adr, BC= Length | None | All | +| 26 | TIME | C= 0(Read) / 1(Set), DE-> 6-byte Time | A= 1 if Ok, 0 Errs, E= Orig 6th byte, D= 1/10th Secs (Read) | All | +| 27 | SELMEM | A= Bank Number | None | None | +| 28 | SETBNK | A= Bank Number | None | None | +| 29 | XMOVE | C= Source bank, B= Dest bank | None | None | +| **----** | **----** | **----------** | **<<< End of CP/M 3 "Type" Vectors >>>** | **----** | +| 30 | RETBIO | None | A= Bios Vers, BC-> Bios base, DE-> Config area, HL-> Device Cnfg Table | A, BC, DE, HL | +| 31 | DIRDIO | B= Driver Type, C= Fnc # | _see below for Direct Device IO_ | | +| 32 | STFARC | A= Bank Number | None | None | +| 33 | FRJP | HL= Dest addr | ?? | ?? | +| 34 | FRCLR | HL= Return addr | ?? | None | +| 35 | FRGETB | HL-> Byte to Get, C= Bank # | A=Byte at (C:HL) | AF | +| 36 | FRGETW | HL-> Word to Get, C= Bank # | DE=Word at (C:HL) | F, DE | +| 37 | FRPUTB | HL-> Byte Dest, C= Bank #, A= Byte to Put | None | F | +| 38 | FRPUTW | HL-> Word Dest, C= Bank #, DE= Word to Put | None | F | +| 39 | RETMEM | None | A= Current Bank Number | AF | + +_Status Code:_ +A= 0, Zero Set (Z) if Operation successfully performed +A <> 0, Zero Clear (NZ) if Errors occured in Operation + + +**FLOPPY DISK SUBFUNCTIONS (Function 31)** +Input Parameters: B= 1 Floppy, C= Subfcn # +| Number | Fcn Name | Input Parameters | Returned Values | Uses | +|:------:|:---------|:---------------------|:------------------------ |:------| +| 0 | STMODE | A= 0 (Double Dens), FFH (Single) | None | AF | +| 1 | STSIZE | A= 0 (Normal Speed), 0FFH (Hi capable), D= 0 (Motor On Cont) 0FFH (Motor Contr), E= 0 (Hard), 1 (8"), 2 (5.25"), 3 (3.5") | None | AF | +| 2 | STHDRV | A= Unit (B0,1) Head (D2) | None | AF | +| 3 | STSECT | A=Phys Track #, D= 0..3 (128 .. 1024 Sctrs), E= Last Sector # | None | AF | +| 4 | SPEC | A= Step rate in mS (B7=1 for 8" Drv), D= Head Unload in mS, E= Head Load in mS | None | AF | +| 5 | RECAL | | _[Status Code]_ | AF | +| 6 | SEEK | A= Desired Trk #, D= 0FFH Verify, E= 0 (Single-step) <>0 (Double) | _[Status Code]_ | AF | +| 7 | SREAD | HL-> Read Buffer | _[Status Code]_ | AF, HL | +| 8 | SWRITE | HL-> Write Buffer | _[Status Code]_ | AF, HL | +| 9 | READID | | _[Status Code]_ | AF | +| 10 | RETDST | | A= Status Byte, BC= Controller Type, HL-> Status Byte | AF, BC, HL | +| 11 | FMTTRK | HL-> Format Data, D= Sctrs/Trk, E= Gap 3 Byte Count | _[Status Code]_ | AF | + + +**HARD DISK SUBFUNCTIONS (Function 31)** +Input Parameters: B= 2 HD, C= Subfcn +| Number | Fcn Name | Input Parameters | Returned Values | Uses | +|:------:|:---------|:---------------------|:------------------------ |:------| +| 0 | HDVALS | DE-> 512 byte Buff | A= # Bytes in CDB | AF, HL | +| 1 | HDSLCT | A= Device Byte | A= Physical Device Bit | AF | +| 2 | DOSCSI | DE-> Cmd Desc Blk, A= 0 (No Write Data) | H= Msg Byte, L= Status Byte, A= Masked Status Byte | All | + + +## 5.3 Bios Functions + +| Function 0 (xx00) | CBOOT Cold Boot | +|---:|:---| +| Enter: | None | +| Exit: | None | +| | Execution resumes at CPR | +| Uses: | All Registers | + +Execute Cold Start initialization on the first execution. The jump argument is later overwritten, and points to the IOP Device jump table. The reason for this is that code to perform the initialization is often placed in areas of memory which are later used to store system information as a memory conservation measure. Attempts to re-execute the initialization code would then encounter data bytes instead of executable instructions, and the system would most assuredly "crash". + +Among other functions performed during initial execution of the Cold Boot code are; Establishing an initial Z3 Environment if necessary, initializing any Z3 system segments such as an Extended Path, Flow Control Package, Named Directory Buffer and such; setting system-specific values such as the locations of Allocation Vector buffers for RAM and Hard Drives; and executing the Device Initialization routine (see Function 21). The Cold Boot routine usually exits by chaining to the Warm Boot Function (Function 1) to set vectors on Page 0 of the TPA memory bank. + +| Function 1 (xx03) | WBOOT Warm Boot | +|---:|:---| +| Enter: | None | +| Exit: | None | +| | Execution resumes at CPR | +| Uses: | All Registers | + +This function re-initializes the Operating System and returns to the Command Processor after reloading it from the default drive boot tracks, or banked memory if the Bios was assembled with the Fast Warm Boot option. + +Unless altered by an ill-behaved Resident System Extension (RSX) or other operating transient program, the Warm Boot Vector at location 0 in memory points to this vector. Well-behaved programs will not alter this address but should, instead, alter the destination argument of the Jump vector in the Bios header. There is a singular exception to this in the case of NZCOM where the Warm Boot vector points to the NZBIOS, and Not the "Real" Bios. In such a case, the address of the "Real" Bios must be separately determined (See Function 30). + +| Function 2 (xx06) | CONST Console Input Status | +|---:|:---| +| Enter: | None | +| Exit: | A = 0FFH if Char Ready, NZ | +| | A = 0 if No Char Ready, Z | +| Uses: | AF | + +This function returns a flag indicating whether or not a character has been entered from the Console device selected by the IOBYTE on Page 0 of the TPA Bank. The return status is often used by Transient Programs to determine if the user has attempted to start or stop program execution. + +| Function 3 (xx09) | CONIN Console Input | +|---:|:---| +| Enter: | None | +| Exit: | A = Masked Input Character | +| Uses: | AF | + +This function waits for a character to be entered from the Console device selected by the IOBYTE on Page 0 of the TPA Bank, and returns it to the calling routine. According to strict CP/M 2.2 standards, the Most Significant bit of the input byte must be set to Zero, but this may be altered by the input mask for the Console Device. + +| Function 4 (xx0C) | CONOUT Console Output | +|---:|:---| +| Enter: | C = Character to send to Console | +| Exit: | None | +| Uses: | AF | + +This function sends a specified character to the Console Device defined by theIOBYTE on Page 0 of the TPA Bank. It will wait for the device to become ready, if necessary, before sending the character, and will mask bits as specified in the Character Device Configuration for the device as an Output. + +| Function 5 (xx0F) | LIST List Output | +|---:|:---| +| Enter: | C = Character to send to List Device (Printer) | +| Exit: | None | +| Uses: | AF | + +This function will send a specified character to the List Device (Printer) defined by the IOBYTE on Page 0 of the TPA Bank. It will wait for the device to become ready, if necessary, before sending the character, and will mask it as specified in the Character Device Configuration for the Output device. + +| Function 6 (xx12) | AUXOUT Auxiliary Output | +|---:|:---| +| Enter: | C = Character to send to Auxiliary Device | +| Exit: | None | +| Uses: | AF | + +This function will send a specified character to the Auxiliary Output Device defined by the IOBYTE on Page 0 of the TPA Bank. It will wait for the device to become ready, if necessary, before sending the character, and will mask it as specified in the Character Device Configuration for the Output device. + +| Function 7 (xx15) | AUXIN Auxiliary Input | +|---:|:---| +| Enter: | None | +| Exit: | A = Masked Input Character | +| Uses: | AF | + +This function will read a character from the Auxiliary Input Device defined by the IOBYTE on Page 0 of the TPA Bank. It will wait for a character to be received, and will mask it as specified in the Character Device Configuration for the Input device. + +| Function 8 (xx18) | HOME Home Drive | +|---:|:---| +| Enter: | None | +| Exit: | None | +| | Heads on selected drive moved to Track 0 | +| Uses: | All Primary Registers | + +This function will position the head(s) on the selected drive to Track 0. In B/P Bios, This operation performs no useful action, and is simply a Return. Pending Write purges and head repositioning is handled by the individual device drivers (Specifically Select Drive functions). + +| Function 9 (xx1B) | SELDSK Select Logical Drive | +|---:|:---| +| Enter: | C = Desired Drive (A=0..P=15) | +| Exit: | (Success) A <> 0, NZ, HL = DPH Address | +| | (No Drive) A = 0, Zero (Z), HL = 0 | +| Uses: | All Primary Registers | + +This function selects a specified logical drive as the current drive to which disk operations refer. If the operation is successful, the Disk Parameter Header (DPH) address is returned for later determination of the unit parameters If the operation fails for any reason (non-existant drive, unknown or bad media, etc), a Zero value pointer is returned to signify that the drive cannot be accessed through the Bios. + +| Function 10 (xx1E) | SETTRK Select Track | +|---:|:---| +| Enter: | BC = Desired Track Number | +| Exit: | None | +| | Track Number saved | +| Uses: | No Registers | + +This function stores a specified Logical Track number for a future disk operation. The last value stored with this function will be the one used in Disk Reads and Writes. + +**NOTE:** While a 16-bit value is specified for this function, only the lower byte (8-bits) is used in most drivers. + +| Function 11 (xx21) | SETSEC Select Sector | +|---:|:---| +| Enter: | BC = Desired Sector Number | +| Exit: | None | +| | Sector Number saved | +| Uses: | No Registers | + +This function stores a specified Logical Sector Number for a future disk operation. The last value stored with this function will be the one used in Disk Reads and Writes. + +**NOTE:** While a 16-bit value is specified for this function, only the lower byte (8-bits) is used in all Floppy Disk and most Hard and RAM Disk drivers. + +| Function 12 (xx24) | SETDMA Set DMA Address for Transfer | +|---:|:---| +| Enter: | BC = Buffer Starting Addr | +| Exit: | None | +| | DMA Address saved | +| Uses: | No Registers | + +This Function stores a specified address to be used as the Source/Destination for a future disk operation. The last value stored with this function will be the one used in Disk Reads and Writes. In banked systems, the Bank selected for the transfer may be altered by Function 28. + +| Function 13 (xx27) | READ Disk Read | +|---:|:---| +| Enter: | None | +| Exit: | A = 0, Z if No Errors | +| | A = Non-Zero if Errors, NZ | +| Uses: | All Primary Registers | + +This function reads a Logical 128-byte sector from the Disk, Track and Sector set by Functions 9-11 to the address set with Function 12. On return, Register A=0 if the operation was successful, Non-Zero if Errors occurred. + +| Function 14 (xx2A) | WRITE Disk Write | +|---:|:---| +| Enter: | C = 1 for immediate write | +| | C = 0 for buffered write | +| Exit: | A = 0, Z if No Errors | +| | A = Non-Zero if Errors, NZ | +| Uses: | All Primary Registers | + +This function writes a logical 128-byte sector to the Disk, Track and Sector set by Functions 9-11 from the address set with Function 12. If Register C=1, an immediate write and flush of the Bios buffer is performed. If C=0, the write may be delayed due to the deblocking. + +| Function 15 (xx2D) | LISTST List Output Status | +|---:|:---| +| Enter: | None | +| Exit: | A = 0FFH, NZ if ready for Output Character | +| | A = 0, Z if Printer Busy | +| Uses: | AF | + +This function returns a flag indicating whether or not the printer is ready to accept a character. It uses the IOBYTE on Page 0 of the TPA Bank to determine which physical device to access. + +| Function 16 (xx30) | SECTRN Perform Sector Translation | +|---:|:---| +| Enter: | BC = Logical Sector Number | +| | DE = Addr of Translation Table | +| Exit: | HL = Physical Sector Number | +| Uses: | All Primary Registers | + +This function translates the Logical Sector Number in register BC (Only C used at present) to a Physical Sector number using the Translation Table obtained from the DPH and addressed by DE. + +----- + +This ends the strict CP/M 2.2-compliant portion of the Bios Jump Table. The next series of entry Jumps roughly follows those used in CP/M 3, but with corrections to what we perceived to be deficiencies and inconsistencies in the calling parameters and structures. + +----- + +| Function 17 (xx33) | CONOST Console Output Status | +|---:|:---| +| Enter: | None | +| Exit: | A = 0FFH, NZ if Console ready for output char | +| | A = 0, Z if Console Busy | +| Uses: | AF | + +This function returns a flag indicating whether or not the Console Device selected by the IOBYTE on Page 0 of the TPA Bank is ready to accept another output character. + +| Function 18 (xx36) | AUXIST Auxiliary Input Status | +|---:|:---| +| Enter: | None | +| Exit: | A = 0FFH, NZ if Aux Input has character waiting | +| | A = 0, Z if No char ready | +| Uses: | AF | + +This function returns a flag indicating whether or not the Auxiliary Input selected by the IOBYTE on Page 0 of the TPA Bank has a character waiting. + +| Function 19 (xx39) | AUXOST Auxiliary Output Status | +|---:|:---| +| Enter: | None | +| Exit: | A = 0FFH, NZ if Aux Output ready for output char | +| | A = 0, Z if Aux Out Busy | +| Uses: | AF | + +This function return a flag indicating whether or not the Auxiliary Output selected by the IOBYTE on Page 0 of the TPA Bank is ready to accept another character for output. + +| Function 20 (xx3C) | DEVTBL Return Pointer to Device Table | +|---:|:---| +| Enter: | None | +| Exit: | HL = Address of Device Table | +| Uses: | HL | + +This function roughly corresponds to an analogous CP/M Plus function although precise bit definitions vary somewhat. The Character IO table consists of four devices; COM1, COM2, PIO, and NUL. Each has an input and output mask, data rate settings and protocol flags. Not all defined settings (e.g. ACK/NAK and XON/XOFF handshaking, etc) may be fully implemented in each version, but are available for later expansion and use. + +| Function 21 (xx3F) | DEVINI Initialize Devices | +|---:|:---| +| Enter: | None | +| Exit: | None | +| | Initialization done | +| Uses: | All Primary Registers | + +This function initializes Character IO settings and other functions which may be varied by a Configuration Utility. It is an extended version of the corresponding CP/M Plus function. Its primary use is to restore IO configurations, system parameters such as clock rate, wait states, etc, after alteration by programs which directly access hardware such as many modem programs and the configuration utility, BPCNFG (see 6.2). + +| Function 22 (xx42) | DRVTBL Return DPH Pointer | +|---:|:---| +| Enter: | None | +| Exit: | HL = Address of start of Table of DPH Pointers | +| Uses: | HL | + +This function returns a Pointer to a table of 16-bit pointers to Disk Parameter Headers for Drives A-P. A Null (0000H) entry means that no drive is defined at that logical position. + +| Function 23 (xx45) | reserved | +|---:|:---| +| Enter: | None | +| Exit: | None | +| Uses: | No Registers | + +This function is reserved in the initial B/P Bios release and simply returns. + +| Function 24 (xx48) | FLUSH Flush Deblocker | +|---:|:---| +| Enter: | None | +| Exit: | None | +| | Pending Disk Writes executed | +| Uses: | All Primary Registers | + +This function writes any pending Data to disk from deblocking buffers as mentioned in Function 14 above. This function should be called in critical areas where tasks are being swapped, or media is being exchanged when it is possible that the Operating System will not detect the change. + +| Function 25 (xx4B) | MOVE Perform Possible Inter-Bank Move | +|---:|:---| +| Enter: | HL = Start Source Address | +| | DE = Start Dest Address | +| | BC = Number Bytes to Move | +| Exit: | None | +| | Data is moved | +| Uses: | All Primary Registers | + +This function moves the specified number of bytes between specified locations. For banked moves, the Source and Destination banks must have been previously specified with an XMOVE call (function 29). Note that the B/P implementation of this function reverses the use of the DE and HL register pairs from the CP/M 3 equivalent function. + +| Function 26 (xx4E) | TIME Get/Set Date and Time | +|---:|:---| +| Enter: | DE = Start of 6-byte Buffer | +| | C = 0 (to Get Date/Time) | +| | C = 1 (to Set Date/Time) | +| Exit: | A = 1 of Successful | +| | A = 0 if Error or No Clock | +| Uses: | All Primary Registers | + +This function provides an interface to programs for a Real-Time Clock driver in the Bios. The function uses a 6-byte Date/Time string in ZSDOS format as opposed to Digital Research's format used in CP/M Plus for this function. Also, This function must conform to additional requirements of DateStamper(tm) in that on exit, register E must contain the entry contents of (DE+5) and HL must point to the entry (DE)+5. If the actual hardware implementing the clock supports 1/10 second increments, the current 1/10 second count may be returned in register D. + +| Function 27 (xx51) | SELMEM Select Memory Bank | +|---:|:---| +| Enter: | A = Desired Memory Bank | +| Exit: | None | +| | Bank is in Context in range 0..7FFFH | +| Uses: | AF | + +This function selects the Memory Bank specified in the A register and make it active in the address range 0-7FFFH. Since character IO may be used when a bank other than the TPA (which contains the IOBYTE) is activated with this function, the B/P Bios automatically obtains the IOBYTE from the TPA bank to insure that Character IO occurs with the desired devices. + +| Function 28 (xx54) | SETBNK Select Memory Bank for DMA | +|---:|:---| +| Enter: | A = Memory Bank for Disk DMA Transfers | +| Exit: | None | +| | Bank Number saved for later Disk IO | +| Uses: | No Registers | + +This function selects a memory Bank with which to perform Disk IO. Function 12 (Set DMA Transfer Address) operates in conjunction with this selection for subsequent Disk IO. + +| Function 29 (xx57) | XMOVE Set Source and Dest Banks for Move | +|---:|:---| +| Enter: | B = Destination Bank Num | +| | C = Source Bank Number | +| Exit: | None | +| | Bank Nums saved for MOVE operation | +| Uses: | No Registers | + +This function sets the Source and Destination Bank numbers for the next Move (Function 25). After a Move is performed, the Source and Destination Banks are automatically reset to TPA Bank values. + +----- + +This marks the end of the CP/M Plus "Type" jumps and begins the unique additions to the B/P Bios table to support Banking, Direct IO and interfacing. + +----- + +| Function 30 (xx5A) | RETBIO Return BIOS Addresses | +|---:|:---| +| Enter: | None | +| Exit: | A = Bios Version (Hex) | +| | BC = Addr of Bios Base | +| | DE = Addr of Bios Config | +| | HL = Addr of Device Table | +| Uses: | All Primary Registers | + + +This function returns various pointers to internal BIOS data areas and the Bios Version Number as indicated above. The Bios Version may be used to determine currency of the system software, and will be used by various support utilities to minimize the possibility of data corruption and/or as an indicator of supported features. + +The Base Address of the Bios Jump Table returned in register BC is often used to insure that the proper indexing is achieved into the B/P data structures in the event that a Bios "shell" has been added such as when running NZCOM. While the Warm Boot jump at memory location 0000H normally points to the Bios Base+3, it is not always reliable, whereas this function will always return a true value with B/P Bios. + +Registers DE and HL return pointers which are of value to programs which alter or configure various Bios parameters. The pointer to the configuration area of the Bios should be used in utilities as opposed to indexing from the start of the Bios Jump Table since additions to the Jump Table or insertion of other data will affect the Configuration Area starting address. The pointer in HL is available for use in systems which may contain more than four character IO devices. This pointer enables exchanges of devices to place desired devices in the first four positions of the table making them available for selection via the IOBYTE. After any alterations are made to the devices, a call to the Device Configuration Bios Function 21 should be made to activate the features. + +| Function 33 (xx5D) | Floppy Disk and Hard Disk Subfunctions | +|---:|:---| +| _see below_ | | + + +| Function 32 (xx60) | STFARC Set Bank for Far Jump/Call | +|---:|:---| +| Enter: | A = Desired Bank Number | +| Exit: | None | +| Uses: | No Registers | + +This Function sets the bank number for a later Function 33 Jump to a routine in an alternate Memory Bank. + +| Function (xx63) | FRJP Jump to (HL) in Alternate Bank | +|---:|:---| +| Enter: | HL = Address to execute in Bank set w/Fn 32 | +| Exit: | | +| | Called routine sets return status | +| Uses: | All Primary Regs (assumed) | + +This Function switches to the bank number previously specified with Function 32, then calls the routine addressed by HL. Upon completion, operation returns to the bank from which called, and the address on the top of the stack. + +| Function 34 (xx66) | FRCLR Clear Stack Switcher | +|---:|:---| +| Enter: | HL = Addr to resume exec in entry bank | +| Exit: | None | +| | Execution resumes at addr in HL in entry bank | +| Uses: | No Registers | + +This Function is used for error exits from banked routines to return to the entry bank. + +| Function 35 (xx69) | FRGETB Load A,(HL) from Alternate Bank | +|---:|:---| +| Enter: | HL = Addr of desired byte | +| | C = Desired Bank Number | +| Exit: | A = Byte from C:HL | +| Uses: | AF | + +This Function gets a byte (8-bits) from the specified Bank and Address. The bank is temporarily switched in context for the access (if required), then restored to entry conditions. Interrupts are temporarily disabled during the brief access time. + +| Function 36 (xx6C) | FRGETW Load DE,(HL) from Alternate Bank | +|---:|:---| +| Enter: | HL = Addr of desired word | +| | C = Desired Bank Number | +| Exit: | DE = Word from C:HL | +| Uses: | AF, DE | + +This Function gets a Word (16-bits) from the specified Bank and Address. The bank is temporarily switched in context for the access (if required), then restored to entry conditions. Interrupts are temporarily disabled during the brief access time. + +| Function 37 (xx6F) | FRPUTB Load (HL),A to Alternate Bank | +|---:|:---| +| Enter: | HL = Addr of Dest Byte | +| | C = Desired Bank Number | +| | A = Byte to save at C:HL | +| Exit: | None | +| | Byte stored at C:HL | +| Uses: | AF | + +This Function saves a Byte (8-bits) to the specified Address and Bank. The bank is temporarily switched in context for the access (if required), then restored to entry conditions. Interrupts are temporarily disabled during the brief access time. + +| Function 38 (xx72) | FRPUTW Load (HL),DE to Alternate Bank | +|---:|:---| +| Enter: | DE = Word to store at C:HL | +| | HL = Addr of Dest Byte | +| | C = Desired Bank Number | +| Exit: | None | +| | Word stored at C:HL | +| Uses: | AF | + +This Function saves a Word (16-bits) to the specified Address and Bank. The bank is temporarily switched in context for the access (if required), then restored to entry conditions. Interrupts are temporarily disabled during the brief access time. + +| Function 39 (xx75) | RETMEM Return Current Bank in Context | +|---:|:---| +| Enter: | None | +| Exit: | A = Bank currently active in Addr 0..7FFFH | +| Uses: | AF | + +This Function returns the Memory Bank currently in Context in the address range of 0..7FFFH. It may be used in the "where am I" role in application programs to track memory accesses. + + +----- + +### Function 31 - FLOPPY DISK SUBFUNCTIONS + +Function 31 permits low-level access to Floppy and Hard Disks (via SCSI interface) by specifying a Driver Number and desired Function. While some hardware types do not support all of the parameters specified, particularly for Floppy Drives, this architecture supports all types, although specific systems may ignore certain functions. In this manner, for example, a single Format program supports NEC765, SMC9266, WD1770/1772/179x and other controller types with widely differing interfaces. Floppy Disk functions are accessed by entering a 1 value into Register B (Floppy Driver Number) and the desired function number in Register C, then jumping to or calling BIOS Entry jump number 31. + + +| Function 31 (xx5D) | DIRDIO Floppy SubFunction 0 | +|---:|:---| +| | **Set Floppy Read/Write Mode** | +| Enter: | A = 0 for Double Density, | +| | FF for Single Density | +| | B = 1 (Floppy Driver) | +| | C = 0 (Subfunction #) | +| Exit: | None | +| Uses: | AF | + +This routine establishes the Density mode of operation of the Floppy Disk Controller for Read and Write accesses. It assumes that SubFunctions 1 (Set Size and Motor) and 3 (Set Sector) have been called first. + + +| Function 31 (xx5D) | DIRDIO Floppy SubFunction 1 | +|---:|:---| +| | **Set Floppy Disk & Motor Parms** | +| Enter: | A = 0 for 300 rpm (normal), | +| | FF for 360 rpm (8"/HD) | +| | D = FF for Motor Control, | +| | 0 if Motor always on | +| | B = 1 (Floppy Driver) | +| | C = 1 (Subfunction #) | +| Exit: | None | +| Uses: | AF | + +This routine establishes some of the physical parameters for a Floppy Drive. The normal 5.25" and 3.5" disk drives holding 400 or 800 kb or less rotate at 300 rpm. Many of the newer drives can increase this speed to 360 rpm which is the rate used on older 8" floppy drives. This is the speed used on the "High Density" 1.2 MB (IBM formatted) 5.25" drives. The A register is used to indicate the fastest speed capable on the specified drive. Register D is used to indicate whether the Motor is always On, or will start and stop periodically. This is normally used by the Bios to delay for a period before writing if the motor is stopped to allow the diskette to come up to speed thereby minimizing chances of data corruption. Register E is used to indicate the physical media size as; 0=Hard Disk, 001B=8" Drive, 010B=5.25" Drive, and 011B=3.5". Nothing is returned from this command. + +While all of these functions may not be supported on any specific computer type, the interface from using programs should always pass the necessary parameters for compatibility. + +**NOTE:** This routine assumes that SubFunction 2 (Set Head and Drive) has been called first. Call this routine before calling Function 0 (Set Mode). + + +| Function 31 (xx5D) | DIRDIO Floppy SubFunction 2 | +|---:|:---| +| | **Set Head and Drive** | +| Enter: | A = Drive # (Bits 0,1), | +| | Head # (Bit 2) | +| | B = 1 (Floppy Driver) | +| | C = 2 (Subfunction #) | +| Exit: | None | +| Uses: | AF | + +This routine is entered with register A containing the Floppy unit number coded in bits 0 and 1 (Unit 0 = 00, 1 = 01 .. 3 = 11), and the Head in Bit 2 (0 = Head 0, 1 = Head 1). Nothing is returned from this function. Call this Subfunction before most of the others to minimize problems in Floppy accesses. + + +| Function 31 (xx5D) | DIRDIO Floppy SubFunction 3 | +|---:|:---| +| | **Set Floppy Disk Mode** | +| Enter: | A = Physical Sector Number | +| | D = Physical Sector Size | +| | E = Last Sctr # on Side | +| | B = 1 (Floppy Driver) | +| | C = 3 (Subfunction #) | +| Exit: | None | +| Uses: | AF | + +This routine establishes information needed to properly access a specified sector unambiguously with a number of different controller types. On entry, Register A contains the desired physical sector number desired, D contains the sector size where 0 = 128 byte sectors, 1 = 256 .. 3 = 1024 byte sectors, and E contains the last sector number on a side. Normally register E is unused in Western Digital controllers, but is needed with 765 and 9266 units. Nothing is returned from this subfunction. + + +| Function 31 (xx5D) | DIRDIO Floppy SubFunction 4 | +|---:|:---| +| | **Specify Drive Times** | +| Enter: | A = Step Rate in milliSec | +| | D = Head Unload Time in mS | +| | E = Head Load Time in mS | +| | B = 1 (Floppy Driver) | +| | C = 4 (Subfunction #) | +| Exit: | None | +| Uses: | AF | + +This subfunction set various timing values used for the physical drive selected. On entry, the A register contains the drive step rate in milliseconds. Within the Bios, this rate is rounded up to the nearest controller rate if the specified rate is not an even match. Register D should contain the desired Head Unload time in milliseconds, and E to the desired Head Load time in mS. + +NOTE: With Western Digital type controllers, only the Step Rate is universally variable. In these systems, rates signaled by the Bios settings are rounded up to the closest fixed step rate such as the 2, 3, 5, or 6 milliSecond rates in the WD1772 or 6, 10, 20, or 30 milliSecond rates used in the older WD1770 and WD1795. Nothing is returned from this function. + + +| Function 31 (xx5D) | DIRDIO Floppy SubFunction 5 | +|---:|:---| +| | **Home Disk Drive Heads** | +| Enter: | B = 1 (Floppy Driver) | +| | C = 5 (Subfunction #) | +| Exit: | A = 0, Zero Set (Z) if Ok | +| | A <> 0, NZ if Errors | +| Uses: | AF | +| **NOTE:** | Subfcns 1, 2, & 4 Needed | + +This subfunction moves the head(s) on the selected drive to track 0 (home). Only success/failure is indicated by the value in the A register. No other registers may be altered by this function (especially BC). + +**NOTE:** This function requires that Subfunctions 1 (Set Disk and Motor Parameters), 2 (Set Head and Drive) and 4 (Specify Drive Times) be called first in order to establish the physical characteristics of the Drive. + + +| Function 31 (xx5D) | DIRDIO Floppy SubFunction 6 | +|---:|:---| +| | **Seek Track** | +| Enter: | A = Desired Track Number | +| | D = 0FFH to Verify, | +| | 0 for No Verification | +| | E = 0 for No Double-Step | +| | <>0 for Double-Step | +| | B = 1 (Floppy Driver) | +| | C = 6 (Subfunction #) | +| Exit: | A = 0, Zero Set (Z) if Ok | +| | <> 0, NZ if Error | +| Uses: | AF | +| **NOTE:** | Subfcns 2, 3 & 4 Needed | + +This subfunction moves the head(s) for the selected drive to a specified track on the media. If the Double-Step flag (Register E) is set to a Non-Zero value, then the controller will issue two step pulses for every track increment or decrement which is required. After the Seek, a Read ID function will be performed to verify that the desired track was found if the Verification Flag (Register D) is set to a Non-Zero Number, preferably 0FFH. Only the AF registers may be altered by this function. + +**NOTE:** This function requires that Subfunctions 2 (Set Head and Drive), 3 (Set Floppy Disk Mode) and 4 (Specify Drive Times) be called first in order to establish the physical characteristics of the Drive. + + +| Function 31 (xx5D) | DIRDIO Floppy SubFunction 7 | +|---:|:---| +| | **Read Floppy Disk Sector** | +| Enter: | HL = Dest Buffer Address | +| | B = 1 (Floppy Driver) | +| | C = 7 (Subfunction #) | +| Exit: | A = 0, Zero Set (Z) if Ok | +| | <> 0, NZ if Error | +| Uses: | AF, HL | +| **NOTE:** | Subfcns 0, 1, 2, 4 & 6 Needed | + +This subfunction Reads a physical sector of data from the selected drive and places it in the buffer at the specified address. It is important that an appropriately sized buffer is provided for this task. The Value in the A register will indicate the success or failure of the function as indicated in the above chart. Only the AF and HL registers may be altered by this function. + +**NOTE:** This function requires that Subfunctions 0 (Set Read/Write Mode), 1 (Set Disk & Motor Parms), 2 (Set Head & Drive), 4 (Specify Drive Times) and 6 (Seek Track) be called first in order to establish the physical and logical characteristics of the data transfer. + + +| Function 31 (xx5D) | DIRDIO Floppy SubFunction 8 | +|---:|:---| +| | **Write Floppy Disk Sector** | +| Enter: | HL = Source Buffer Address | +| | B = 1 (Floppy Driver) | +| | C = 8 (Subfunction #) | +| Exit: | A = 0, Zero Set (Z) if Ok | +| | A <> 0, NZ if Error | +| Uses: | AF, HL | +| **NOTE:** | Subfcns 0, 1, 2, 4 & 6 Needed | + +This subfunction writes data from the buffer beginning at the specified address to the track, sector and head selected by other subfunctions. The value in the A register along with the setting of the Zero Flag will indicate whether the operation succeeded or not. Only the AF and HL registers may be altered by this function. + +**NOTE:** This function requires that Subfunctions 0 (Set Read/Write Mode), 1 (Set Disk & Motor Parms), 2 (Set Head & Drive), 4 (Specify Drive Times) and 6 (Seek Track) be called first in order to establish the physical and logical characteristics of the data transfer. + + +| Function 31 (xx5D) | DIRDIO Floppy SubFunction 9 | +|---:|:---| +| | **Read Disk Sector ID** | +| Enter: | B = 1 (Floppy Driver) | +| | C = 9 (Subfunction #) | +| Exit: | A = 0, Zero Set (Z) if Ok | +| | A <> 0, NZ if Error | +| Uses: | AF | +| **NOTE:** | Subfcns 0 & 2 Needed | + +This Subfunction reads the first correct ID information encountered on a track. There are no entry parameters for this function other than the Driver and Subfunction number. A flag is returned indicating whether or not errors occurred. An error indicates that no recognizable Sector ID could be read on the disk. In most cases, this is due to an incorrect Density setting in the Bios. + +**NOTE:** This function requires that Subfunctions 2 (Set Head & Drive) and 3 (Set Floppy Disk Mode) are called first in order to establish the physical characteristics of the disk. + + +| Function 31 (xx5D) | DIRDIO Floppy SubFunction 10 | +|---:|:---| +| | **Return Floppy Drive Status** | +| Enter: | B = 1 (Floppy Driver) | +| | C = 10 (Subfunction #) | +| Exit: | A = Status Byte of last Opn | +| | BC = FDC Controller Type | +| | HL = Address of Status Byte | +| Uses: | AF, BC, HL | +| **NOTE:** | Subfcn 2 Needed | + +This function returns the status of the currently-selected drive. There are no entry parameters for this function other than the Floppy Driver and Function number. On exit, the raw unmasked status byte of the drive, or the last operation depending on the controller type, is returned along with a binary number representing the FDC controller type (e.g. 765, 9266, 1772, etc). + +**NOTE:** This routine assumes that Subfunction 2 (Set Head & Drive) has been called before this routine to select the Physical Parameters. + + +| Function 31 (xx5D) | DIRDIO Floppy SubFunction 11 | +|---:|:---| +| | **Format Floppy Disk Track** | +| Enter: | HL = Pointer to Data Block | +| | D = # of Sectors/Track | +| | E = # of Bytes in Gap 3 | +| | B = 1 (Floppy Driver) | +| | C = 11 (Subfunction #) | +| Exit: | A = 0, Zero Set (Z) if Ok | +| | A <> 0, NZ if Error | +| Uses: | AF, BC, DE, HL | +| **NOTE:** | Use Subfcn 10 for Cont Type | + +This Sub function formats a complete track on one side of a Floppy Disk. It assumes that the Mode, Head/Drive, Track, and Sector have already been set. On entry, HL points to data required by the controller to format a track. This varies between controllers, so RETDST should be called to determine controller type before setting up data structures. On entry, D must also contain the number of Sectors per Track, and E must contain the number of bytes to use for Gap 3 in the floppy format. On exit, A=0 and the Zero flag is Set (Z) if the operation was satisfactorily completed, A <> 0 and the Zero flag cleared (NZ) if errors occurred. This routine may alter all primary registers (AF, BC, DE, HL). + +**NOTE:** This routine assumes that Subfunction 10 (Return Floppy Drive Status) has been called first to determine the Controller type and insert the correct information in the Format Data Block. + +----- + +### Function 31 - HARD DISK SUBFUNCTIONS + +These functions are available to directly access Hard Drives connected by a SCSI type interface. They are accessed by loading the desired function number in the C register, loading a 2 (SCSI driver) into the B register and calling or jumping to Jump number 31 in the Bios entry jump table. Since this interface is not as standardized as Floppy functions in order to handle SASI as well as SCSI devices, the interface has only basic functions with the precise operations specified by the User in the Command Descriptor Block passed with Function 2. While this places a greater burden on User programs, it allows more flexibility to take advantage of changing features in the newer SCSI drives. + + +| Function 31 (xx5D) | DIRDIO Hard Disk SubFunction 0 | +|---:|:---| +| | **Set Hard Disk Addresses** | +| Enter: | DE = Address of Data Area | +| | B = 2 (Hard Disk Driver) | +| | C = 0 (Subfunction #) | +| Exit: | A = # Bytes in Comnd Block | +| Uses: | AF | + +This Subfunction sets the User Data Area Address for Direct SCSI IO, and returns the number of bytes available in the SCSI Command Descriptor Block. The Data Area must be AT LEAST 512 bytes long and is used to store data to be written, and to receive data read from the selected drive. This Data Area size is mandatory since 512 bytes are always returned from a direct access in order to handle the wide variety of controller types recognized in the B/P Bios drivers. The number of bytes available in the Command Descriptor Block within the physical driver is usually 10 in order to handle the extended SCSI commands, but may be scaled back to 6 in limited applications. + + +| Function 31 (xx5D) | DIRDIO Hard Disk SubFunction 1 | +|---:|:---| +| | **Set Physical & Logical Drive** | +| Enter: | A = Device Byte (5.2.1) | +| | B = 2 (Hard Disk Driver) | +| | C = 1 (Subfunction #) | +| Exit: | A = Physical Device Bit | +| Uses: | AF | + +This Subfunction sets the Physical Device bit in the Bios for SCSI accesses and the Logical Unit Number in the SCSI Command Block (Byte 1, bits 7-5). The format of the Device Byte provided to this routine is defined in the Configuration Data, Section 5.2.1, CONFIG+61, and is available from the Extended Disk Parameter Header at DPH-1. On exiting this routine, a byte is returned with a "One" bit in the proper position (Bit 7 = Device 7...Bit 0 = Device 0) to select the desired unit via a SCSI command. + + +| Function 31 (xx5D) | DIRDIO Hard Disk SubFunction 2 | +|---:|:---| +| | **Direct SCSI Driver** | +| Enter: | DE = Ptr to Comnd Desc Blk | +| | A = 0 if No Write Data | +| | A = FF if Data to Write | +| | B = 2 (Hard Disk Driver) | +| | C = 2 (Subfunction #) | +| Exit: | A = Bit1 Status, Flags Set | +| | H= Message Byte Value | +| | L = Status Byte Value | +| Uses: | AF, BC, DE, HL | +| **NOTE:** | Subfcns 0 & 1 Needed | + +This Subfunction performs the actions required by the command in the specified Command Descriptor Block. The flag provided in Register A signifies whether or not user data is to be written by this command. If set to a Non-Zero value, Data from the area specified with Function 0 will be positioned for SCSI Write operations. At the end of the routine, 512 bytes are always transferred from the Bios IO Buffer to the Users Space set by Subfunction 0. This may be inefficient, but was the only way we could accommodate the wide variety of different SASI/SCSI controllers within reasonable code constraints. The status returned at completion of this function is the Status byte masked with the Check Bit, Bit 1. The full Status Byte and Message Byte from SCSI operations are also provided for more definition of any errors. + +**NOTE:** This routine assumes that the Command Descriptor Block has been properly configured for the type of Hard Disk Controller set in B/P Bios, and that the selected disk is properly described (if necessary) in the Bios Unit definitions. Errors in phasing result in program exit and Warm Boot. It assumes the user has called Functions 0 (Set Hard Disk Addresses) and 1 (Set Physical & Logical Drives) before using this Subfunction. + +---- + +## 5.2 Bios Data Structures + +### 5.2.1 Configuration Area + +Much of the ability to tailor B/P Bioses to your specific operating needs is due to the standardized location of many discrete elements of data, and a facility to easily locate and change them, regardless of the particular hardware platform in operation. Bios Function 30, Return Bios Addresses, reports the base address of the Configuration Area in the DE register pair. In this section, we will review each of the specified elements, their functions, and which parts of the data must be rigidly controlled to insure that the supplied utilities continue to function, as well as guarantee the portability of other programs. + + +| Offset (hex) | (dec) | Description | Data type | +| :---: | :---: | :--- | :--- | +| -0x06 / 0xFA | -6 | Bios ID | String, 6 bytes | +| +0x00 | +0 | IOBYTE | Byte | +| +0x02 | +2 | Bios Option Flags | Byte | +| +0x03 | +3 | User Bank | Byte | +| +0x04 | +4 | TPA Bank | Byte | +| +0x05 | +5 | SYStem Bank | Byte | +| +0x06 | +6 | RAM Drive Bank | Byte | +| +0x07 | +7 | Maximum Bank Number | Byte | +| +0x08 | +8 | Common Page Base | Byte | +| +0x09 | +9 | DPB Size | Byte | +| +0x0A | +10 | Number of DPBs in Common RAM | Byte | +| +0x0B | +11 | Number of DPBs in System Bank | Byte | +| +0x0C | +12 | Pointer to first Common DPB | Word | +| +0x0E | +14 | Pointer to first Banked DPB | Word | +| +0x10 | +16 | Initial Startup Command | String, 10 bytes | +| +0x1A | +26 | Pointer to Environment Descriptor | Word | +| +0x1C | +28 | Banked User Flag/Bank Number | Byte | +| +0x1D | +29 | Pointer to Start of Banked User Area | Word | +| +0x1F | +31 | CPU Clock Rate in Megahertz | Byte | +| +0x20 | +32 | Additional Wait State Requirements | Byte | +| +0x21 | +33 | Timer Reload Value | Word | +| +0x23 | +35 | Floppy Disk Physical Parameters | Table | +| +0x37 | +55 | Motor On Time in 1/10th Seconds | Byte | +| +0x38 | +56 | Motor Spinup Time in 1/10th Seconds | Byte | +| +0x39 | +57 | Maximum Number of Retries | Byte | +| +0x3A | +58 | Pointer to Interrupt Vector Table | Word | +| +0x3C | +60 | SCSI Controller Type | Byte | +| +0x3D | +61 | Hard Drive Physical Parameters | Table | +| +0x58 | +88 | (Reserved Bytes) | 5 Bytes | +| +0x5D | +93 | Character Device Definitions | Table | + + +`CONFIG-6` Bios ID (Character String, 6 bytes) + +This character string **MUST** begin with the three characters "B/P" in Uppercase Ascii, followed by three Version-specific identifying characters. As of March 1997, the following identifiers have been assigned to systems: + +| ID | Computer system | +| :---: | :--- | +| `"B/P-YS"` | YASBEC | +| `"B/P-AM"` | Ampro Little Board 100 | +| `"B/P-18"` | MicroMint SB-180 | +| `"B/P-CT"` | Compu/Time S100 Board Set | +| `"B/P-TT"` | Teletek | +| `"B/P-XL"` | Intelligent Computer Designs XL-M180 | +| `"B/P-DX"` | D-X Designs Pty Ltd P-112 | + + +`CONFIG+0` IOBYTE (Byte) + +This byte contains the initial definition of the byte placed at offset 3 on the Base Page (0003H) during a Cold Boot and determines which of the four defined character IO devices will be used as the Console, Auxiliary and Printer devices. The default setting may be altered by BPCNFG to reflect changed device configurations, or by reassembly of the Bios. The bit definitions in this byte are: + +```generic +Bit 7 6 5 4 3 2 1 0 + | | | | | | \------ Console Device + | | | | \---------- Auxiliary Input Device + | | \-------------- Auxiliary Output Device + \------------------ Printer Device +``` + +`CONFIG+2` Bios Option Flags (Byte) + +This byte consists of individually mapped bits which display which options are active in the assembled Bios. The bits listed as should not be defined without prior coordination with the system developers to preclude conflicts with planned enhancements. The byte is currently defined as: + +```generic +Bit 7 6 5 4 3 2 1 0 + | | | | | | | \---- 0 = Unbanked Bios 1 = Banked Bios + | | | | | | \------ 0 = Bank in RAM 1 = Bank in ROM + | | | | | \-------- 0 = DPBs Fixed 1 = DPBs Assignable + | | | | \---------- 0 = ALV/CSV in TPA 1 = ALV/CSV in Bank (ZSDOS2) + | \---------------- + \------------------ 0 = Not Locked 1 = Locked, Can't Reload +``` + +The next five bytes define the memory map of a banked system in 32k slices. For a complete description of Bank allocations, please refer to Section 4. In non-banked systems, all except the RAM Drive Bank should all be set to 0. If no memory is available for re-assignment as a RAM drive, this byte as well should be set to 0. + +`CONFIG+3` User Bank (Byte) + +This Byte reflects the Bank number reserved for User Applications. + +`CONFIG+4` TPA Bank (Byte) + +This Byte reflects the Bank number reserved for the Transient Program Area in the address range of 0..7FFFH. The next sequential bank number is normally the Common Bank which always remains in Context in the addressing range of 8000..FFFFH and contains the Operating System, Bios and Z-System tables. + +`CONFIG+5` SYStem Bank (Byte) + +This byte reflects the Bank number containing any executable code and data specified for the System Bank. + +`CONFIG+6` RAM Drive Bank (Byte) + +This byte reflects the starting Bank number available for use as a RAM Drive. It is assumed that all RAM from this Bank through the Maximum Bank Number is contiguous and available as a RAM Drive. + +`CONFIG+7` Maximum Bank Number (Byte) + +This byte reflects the number of the last available bank of RAM in the system. In many systems, it may be set to different numbers depending on the number of RAM chips installed in the system. + +`CONFIG+8` Common Page Base (Byte) + +This byte reflects the Base Page of the Common area in systems which do not fully comply with the 32k Memory Banking architecture of B/P Bios, but can be made somewhat compliant. This Byte must be AT LEAST 80H, but may be higher if needed. + +`CONFIG+9` DPB Size (Byte) + +This byte contains the length of Disk Parameter Block allocations within the Bios. Since more information is needed than the 15 bytes defined by Digital Research in CP/M 2.2, an extended format is used. All re-assignments of Disk Parameter data should use this byte to determine the size of records. + +`CONFIG+10` Number of DPBs in Common RAM (Byte) +`CONFIG+11` Number of DPBs in System Bank (Byte) + +These two bytes indicate the complete complement of Floppy Disk formats available within the Bios. In most cases, one of these two bytes will reflect a zero value with all Disk Parameter Blocks resident either in the Common area or in the System Bank. The provisions are available, however with these two bytes to split the definitions for custom versions without voiding the support tools provided. + +`CONFIG+12` Pointer to first Common DPB (Word) +`CONFIG+14` Pointer to first Banked DPB (Word) + +These two words point to the first DPB in a sequential list within the respective memory banks for Disk Parameter Blocks defined in the preceding bytes. In most cases one of these two words will be a Null pointer (0000H) corresponding to no data as described in the count bytes above. + +`CONFIG+16` Initial Startup Command (String, 10 Bytes) + +This string contains the first command which will be initiated on a Cold Boot. It is loaded into the Multiple Command Buffer defined in the Environment Descriptor (See 5.2.4) and calls a file of the specified name with a type of "COM". The string may have up to eight characters and must be Null-terminated (end with a Binary 0). The string is defined as: + +| | Initial Startup Command String | +| :---: | :--- | +| Byte | Number of Characters (0..8) | +| String | 8 bytes for Ascii characters (usually Uppercase) | +| Byte | Terminating Null (binary 0) | + +`CONFIG+26` Pointer to Environment Descriptor (Word) + +This Word points to the first byte of an extended Z34 Environment which **MUST** begin on a Page boundary (xx00H). See Section 5.3.1 for a complete description of the Environment Descriptor and B/P Bios unique features. + +`CONFIG+28` Banked User Flag/Bank Number (Byte) + +This Byte may be used as a flag to indicate whether or not a User Bank is defined. Bank 0 cannot be used as a User bank by decree of the system authors. Therefore, if this byte contains a binary 0, no User Bank is available. + +`CONFIG+29` Pointer to Start of Banked User Area (Word) + +This word contains the address of the first available byte in the Banked User Area, if one exists. Routines loaded into the User Bank should contain a standard RSX header structure to link sequential programs and provide a primitive memory management function. + +`CONFIG+31` CPU Clock Rate in Megahertz (Byte) + +This byte must contain the processor speed rounded to the nearest Megahertz. It may be used by software timing loops in application and utility programs to adapt to the clock speed of the host computer and provide an approximate time. This byte is reflected in the Environment Descriptor (see 5.2.4) as well for programs which are Z-System "aware". + +`CONFIG+32` Additional Wait State Requirements (Byte, nybble-mapped) + +This byte is "nybble-mapped" to reflect the number of wait states needed for memory and IO accesses when these functions can be set via software. In the Z80/Z180, IO port accesses have one wait state inserted within the processor. This byte does not account for this fact, and reflects wait states **IN ADDITION TO** any which are built into the hardware. For older processors such as the Z80, these bytes normally have no effect since additional wait states must be added with hardware. + +`CONFIG+33` Timer Reload Value (Word) + +In many systems, Interrupts or Timer values are set by software-configurable countdown timers. the 16-bit value at this location is reserved for setting the timer value and may be "fine tuned" to allow the system to maintain correct time in the presence of clock frequencies which may deviate from precise frequencies needed for accurate clocks. + +`CONFIG+35` Floppy Disk Physical Parameters (Table) + +This table consists of four 5-byte entries which contain information on up to four physical drives. Each entry is defined as: + +| Byte | Description | +| :---: | :--- | +| 0 | Provides base for XDPH byte, _see bit mapping below_ | +| 1 | Step Rate in milliseconds | +| 2 | Head Load Time in milliseconds | +| 3 | Head Unload Time in milliseconds | +| 4 | Number of Tracks (Cylinders) on drive | + +```generic +XDPH Base +Bit 7 6 5 4 3 2 1 0 + | | | | | \-------- Disk Size 000=Fixed Disk, 001=8", 010=5.25", 011=3.5" + | | | | \---------- 0 = Single-Sided, 1 = Double-Sided + | | | \------------ + | | \-------------- 0 = Motor Always On 1 = Motor Control Needed + | \---------------- 0 = 300 RPM Max Speed 1 = 360 RPM (8" & HD) + \------------------ +``` +Those bits in Byte 0 which are listed as unused must be set to 0 since this byte provides the initial value stored in the XDPH when assignable drives are used. For controllers which do not need the available information (e.g. Western Digital controllers do not need Byte 3), these values may be set to any arbitrary value, but **MUST** remain present in the structure to prevent changing subsequent addresses. + +`CONFIG+55` Motor On Time in 1/10th Seconds (Byte) + +This time may be used in some types of Floppy Disk controllers to keep the drive motors spinning for a specified time after the last access to avoid delays in bringing the spindle up to speed. Some controllers, notably the Western Digital 17xx and 19xx series to not support this feature. In this case, the byte may be set to any arbitrary value, but **MUST** remain present. + +`CONFIG+56` Motor Spinup Time in 1/10th Seconds (Byte) + +This time is the delay which will be imposed by the Bios before attempting to access a Floppy Disk drive when it senses that the motor is in a stopped condition. Providing such a delay will minimize the probability of data corruption by writing to disk which is rotating at the incorrect speed. + +`CONFIG+57` Maximum Number of Retries (Byte) + +This byte specifies the number of attempts which will be made on a Floppy Disk access before returning an error code. In some cases, such as diagnostic programs, it may be desirable to set this value to 1 to identify soft errors, or ones which fail on the first attempt, but succeed on a subsequent try. We recommend a value of 3 or 4 based on our experience. Larger values may result in inordinately long delays when errors are detected. + +`CONFIG+58` Pointer to Interrupt Vector Table (Word) + +This Word contains the address of the base of an Interrupt Vector Table which, when used, contains pointers to service routines. The precise definition of the table is not standardized and may vary considerably between systems. This pointer serves only to provide an easy and standardized method of locating the table for re-definition of services or system features. + +`CONFIG+60` SCSI Controller Type (Byte) + +To accommodate the widest variety of different controllers including the older SASI models, this byte is defined as containing a byte code to the specific model being used. In most cases, this byte has little if any effect within the Bios, but may have significant effects on Hard Disk Diagnostic programs, or User-developed utilities. Any additions to this table should be coordinated with the authors to insure that the standard support utilities continue to function. Current definitions are: + +| ID | Controller type | +| :---: | :--- | +| 0 | Owl | +| 1 | Adaptec ACB-4000A | +| 2 | Xebec 1410A/Shugart 1610-3 (SASI) | +| 3 | Seagate SCSI | +| 4 | Shugart 1610-4 (Minimal SCSI subset) | +| 5 | Conner SCSI | +| 6 | Quantum SCSI | +| 7 | Maxtor SCSI | +| 8 | Syquest SCSI | +| 9 | GIDE (IDE/ATA) | + +`CONFIG+61` Hard Drive Physical Parameters (Table) + +This table consists of three 9-byte entries defining up to three physical Hard Drives. While the SCSI definition allows for more units, three was considered adequate for most systems. If additional drives are needed, please contact the authors for methods of including them without invalidating any of the standard utilities or interfaces. Each of the three entries is defined as: + +| Entry | Description | +| :--- | :--- | +| Byte | Physical and Logical Address, _see bit mapping below_ | +| Word | Number of Physical Cylinders on Drive | +| Byte | Number of Usable Physical Heads on Drive | +| Word | Cylinder Number to begin Reduced Write Current | +| Word | Cylinder Number to begin Write Precompensation | +| Byte | Step Rate. This byte may either be an absolute rate in mS or a code based on controller-specific definitions | + +```generic +Physical and Logical Address + Bit 7 6 5 4 3 2 1 0 + | | | | | \-------- Physical Device (000-110B, 111B reserved for Host) + | | | | \---------- + | | | \------------ 0 = Drive NOT Present, 1 = Drive Present + \------------------ Logical Unit Number (000-111B) for controllers +``` + +For many of the newer controllers, the last three items may not have any meaning in which case they can be set to any arbitrary value. Also in newer drives, the physical characteristics such as the number of cylinders and heads may be hidden within the drive electronics with re-mapped values provided to the controller via various SCSI commands. As with the last three entries, in this case, they may be set to any arbitrary value. + +`CONFIG+88` Reserved (5 Bytes) + +Five Bytes are reserved for future expansion. + +`CONFIG+93` Character Device Definitions (Table) + +This table consists of four or more 16-byte (8-byte in B/P versions prior to 1.1) entries and must be terminated by a Null (binary Zero) byte. Each entry defines the name and characteristics of a character device in the system. The first four of these are directly available for selection by the IOBYTE as the Console, Auxiliary IO and Printer. Other entries may be defined and exchanged with the first four to make them accessible to the system. The entries are defined as: + +| Entry | Description | +| :---: | :--- | +| String | Four Ascii character Name as: COM1, PIO1, NULL, etc. | +| Byte | Data Rate capabilities, _see bit mapping below_ | +| Byte | Configuration Byte, _see bit mapping below_ | +| Byte | Input Data Mask | +| | Bit-mapped byte used to logically AND with bytes read from Device Input | +| Byte | Output Data Mask | +| | Bit-mapped byte used to logically AND with bytes before being output to device | +| Word | Pointer to Character Output routine | +| Word | Pointer to Output Status routine | +| Word | Pointer to Character Input routine | +| Word | Pointer to Input Status routine | + +**NOTE:** The last four pointers are not at these locations in B/P Bios versions prior to 1.1, but were accessed by a pointer returned by Bios Function 30. + +```generic +Data Rate capabilities +Bit 7 6 5 4 3 2 1 0 + | | | | \---------- Current Data Rate Setting + \------------------ Maximum Rate Available (Bits-per-Second) as: + 0000 = None 0001 = 134.5 0010 = 50 0011 = 75 + 0100 = 150 0101 = 300 0110 = 600 0111 = 1200 + 1000 = 2400 1001 = 4800 1010 = 9600 1011 = 19200 + 1100 = 38400 1101 = 76800 1110 = 115200 1111 = Fixed +``` + +```generic +Configuration Byte +Bit 7 6 5 4 3 2 1 0 + | | | | | | | \---- 0 = 2 Stop Bits, 1 = 1 Stop Bit + | | | | | | \------ 0 = No Parity, 1 = Parity Enabled + | | | | | \-------- 0 = Odd Parity, 1 = Even Parity + | | | | \---------- 0 = 8-bit Data, 1 = 7-bit Data + | | | \------------ 0 = No XON/XOFF, 1 = XON/XOFF Control Enabled + | | \-------------- 0 = No CTS/RTS, 1 = CTS/RTS Control Enabled + | \---------------- 0 = Device NOT Input, 1 = Device can be read + \------------------ 0 = Device NOT Output, 1 = Can Write Device +``` + + +### 5.2.2 Disk Parameter Header + +The Disk Parameter Header (DPH) is a logical data structure required for each disk drive in a CP/M compatible Disk Operating System. It consists of a series of eight pointers which contain addresses of other items needed by the DOS as well as some scratchpad space. The Address of the DPH associated with a given drive is returned by the Bios after a successful selection with Bios Function 9. If Errors occur during selection, or the drive does not exist, a Null Pointer (0000H) is returned. + +For B/P Bios, it was necessary to add an additional four bytes to each DPH which contain additional information on physical and logical parameters as well as flag information. These additional bytes are referred to as the Extended DPH, or XDPH. While similar in concept to the extension added to CP/M 3, the implementation is different. The XDPH prepends the DPH and may be accessed by decrementing the returned address. As a convention, DPHs in B/P Bios source code have reserved certain label sequences for specific types of units with DPH00-DPH49 used for Floppy Drives, DPH50-DPH89 for Hard Drive Partitions and DPH90-DPH99 for RAM Drives. + +An entire DPH/XDPH block is required for each logical drive in a B/P Bios system. While some pointers, such as the pointer to the Directory Buffer, may be common across a number of drives, for most systems, the other items will point to unique areas. + + +| Offset (hex) | (dec) | Description | Data type | +| :---: | :---: | :--- | :--- | +| -0x04 / 0xFC| -4 | Format Lock Flag | Byte | +| -0x03 / 0xFD | -3 | Disk Drive Type | Byte | +| -0x02 / 0xFE | -2 | Driver ID Number | Byte | +| -0x01 / 0xFF | -1 | Physical Drive/Unit Number | Byte | +| +0x00 | +0 | Skew Table Pointer | Word | +| +0x02 | +2 | Dos Scratch Area | 3 Words | +| +0x08 | +8 | Directory Buffer Pointer | Word | +| +0x0A | +10 | DPB Pointer | Word | +| +0x0C | +12 | Disk Checksum Buffer | Word | +| +0x0E | +14 | Allocation Vector (ALV) Buffer | Word | + + +The DPH/XDPH elements as indexed from the DPH addresses accessible to application programs are: + +`DPH-4` Format Lock Flag (Byte) + +A Zero value indicates that the format of the disk is not fixed, but may be changed. If the Bios was assembled with the Auto-select option, the Bios will scan a number of different formats in order to identify the disk. If a 0FFH value is placed in this byte, it indicates that the format is fixed and cannot be changed. This is normally the case for RAM and Hard disk drives, as well as for alien floppy formats which have been selected in the emulation mode. If the Auto-select option was not chosen during assembly of the Bios, all Floppy Disk drives will also have a 0FFH byte in this position showing that the formats cannot be changed. + + +`DPH-3` Disk Drive Type (Byte) + +This byte is bit mapped and contains flags indicating many parameters of the drive. For Floppy Drives, this byte contains a copy of the first byte in the Physical Drive Table (See 5.2.1, CONFIG+35) with the two reserved bytes set during the drive selection process. The byte is then defined as: + +```generic +Bit 7 6 5 4 3 2 1 0 + | | | | | \-------- Disk Size 000=Fixed Disk, 001=8", 010=5.25", 011=3.5" + | | | | \---------- 0 = Single Sided 1 = Double Sided + | | | \------------ 0 = Single Step Drive 1 = Double Step Drive + | | \-------------- 0 = Motor Always On 1 = Drive Motor Control Needed + | \---------------- 0 = Max Speed 5.25" (300 rpm) 1 = 8" & HD Max Speed (360 rpm) + \------------------ 0 = Double Density 1 = Single Density +``` + +For Hard Disk Partitions and the RAM Drive, this byte is not used and is set to all Zeros indicating a Fixed Drive type. + +`DPH-2` Driver ID Number (Byte) + +Three Driver Types are used in the basic B/P Bios configuration. A Zero value indicates a Non-existent driver, with other values used to direct disk accesses to the respective code appropriate to the device. Basic defined driver types exist for Floppy Disk (1), Hard Disk via the SCSI interface (2), and RAM Disk (3). If you wish to extend this table to include tailored drivers, please consult with the authors to preclude possible conflicts with planned extensions. + +`DPH-1` Physical Drive/Unit Number (Byte) + +This byte contains the Physical Drive or Unit Number hosting the logical drive. For Floppy Drives, this will usually be in the range of 0 to 3 for four drives. Hard drives may have several DPHs sharing the same physical drive number, while this field is ignored in the single RAM drive supported in the distribution B/P Bios version. + +**NOTE:** The Physical Drive Number byte for Hard Drives is comprised of two fields to ease handling of SCSI devices. Up to seven devices (device 111B is reserved for the Host Computer) each having up to 8 Logical Units may be defined. The Byte is configured as: + +```generic +Bit 7 6 5 4 3 2 1 0 + | | | | | \-------- Physical Device (000-110B, 111B reserved for Host) + | | | | \---------- + | | | \------------ 0 = Unit Not Available, 1 = Unit Active + \------------------ Logical Unit Number (000-111B) +``` + +`DPH+0` Skew Table Pointer (Word) + +This word contains a pointer to the Skew table indicator. It rarely is used for Hard and RAM drives, but is required in Floppy Disk drives. If the Bios was assembled using the Calculated Skew option, the address is of a Byte whose absolute value indicates the numerical value of skew (normally in the range of 1 to 6) used for disk accesses. This term is often replaced with Interleave, and is synonymous for this purpose. If the value of the byte is negative, it means that the sectors are recorded in a skewed form on the disk and that Reads and Writes should be sequential. If the value is positive, then an algorithm is called to compute a physical sector number based on the desired logical sector and the skew factor. For systems assembled without Calculated skew, this word points to a table of up to 26 bytes which must be indexed with the desired Physical Sector number (0..Maximum Sector Number) to obtain the corresponding Disk Sector number. + +`DPH+2` Dos Scratch Area (3 Words) + +These three words are available for the Dos to use as it requires. No fixed values are assigned, nor are meanings for the data stored there of any value. + +`DPH+8` Directory Buffer Pointer (Word) + +This word points to a 128-byte Data area that is used for Directory searches. It is usually a common area to all DPH's in a system and is frequently updated by the Dos in normal use. + +`DPH+10` DPB Pointer (Word) + +This word points to another data structure which details many of the logical parameters of the selected drive or partition. Its structure is detailed in Section 5.2.3 below. Drives of the same type and logical configuration may share DPB definitions, so it is not uncommon to find the DPB pointers in different DPH structures pointing to the same area. + +`DPH+12` Disk Checksum Buffer (Word) + +This word points to a scratch RAM buffer area for removable-media drives used to detect disk changes. Normally this feature is used only for Floppy Disk Drives, and is disabled by containing a Zero word (0000H) for Hard and RAM drives. For Floppy Drives, a RAM area with one byte for every four directory entries (128-byte sector) is needed (See 5.2.3, DPH+11/12). This scratch area cannot be shared among drives. + +It should be noted that in a fully Banked B/P Bios system with ZSDOS2, the Checksum Buffer is placed in the System Bank and not directly accessible by applications programs. + +`DPH+14` Allocation Vector (ALV) Buffer (Word) + +This word points to a bit-mapped buffer containing one bit for each allocation block on the subject drive (See 5.2.3, DPB+5/6). A "1" bit in this buffer means that the corresponding block of data on the device is already allocated to a file, while a "0" means that the block is free. This buffer is unique to each logical drive and cannot be shared among drives. + +It should be noted that in a fully Banked B/P Bios system with ZSDOS2, the ALV Buffer is placed in the System Bank and not directly accessible by applications programs. Since access to the ALV buffer is frequently needed to compute free space on drives, ZSDOS2 contains an added function to return disk free space. Using this call allows applications access to the information without directly accessing the data structure. + + +### 5.2.3 Disk Parameter Block + +The Disk Parameter Block (DPB) is a data structure defined by Digital Research for CP/M which defines the logical configuration of storage on mass storage. It has been expanded in B/P Bios to include additional information to provide enhanced flexibility and capability. The expansion is referred to as the Extended DPB or XDPB, and prepends the actual DPB structure. The address of the DPB may be obtained from the DPH pointer returned by the Bios or Dos after a disk selection (See 5.2.2 above). All DPBs reside in the Common Memory area and are available to applications programs whether in a Banked or Unbanked system. For the sake of a convention, the DPBs are labeled in the same manner as DPHs with DPB00-DPB49 used for Floppy Drives, DPB50-DPB89 for Hard Drive Partitions, and DPB90-99 for RAM Drives. + + +| Offset (hex) | (dec) | Description | Data type | +| :---: | :---: | :--- | :--- | +| -0x10 / 0xEA | -16 | Ascii ID String | 10 Bytes | +| -0x06 / 0xFA | -6 | Format Type Byte 0 | Byte | +| -0x05 / 0xFB | -5 | Format Type Byte 1 | Byte | +| -0x04 / 0xFC | -4 | Skew Factor | Byte | +| -0x03 / 0xFD | -3 | Starting Sector Number | Byte | +| -0x02 / 0xFE | -2 | Physical Sectors per Track | Byte | +| -0x01 / 0xFF | -1 | Physical Tracks per Side | Byte | +| +0x00 | +0 | Sectors per Track | Word | +| +0x02 | +2 | Block Shift Factor | Byte | +| +0x03 | +3 | Block Mask | Byte | +| +0x04 | +4 | Extent Mask | Byte | +| +0x05 | +5 | Disk Size (Capacity) | Word | +| +0x07 | +7 | Maximum Directory Entry | Word | +| +0x09 | +9 | Allocations 0 and 1 | Word | +| +0x0B | +11 | Check Size | Word | +| +0x0D | +13 | Track Offset | Word | + + +The layout of the Disk Parameter Block as indexed from the available DPB pointer is: + +`DPB-16` Ascii ID String (10 Bytes) + +This string serves as an identification which may be printed by applications programs such as our BPFORMAT. This string may be a mixed alphanumeric Ascii set of up to ten characters, but the last valid character must have the Most Significant Bit (Bit 7) Set to a "1". + +`DPB-6` Format Type Byte 0 (Byte) + +This byte contains some of the information about the format of the drive, and the logical sequencing of information on the physical medium. The bits in the byte have the following significance: + +```generic +Bit 7 6 5 4 3 2 1 0 + | | | | | \-------- Disk Size: 000 = Fixed Disk, 001 = 8", 010 = 5.25", 011 = 3.5" + | | \-------------- Track Type + | | 000 = Single Side 001 = Reserved + | | 010 = Sel by Sec, Cont 011 = Sel by Sec, Sec # Same + | | 100 = S0 All, S1 All 101 = S0 All,S1 All Reverse + | | 110 = Sel by Trk LSB 111 = Reserved + | \---------------- 0 = Track 0 Side 0 is Double Density, 1 = Single Density + \------------------ 0 = Data Tracks are Double Density, 1 = Single Density +``` + +For Hard Drives and RAM Drives, this byte contains all Zero bits to signify Fixed Media and format. + +`DPB-5` Format Type Byte 1 (Byte) + +This byte contains additional information about the format of information. The bits have the following meanings: + +```generic +Bit 7 6 5 4 3 2 1 0 + | | | | | \--------- Sector Size: 000 = 128, 001 = 256, 010 = 512, 011 = 1024 + | | \--------------- Allocation Size: 000=1K, 001=2K, 010=4K, 011=8K, 100=16K + | | (NOTE: This should match the definition in DPH) + | \----------------- + \------------------- 0 = Normal Speed (300 rpm) + 1 = 8" & HD Floppy (360 rpm) or Hard Drive +``` + +For Hard Drives, The distribution version of B/P Bios and the support utilities assume that the Sector size is always 512 bytes. The remaining bits should be set as indicated. + +`DPB-4` Skew Factor (Byte) + +This byte is a signed binary value indicating the skew factor to be used during Format, Read and Write. It is normally used only with Floppy Drives and usually set to -1 (0FFH) for Hard and RAM drives to indicate that Reads and Writes should be done with No skew. If the option to calculate skew is in effect during Bios assembly, the Skew pointer in the DPH (BPH+0/1) points to this byte. If a skew table is used, this byte has no effect and should be set to 80H. + +`DPB-3` Starting Sector Number (Byte) + +This byte contains the number of the first Physical Sector on each track. Since most Disk Operating Systems use a Zero-based sequential scheme to reference sectors, this value provides the initial offset to correct logical to physical sector numbers. + +`DPB-2` Physical Sectors per Track (Byte) + +This byte contains the number of Physical (as opposed to logical) Sectors on each track. For example, CP/M computes sectors based on 128-byte allocations which are used on single-density 8" Floppy Disks. One of the popular five- inch formats uses five 1k physical sectors which equates to 40 logical CP/M sectors. This byte contains 5 in this instance for the number of 1k Physical Sectors. + +`DPB-1` Physical Tracks per Side (Byte) + +This byte contains the number of Physical Tracks per Side, also called the Number of Cylinders. It reflects the Disk, as opposed to the Drive capabilities and is used to establish the requirements for double-stepping of Floppy Drives. In the case of a 40-track disk placed in an 80-track drive, this byte would contain 40, while the Drive parameter in the Configuration Section contains 80 as the number of tracks on the drive. This byte has no meaning for Hard Drive partitions or RAM drives and should be set to Zero, although any arbitrary value is acceptable. + +`DPB+0` Physical Tracks per Side (Word) + +This value is the number of Logical 128-byte sectors on each data track of the disk. It is equivalent to the number of Physical Sectors times the Physical Sector Size MOD 128. + +`DPB+2` Block Shift Factor (Byte) +`DPB+3` Block Mask (Byte) +`DPB+4` Extent Mask (Byte) + +These three bytes contain values used by the Operating System to compute Tracks and Sectors for accessing logical drives. Their values are detailed in various references on CP/M and ZSDOS programming and should not be varied without knowledge of their effects. + +`DPB+5` Disk Size / Capacity (Word) + +This Word contains the number of the last allocation block on the drive. It is the same as the capacity in allocation blocks - 1. For example, if 4k allocation blocks are being used and a 10 Megabyte drive is being defined, this word would contain 10,000,000/4000 - 1 or 2499. + +`DPB+7` Maximum Directory Entry (Word) + +This Word contains the number of the last Directory Entry and is the same as the Number of Entries - 1. For example, if 1024 directories are desired, this word would be set to 1024 - 1 = 1023. + +`DPB+9` Allocations 0 and 1 (2 Bytes) + +These two Bytes hold the initial allocations stored in the first two bytes of the ALV Buffer (See 5.2.2, DPH+14/15) during initial drive selection. Their primary use is to indicate that the Directory Sectors are already allocated and unavailable for data storage. They are bit-mapped values and are used in Hi-byte, Lo-byte form as opposed to the normally used Lo-byte, Hi-byte storage used in Z80 type CPUs for Word storage. The bits are allocated from the MSB of the first byte thru the LSB, then MSB thru LSB of the second byte based on one bit per allocation block or fraction thereof used by the Directory. The bits may be calculated by first computing the number of entries per allocation block, then dividing the desired number of entries by this number. Any remainder requires an additional allocation bit. + +For example, if 4k allocation blocks are used, each block is capable of 4096/32 bytes per entry = 128 Directory Entries. If 512 entries are desired, then 512/128 = 4 allocation blocks are needed which dictates that Allocation byte 0 would be 11110000B (0F0H) and Allocation Byte 1 would be 00000000B. + +`DPB+11` Check Size (Word) + +This Word is only used in removable media (normally only Floppy Drives) and indicates the number of sectors on which to compute checksums to detect changed disks. It should be set to 0000H for Fixed and RAM Disks to avoid the time penalty of relogging after each warm boot. + +`DPB+13` Track Offset (Word) + +This Word indicates the number of Logical Tracks to skip before the present DPB is effective. It is normally used to reserve boot tracks (usually 1 to 3), or to partition larger drives into smaller logical units by skipping tracks used for other drive definitions. + + +### 5.3.1 Environment Descriptor + +The Environment Descriptor, referred to as simply the ENV, is the heart of what is now known as The Z-System. The most recent additions to the system by Joe Wright and Jay Sage replaced some relatively meaningless elements in the ENV with system dependent information such as the location of the Operating System components. Consequently, the ENV is not just a feature of the ZCPR 3.4 Command Processor Replacement, but is an Operating System Resource which allows other programs such as ZCPR 3.4 to access its information. + +The B/P Bios requires an ENV to be present, and uses several items of information contained in it. The banked ZSDOS2 and Z40 Command Processor Replacement use even more ENV features. A few remaining bytes have been re-defined for support to B/P Bios-based systems. To denote the definition of B/P Bios data elements, a new Type, 90H, has been reserved. Using this "Type" byte, user programs can access and take advantage of the new definitions and features. + +A template for the Environment Descriptor used in B/P Bios which takes its values from the Z3BASE.LIB file included in the distribution disk is: + + +### 5.3.2 Terminal Capabilities + +In addition to the Basic Environment Descriptor described above, a dummy Terminal Capability record structure (TCAP, also known as TERMCAP) is attached to reserve space for, and define default capabilities of the computer terminal. The default TERMCAP is fully compliant with the VLIB routines used in the Z-System Community after VLIB4D. The skeleton record structure is: + + +## 5.4 ZSDOS2 Function Reference + +| Number | Fcn Name | Input Parameters | Returned Values | +|:------:|:---------|:---------------------|:------------------------| +| 0 | Boot | None | None | +| 1 | Console Input | None | A=Character | +| 2 | Console Output | E=Character | A=00H | +| 3 | Reader Input | None | A=Character | +| 4 | Punch Output | E=Character | A=00H | +| 5 | List Output | E=Character | A=00H | +| 6 | Direct Console I/O | E=0FFH (In) | A=Input Character | +| | | E=0FEH (In) | A=Console Status | +| | | E=0FDH (In) | A=Input Character | +| | | E=00H..0FCH (Out) | A=00H | +| 7 | Get I/O Byte | None | A=I/O Byte (0003H) | +| 8 | Set I/O Byte | E=I/O Byte | A=00H | +| 9 | Print String | DE=Address String | A=00H | +| 10 | Read Console Buffer | DE=Address Buffer | A=00H | +| 11 | Get Console Status | None | A=00H = No character | +| | | | A=01H = Char. present | +| 12 | Get Version Number | None | A=Version Number (22H) | +| 13 | Reset Disk System | None | A=00H No $*.* on A | +| | | | A=FFH $*.* on A | +| 14 | Select Disk | E=Disk Number | A=00H No $*.* File | +| | | | A=FFH $*.* File | +| 15 | Open File | DE=Address of FCB | A=Directory Code | +| 16 | Close File | DE=Address of FCB | A=Directory Code | +| 17 | Search for First | DE=Address of FCB | A=Directory Code | +| 18 | Search for Next | DE=Address of FCB | A=Directory Code | +| 19 | Delete File | DE=Address of FCB | A=Error Code | +| 20 | Read Sequential | DE=Address of FCB | A=Read/Write Code | +| 21 | Write Sequential | DE=Address of FCB | A=Read/Write Code | +| 22 | Make File | DE=Address of FCB | A=Directory Code | +| 23 | Rename File | DE=Address of FCB | A=Error Code | +| 24 | Get Login Vector | None | HL=Login Vector | +| 25 | Get Current Disk | None | A=Current Disk | +| 26 | Set DMA Address | DE=DMA Address | A=00H | +| 27 | Get Alloc. Address | None | HL=Addr Alloc Vector | +| 28 | Write Protect Disk | None | A=00H | +| 29 | Get R/O Vector | None | HL=R/O Vector | +| 30 | Set File Attributes | DE=Address FCB | A=Error Code | +| 31 | Get DPB Address | None | HL=Address of DPB | +| 32 | Set/Get User Code | E=FFH (Get) | A=User Number | +| | | E=User Number (Set) | A=00H |< +| 33 | Read Random | DE=Address of FCB | A=Read/Write Code | +| 34 | Write Random | DE=Address of FCB | A=Read/Write Code | +| 35 | Compute File Size | DE=Address of FCB | A=Error Code | +| 36 | Set Random Record | DE=Address of FCB | A=00H | +| 37 | Reset Mult Drive | DE=Mask | A=00H | +| 38 | Not Implemented | | | +| 39 | Get fixed disk vector | None | HL=Fixed Disk Vector | +| 40 | Write random, 00 fill | DE=Addr of FCB | A=Read/Write Code | +| 41-44 | Not Implemented | | | +| 45 | Set error mode | E=FFH (Get) | A=00H | +| | | E=FEH (Get Err/Disp) | A=00H | +| | | E=01H (Set ZSDOS) | A=00H | +| | | E=00H (Set CP/M) | A=00H | +| 46 | Return Free Space | E=Disk Number | A=Error Code | +| | | | Space in DMA+0..DMA+3 | +| 47 | Get DMA address | None | HL=Current DMA Address | +| 48 | Get DOS & version | None | H=DOS type: "S"=ZSDOS, "D"=ZDDOS | +| | | | L=BCD Version Number | +| 49 | Return ENV Address | None | HL=Env. Descriptor Addr | +| 50-97 | Not Implemented | | | +| 98 | Get time | DE=Address to Put Time | A=Time/Date Code | +| 99 | Set time | DE=Address of Time | A=Time/Date Code | +| 100 | Get flags | None | HL=Flags | +| 101 | Set flags | DE=Flags | None | +| 102 | Get file stamp | DE=Addr of FCB | A=Time/Date Code, | +| | | | Stamp in DMA Buffer | +| 103 | Set file stamp | DE=FCB Address, | A=Time/Date Code | +| | | Stamp in DMA Buffer | | +| 104-151 | Not Implemented | | | +| 152 | Parse FileSpec | DE=FCB Address, | A=No. of "?"s in Fn.Ft | +| | | String in DMA Buffer | DE=Addr of delimit chr | +| | | | FCB+15=0 if Parse Ok, 0FFH if Error(s) | +| 153-255 | Not Implemented | | | + + +| BDOS Codes | | +| :--- | :--- | +| Directory Codes: | A=00H, 01H, 02H, 03H if No Error | +| | A=FFH if Error | +| Error Codes: | A=00H if No Error | +| | A=0FFH if error | +| Time/Date Codes: | A=01H if No error | +| | A=0FFH if error | +| Read/Write Codes: | A=00H if No error | +| | A=01H Read - End of File / Write - Directory Full | +| | A=02H Disk Full | +| | A=03H Close Error in Random Record Read/Write | +| | A=04H Read Empty Record during Random Record Read | +| | A=05H Directory Full during Random Record Write | +| | A=06H Record too big during Random Record Read/Write | +| Extended Error codes | A=0FFH Extended Error Flag | +| in Return Error Mode: | H=01H Disk I/O Error (Bad Sector) | +| | H=02H Read Only Disk | +| | H=03H Write Protected File | +| | H=04H Invalid Drive (Select) | + + +## 5.5 Datespec and File Stamp Formats + +The universal stamp and time formats used by ZSDOS are based on packed BCD digits. It was decided that these were the easiest format for Z80 applications programs to work with, and were compatible with most real time clocks. The format for the stamps and for the clock functions are identical to the Plu*Perfect DateStamper's formats for these functions. + +Some file stamping formats (for example CP/M Plus type) do not store all the information present in the universal format to disk. In the case of CP/M Plus type stamps, there is no provision for stamping the Last Access time. The ZSDOS interface routines fill unimplemented fields in the stamp with 0 when the Get Stamp function is used, and ignore the contents of the unused fields when the Put Stamp function is used. + +Depending on the stamping method selected, the format of the stamps on the disk may differ from the universal format. These differences are effectively hidden from users by ZSDOS and the Stamp routines so long as ZSDOS's functions are used to get or manipulate the stamps. + +Time format (6 bytes packed BCD): + +| Byte | Description | +| :---: | :--- | +| `TIME+0` | last 2 digits of year | +| | (prefix 19 assumed for 78 to 99, else 20 assumed) | +| `TIME+1` | month [1..12] | +| `TIME+2` | day [1..31] | +| `TIME+3` | hour [0..23] | +| `TIME+4` | minute [0..59] | +| `TIME+5` | second [0..59] | + +File Stamp format (15 bytes packed BCD): + +| Location | Description | +| :---: | :--- | +| `DMA+0 ` | Create field (first 5 bytes of time format) | +| `DMA+5 ` | Access field (first 5 bytes of time format) | +| `DMA+10` | Modify field (first 5 bytes of time format) | diff --git a/Doc/CPM/BPBIOS/BPBIOS_6_Utilities.md b/Doc/CPM/BPBIOS/BPBIOS_6_Utilities.md new file mode 100644 index 00000000..e5e56773 --- /dev/null +++ b/Doc/CPM/BPBIOS/BPBIOS_6_Utilities.md @@ -0,0 +1,2579 @@ +# 6. B/P Bios Utilities + +We have developed and adapted many support routines to assist you in using and tailoring B/P Bios installations. Many of these follow generally established functions, and their use may be readily perceived. Others are adaptations of routines which we developed to support our earlier ZSDOS operating system, or are adapted from routines available in the Public Domain. The remainder were written specifically to support this product. + +Each support routine follows generally-acknowledged practices of Z-System Utilities, including built-in Help, and re-execution with the `GO` command. + +Help is accessed by typing the name of the desired routine followed by a double-slash (e.g. `LDSYS //`). Additional information is provided in the following sections of this manual. + +Some of the features of B/P Bios are supported with Version-dependent programs. These vary among specific systems and should not be intermingled if you support a number of different computer types. Contact us if you need to create such a specific tailored version of one of these programs. In the following descriptions, the routines which are restricted to a specific system or which require tailoring are so annotated. + + +## 6.1 BPBUILD - System Image Building Utility + +The purpose of BPBUILD is to create a loadable System Image. Input files needed by this utility include the output of assembling the `BPBIO-xx` file (in Microsoft relocatable format), a `.REL` or `.ZRL` image of an Operating System (ZSDOS for unbanked or ZSDOS2 [`ZS203.ZRL` or `ZS227G.ZRL`] for fully banked systems are recommended), and a `.REL` or `.ZRL` image of a Command Processor (`ZCPR33.REL` for unbanked, `Z41.ZRL` for fully banked systems are recommended). + +BPBUILD is capable of incorporating many types of operating system components into the executable image. Among systems tested are customized BIOSes, ZRDOS, CP/M 2.2, ZCPR2, ZCPR3x and others. One restriction in any segment occurs in the use of Named COMMONs for locating various portions of the system within the processor's memory map. Most assemblers and linkers are limited in the number of different named COMMON bases which can be supported. The linker incorporated in BPBUILD can handle only the following named COMMONs: `_ENV_`, `_MCL_`, `_MSG_`, `_FCB_`, `_SSTK_`, `_XSTK_`, `_BIOS_`, `BANK2`, `B2RAM`, and `RESVD`. + + +### 6.1.1 Using BPBUILD + +BPBUILD operates with layered Menus and may be invoked to build a replacement for an existing Image file, or with defaults to construct a totally new Image file. All files needed to construct the desired image; Bios, Dos, and CPR must reside in the current Drive and User Area, or be accessible via the PUBlic attribute if operating under ZSDOS. The syntax for BPBUILD is: + +| Command | Description | +| :--- | :--- | +| `BPBUILD` | Generate system w/ defaults | +| `BPBUILD fn[.ft]` | Make/Modify a specific system (Default type is `.IMG`) | +| `BPBUILD //` | Display this Message | + +It should be noted that if ZSDOS2 is the selected Dos, Bit Allocation buffers for Hard Drives are located in the System Bank. + + +### 6.1.2 Menu Screen Details + +Upon starting BPBUILD, you will be presented with the main menu screen. From this screen, you may select one of the three main categories to tailor the output image. At any point in the configuration, pressing Control-C or ESCape will exit the menu and return to the Command Processor prompt. + +```generic +/---------------------------------------------------------------------------\ +| Main | +| | +| | +| 1 File Names | +| | +| 2 BIOS Configuration | +| | +| 3 Environment | +| | +| Selection : | +\---------------------------------------------------------------------------/ +``` + + +#### 6.1.2.1 Screen 1 - File Names + +Selecting option One from the main menu will present a screen listing the current file names for the three input files needed to build an image, and the name to be applied to the output file. If BPBUILD was executed with the name of an existing Image file, the file names will be those of the files used to build the specified Image file, otherwise it will be default names furnished by BPBUILD. A sample screen for a non-banked YASBEC system might be: + +```generic +/---------------------------------------------------------------------------\ +| Files (1.1) | +| | +| | +| 1 Command Processor File : ZCPR33 .REL | +| | +| 2 Operating System File : ZSDOS .ZRL | +| | +| 3 B/P Bios Source File : B/P-YS .REL | +| | +| 4 B/P Executable Image : BPSYS .IMG | +| | +| Selection : | +\---------------------------------------------------------------------------/ +``` + +Selecting any one of the four options will allow you to change the name of the file to use for the desired segment. Default File types exist for each entry with both the Command Processor and Operating System files defaulting to `.ZRL` if no type is entered. The Bios file defaults to `.REL`, while the Image output file defaults to `.IMG`. + + +#### 6.1.2.2 Screen 2 - BIOS Configuration + +Selecting BIOS Configuration from the Main Menu (Selection 2) presents the basic screen from which the sizes and locations of either existing system segments (if building from an existing IMG file) or default values from within BPBUILD. A sample screen might appear as: + +```generic +/---------------------------------------------------------------------------\ +| Environment (2.1) | +| | +| COMMON (Bank 0) MEMORY BANK 2 MEMORY | +| ---------------------- ------------------------ | +| A Common BIOS - D400H E Banked BIOS - 0000H | +| Size - 83 Size - 0 | +| B Common BDOS - C600H F Banked BDOS - 0000H | +| Size - 28 Size - 0 | +| C Command Proc - BE00H G Command Proc - 0000H | +| Size - 16 Size - 0 | +| D User Space - E900H H User Space - 0000H | +| Size - 6 Size - 0 | +| | +| Selection : | +\---------------------------------------------------------------------------/ +``` + +While the ability to dictate locations and sizes for various system sizes is provided at this point, we urge you not to alter the values for Bank 2 Memory unless you are VERY familiar with the potential effects and willing to risk potentially disastrous consequences. The primary reason for including this screen was to allow setting Common Memory base locations and to dictate the size of the Resident User Space. Other than specifying the Common User Space size (the starting location defaults to the address in `Z3BASE.LIB`), the remaining values were included primarily for the few specialized users who require custom system locations. + + +#### 6.1.2.3 Screen 3 - Environment Configuration + +Since the Environment Descriptor is an integral part of the Operating System due to the specification of low-level parameters such as memory allocations, this screen is provided to configure the memory map in a suitable fashion for the system being built. For example, in a Fully Banked system with ZSDOS2, there is normally no need for a Resident Command Processor. Using this screen then, selection D may be used to indicate that no space is used for the RCP by setting its location and size to zero. With this space freed, the IO Package (Selection C) may be raised to F400H, keeping its size at 12 records. Since these are the two lowest segments in the memory map, BPBUILD will use this as the lowest value used in the Environment, and move the Operating System segments (including the Resident User Space) up in memory for an increase of 2k bytes in Transient Program Area. + +It is important to note that the Environment Descriptor defined in this screen is stored in a special area within the IMG file produced and placed in memory by LDSYS when activated. Any alteration after loading, for example loading another ENV file as part of the STARTUP script may cause the system to operate incorrectly. + +```generic +/---------------------------------------------------------------------------\ +| Environment (3.1) | +| | +| A - Environment - FE00H F - Named Dirs - FC00H | +| Size (# recs)- 2 # of Entries - 14 | +| B - Flow Ctrl Pkg - FA00H G - External Path - FDF4H | +| Size (# recs)- 4 # of Entries - 5 | +| C - I/O Package - EC00H H - Shell Stack - FD00H | +| Size (# recs)- 12 # of Entries - 4 | +| D - Res Cmd Proc - F200H Entry Size - 32 | +| Size (# recs)- 16 I - Msg Buffer - FD80H | +| E - Command Line - FF00H J - Ext. FCB - FDD0H | +| Size (bytes) - 208 K - Ext. Stack - FFD0H | +| | +| Selection : | +\---------------------------------------------------------------------------/ +``` + +When all configuration or inspection activity is complete at any menu, entering a return with no selection will return to the previous menu screen (Main menu from lower screens), and will start the build activity if a single return is entered from the main menu. All specified files are first read to determine their sizes, and internal memory address calculations are performed. You will be asked if you desire BPBUILD to use optimal addresses for the maximum amount of Transient Program Area (AutoSize), or use the values which were specified in menu 2.1. If you enter N at this point, the build will progress under the assumption that you want to use the values from Menu 2.1. A second prompt will ask you if you want to build a system of "standard" segment sizes. This refers to the CP/M 2.2 standard sizes of 16 records (2k) for the Command Processor and 28 records (3.5k) for the Basic Disk Operating System (BDOS). If you answer Yes, AND the segments are equal to or less than these sizes, the system will be built to reflect these system segment sizes. Since many ill-behaved, but very popular, programs assume the old CP/M segment sizes, this option should generally be used. If the autosize query is selected, BPBUILD automatically executes to completion and returns to the Command Processor prompt. + +To obtain the maximum Transient Program Area with "standard" segment sizes, the easiest method is to execute BPBUILD exiting with the Autosize query answered in the affirmative (Yes), then execute BPBUILD again on the produced image answering the first query with N for No Autosizing, and the second query with a Y to adjust the lower segment sizes for "standard" segment locations. While this is a somewhat cumbersome procedure, it results in a much smaller and faster running utility than otherwise possible, and was a design tradeoff in the development process. + + +## 6.2 BPCNFG - Configuration Utility + +The flexibility of the B/P Bios architecture permits customizing to your system and desired methods of operation. This utility consolidates some of the more common and important tailoring features in a single utility. BPCNFG, the B/P Bios Configuration Utility, provides an easy, menu-driven means of tailoring Hard and Floppy Drive Boot Sector images, Relocatable Image (`.IMG`) files, and certain elements in an executing system. Using BPCNFG reduces the need to assemble a new Bios image for simple changes, and increases the speed with which changes can be made. + + +### 6.2.1 Using BPCNFG + +BPCNFG syntax follows the standard conventions summarized in Section 1.2, and responds to the standard help option sequence of two slash characters. The syntax under which BPCNFG is invoked is dictated by the type of system you wish to configure. The BPCNFG Syntax is: + +| Command | Description | +| :--- | :--- | +| `BPCNFG //` | Print Built-in Help Summary | +| `BPCNFG` | Run interactive, screen mode | +| `BPCNFG *` | Configure Executing System | +| `BPCNFG d[:]` | Configure Drive "d" | +| `BPCNFG [du:]filename[.typ]` | Configure Image File | + +The first form of the syntax is self-explanatory and simply prints a short help file listing the purpose of the utility and the syntax of the program use. The Interactive mode of operation, execution of BPCNFG with no arguments, will first ask you whether you wish to configure a Memory, Disk or Image version of a B/P Bios system, and set internal parameters to that mode, as well as loading the requisite data if needed. If no file type is specified for an Image file, a type of `.IMG` is assumed. + +BPCNFG may configure options in the currently operating system with some limitations. The most significant limitation is that Hard Drive partitions may not be altered since space for the required bit buffers (ALV and CSV) is allocated at system load (boot) time and cannot be reset when a system is already installed. With this exception, all other parameters may be varied and will be in effect until another system is loaded by Cold Booting the computer, or loading an Image file with LDSYS. + +To abort the BPCNFG without changing current parameters, press either ESCape or Control-C from the main menu display. Option setting will occur if a Carriage Return only is entered from the Main Menu Screen. + + +### 6.2.2 Menu Screen Details + +BPCNFG is a Screen-oriented support routine using the terminal attributes defined in the currently installed Termcap. Five main screens are currently defined at the main menu, with several selections resulting in sub-menu screens. The first is the main menu from which the general category is selected for alteration. The top screen line reflects the level and mode as: + +```generic +/---------------------------------------------------------------------------\ +| Main Menu - Configuring Image File [A10:T1.IMG ] | +| Bios Version 2.0 | +| | +| 1 System Options | +| | +| 2 Character IO Options | +| | +| 3 Floppy Subsystem Options | +| | +| 4 Hard Disk Subsystem Options | +| | +| 5 Logical Drive Layouts | +| | +| | +| Enter Selection : | +\---------------------------------------------------------------------------/ +``` + +Each of the five selections results in a sub-menu screen which depicts the specific elements which may be changed and the current values/settings. Each of the selection screens is detailed below. + + +#### 6.2.2.1 Screen 1 - System Option Parameters + +The System Options may be set from Menu Screen 1 which may appear as: + +```generic +/---------------------------------------------------------------------------\ +| Menu 1 - System Options | +| | +| | +| 1 System Drive = A: | +| | +| 2 Startup Command = "START01 " | +| | +| 3 Reload Constant = 23040 (5A00H) | +| | +| 4 Processor Speed = 9 MHz | +| | +| 5 Memory Waits = 0, IO Waits = 0 | +| | +| | +| Enter Selection : | +\---------------------------------------------------------------------------/ +``` + +The Logical System drive selected by the first entry is used by the Bios Warm boot to load the operating system on a Cold boot, and on Error Exits. The Startup command is normally the name of a `.COM` file which performs additional system initialization when first started. Such a file is normally created by entering a sequence of instructions (file names and arguments) into a script using ALIAS, SALIAS, VALIAS or other similar ZCPR3 tool. + +The remainder of the entries concern the Physical hardware within the computer and generally do not need to be changed for other than initial installation. The Reload Constant at Selection 3 may be "fine tuned" by slightly varying the value. The normal effect of this is to adjust the speed of the Real Time clock within the computer to allow it to keep proper time. The Processor Speed (Selection 4) should be the CPU Clock speed rounded to the nearest MegaHertz. For example, the rate shown in the sample screen is, in fact, 9.216 MHz. When the Clock Speed is changed, an option is offered to automatically scale the Reload Constant (Selection 3) to scale it by a proper factor based on the amount that the Clock Frequency was changed. This is not always needed, but is generally desirable in HD64180/Z-180 systems using an interrupt clock timer. + +The number of Memory and IO Waits at Selection 5 are in addition to any Wait states inserted automatically in the hardware. For example, the Zilog Z180 inserts one wait state into all IO Port addresses. Since BPCNFG is a general purpose utility, it cannot know this. The number set with this selection is therefore in addition to any hardware injected wait states. + +A sixth menu also exists, but since inadvertent alteration of its values can result in bizarre and potentially destructive consequences, its existence is hidden and prompted if selected. The interaction to select option 6 is: + +```generic +Enter Selection : 6 +-- This is DANGEROUS...Proceed? (Y/[N]) : +``` + +If an explicit Y is entered, the hidden menu is displayed appearing as follows for a YASBEC with the MEM4 addressing PAL which allows the full 1 Megabyte range to be used: + +```generic +/---------------------------------------------------------------------------\ +| Menu 1.1 - System Bank Numbers | +| | +| | +| 1 TPA Bank # = 1 | +| | +| 2 System Bank # = 3 | +| | +| 3 User Bank # = 4 | +| | +| 4 RAM Drive Bank # = 5 | +| | +| 5 Maximum Bank # = 31 | +| | +| | +| Enter Selection : | +\---------------------------------------------------------------------------/ +``` + +The bank numbers should reflect the Physical 32k bank numbers in the system progressing from the lowest, or first available, to the highest. The Bank numbers are Zero-based, and may range from 0 to 255 (0FFH). The User Bank and RAM Drive Banks may be set to Zero if No Banked User area or RAM Drive respectively is desired. It should be noted that the actual control for these two features is in other screens, and setting the Bank Numbers to Zero while the options are active can have adverse consequences. + + +#### 6.2.2.2 Screen 2 - Character IO Parameters + +Screen Menu 2 allows configuration of the Character IO subsystem, to include assignment of logical devices to physical devices. A sample screen for the YASBEC might appear as: + +```generic +/---------------------------------------------------------------------------\ +| Menu 2 - Character IO Options | +| | +| | +| 1 IOBYTE Assignment: | +| Console = COM2 | +| Auxiliary = COM1 | +| Printer = PIO | +| | +| 2 COM1 - 9600 bps, 8 Data, 1 Stop, No Parity, [In(8)/Out(8)] | +| | +| 3 COM2 - 19.2 kbps, 8 Data, 1 Stop, No Parity, [In(7)/Out(8)] | +| | +| 4 PIO1 - [Out(7)] | +| | +| 5 NULL - [In(8)/Out(8)] | +| | +| 6 COM3 - 38.4 kbps, 8 Data, 1 Stop, No Parity, [In(8)/Out(8)] | +| | +| 7 Swap Devices | +| | +| Enter Selection : | +\---------------------------------------------------------------------------/ +``` + +Selection 1 determines which of the active devices is assigned to the addressable functions dictated by the IOBYTE. This location in memory is used by the operating system for Character IO normally consisting of the Console, Printer (List Device in CP/M terminology) and an Auxiliary IO (Reader and Punch in CP/M). The exact Devices assigned to these Logical functions depends on the bit-mapped characteristics of the IOBYTE, and positioning within the table portrayed in this Menu. + +Early versions of B/P Bios (Versions 1.0 and earlier) distributed as "Starter Systems" and test versions used a fixed number of devices and a different data structure for device access. B/P Bios Production systems with Version numbers of 1.1 through 1.9 will contain only four device drivers, but use the newer data structures. Beginning with Version 2.0, however, many Character Devices may be accommodated, with the first four being directly accessible by the IOBYTE, and the ability to exchange devices to place any four in the first positions for access by applications programs. The above screen depicts a typical display under a Version 2.0 Bios. Smaller systems such as placed on the Boot Tracks will use only four fixed devices with a typical Version Number of 1.1 and will not include selections 6 or 7. + +Selection 1 offers the opportunity to select which of the first four physical devices is assigned to the three logical IOBYTE defined functions. A secondary menu will prompt you for the exact functions and devices. An example of the interaction with selection 1 is: + +```generic +Set [C]onsole, [A]uxiliary, or [P]rinter : C + Set Com[1], Com[2], [P]io, or [N]ull ? +``` + +Selections 2, 3 and 6 in this sample screen allow configuration of the serial ports included in this B/P Bios. If you are making hardware changes in the Bios, please follow the specifications in the source code to insure that this utility will function as described. For most system installations covered to date, one or more of these options will have no effect, but the capability still exists to configure the option. This selection results in a series of options being presented for verification or alteration. Current settings are listed as default values which will remain selected if no entry is made before the ending Carriage Return (Enter key). A Sample interaction on a YASBEC is: + +```generic +Configuring COM1 [In(8)/Out(8)]: + Baud Rate (Max=38.4 kbps) = Selections are: + 1-134.5 bps 2-50 bps 3-75 bps 4-150 bps + 5-300 bps 6-600 bps 7-1200 bps 8-2400 bps + 9-4800 bps 10-9600 bps 11-19.2 kbps 12-38.4 kbps + Select [10] : + Data = 8-bits. Change? (Y/[N]) : + Stop Bits = 1-bits. Change? (Y/[N]) : + Parity = None Change? (Y/[N]) : + XON/XOFF Flow = No Change? (Y/[N]) : * Defaults selected + RTS/CTS Flow = No Change? (Y/[N]) : + Input is 8-bits. Change? (Y/[N]) : + Output is 8-bits. Change? (Y/[N]) : +``` + +Selection four tailors the default parallel port, normally a Centronics printer interface. As with previous selections, not all options may be active, but will appear in the configuration sequence to retain the generality of BPCNFG. Current settings (in braces) will be retained if a Carriage Return is entered. + +```generic +Configuring PIO1 [Out(7)]: + XON/XOFF Flow = No Change? (Y/[N]) : + RTS/CTS Flow = No Change? (Y/[N]) : + Output is 7-bits. Change? (Y/[N]) : +``` + +The final selection (only appearing in Bios Versions 2.0 and later) allows the exchange of devices. In the sample Menu 2, Selections 2-5 are active devices, with Selection 6 existing in the Bios, but not accessible. Using the last selection, COM3 could be exchanged with one of the first four making it an active device upon exiting BPCNFG which calls the Device Configuration function. The interaction may appear as: + +`Exchange Device : 3 With Device : 6` + +After this choice, active devices will be COM1, COM3, PIO1 and NULL. + + +#### 6.2.2.3 Screen 3 - Floppy Disk Parameters + +Extensive tailoring of the Floppy Disk subsystem is possible at this Screen. While many popular systems do not support all options (mainly due to the Controller logic), all options and respective settings will appear to be set at this point. Also, while such items as the Step rate will accept increments of a set size (1 mS for Step Rate), many systems have discrete increments that do not match allowable values. For example, the SMS 9266 used in MicroMint's SB-180 will only accept 2 mS increments with 5 1/4" Floppy Drives, the WD 1770 used in the Ampro Little Board only steps at 6, 12, 20 and 30 mS, while the 1772 used in the YASBEC permits 2, 3, 5, and 6 mS Steps. The rates set with BPCNFG are suitably rounded up to the most appropriate rate within the Bios code during drive selection to allow tailoring of drives in a generalized manner. Options tailorable for Floppy Disk drives as seen on a YASBEC are: + +```generic +/---------------------------------------------------------------------------\ +| Menu 3 - Floppy Disk Options | +| | +| | +| 1 Floppy Drive Characteristics: | +| Drv0 = 3.5" DS, 80 Trks/Side | +| Step Rate = 3 mS, Head Load = 4 mS, Unload = 240 mS | +| Drv1 = 5.25" DS, 40 Trks/Side | +| Step Rate = 4 mS, Head Load = 24 mS, Unload = 240 mS | +| Drv2 = 5.25" DS, 80 Trks/Side | +| Step Rate = 3 mS, Head Load = 24 mS, Unload = 240 mS | +| Drv3 = 5.25" DS, 80 Trks/Side | +| Step Rate = 6 mS, Head Load = 24 mS, Unload = 240 mS | +| | +| 2 Motor ON Time (Tenths-of-Seconds) : 100 | +| | +| 3 Motor Spinup (Tenths-of-Seconds) : 5 | +| | +| 4 Times to Try Disk Operations : 4 | +| | +| | +| Enter Selection : | +\---------------------------------------------------------------------------/ +``` + +Selecting one of the four items on this menu will prompt you for the information needed, allowing you to retain current settings as a default. An example of the additional prompts resulting from selection one on the above screen is: + +```generic +Configure which unit [0..3] : 2 + Size 8"(1), 5.25"(2), 3.5"(3)? [2] : + Single or Double-Sided Drive ? (S/[D]) : + Motor On/Off Control Needed ? ([Y]/N) : + Motor Speed Standard or Hi-Density ([S]/H) : + Tracks-per-Side (35,40,80) [80] : + Step Rate in Milli-Seconds [3] : + Head Load Time in Milli-Seconds [24] : + Head Unload Time in Milli-Seconds [240] : +``` + + +#### 6.2.2.4 Screen 4 - Hard Disk Parameters + +The B/P Bios Hard Disk Subsystem is centered around the Small Computer Systems Interface (SCSI) standard. Backward compatibility with the earlier Shugart Associates System Interface (SASI) is also provided to allow older controllers to be used. During the course of B/P Bios development, several controller types were incorporated, with unique features accommodated in a transparent way within the utilities. As a compromise between flexibility and program size, a limit of three physical hard drive units was placed on the system. This limit does not impact the 16 possible logical drives which the computer may handle. A sample Menu for a single Conner CP-3100 SCSI Drive of 100 Megabytes is: + +```generic +/---------------------------------------------------------------------------\ +| Menu 4 - Hard Disk Options | +| | +| 1 Hard Drive Controller = Conner SCSI | +| | +| 2 First Drive : Physical Unit 0, Logical Unit 0 | +| No. of Cylinders = 776, No. of Heads = 8 | +| | +| 3 Second Drive : - inactive - | +| | +| 4 Third Drive : - inactive - | +| | +| | +| Enter Selection : | +\---------------------------------------------------------------------------/ +``` + +The first available selection allows you to select the type of controller installed or used in the system. The controller definition applies across all three physical drives, so some care must be applied in mixing different controller types on the same system. For example, a Shugart 1610-3 controller is incompatible with a Seagate SCSI or SCSI-2 drive attached directly to the SASI bus since initialization information is required of drives on the 1610-3 which must not be sent to the SCSI due to the differing commands. The controller types defined in the initial release of B/P Bios appear in Selection 1 as: + +```generic + Select Controller Type as: + (0) Owl + (1) Adaptec ACB-4000a + (2) Xebec 1410a/Shugart 1610-3 + (3) Seagate SCSI + (4) Shugart 1610-4/Minimal SCSI + (5) Conner SCSI + (6) Quantum SCSI + +Enter Selection : +``` +(more added in later versions) + +Selections two, three and four from Menu 4 allow you to specify the physical parameters of one of the three possible drives. As with other options, some of the parameters do not apply, such as Reduced Write and Precompensation with SCSI drives, but appear here to allow a general configuration tool. Current settings appear in square braces and are selected if only a Carriage Return is entered. A sample entry configuring the Conner CP-3100 is: + +```generic +Activate Drive ([Y]/N) ? +Physical Unit (0..7) [0] : +Logical Unit Number (0..7) [0] : +Number of Physical Cylinders [776] : +Number of Heads [8] : +Reduced Write Starting Cylinder [0] : +Write Precomp. Start Cylinder [0] : +``` + + +#### 6.2.2.5 Screen 5 - Partition Parameters + +Menu 5 permits arranging the physical drive complement into Logical Drives, and dividing physical units into multiple logical Partitions. + +```generic +/---------------------------------------------------------------------------\ +| Menu 5 - Logical Drive Layout | +| | +| A: = Unit 0, 64 Sctrs/Trk, 4k/Blk, 7984k (998 Trks), 1024 Dirs | +| B: = Unit 0, 64 Sctrs/Trk, 4k/Blk, 20000k (2500 Trks), 1024 Dirs | +| C: = Unit 0, 64 Sctrs/Trk, 4k/Blk, 20000k (2500 Trks), 1024 Dirs | +| D: = Unit 0, 64 Sctrs/Trk, 4k/Blk, 54432k (6804 Trks), 2048 Dirs | +| E: = Floppy 0 | +| F: = Floppy 1 | +| G: = Floppy 2 | +| H: = -- No Drive -- | +| I: = -- No Drive -- | +| J: = -- No Drive -- | +| K: = -- No Drive -- | +| L: = -- No Drive -- | +| M: = RAM | +| N: = -- No Drive -- | +| O: = -- No Drive -- | +| P: = -- No Drive -- | +| | +| 1 Swap Drives, 2 Configure Partition 3 Show Drive Allocations | +| | +| | +| Enter Selection : | +\---------------------------------------------------------------------------/ +``` + +Selection 1 allows for swapping two specified logical drives. For example, the above screen shows a system which will boot from a hard drive. If the system were being configured for a Floppy-based system you might swap drive A with drive E with Selection 1 as: + +```generic + Enter Selection : 1 +Swap drive [A..P] : A with drive [A..P] : E +``` + +Selection 2 permits defining logical partitions on a Hard drive, and of the RAM drive, if active. It queries you for the needed information from which to set internal Bios values. If converting from an existing system, SHOWHD (See 6.19) will display the values to enter for a specified Partition. An example of the interaction is: + +```generic +Configure which Drive [A..P] : D +Allocation Size (1, 2, 4, 8, 16, 32k) [4] : + Number of Dir Entries [2048] : + Starting Track Number [6000] : + # Tracks in Partition [6804] : + Physical Unit Number [0] : +``` + +Selection 3 from Menu 5 may be used in conjunction with the allocation to view the existing allocations for a given Hard Drive Unit. Selecting 3 prompts you for the Desired Hard drive as: + +`Display Allocations for which Hard Drive [0..2] :` + +and will show the current Partitions and allocations. As an example, the four partitions on the Conner CP-3100 depicted in the Menu 5 screen are reported here on a separate screen as: + +```generic +/---------------------------------------------------------------------------\ +| Partition Data Hard Drive Unit : 0 | +| | +| Drv Start Trk End Trk | +| | +| A 2 999 | +| B 1000 3499 | +| C 3500 5999 | +| D 6000 12803 | +| [any key to continue] | +\---------------------------------------------------------------------------/ +``` + + +### 6.2.3 NOTES Spring 2001 + +A new menu item was added to the primary screen to allow configuration from a script configuration (`.CNF`) file. The format is explained in the built-in help. + + +## 6.3 BPDBUG - B/P Bios Debug Utility + +This utility provides a low-level tool patterned after Digital Research's DDT, but extended to provide a more useful user interface, the ability to handle Z80 and Z180 mnemonics in disassembly, and memory banking using B/P Bios interfaces. While the description is primarily oriented to screen output, the Operating system permits also sending output to the defined Printer by toggling Control-P which may be enabled and disabled within BPDBUG. + +### 6.3.1 Using BPDBUG + +The syntax for BPDBUG is simple with only three variants as: + +| Command | Description | +| :--- | :--- | +| `BPDBUG //` | Print a short help message | +| `BPDBUG` | Execute BPDBUG | +| `BPDBUG [fn[.ft]]` | Execute BPDBUG, Loading named file | + +When executed, BPDBUG relocates the majority of the code to high memory immediately below the BDOS, overwriting the Command Processor. If a file load is specified as in the third method of invocation shown above, and the file type is `.HEX`, then a file in Intel HEX format is assumed and it is converted to binary form at the specified address. + +In addition to the short help message available with the double-slash option, a built-in command summary is available at all times from the main BPDBUG prompt by entering a Question Mark. The summary appears as: + +```generic +/---------------------------------------------------------------------------\ +| B/P Bios DBug V 0.3 | +| -? | +| | +| Available commands: | +| B{ank} Bank# | +| D{ump} [From [To]] | +| E{nter} Addr | +| F{ill} Start End Byte | +| G{o} Addr | +| H{ex sum/diff} Word1 Word2 | +| I{nput} Port# | +| L{ist} [From [Thru]] | +| M{ove} Start End Dest | +| N{ame} FN[.FT] {for Read/Write} | +| O{utput} Port# Byte | +| R{ead file} [Offset] | +| T{race} {Trace mode On} | +| U{ntrace} {Trace mode Off} | +| W{rite file} Number_of_128-byte_blocks | +| X {set breakpoint} Addr | +| Z{ero breakpoints} | +| ? {Show this msg} | +\---------------------------------------------------------------------------/ +``` + +Square braces in the summary indicate optional parameters, while text strings and abbreviated names indicate parameters and types. + + +### 6.3.2 BPDBUG Commands + + +#### 6.3.2.1 Select Memory Bank _[ B ]_ + +To select a memory bank in the range of 0..255, simply enter the Command "B" followed by the bank number in Hexadecimal. Optional spaces may be placed between the command letter and the Bank number. The syntax for this command is: + +`B[ ]nn` + +The Bank number selected by this command will be made the current bank for Display (D), Enter (E) and List (L) commands. If the specified bank number exceeds the largest bank number physically existing in the system, the bank number will be set to the last bank defined in the B/P Bios Header. + + +#### 6.3.2.2 Dump (Display) Memory in Hex and Ascii _[ D ]_ + +This command displays memory contents in both hexadecimal and ascii form. Where the current byte in the display is a control character (less than 20H), a period character is printed in the ascii column. + +Defaults for this command are 100H and the TPA bank as the starting address, and 256 as the number of bytes to display if no End Address is specified. For subsequent uses of the Dump command, the Starting address will be one more than the ending address of the last Dump. The Bank Number will remain that last specified, or the TPA bank if never changed in a session. The syntax is: + +`D[ ][Start_Addr] [End_Addr]` + +A sample of the output appearing on the screen is: + +```generic +-d100 12f +01:0100 ED73 FE03 31FE 0321 5D00 7E23 FE2F 2006 .s..1..!].~#./ . +01:0110 BE11 AD01 2825 2A01 002E 5A7E FEC3 2018 ....(%*...Z~.. . +01:0120 CDAC 0121 FAFF 197E FE42 200C 237E FE2F ...!...~.B .#~./ +``` + + +#### 6.3.2.3 Enter Values in Memory _[ E ]_ + +This command permits entering values into memory. A period terminates entry. + +`E[ ][Start_Addr]` + +```generic +-e100 +:41 43 44 +:. +``` + + +#### 6.3.2.4 Fill Memory with Constant Value _[ F ]_ + +Entire memory areas may be set to a single constant value with this command. All three arguments (Start, End and Value) must be specified, and the command will not be executed if fewer arguments are given. The syntax is: + +`F[ ]Start End Value? + +As an example, the following command sets the sixteen bytes from 100H through 10FH in the currently selected bank to binary Zero; + +```generic +-f100 10f 0 +``` + + +#### 6.3.2.5 Go (Execute) Program in Memory _[ G ]_ + +Execution may be started at any arbitrary address with the "Go" command. If no target address is specified, 100H is assumed since it is the normal starting address of programs loaded into the Transient Program Area. The syntax of the command is: + +`G[ ][Address]` + + +#### 6.3.2.6 Hex Sum and Difference _[ H ]_ + +Simple Hexadecimal addition and subtraction is performed with the "Hex" command. When the command is executed with two addresses, both their sum (modulo 65536) and difference (also modulo 65536) are displayed in that order. The syntax of this command is: + +`H[ ]Value1 Value2` + +For example, if an offset of 45H from a base of 0ED3FH was desired, the resulting g positive and negative address could be determined as: + +`-hed3f 45` <-- Entered +`ED84 ECFA` <-- ..returned Sum and Difference + + +#### 6.3.2.7 Display Value from Input Port _[ I ]_ + +This command will read the desired Input Port in the range of 0 to 0FFFFH and display the resulting byte. Since 16-bit address calculations are used, this command will properly read the built-in ports of the HD64180 and Z180. The syntax of the Input command is: + +`I[ ]Port_num` + + +#### 6.3.2.8 List (Disassemble) Memory Contents _[ L ]_ + +Disassembly of executable instructions in memory is accomplished with this command. As with the "Dump" command, the starting address defaults to 100H when first loaded, and is assumed to be the instruction following the last one disassembled for subsequent uses of this command if no address is explicitly entered. If no Ending address is specified, 23-26 bytes will be contained in the listing depending on the length of the last instruction. The syntax is: + +`L[ ][Start] [End]` + +A sample of an entry and the resulting output with an arbitrary program is: + +`-l120 127` <-- Entered + +```generic +0120 CDAC01 CALL 01AC +0123 21FAFF LD HL,FFFA +0126 19 ADD HL,DE +0127 7E LD A,(HL) +``` +..displayed + +Note that the actual bytes included in the disassembled instructions are also listed in contrast to other similar programs to provide additional information for you. Additionally, an extra blank line is displayed after all unconditional jumps and returns to serve as a visual representation as an absolute change in control flow. The mnemonics are standard Zilog Z180 codes. + + +#### 6.3.2.9 Move Memory Contents _[ M ]_ + +This command permits blocks of data to be moved within memory. Memory address bounds checking is performed to insure that overlapping addresses are handled correctly so that minor shifts in blocks of data may be accomplished. The syntax for this command is: + +`M[ ]Start End Destination` + + +#### 6.3.2.10 Set File Name for Read/Write _[ N ]_ + +This command is used to set the file name and optional type prior to a read or write operation. The name remains active until changed or BPDBUG is exited. The syntax is: + +`N[ ]FileName[.FileTyp]` + + +#### 6.3.2.11 Send Value to Output Port _[ O ]_ + +This command forms the complement of the Input command covered above. It sends a specified byte to the addressed Output port. The syntax is: + +`O[ ]Port_num Value` + +As with all arguments, if more digits than the number needed are specified, only the last two (for a Byte) or four (for an address) are used in the expression. + + +#### 6.3.2.12 Read a File into Memory _[ R ]_ + +This command reads the file specified by the Name command into memory at the default address of 100H (if no offset is specified), or at a starting address of Offset+100H. The Offset value must be specified in Hexadecimal. The syntax of the Read Command is: + +`R[ ][Offset]` + +When the file is loaded, you will be informed of the current setting of the default address for the base of current memory (PC value) and the byte after the last one loaded by the Read Command (Next). The display might appear as: + +```generic +Next PC +0880 0100 +``` + +#### 6.3.2.13 Activate Trace Mode _[ T ]_ + +To assist in debugging programs, a Trace function is included which is activated with this command. Upon encountering a breakpoint (See X Command below) the program enters the Trace mode in which each instruction is trapped and the state of the processor displayed along with a Disassembled listing of the instruction. Entering a single letter "T" activates the Trace Mode. + +A fragment of a program run with Trace On is: + +```generic +S0Z0H0P0N1C0 A=00 BC=0000 DE=0000 HL=0000 SP=0100 + IX=A4AE IY=FFFE 0100 C30B01 JP 010B + +S0Z0H0P0N1C0 A=00 BC=0000 DE=0000 HL=0000 SP=0100 + IX=A4AE IY=FFFE 010B 2A0500 LD HL,(0005) +S0Z0H0P0N1C0 A=00 BC=0000 DE=0000 HL=52C3 SP=0100 + IX=A4AE IY=FFFE 010E CDBD07 CALL 07BD +S0Z0H0P0N1C0 A=00 BC=0000 DE=0000 HL=52C3 SP=00FE + IX=A4AE IY=FFFE 07BD 7C LD A,H +S0Z0H0P0N1C0 A=52 BC=0000 DE=0000 HL=52C3 SP=00FE + IX=A4AE IY=FFFE 07BE B5 OR L +S1Z0H0P0N0C0 A=D3 BC=0000 DE=0000 HL=52C3 SP=00FE + IX=A4AE IY=FFFE 07BF C8 RET Z +``` + + +#### 6.3.2.14 De-Activate Trace Mode _[ U ]_ + +This command turns the Trace Mode Off so that subsequent execution occurs at full speed with no trapping. Entering a single letter "U" deactivates the Trace Mode. + + +#### 6.3.2.15 Write File to Storage _[ W ]_ + +This command is the complement to the Read command covered above. It assumes that the data to be written starts at 100H and writes the specified number of 128-byte blocks to the file last specified with a "Name" command. The syntax of this command is: + +`W[ ]#Blocks` + + +#### 6.3.2.16 Set Breakpoint _[ X ]_ + +This command is used to tag locations within the program to be executed under BPDBUG which, when executed, will temporarily stop executing and either return to the BPDBUG prompt or print information for the Trace output. Up to two breakpoints may be active at any point in time. The syntax is: + +`X[ ]Address` + + +#### 6.3.2.17 Clear Breakpoints _[ Z ]_ + +This command clears all breakpoints set with the X command cited above. Entering the single letter "Z" clears all breakpoints. + + +#### 6.3.2.18 Display On-Line Help _[ ? ]_ + +Entering a single Question Mark ("?") as a command displays the Build-In help display containing a summary of the commands available from within BPDBUG. + + +## 6.4 BPFORMAT - Floppy Disk Format Utility + +BPFORMAT is the general-purpose format routine for Floppy Disk Drives in the B/P Bios system. It automatically adapts to the specific hardware used in your computer to present a single interface across a wide range of platforms, and incorporates the ability to format disks in formats not implemented in your computer. This capability allows you to format disks for exchange with other users in their native disk format using the same library of alien disk formats used by the EMULATE program (see 6.8). + +This program is B/P Bios-specific and will not function under other Bios systems. Its operation is the same under banked or unbanked systems, and with the many types of physical Disk Controller integrated circuits available. In the initial version, the following Controller types are supported: + +- 765 +- 1692 +- 1770 +- 1771 +- 1772 +- 1790 +- 1791 +- 1792 +- 1793 +- 1795 +- 2790 +- 8473 +- 9266 + +### 6.4.1 Using BPFORMAT + + +#### 6.4.1.1 Built-in Formats + +The simplest way of formatting diskettes is to use one of the formats included in the currently running B/P Bios. BPFORMAT may be invoked by simply entering the program name, or by following it with a drive letter and colon as: + +`BPFORMAT D:` + +Optionally, a Named directory may replace the drive letter and will format the drive associated with the named directory. For example, if a directory named WORK: is defined to be Drive C:, User 10, the command WORK: + +`BPFORMAT WORK:` + +would format Drive C:. When invoked in either of the above manners, BPFORMAT will list the built-in formats available for this drive from those included in the file `DPB.LIB` (and optionally `DPB2.LIB`, see sections 4.1 and 4.2). Only those formats which exactly match the drive characteristics will be presented, so only 80-track formats will be offered for an 80-track drive and so forth. For example, the offerings for a 40-track 5.25" disk drive may result in: + +```generic +Available formats are: + + A - Ampro DSDD B - Ampro SSDD + +Select format (^C to exit) : +``` + +As precautions against inadvertently formatting diskettes, confirmation prompts are included as the program progresses, and the opportunity exists to escape from the format program to Command processor. An example appears at this point where a Control-C aborts the format operation. + + +#### 6.4.1.2 Library Formats + +If formatting of a diskette is desired in a format not supported by the built-in selections featured in the executing Bios, the library of formats used by EMULATE (see 6.8) may be used. Reasons for using the library may range from the need to format in a mode used on another type of computer to a choice made internally unavailable by sizing constraints, as when tailoring a system for Boot Track installation. Whatever the reason, this flexibility is offered as an inherent feature of B/P Bios and is specified by specifying the L Option when invoking BPFORMAT. If specifying the desired drive on the command line as in either example above, simply add the option character at the end (with optional slash) as: + +`BPFORMAT D: L` + +If you wish to be prompted for the drive letter as part of the program flow, the slash becomes mandatory to inform BPFORMAT that you are specifying the Library option instead of Drive L:. The invocation thereby becomes: + +`BPFORMAT /L` + +When executed with the Library option, you will be presented with a menu of formats which may be used with the physical drive as defined in the Bios header. A sample display appears as: + +```generic +Available formats are: + + A - Actrx SSDD B - Ampro SSDD C - VT180 SSDD D - H-100/4 1D + E - H89/40 1S F - H89/40 1D G - H89/40 1X H - Kaypro 2 + I - Osborne 1S J - Osborne 1D K - Ampro DSDD L - H-100 DSDD + M - H89/40 2D N - H89/40 2X O - QC-10 DSDD P - Kaypro 4 + Q - MD-3 DSDD R - PMC-101 S - Sanyo 1000 T - TV 802/803 + U - XBIOS-3 2D V - XL-M180 T2 + +Select format (^C to exit) : +``` + +Entering one of the letters corresponding to a format will set all parameters and proceed with the format operation. Entering a Control-C at this point will return you to the Command Processor at this point avoiding any inadvertent disk formatting. + +The Assembly source to the Format library is provided in the B/P Bios package as an aid in accepting formats not included in the default distribution package, or to experiment with new formats. + + +### 6.4.2 Configuration + +Two options exist for custom tailoring BPFORMAT to operate in a method you find most comfortable. The first is a Quiet option which will minimize extraneous output to the Console. It is set by a Boolean flag consisting of a Byte at an offset of 22 (16H) bytes from the beginning of the program. A Zero byte in this location signifies Verbose operation where all defined prompts and status information is displayed. A Non-Zero value (normally 0FFH) indicates that Console output should be minimized with only essential output displayed. + +The second option is for selection of the File Name and Type to be used for the Library of formats used with the L option. The default value of this entry is `ALIEN.DAT` (in formatted FCB form) which is also used with the EMULATE program. This field begins at an offset of 23 (17H) bytes from the beginning of the program. + + +### 6.4.3 BPFORMAT Error Messages + +`Must be wheel to FORMAT!!!` + +As a safety feature, only users with Wheel privileges may format diskettes. This error message identifies an attempt without the proper authorization. + +`*** ERROR ! Not B/P Bios, or Old Version !` + +In most cases, this error will be seen if an attempt is made to format a disk under a Bios other than B/P Bios. If some of the mandatory data structures have been altered, or if an attempt is made to run the release version of B/P Bios under one of the early test versions of B/P Bios, this message will also be displayed. + +`*** ERROR ! The selected format is not supported by FORMAT!` + +This error will be displayed if a format from a library of formats is incompatible with the specified drive, such as if a 5.25" format is selected for an 8" drive. + +`*** ERROR ! The detected FDC is not supported by FORMAT!` + +The Bios reported a Floppy Disk Controller (FDC) that is not in the list of Controllers supported by BPFORMAT. To view the list of controllers supported, view the internal Help by using the double-slash option. + +`*** ERROR ! Disk is Write Protected!` + +An attempt was made with the Write Protect Tab ON (for 5.25"), OFF (for 8") or in the Protect position (3.5") for the specified disk. Set the disk to Read/Write by altering the physical setting and try to format the disk again. + +`*** ERROR ! Disk won't recalibrate` + +The drive heads could not be restored to Track 0 position. Thiserror is often due to a failure in the drive mechanism, but can also be caused by deformed diskettes or loose drive cable. + +`Format Error : xx` + +An error was detected during the format process. The "xx" will be the Hexadecimal byte returned by the Bios portion of the format routine, and bits set to a "1" value should represent an error code decipherable from the FDC Data or programming sheet. + +`+++ Can't Open : fn.ft` + +BPFORMAT could not open the format library file. To access a format library, it must either be in the default library, or accessible from it either via the PUBlic bit or along the ZSDOS path. + +`No formats available for this drive!` + +This error will be reported if no formats (internal or from a format library, depending on how it was invoked) are supported on the specified drive. For example, if all internal formats are for 5.25/3.5" drives and the target drive is specified as an 8" drive, then no formats will be available if BPFORMAT is invoked using the internal format method of operation. + + +## 6.5 BPSWAP - Logical Disk Swap Utility + +This utility allows you to exchange the drive letters defining two logical drives or partitions within the system. It performs any operations necessary to properly adjust the Operating System to account for drive redefinition, and relogs both drives using Dos Function 37 to force rebuilding of the Allocation Bit Map. + +BPSWAP is a B/P Bios utility and will not execute under any other system. It may be operated in an interactive mode, fully "expert" mode with arguments passed on the command line, or a combination where the first drive letter is passed on the command line and the second entered in response to a query. If running in the interactive mode, entering a Control-C instead of a drive letter will interrupt the program and return to the Command Processor. BPSWAP is re-executable under ZCPR with the `GO` command. + + +### 6.5.1 Using BPSWAP + + +#### 6.5.1.1 Interactive Operation + +To execute BPSWAP in the interactive query/response mode, simply invoke the program by entering its name as: + +`BPSWAP` + +The program will insure that the system is running a B/P Bios, gather internal data from the operating environment, and display the prompt: + +`First Drive to Swap [A..P] :` + +At this point, a drive letter (upper or lowercase) should be entered within the specified range of "A" through "P". All invalid characters, except for Control-C which aborts the program, will result in repeated prompts for the first drive letter. When a valid drive letter is detected, the second is likewise requested with the prompt: + +`Second Drive to Swap [A..P] :` + +BPSWAP responds to entries at this point in an identical manner to the first, repeatedly prompting for a valid letter, or the abort character. When a valid letter is received, each logical drive is reassigned to the physical definitions of the other. + + +#### 6.5.1.2 Command Line Operation + +BPSWAP can accept and parse drive letters passed to it on the Command Line in order to include drive exchanges in Startup scripts or other alias commands. To invoke the program in this manner, enter the program name with two drive letters in the range of "A" through "P" with a delimiter between each field. Each of the drive letters may be followed by an optional colon. Delimiting characters are Tab, Space, and Comma. A summary of the complete syntax is: + +`BPSWAP d1[:] | | d2[:]` + +To illustrate, the following are valid commands executing BPSWAP: + +| Command | Description | +| :--- | :--- | +| `BPSWAP A: E:` | Exchange E drive with A | +| `BPSWAP D,H` | Exchange D drive with H | + +If an invalid character is detected for either or both of the drive letters when called in the Command Line mode, operation automatically reverts to the Interactive mode and the respective prompt(s) will be given for valid drive letter(s). This feature permits a hybrid mode of operation to be specified wherein the first drive letter is passed on the Command Line, and the second entered in response to the second drive prompt. + + +### 6.5.2 BPSWAP Error Messages. + +The only error message which may be printed by BPSWAP is in response to internal routines which validate the presence of a B/P Bios. Any attempt to run this utility on other Bioses results in the error: + +`+++ Not B/P Bios ... aborting +++` + +after which point the program aborts and control returns to the Command Processor. No effect on drive allocations will occur if this error is displayed. + + +## 6.6 BPSYSGEN - System Generation Utility + +BPSYSGEN is our generic version of the classic SYSGEN program used to place an executable system image onto the boot sectors of a Floppy or Hard Disk. It uses information provided by the Bios in the form of DPB/XDPB data (see 5.2.3) which defines the physical and logical drive characteristics to write system information from the system tracks of one drive to another, or from an image produced by MOVxSYS (see 6.16) to the boot tracks of a drive. + + +### 6.6.1 Using BPSYSGEN + + +#### 6.6.1.1 Interactive Operation + +The basic Interactive mode is initiated by simply entering the program name at the Command Line prompt as: + +`BPSYSGEN` + +You will first be prompted for the source drive from where to obtain a bootable system image, then for a destination drive to save the image. To provide a visual clue that the program is executing, a series of periods is printed on the screen with each period representing a physical sector of data. At the conclusion of the operation, the program exits to the Command Processor prompt. + +A binary file produced by MOVxSYS (see 6.16) may be placed on the system tracks of a hard or floppy disk by specifying the file name as a command line argument as: + +`BPSYSGEN B:ZSDOS64.BIN` + +When activated in this manner, you will be prompted for the destination drive letter after BPSYSGEN loads the image file and validates it as a valid system image. Alternatively, you may replace the file name with a drive letter followed by a colon to automatically load the image from a specific drive, and be prompted for the destination drive. + + +#### 6.6.1.2 Command Line Operation + +A single operation may be completely specified from the command line arguments thereby avoiding drive prompts. When invoked in this manner, the first argument specifies the source for the system (drive designator or file) with the second argument being the drive specification on which to place the bootable system image. The syntax for the Command Line method of operation is: + +`BPSYSGEN {d: | fn[.ft]} d:` + + +### 6.6.2 BPSYSGEN Error Messages + +`*** Read Error` + +An unrecoverable error was encountered reading either the boot tracks of a drive, or a specified bootable file. + +`*** Bad Source!` + +The source drive does not exist or could not be selected. + +`*** Write Error` + +An unrecoverable error was encountered writing the boot tracks of the specified destination drive. + +`*** Bad Destination!` + +The destination drives does not exist or could not be selected. + +`*** No System!` + +There are no valid System Tracks on the Source or Destination Drive, or an anomalous condition (more than 3 reserved tracks) was detected. + +`*** Can't Open Source File!` + +The specified boot image file could not be located, or an error occurred during the attempted File Open. + + +## 6.7 COPY - Generic File Copy Utility + +`COPY.COM` is a file copy program derived from the ZCPR3 MCOPY tool written by Richard Conn. It blends the many modifications by Bruce Morgen, Howard Goldstein and others in MCOPY48 with further enhancements in the spirit of the ZSDOS environment. File date stamping is supported for the full range of stamping capabilities provided by ZSDOS. A user-definable "Exclusion list" is now supported to prevent copying of specific files or file groups, and two options to ease file backups with the Archive bit have been added. COPY is also more user-friendly than MCOPY, and provides increased error checking and user feedback. + +COPY only operates in the Command Line Driven or Expert mode. As with the other utilities provided with ZSDOS, COPY displays a short Help message when invoked with a double-slash argument as explained in Section 1.2. The Help message also includes a list of available options along with the effect of each when included as command line arguments. + +While COPY is ready to run without special installation procedures, you may wish to change the default parameters to customize it to your operating style. In this manner, you can minimize the number of keystrokes required to perform routine operations by avoiding passing many options on the command line. To set default conditions, insure that `COPY.COM`, `COPY.CFG` and `ZCNFG.COM` are available to the system, and execute ZCNFG as described in Section 4.8 of the ZSDOS 1.0 Manual. + + +### 6.7.1 Using COPY + +The basic syntax for COPY follows the original CP/M format by listing the destination drive/user, an equal sign, then the source drive/user and file name. An alternate syntax added by Bruce Morgen in MCOPY48 permits specifying transfers in the "Source-Destination" form popularized in MS-DOS. In this alternate form, you first enter the source drive/user and filename, a space, and then the destination drive/user and optional filename. Using the normal symbology, the syntax is summarized as: + +`COPY dir:[fn.ft]=[dir:]fn.ft,... [/]options` + +or + +`COPY [dir:]fn.ft dir:,... [/]options` + +If no destination filename is specified, a number of unique files may be copied to a specified directory by catenating source files separated with commas. Where a destination file name is specified, both source and destination file names and types must be free of wildcard characters. This popular "Rename" feature in a copy was a much requested addition to the ZSDOS copy utility. Options to tailor the actions of COPY may be appended after the source file list. + +Yet another method of transferring files was retained from the original MCOPY roots. If no destination drive/user is recognized in the command line arguments, all referenced files will be copied to a default drive/user location which is contained in the header portion of COPY. The default location is Drive B, User 0 in the distribution program, but may be changed as described below. If options are desired with this syntax, the slash option delimiter is mandatory. The syntax for this method is summarized as: + +`COPY [dir:]fn.ft,... /options` + +Various configuration options detailed later allow you to customize COPY to suit your operating style. For example, status displays of each operation may be suppressed for a "Quiet" mode, verification that copied files match the original (or at least produce the same error check code) may be enabled or disabled, etc. If a method of Date and Time Stamping is active under ZSDOS, the original Stamp information will be transferred to the destination file. The following examples in the "Verbose" method of operation will serve to illustrate by copying a file from the current Drive and User area to the same drive, User 10. + +```generic + COPY ZXD.COM 10: + +COPY Version 1.71 (for ZSDOS) +Copying C2:ZXD .COM to C10: + -> ZXD .COM..Ok (Dated) Verify..Ok + 0 Errors +``` + +In this case, No file of the same name existed in the destination area, but some form of File Stamping was active, so the source Stamp information was successfully transferred to the destination. Performing the same activity with the other syntax now produces: + +```generic + COPY 10:=ZXD.COM + +COPY Version 1.71 (for ZSDOS) +Copying C2:ZXD .COM to C10: + -> ZXD .COM Replace Same (Y/N)? Y..Ok (Dated) Verify..Ok + 0 Errors +``` + +Since COPY now detected a destination file of the same name, and File Stamping as well as duplicate checking (another option flag) were in effect, COPY compared the Last Modified dates for both source and destination files. Finding a match, the prompt "Replace Same" was issued, and received a (Y)es response to copy the file anyway. Other responses, depending on the results of the date comparison are "Replace Older", which means that an older file exists on the destination, and "Replace Newer" which means that you are trying to replace a newer file on the destination with an older version. + +A similar error check is made if a duplicate file is found to determine if the file was found with the PUBlic Attribute bit. If a Public file is detected on the destination drive, a warning to the effect is printed. Answering Yes to replacement at this point will result in a Read-Only error unless ZSDOS has been set to permit writes to Public Files (see 2.8.3 of the ZSDOS 1.0 Manual). + +As stated earlier, COPY has no Interactive mode of operation per se, but the Inspect option provides a means to select files for transfer in a somewhat interactive manner. In this mode, all files selected by the file specification in the command line are displayed, one at a time, and you may enter "Y" to copy the file, "N" to Not copy the file, or "S" to forget the rest of the selected files. An example copying all files from the current Drive and User to User 10 is: + +```generic + COPY *.* 10: /I + +COPY Version 1.71 (for ZSDOS) +Copying C2:????????.??? to C10: + Inspect -- Yes, No (def), Skip Rest +BU16 .COM - (Y/N/S)? Y +BU16 .MZC - (Y/N/S)? N +COPY .COM - (Y/N/S)? Y +COPY .Z80 - (Y/N/S)? S +``` + +If operating in the Verbose mode, status on each file will be printed as the copies progress. + + +### 6.7.2 COPY Options + +Several option characters are available to customize COPY operations. Most of these options may be set as default conditions using Al Hawley's ZCNFG Configuration Utility. Alternatively, you may enter any of them on the command line to alter the functions of a single operation. The command line option characters are as follows: + +| Option | Description | +| :---: | :--- | +| `A` | Archive | +| `E` | Test for File Existence | +| `I` | Inspect Files | +| `M` | Multiple Copy | +| `N` | No replacement if File exists | +| `O` | Test Existence of R/O Files on Destination | +| `Q` | Quiet | +| `S` | exclude System Files | +| `V` | Verify | +| `X` | Archive Only if File exists | + +From the brief syntax summaries listed above, you will note that the standard option delimiter, a slash, is optional if both source and destination specifications are listed on the command line. If only one specification is listed, is when copying to the default drive, the delimiter is Mandatory. Each option is described in the following paragraphs. + + +#### 6.7.2.1 Archive Option + +When this option is active either by specifying in the command line or as a default, only files which do Not have their Archive Attribute set will be selected. After the selected files are copied, the Archive Attribute on the Source file will be Set to indicate that the file has been "Archived". When used in conjunction with the default drive and user settings, the A option provides a simple method of archiving files in a single user area. The default for this option is Off, for No control of selection by the Archive Attribute. Adding the A option to the command line reverses the configured setting. + +It should be noted that this option is incompatible with the "M" (Multiple Copy) option. The first copy operation will set the Archive bits on selected files, and they will not appear in subsequent copies. + + +#### 6.7.2.2 File Existence Option + +This option controls the test for an already-existing file on the destination drive by the same name. Adding the E option to the command line argument reverses the configured setting. The default in the ZSDOS distribution version is On, or Check for Existing files. This option does not affect the check for PUBlic files on the destination drive, which is always active. + + +#### 6.7.2.3 Inspect Files Option + +As illustrated previously, the I option provides a means of selectively copying files, without entering the name of each file. The distribution default for this option is Off, or do Not inspect the selected file list. Specifying this option on the command line argument list reverses the configured setting. + + +#### 6.7.2.4 Multiple Copy Option + +This option may be used to copy a file, or group of files to the same drive several times, as when making several copies of the same file group on different disks. A prompt is given before each copy operation begins, and you may abort at the prompt, or change disks before beginning the copy. The distribution default for this option is Off, for No Multiple copying. Adding the M option to the command line argument list reverses the configured setting for this option. + + +#### 6.7.2.5 No Replacement Option + +When added as a command line argument, the N option will not allow replacement of a file which already exists on the destination Drive/User. This option cannot be configured, and always assumes the same initial state when COPY is called. The default initial state for this option is Off to permit replacement of existing files. + + +#### 6.7.2.6 Read-Only File Test + +This option, when added as an argument, reverses the configured setting of a flag which checks for the existence of file(s) satisfying the specified name and type with the Read-Only attribute set. If this flag is active and a Read-Only file is located satisfying the criteria, the file will not be automatically overwritten. The E (File Existence) flag will still dictate how other files are handled. + + +#### 6.7.2.7 Quiet Option + +When used on a system with ZCPR3, this option causes a reversal in operation of the ZCPR3 Quiet flag. If the ZCPR3 Quiet flag is active, COPY with the Q option operates in a Verbose mode. If you do not use ZCPR3, or the ZCPR3 Environment defines the Quiet flag as inactive, this option will disable unnecessary console messages for a Quiet mode of operation. There is no default condition for this option, and it is only effective for a single call of COPY. + + +#### 6.7.2.8 System Files Option + +This option controls whether or not files with the SYStem Attribute set will be located by COPY. The distribution default is Off to include SYStem files in COPY file lists and permit copying of such files. The default may be configured as described below, and the default may be reversed by adding an S in the command line option list. + + +#### 6.7.2.9 Verify Option + +To add a measure of confidence that no errors occurred in a COPY operation, the Verify option may be activated. When active, the destination file is read in order to compute a Cyclic Redundancy Check (CRC) word. This word is then compared to a value calculated when reading the source file. If the two values match, you can be reasonably sure that the destination file is a true copy of the source file. The distribution default for this option is True to verify each file copied. This option may be changed by configuration, or reversed by adding a V to the command line option list. + + +#### 6.7.2.10 Archive if Only if File Exists Option + +Occasionally, you may wish to update frequently archived files to the same destinations in a simpler manner than naming each file, or by using the Inspect option. The X option was created for just this purpose. When this option is added, COPY first searches the source directory for files which have not been archived, then checks the destination directory for each file. If a match is found, the file is copied, and the source file deleted, unless it is marked as Read-Only. There is No configurable setting for this option which is always assumed to be OFF when beginning COPY. + + +## 6.8 EMULATE - Alien Disk Emulation Utility + +EMULATE locks any or all Floppy Disk Drive(s) to specified formats, native or alien, from a Database of formats. It may also be used to display current settings and restore drives to auto-selection if the Bios was assembled with the AutoSelect option (see 4.2). The Floppy Disk format information is contained in a file named ALIEN.DAT whose use is shared with BPFORMAT (see 6.4). This sharing of a common database of formats allows formatting, as well as reading and writing of a large number of the hundreds of formats used by CP/M vendors over the years. + + +### 6.8.1 Using EMULATE + +This utility is only usable with B/P Bioses which have been assembled with the Auto-Select option (`AUTOSEL`) active. This is the normal mode for release versions of B/P Bios, although some versions placed on the boot tracks of floppy disks may have a scaled-down complement of built-in formats to reduce the system image size (see 4.3). EMULATE can be executed either in an interactive query/response mode or in a command line "expert" mode with arguments passed on the command line. The EMULATE syntax is: + +| Command | Description | +| :--- | :--- | +| `EMULATE //` | Print Built-in Help Summary | +| `EMULATE [/]X` | List Current Floppy Format Settings | +| `EMULATE [/]U` | Return All Floppies to Autoselect | +| `EMULATE` | Execute in interactive Query/Response mode | +| `EMULATE d[:]` | Select format of Drive d: interactively | +| `EMULATE d[:] [nn]` | Set Drive d: format to entry nn (expert) | + +To keep the numbering of formats in the Database file constant, thereby allowing the expert mode of configuration, all formats in the `ALIEN.DAT` file are loaded without validation against the actual drive parameters. Once a format is selected, the required drive characteristics (disk size, number of sides, speed and number of tracks) are compared to the physical drive parameters contained in the B/P Bios header structure (see 5.2.1, `CONFIG+35`). If the selected format can be accommodated by the physical drive, then the format information is loaded into the Extended DPH/DPB fields for the specified drive and the format locked to prevent re-assignment on warm boots. + +The following formats are currently included in the ALIEN.DAT file, the source code for which is included in the distribution version of B/P Bios as ALIEN.LIB: + +```generic + 1 Actrx SSDD 2 Ampro SSDD 3 VT180 SSDD 4 H-100/4 1D + 5 H89/40 1S 6 H89/40 1D 7 H89/40 1X 8 Kaypro 2 + 9 Osborne 1S 10 Osborne 1D 11 Ampro DSDD 12 H-100 DSDD +13 H89/40 2D 14 H89/40 2X 15 QC-10 DSDD 16 Kaypro 4 +17 MD-3 DSDD 18 PMC-101 19 Sanyo 1000 20 TV 802/803 +21 XBIOS-3 2D 22 XL-M180 T2 23 Ampro SSQD 24 DEC Rainbo +25 Eagle-IIE 26 H89/80 1D 27 H89/80 1X 28 Ampro DSQD +29 Amstrad WP 30 H89/80 2D 31 H89/80 2X 32 XBIOS-4 2Q +33 CCS SSDD 34 IBM 3740 35 Bower 8"1D 36 TTek SSDD +37 Bower 8"2D 38 CCS DSDD 39 TTek DSDD2 40 TTek DSDD1' +``` + +Current drive format allocations may be examined at any time with the X option which will list the 10-character name the format assigned to each floppy drive in the system, or state that it is Autoselecting. The U option removes all fixed formats, returning them to Autoselecting. + + +### 6.8.2 EMULATE Error Messages + +`+++ Can't Open Database File +++` + +EMULATE could not locate the `ALIEN.DAT` file in the currently logged directory. Solutions include setting the PUBlic attribute of `ALIEN.DAT` and insuring that the Dos Path includes the drive containing the file. + +`+++ Format Not Supported on this drive!` + +Self-explanatory. Common causes of this error are selecting an 80-track format on a 40-track drive, or an 8" format on a 5.25" drive. Check the `ALIEN.DAT` source code to determine any needed data on the exact drive requirements for each format. + + +## 6.9 HDBOOT - Hard Drive Boot Utility (tailored) + +HDBOOT is a specialized routine which is only available for those computers which feature the ability to boot from Hard Drives from a cold start such as the YASBEC and Ampro Little Board computers in the initial version. HDBOOT is a customized utility which is tailored for specific versions and will not execute on B/P Versions which it does not recognize. It modifies the boot record of a Floppy Disk System image placed on a drive by BPSYSGEN (see 6.6) to allow the system to be started from the Hard Drive at power-on or from a system Reset. + + +### 6.9.1 Using HDBOOT + +HDBOOT is extremely simple to use, and accesses the B/P Bios Data structures of the target system for any system-specific data required, such as initialization parameters for the Shugart/Xebec controller types. When invoked, the existing system is checked to insure that it is a valid B/P Bios version. If valid, you will be asked to specify which of the three possible physical SCSI units to access, and from there on the operation is automatic. A sample screen for a successful execution of this utility is: + +```generic +/---------------------------------------------------------------------------\ +| B/P HDBOOT Utility V1.0 31 Aug 92 | +| Copyright 1992 by H.F.Bower/C.W.Cotrill | +| | +| Configure which unit for Booting [0..2] : 0 | +| | +| Target Controller is : Seagate SCSI | +| ...Reading Boot Record... | +| ...Writing Boot Record... Ok.. | +| | +| A0:BASE>_ | +\---------------------------------------------------------------------------/ +``` + +It should be noted that a system must have been placed on the target unit with BPSYSGEN (see 6.6) before executing this utility, or an error message will be issued and the operation aborted. + + +### 6.9.2 HDBOOT Error Messages + +`*** No System!` + +The specified target Unit does not contain a valid Boot System. Place a valid Boot Track system on the unit with BPSYSGEN and execute HDBOOT again. + +`*** Invalid Unit Number ***` + +The Unit number specified on the command line is invalid. Either it is not "0", "1" or "2", or the unit is not active. + +`*** Invalid Boot Record ***` + +The Boot Record existing on the specified Unit is not valid for this type of Computer. Normal causes are no system currently exists on the specified unit or the system in place is not a valid one for this system. Both of these may be corrected by placing a system on the first physical partition of the unit with BPSYSGEN (see 6.6) + +`+++ Image is Not B/P Bios, or Wrong Version +++` + +The image read from the Boot Tracks of the specified system was not a valid version of B/P Bios. The two most common causes of this are; not placing a Boot System on the System Tracks with BPSYSGEN, or altering the fixed data structures of the Bios source code in a way which violates the standard layout resulting in a system which cannot be recognized. + +`+++ Unit Not Active! Run BPCNFG to Set Drives.` + +The specified Hard Drive Unit (0, 1 or 2) was not tagged as an active unit. This can be changed by first executing BPCNFG (see 6.2) on the executing memory system, then re-invoking HDBOOT. + + +`+++ Not B/P Bios ... aborting +++` + +An attempt was made to execute this utility on a system which was not running under B/P Bios. Boot the system with a B/P Bios-equipped system and try again. + + +`*** Read Error` + +An unrecoverable error occurred while trying to read the target system's Boot Record. This is most often due to media errors on the first cylinder of the target unit and cannot be rectified. Another cause may be an incorrect definition of the physical characteristics of the controller and/or drive. + + +`*** Write Error` + +An unrecoverable error occurred while trying to write the modified Boot Record to the Hard Drive unit. If a second attempt at execution is unsuccessful, it probably indicates either an incorrect physical definition of the Hard Drive unit, or unrecoverable media errors on the first cylinder of the drive. + + +## 6.10 HDIAG - Hard Disk Format/Diagnostic Utility + +HDIAG is a generic B/P Utility program to Run Diagnostics, Format, Verify and examine Hard Drive parameters using any of the defined controller types in a B/P Bios system where such capabilities are defined. The ability to select the controller type in the beginning of the program is allowed to enable you to check and initialize drives using controller types other than that defined in the executing Bios for added flexibility. The following controller types are handled in the initial B/P Bios release: + +- Adaptec ACB-4000A +- Shugart 1610-3 / Xebec 1410A +- Seagate SCSI +- Shugart 1610-4 (Minimal SCSI) +- Conner SCSI +- Quantum SCSI +- Maxtor SCSI (others added in later releases) + + +### 6.10.1 Using HDIAG + +This utility tool only operates in an interactive mode, so it is simply invoked with its name and no arguments (other than the standard double-slash Help request). When activated, it reads the controller type from the B/P Bios header structure and asks you if this is the controller type you wish to use. If you wish to use a different controller type, such as diagnosing a Seagate SCSI drive from a system which has an Adaptec controller for normal use, you may alter the controller definition for the remainder of the HDIAG session. The interaction through to the main loop prompt may appear as: + +```generic +/---------------------------------------------------------------------------\ +| B/P Bios Hard Disk Utility V1.3a, 14 Jun 97 | +| | +| Controller = Adaptec Ok ([Y]/N) ? : Y | +| | +| Functions: F - Format | +| V - Verify | +| D - Run Diagnostics | +| P - Show Disk Parameters | +| | +| Select (^C or ESC to Quit) : | +| | +\---------------------------------------------------------------------------/ +``` + + +#### 6.10.1.1 Show Disk Parameters _[ P ]_ + +If you are running HDIAG on a Hard Drive Unit which is already defined in the Bios and was previously formatted, or one of the self-identifying SCSI drives, then you may view the current drive parameters with the P command. The display varies with the controller type and the amount and type of information that is available. Some of the data may be from Bios definitions, and other data from either the controller (e.g. Adaptec) or the drive electronics (SCSI or SCSI-2). Samples of the forms of information are: + +SCSI1 setting +```generic +Unit : 0 CONNER CP3100-100mb-3.5 + + Total Blocks = 204864 (12804 Eq. Tracks) + Sctrs/Track = 33 + Sector Size = 512 + Interleave = 1 + # Cylinders = 776 + Num of Heads = 8 +``` + +Adaptec ACB-4000, Syquest SQ-312 10 MB +```generic +Unit : 0 + + Total Blocks = 22140 (1383 Eq. Tracks) + Sctrs/Track = 18 + Sector Size = 512 + # Cylinders = 615 + Num of Heads = 2 + Reduced Wrt. = 615 + Precomp. Cyl = 615 + Step Rate = 12 uS Buffered + Media type = Removable + Landing Zone = 615 +``` + +#### 6.10.1.2 Hard Disk Diagnostics _[ D ]_ + +Some drives feature built-in diagnostics routines which test the unit's electronics and media. Other systems simply execute the power-up sequence which generally includes a sequence of self-tests. Normally, only the re-initialize function can be relied on, and is included in the standard suite of HDIAG functions with this command. Sample output resulting from this function is: + +```generic + Select (^C or ESC to Quit) : D + Unit Number [0..2] (^C or ESC to Abort) : 0 +Re-Initializing Unit : 0 ..Ok + ..Waiting for Ready.. +``` + +Pauses may occur in the execution of the sequence, most noticeably after the status prompt stating "Re-Initializing Unit" before the "..Ok" appears. Depending on the exact system, this time is often when the actual controller electronics are being checked, and may involve moving the drive head which can be a time consuming task. There is also a pause very often after the prompt "..Waiting for Ready..", particularly if the heads were moved and must be repositioned over the outer cylinder of the drive. When the drive returns a ready status, then the main selection menu is again displayed and HDIAG is ready for another command. + + +#### 6.10.1.3 Verify Drive Media _[ V ]_ + +This function permits evaluating the condition of a formatted drive to identify defects to a varying extent. By using a mix of defeating the Error Correcting code where possible, and enabling or disabling the Individual Sector checks, a relatively extensive, albeit often time consuming, non-destructive status of the drive unit may be obtained. + +```generic + Select (^C or ESC to Quit) : V + Unit Number [0..2] (^C or ESC to Abort) : 0 + Verify Individual Sectors (Y/[N]) : N +Verifying Unit : 0 CONNER CP3100-100mb-3.5 + +Block 891 + ...aborted... +``` + + +#### 6.10.1.4 Format Drive _[ F ]_ + +Setting all of the data storage areas on the disk to a constant value, and renewing the control information on the drive is the purpose of this function. It is destructive, and any data on the drive will be lost. For this reason, several checks are included in the program to insure that you do not inadvertently activate this command. + +While most of the information needed to format a drive is available from either the built-in data which can be read from the drive or controller, or from the Bios data areas, some items are still required from the user. You will therefore be asked to provide any data necessary to format the drive. In the older SASI systems (1610-3, Xebec, etc) this can amount to a considerable number of entries. Fortunately, formatting of drives is not often required, and the method of formatting used in HDIAG is flexible enough to allow a wide range of devices to be connected. + + +### 6.10.2 HDIAG Error Messages + +Several error messages will be presented for specific problems encountered in the operation of HDIAG. Many of the messages will be specific to certain operations, and others will change the specific information depending on the capabilities of the controller type selected. The most general of these concerns the SCSI/SASI Sense command. The Newer SCSI systems use "Extended Sense" which can return more information than the basic Sense values. When Extended Sense is detected, the "Key" value is displayed in many error messages rather than the basic "Sense" byte. Consult the programming manual for the specific controller or drive for the specific meanings of these bytes. Such a message will usually be displayed as: + +`Error! (Comnd = xx) Sense: xx` + +or + +`Error! (Comnd = xx) Key = xx` + +Also, to provide additional information during operation of many of the functions, the raw status byte read from the controller when an error occurs is also displayed as part of an error message as: + +`(status = xxH)` + +The interpretation of the hexadecimal byte presented may be gathered from the programming manual for your specific drive or controller type. + +`+++ Not B/P Bios ... aborting +++` + +An attempt was made to execute HDIAG under a Bios other than B/P, or modifications made to the Bios altered the locations or values needed to correctly identify the system. + +`**** SCSI Block Length Error !` + +This fatal error message will be displayed if the Command Descriptor Block returned from the Bios is too small to allow the extended commands needed for the requested operation. It usually results from alterations to the Hard Driver module which change necessary values. + +`**** Controller Not Readable !` + +HDIAG could not read parameters from the drive or controller. This will only appear in the R (Read Drive Parameters) function, when the controller type is "Owl". + +`**** No Diagnostics for : ` + +The Controller selected cannot perform Diagnostics in a way that HDIAG can access or perform the needed functions. This will only appear in the D (Perform Diagnostics) function. + +`**** Verify Not Available !` + +The specific drive/controller selected has not been defined adequately to allow verification of the drive. This will only appear in the V (Verify) function when the controller type is "Owl". + +`+++ 1610-3 Initialization Error...Sense = xxH` + +An error was detected sending the initialization string to a Shugart 1610-3 or Xebec 1410A controller. Insure that this is the correct type of controller setting for your hardware configuration. It will only appear in the V (Verify) function. + + +## 6.11 INIRAMD - RAM Disk Initialization Utility + +INIRAMD is a B/P Bios utility that initializes the Directory of a RAM Drive and optionally initializes it for DateStamper (tm), P2DOS, or both types of file stamps. It contains protective features to preclude inadvertent initialization of an already formatted RAM Disk, and may be command line driven for execution from within STARTUP scripts. + + +### 6.11.1 Using INIRAMD + +This utility is designed to be operated with Command Line arguments, but features built-in defaults which can be configured by either overlaying bytes in the beginning of the program with new default settings, or by configuring with Al Hawley's ZCNFG tool. To execute with the default settings, simply enter: + +`INIRAMD` + +The complete syntax for INIRAMD is: + +`INIRAMD [d:][/][Q][D][P]` + + +### 6.11.2 Command Line Mode + +By entering arguments on the Command Line when INIRAMD is invoked, several internal default values can be set to the specific settings desired at the time. The first argument expected when parsing the Command Line tail is a Drive Letter. This is optional and will override the default drive M: built into the program. To specify a drive other then the default, enter: + +`INIRAMD d:` + +Extraneous prompt and status messages can be withheld during execution of INIRAMD by either setting the default "Quiet" flag embedded in the program, setting the "Quiet" flag in the Environment, or passing a Q as an argument when invoking the program. Initializing the RAM Drive in Quiet mode using the default drive is then accomplished by entering: + +`INIRAMD Q` + +You may also specify which types of Date/Time Stamps to add to the RAM drive during preparation with the P (for P2DOS Stamps) and/or D arguments. If not operating in the Quiet mode, INIRAMD notifies you which type(s) of Stamping methods have been added to the RAM Drive after the directory area is initialized to a blank value. Initializing drive M: for both types of Stamps then is initiated by entering: + +`INIRAMD M: PD` + + +### 6.11.3 INIRAMD Error Messages + +`+++ Not B/P Bios ... aborting +++` + +An attempt was made to execute INIRAMD under a Bios other than B/P, or modifications made to the Bios altered the locations or values needed to correctly identify the system. + +`+++ Already Formatted...Proceed anyway (Y/[N]):` + +This warning and prompt will be issued if INIRAMD detected the dummy file name used as a tag that the RAM Drive is already formatted. This is most often seen in systems that contain battery backed-up RAM and INIRAMD is invoked either directly or in a Startup alias script. To minimize the appearance of this message if you desire to have the RAM Disk initialized in the Startup script, include the following: + +| Command | | +| :--- | :--- | +| `IF ~EX M:-RAM.000` | Assume RAM Disk is M: | +| `INIRAMD M:` | Assume RAM Disk is M: | +| `FI` | | + +`+++ Drive d: does NOT Exist` + +Either the default or explicit drive specified in activating INIRAMD was has not been defined to the system. One possibility is that the RAM Drive was swapped for an undefined drive letter. Check the drive assignments with BPCNFG, Option 5 if you wish to check the Drive assignments. + +`+++ Drive d: is Not a RAM Drive!` + +Either the default or explicit drive specified in activating INIRAMD was a valid drive, but was not a RAM Drive. As with the previous error, one possibility is that the RAM Drive was swapped for another drive which was of another type. Use BPCNFG, Option 5 to check the Drive assignments. + + +## 6.12 INITDIR - P2Dos Stamp Initialization Utility + +INITDIR prepares disks for P2DOS-type file stamping. It does this by replacing every fourth entry in the disk's directory tracks with a time and date entry which is prefixed with a special character (hexadecimal 21). Existing directory entries in the fourth position are then shifted to the first entry in the next logical sector and the initialized directory sectors are written back to the disk. + +| **W A R N I N G** | +| --- | +| INITDIR should not be run on disks containing valid DateStamper file stamps since it rearranges directory data. To install both DateStamper and P2DOS stamping on one disk, start with a blank disk, or one with no datestamps of either type and run both PUTDS and INITDIR on the disk before using it. Doing otherwise will invalidate any existing stamp data. | + + +### 6.12.1 INITDIR Interactive Mode. + +INITDIR can be run in either an interactive mode by simply entering its name at the Command Prompt, or in "Expert Mode" by specifying a drive letter as an argument on the command line. In the interactive mode, you will be asked for a drive letter which will specify the drive to initialize with P2DOS stamps. + +If the DateStamper `!!!TIME&.DAT` file is detected on the disk, INITDIR issues a warning and asks if you want to proceed or not (see 6.12.2 below). To avoid the possibility of loss of Time and Date Stamp information from DateStamper, this routine should only be run on freshly-formatted or blank drives. The syntax of INITDIR is summarizes as: + +| Command | Description | +| :--- | :--- | +| `INITDIR //` | Print summary help message | +| `INITDIR` | Execute in Interactive Mode | +| `INITDIR d[:]` | Initialize Drive D: | + + +### 6.12.2 INITDIR Error Messages + +`Directory already initialized` + +The selected disk is already prepared for P2DOS stamps. + +`Illegal drive name` + +The character entered was not in the range of "A" thru "P". + +`Not enough directory space on disk` + +The directory on the selected disk is more than three-fourths full. Not enough space is available to support P2DOS file stamps. + +`Directory read error` + +An error was encountered in reading the disk directory. + +`Directory write error` + +An error occurred while writing the initialized directory. It will probably result in loss of file data. + +```generic +--> DateStamper !!!TIME&.DAT File Found <-- + Proceed anyway (Y/[N]) : +``` + +The special DateStamper `!!!TIME&.DAT` file exists on the disk. If other files are also on the disk, most of the DateStamper time and date information will be lost. On freshly-formatted or empty disks, no DateStamper file stamp data exists, so it is safe to answer with a Y and initialize the disk. + + +## 6.13 INSTAL12 - Boot Track Support Utility + + +Install CPR, ZSDOS, B/P Bios in a MOVxSYS "type" image from standard size (2k CCP, 3.5k DOS, ~4.375k Bios) files + +INSTAL12 is the latest modification to the ZSDOS INSTALOS utility distributed with ZSDOS 1.0 which automatically overlays your computer's System Image file, such as `MOVCPM.COM` (CP/M) or `MOVZSYS.COM` (ZRDOS) program, or Absolute System Model file (e.g., `CPM64.COM`) with ZSDOS or ZDDOS to produce a new file containing ZSDOS/ZDDOS instead of your original Basic Disk Operating System. INSTAL12 also allows you to set the defaults of various ZSDOS parameters during the installation process (these parameters may also be changed later with the ZSCONFIG program). + +INSTAL12 is designed to make the installation process as easy as possible. With INSTAL12 you may load files from all drives and user areas from A0: to P31:. Error detection is extensive, and Section 6.13.3 of this manual fully explains all INSTAL12 error messages. Finally, you may safely abort INSTAL12 at nearly all points by pressing Control-C. + +Before using INSTAL12, ensure that any necessary files from your B/P Bios and/or ZSDOS Distribution Disk are present: + +* Microsoft .REL formatted assembly of B/P Bios (MOVCPM = YES) +* ZSDOS.ZRL (if replacing Operating System) +* ZCPR33.REL, ZCPR34.ZRL or other Comnd Proc (if replacing CPR) +* INSTAL12.COM + +The following file from your B/P Bios Distribution Disk, CP/M or ZRDOS System Disk must also be accessible: + +* MOVxSYS.COM (B/P Bios), MOVCPM.COM (CP/M), MOVZSYS.COM (ZRDOS), or System Image file for systems such as the Oneac ON! + + +### 6.13.1 Using INSTAL12 + +To run INSTAL12, most users should simply enter + +`INSTAL12` + +at the Command Prompt. This tells INSTAL12 that you are installing a system segment over a System Image relocation file, such as `MOVxSYS.COM`, `MOVCPM.COM` or `MOVZSYS.COM`. If you need to install a segment over an Absolute System Model file such as a `CPM59.COM`, `ZSYSTEM.MDL`, or Oneac ON! file, you should enter + +`INSTAL12 /A` + +to run INSTAL12 in Absolute mode. INSTAL12 now displays its opening banner and requests the name of a file as: + +`System Image file to patch (Default=MOVCPM.COM) :` + +in Relocatable mode, or + +`Absolute System Model (Default=SYSTEM.MDL) :` + +in Absolute mode. + +You need not enter all of the information; INSTAL12 will fill in any missing items with the default disk, user, or filename. If you simply hit RETURN, INSTAL12 searches the current directory for the default System Image or Absolute System Model file (`MOVxSYS.COM`, `MOVCPM.COM` or `SYSTEM.MDL`). Here are some sample responses: + +```generic +System Image file to patch (Default=MOVCPM.COM) : B3: + (Selects MOVCPM.COM on drive "B" in user area 3) + +System Image file to patch (Default=MOVCPM.COM) : 10:MOVYSYS + (Selects MOVYSYS.COM on the current drive, user 10) + +System Image file to patch (Default=MOVCPM.COM) : C:MOV18SYS.OLD + (Selects MOV18SYS.OLD on drive "C", current user area)` +``` + +Once INSTAL12 finds the requested file, it validates your operating system image. If the CCP, BDOS or BIOS portions of the System Image or Absolute System Model file are invalid, INSTAL12 prints an error message and quits at this point. This may occur if an Absolute System Image was loaded but INSTALOS was invoked without the /A suffix. If both methods of calling INSTAL12 fail, first ensure that your system image or generation program is operating properly. If you are sure that you have a working MOVxSYS, MOVCPM, MOVZSYS, or Absolute Model file that INSTAL12 cannot validate, you will need to contact your distributor who will initiate actions to correct your problem. + +If all values in your operating system file match expected parameters, a summary of those values is displayed. If you specified a System Image file (e.g., `MOVxSYS.COM`), the display should be similar to: + +```generic +Addresses in system image (as seen under DDT) : + CCP : 0980H Map @ 3610H + BDOS: 1180H Map @ 3710H + BIOS: 1F80H Map @ 38D0H +``` + +The addresses shown will probably differ from these, but if both columns display values other than 0000H, INSTAL12 will correctly overlay the three system segment portions of the image with specified files. + +If you specified an Absolute System Model, the display will be similar to: + +```generic +Addresses in system image (as seen under DDT) : + CCP : BC00H + BDOS: C400H + BIOS: D200H +``` + +As above, the addresses will probably differ from those in the example, which are for a 54K system. + +If no error message appears, INSTAL12 has properly validated your file. Next, a menu of choices appears: + +```generic + 1 - Replace CCP + 2 - Replace DOS + 3 - Replace BIOS + 4 - Save and Exit +Enter Selection (^C Quits) : _ +``` + +To install a new B/P Bios image from your assembly, select option 3. You will be asked to enter the name of the file as: + +`Name of BIOS file (Default=CBIOS.REL) : _` + +The default file type is `.REL` and the file **MUST** be in Microsoft relocatable format. When a terminating Carriage Return is entered, either the name you entered or the default will be located. If found, the size will be evaluated against the available space in the image file. Often when adding a B/P Bios to an older system generation program, the bit map portion of the program will be relocated. You will be notified with a message signifying the distance in bytes that the map was relocated. This is simply a diagnostic tool, and you should not be alarmed at the message. Following the message "...overlaying BIOS...", INSTAL12 will return to the main menu for the next command. + +Replacement of the Command Processor with `ZCPR33.REL` or `ZCPR34.ZRL` is identical to Bios replacement, except that no relocation of the bit map is possible. The specified file will either fit and overlay the original, or it will be too large and the program will exit with an error message to that effect. + +For ZSDOS installation, enter a 2. You will be asked for the name of a Disk Operating System file as: + +`Name of DOS file (Default=ZSDOS.ZRL) : _` + +The default file type at this point is `.ZRL`, but operating systems in Microsoft `.REL` format such as distribution versions of ZRDOS are also accepted. As above, you may respond with a full or partial file specification and INSTAL12 will fill in any missing items with the default disk, user, or filename. + +Once the Disk Operating System file is found the following prompt appears: + +```generic +ZSDOS.ZRL Size OK...overlaying BDOS.. +Examine/Change ZSDOS parameters ([Y]/N)? : _ +``` + +At this point, INSTAL12 allows you to change the startup settings of all ZSDOS options. If this is your initial installation of ZSDOS, we recommend that you press N for "No" to bypass this step, and skip the following paragraph. + +If you enter any character other than N or n, the default option in brackets ([Y] for "Yes") is assumed, and INSTAL12 displays the current ZSDOS defaults as: + +```generic + 1 - PUBlic Files : YES + 2 - Pub/Path Write Enable : NO + 3 - Read-Only Vector : YES + 4 - Fast Fixed Disk Log : YES + 5 - Disk Change Warning : NO + 6 - Path w/o System Attr : YES + 7 - DOS Search Path : Disabled + 8 - Wheel Byte Protect : Disabled..Assumed ON + T - Time Routine (Clock) : Disabled + A - Stamp Last Access Time : Disabled + C - Stamp Create Time : Disabled + M - Stamp Modify Time : Disabled + G - Get Date/Time Stamp : Disabled + S - Set Date/Time Stamp : Disabled +Entry to Change ("X" if Finished) : _ +``` + +These options are presented in the same manner by ZSCONFIG, and are fully described in Section 4.10 of the ZSDOS 1.0 manual. + +Once you bypass the configuration step or exit by pressing X, one of the following prompts appears depending on whether you are installing an Image or Absolute Model file: + +`Name to save new system (Default=MOVZSDOS.COM) : _` + +or + +`Name to save new system (Default=ZSSYS.MDL) : _` + +Again, you may respond with a full or partial file specification and INSTAL12 will fill in any missing items with the default disk, user, or filename. If a file with the same name exists, INSTAL12 prompts you for a new name. When INSTALOS has a valid name, it creates your new system file and exits, displaying one of the following messages: + +`..Saving MOVZSDOS.COM` (relocatable) + +or + +`..Saving ZSSYS.MDL` (absolute) + + +### 6.13.2 INSTAL12 Error Messages + +Occasionally INSTAL12 may issue error messages. Most errors result when the files you specified do not conform to INSTAL12' expectations. Often the solution is to run INSTAL12 again, specifying relocatable mode instead of absolute mode or vice-versa. Many INSTAL12 errors will also result from damaged files. If INSTAL12 gives errors in both absolute and relocatable modes, try recopying the source file from masters, or re-assemble the source program and execute INSTAL12 again. + +If all of the above fail, your system files may contain information which INSTAL12 cannot recognize. You may be able to attempt an alternate installation with NZCOM or JetLDR for CPR and DOS segments, but you may need to contact the experts on Ladera Z-Node for assistance with Bios-related problems. + +The following is a summary of all INSTAL12 error messages, their meanings, and some possible remedies. + +`*** SORRY! ZSDOS will only run on Z80 type computers!` + +ZSDOS and its utilities will only operate on processors which execute the Z80 instruction set such as the Z80, NSC-800, Z180 or HD64180. There is no fix for this condition other than to run it on another system. + +`*** Unable to open [filename.typ]` + +INSTAL12 cannot locate or open the system file you specified. First, ensure that the file is at the default or specified drive/user location. If you have specified the file correctly but this error persists, obtain a fresh copy of your system file and try again. + +`*** Can't find CCP/BDOS/BIOS at standard locations !!!` + +The operating system contained in your system file is not a standard CP/M system. It contains a CCP which is not exactly 2 kilobytes long, a BDOS which is not exactly 3.5 kilobytes long, or both. If this message appears, first ensure that your system file has not been damaged. If you still receive this message, contact the authors on Ladera Z-Node or your distributor. + +`++ Image Vector does not match Calculations ++` + +INSTAL12 found an internal error in the image file while installing a MOVCPM-type file. If you did not use the /A option when running INSTAL12, you may be trying to perform a relative installation on an absolute file. Try running INSTAL12 again with the command `INSTAL12 /A`. + +`*** Cannot find legal Relocation Bit Map` + +INSTAL12 was unable to locate a valid relocation bit map pattern in the MOVCPM-type file when installing in Relocatable mode. Non-standard relocatable image files are the general cause for this error. A workaround is to generate an Absolute Model with MOVCPM first, then use INSTAL12 in Absolute (/A) mode on the Absolute Model file. + +`---Can't find [filename.typ].. reenter (Y/[N]) :` + +The replacement file (CCP, BDOS or BIOS) specified cannot be located. Ensure that the drive, user and file name are correct. + +`*** Error in .REL sizing [filename.typ] + Err Code : nn` + +An error occurred during the sizing operation of INSTAL12 on the `.REL` or `.ZRL` file. The `.REL` or `.ZRL` must be in Microsoft relocatable format. Named Common segments other than `_CCP_`, `_BDOS_`, and `_BIOS_` are not allowed, and code and data segments (if any) must not overlap. + +`*** file too large to fit...` + +The size of the relocatable CCP or BDOS is greater than the available space in the image file (2048 bytes for the CCP, 3584 bytes for the BDOS). This error may result if the relocatable file is not in proper Microsoft relocatable format, or if a customized file is used. This error should never occur with the distribution `ZSDOS.ZRL` file, which is exactly 3584 bytes (3.5k) long. + +`*** Error opening : [filename.typ]` + +INSTAL12 could not open the specified relocatable file. Ensure that you selected a valid `.REL` file. + +`*** Error reading : [filename.typ]` + +INSTAL12 detected an error when reading the specified relocatable file. Try recopying the file. + +`*** Error in .REL file : nn` + +An error was found in a relocatable input file while attempting to replace the CCP, BDOS or BIOS portions of your operating system. "nn" is a hexadecimal code which may assist in locating the cause of the error. Contact your distributor if you need help in resolving an error of this nature with the code in the error message. + +`--- That file already exists. Overwrite it (Y/[N])?` + +The file you told INSTAL12 to write to already exists. If you enter "Y" here, INSTAL12 will erase the previous copy and create a fresh file with this name. Enter N to select a new name. + +`*** No Directory Space for [filename.typ]` + +There was not enough directory space for the output file on the selected disk. Send the output file to a different drive by preceding the filename with a drive specifier, or change the disk in the output drive. + +`*** Error writing file. Try again with another disk (Y/[N])? :` + +This message usually results from a lack of disk space on the drive you specified for output. Change disks and enter Y to try again. + + +## 6.14 IOPINIT - IO Package Initialization Utility + +IOPINIT initializes an IOP Buffer defined in the Environment Descriptor to the standard Dummy IOP format and patches it into the Bios Jump Table. It serves the same basic function as the older ZCPR3 method of loading a SYS.IOP file, but was added as a stand-alone routine to do essentially the entire installation of the package. In so doing, additional space was freed in the B/P Bios core code allowing other routines to be added which cannot be removed to external programs. + + +### 6.14.1 Using IOPINIT + +This program should be included near the beginning of the initial STARTUP script for any system in which an IOP is defined. **NOTE:** This routine MUST be run before any programs which change the Warm Boot Jump at location 0! + +No arguments are expected when calling IOPINIT with all values determined from the executing system Environment. The routine responds to the normal double-slash help request as with all support routines. + + +### 6.14.2 IOPINIT Error Messages + +`--- No IOP Buffer defined in Environment ---` + +Self-Explanatory. If the IOP Buffer has been deliberately removed during configuration or assembly, no harm will be caused by executing IOPINIT. + +`--- No Z-System Environment Defined ---` + +This message should NEVER appear since a valid Environment Descriptor is REQUIRED in B/P Bios equipped systems. If it does, one possible cause is incorrect value(s) at critical points within the Descriptor that are used to validate the Environment. + +`*** IOP Already Installed! ***` + +Self-Explanatory. No harm is done to the system, this message is simply for information. + + +## 6.15 LDSYS - System Image File Loader + +LDSYS is the primary utility to activate a System Image file prepared by BPBUILD (see 6.1). It first validates the currently-running system, then loads the image file, places the component parts where they belong in the computer's memory, and executes the Bios Cold Boot routine of the newly-loaded system. Image files may be either banked or unbanked and need not be placed in the currently-logged directory, since LDSYS can access files along the system path, or from Z3-style Path specifications. + + +### 6.15.1 Using LDSYS + +This utility provides the only way to install a banked system in a B/P System, and a simple way to test non-banked systems before final conversion to bootable systems to be loaded onto system tracks using INSTAL12, MOVxSYS and BPSYSGEN. LDSYS expects only a single parameter to be passed on the Command Line, that being the name of an Image file to load. If no File Type is explicitly entered, a type of `.IMG` is assumed. The location of the desired file may be explicitly stated in normal ZCPR3 fashion with either DU: or DIR: prefixes. The overall syntax of LDSYS is therefore: + +`LDSYS [du|dir:]name[.typ]` + +When loading, two summary screens are displayed, the first from LDSYS itself, and the second from the Cold Boot routine in the loaded system after control is transferred from LDSYS to the newly-loaded system. A sample display from a banked system during development when installed on a MicroMint SB-180 is: + +```generic +/---------------------------------------------------------------------------\ +| B/P Bios System Loader Vers 1.0 31 Aug 92 | +| Copyright (C) 1991 by H.F.Bower & C.W>Cotrill | +| | +| CCP starts at : CC80 (0F80H Bytes) | +| DOS starts at : DC00 (0F00H Bytes) | +| Banked Dos at : 1080 (0500H Bytes) | +| BIOS starts at : EB00 (0880H Bytes) | +| Banked Bios at : 1580 (1269H Bytes) | +| | +| ...installing Banked System | +| | +| SB180 B/P 60.25k Bios Ver 0.6 26 Jan 92 (Banked) with: | +| | +| ZCPR3+ Env | +| ZSDOS Clock | +| Hard Disk Support | +| Warm Boot from RAM | +| RAM Disk (M:) | +| Full Error Messages | +| _ | +\---------------------------------------------------------------------------/ +``` + +All messages in the above sample screen through the line "...installing Banked System" are printed by LDSYS. All subsequent lines in the above screen are displayed from the newly-loaded Bios. During alteration, or modification of a new system, this subdivision in the display areas may be a clue to any difficulties encountered. The position of the cursor at the bottom of the sample screen is the point at which the new Bios, now in control, attempts to load the Startup file defined in the B/P Header. If none is found, additional initialization will not be performed, and you will see only the prompt for Drive A, User 0. + + +### 6.15.2 LDSYS Error Messages + +`*** No file specified ! ***` + +LDSYS was called without a specifying file to load. You may reinvoke it directly with the ZCPR "GO" command as: `GO filename` or call it in the normal fashion specifying an image file to load. + +`--- Ambiguous File: fn[.ft]` + +At least one question mark (or expanded asterisk) was detected in the specified file to load. Re-execute with an unambiguous file name. + +`--- Error Opening: fn[.ft]` + +The specified image file could not be located. Common causes for this are a mismatch in the file name, no file with the default type of `.IMG` or an inability to find the file along the Dos Path or in a PUBlic directory. + + +## 6.16 MOVxSYS - Boot Track System Utility + +This routine is a program to generate a bootable system image for the boot tracks of a Floppy or Hard Disk. It is customized for each type of hardware system using the B/P Bios. The generic name MOVxSYS translates to a specific name reflecting the standard name ID, examples of which are: + +| Utility | Description | +| :--- | :--- | +| `MOVYSYS` | YASBEC | +| `MOVAMSYS` | Ampro Little Board | +| `MOV18SYS` | MicroMint SB-180 | + + +### 6.16.1 Using MOVxSYS + +This program is patterned after the original `MOVSYS.COM` distributed with most Digital Research CP/M 2.2 systems, but extensively updated to reflect the Z-System standard Help, entry of a base address or system size in kilobytes, and additional checks needed to insure B/P standards. + +Two basic parameters may be passed to this program as arguments on the command line. The first specifies the system size in either the equivalent number of kilobytes in an equivalent CP/M 2.2 system, or as the base address of the Command Processor. MOVxSYS parses the first element to determine if the value is a Hexadecimal number ending in the letter "H", and assumes that the value specifies a starting address if so. Valid addresses must be greater than 8000H to insure that the resident portion of the operating system in the Common Memory area. If the argument is not a Hexadecimal address, it is assumed to be a number of kilobytes in the range of 39 to 63. These sizes are based on the "standard" CP/M component elements of 2k bytes for the Command Processor, 3.5k bytes for the Basic Disk Operating System, and at least 1.5kbytes for the resident Bios portion. Several checks are performed within MOVxSYS and the initial executing portion of the Bios (Cold Boot) to detect invalid locations and incorrectly sized data areas. + +The second parameter which may be specified on the command line is an optional asterisk ("*") or File Name and Type after the size specification. If an argument is present, one of two actions will be taken. The Asterisk instructs the program to relocate the system image to the specified size, and simply retain it in memory upon exitting without saving the image to disk. Any other characters will specify the name of a file under which name the image should be written to disk. If no second argument is given, the image will be written under a file name of SYSnnK.BIN where "nn" will be the number of kilobytes in the system size described above rounded down to the nearest even number. + +Placing a system image on the Boot Tracks of a disk is done by BPSYSGEN (see 6.6) which may be done by immediately following MOVxSYS (invoked with the asterisk argument) by BPSYSGEN using the "Image in Memory" selection, or by specifying a file output from MOVxSYS, and invoking BPSYSGEN with the name of the resultant file. + +If you reconfigure the Bios for your system with the goal of modifying the Boot System, you must assemble B/P Bios in the Non-Banked Mode by setting the `BANKED` equate to NO, and setting the `MOVCPM` equate to YES in the `DEF-xx.LIB` file (see 4.2). The revised Bios may then be added to `MOVxSYS.COM` with INSTAL12 (see 6.13) to produce a customized Boot System reflecting your tailored needs. Refer to Chapter 3 for a more complete description of the installation process. + + +### 6.16.2 MOVxSYS Error Messages + +`**** Start < 8000H !!!` + +A size value or CPR Starting address was specified which results in a base address less than 8000H. Since the lower 32k of memory (0..7FFFH) may be banked, the CPR MUST be in the upper half of memory. Execute the program again with an adjusted size specification. + +`**** Create Error !` + +The program could not create the specified Binary output file. Possible causes are a full directory, Write Protected diskette, or bad media or drive. + +`**** Write Error...Exiting` + +An error occurred while writing the specified Binary output file. Possible causes are a media or drive error, or a disk with inadequate storage space for the file. + +`**** Close Error !` + +An error occurred while attempting to close the specified Binary output file. This is usually due to a media or drive error. + +`**** Size must be in 39..63 !!` + +MOVxSYS was invoked with an invalid size (number of K) specification. Execute the program again with an adjusted size specification. + +`**** Bad Syntax !!` + +The program became confused and could not properly decide what you wanted it to do. Review the built-in help by entering: `MOVxSYS //` and follow the syntax listed. + + +## 6.17 PARK - Hard Drive Head Park Utility + +PARK is a simple B/P Utility routine that moves the Hard Drive heads on all drives to the designated landing zone (also called shipping or park zone) if defined for the type of Controller/Drive in your system. When all drives are parked, the utility executes a HALT instruction which requires a hardware reset or power-off/power-on sequence to overcome. To avoid the possibility of Hard Drive damage by removing power from drives while the heads are positioned over data storage portions of hard drives, PARK should always be executed prior to turning your computer off. This recommendation is particularly important for drives which do not feature automatic hard parking, or where such hardware features have failed. + + +### 6.17.1 Using PARK + +This utility is simply called with no arguments, and sequentially scans all three possible Hard Drive units, executing the SCSI "Stop Unit" command on each. When all three units have been processed, the processor disables interrupts and executes a HALT instruction to prevent the units from becoming reactivated by subsequent instructions. Normally, only cycling the power or pressing the Reset button on the computer will allow processing to resume. Developing the habit of executing HALT before turning your computer off may result in increased life from your hard drives, and should become routine. + +This utility is a specialized version of SPINUP (see 6.20) which permits individual units to be turned off and on during normal operation. + + +### 6.17.2 PARK Error Messages + +`+++ Not B/P Bios ... aborting +++` + +An attempt was made to execute PARK under a Bios other than B/P, or modifications made to the Bios altered the locations or values needed to correctly identify the system. + +`+++ Can't Park this type of Controller! +++` + +PARK was executed with a type of Controller or drive in the Bios that does not implement the "Stop Unit" SCSI function. + +`**** SCSI Block Length Error !` + +The Bios does not support the Extended Commands necessary to park the heads using the "Stop Unit" SCSI Function. This is most probably due to changes during an edit/assembly of the Bios which altered either the Command Descriptor Block size, or the Hard Drive function which returns the values. + + +## 6.18 SETCLOK - Real-Time Clock Set Utility + +This utility provides a means of setting a B/P Bios clock from a physical clock contained in the ZSDOS CLOCKS.DAT library. It presents a similar interface to the ZSDOS 1 utility TESTCLOK from which it was derived. + + +### 6.18.1 Using SETCLOK + +SETCLOK is invoked by entering its name with an optional Clock Driver Number. For initial testing, or trying different clocks (always a dangerous procedure), simply enter the utility name as: + +`SETCLOK` + +You will be asked whether to extract clocks from a library. If you are using a custom clock, answer No. If you wish to use a clock from the prepared ZSDOS library, enter Yes which is the default setting if a Carriage Return is entered. You will also be asked for the location (Drive/User) of the clock file or library. This prompt sequence may appear as: + +```generic +Extract Clock from Library ([Y]/N) : _ +Location of CLOCKS.DAT [B0:] : _ +``` + +Drive B, User 0 illustrated in the above sample prompt will probably differ in your system with the current drive and user always shown as the default location. If the file is on the currently-logged drive and PUBlic, it will also be found without specifying a unique User area. If the default reflects the location of the `CLOCKS.DAT` file, or a location accessible via the PUBlic feature, simply enter a carriage return, otherwise enter the location of `CLOCKS.DAT`, followed by a colon and a carriage return. A list of over 40 available clocks will appear. To select one of these clock drivers, enter the number corresponding to the clock, and the program will do the rest. Various messages will be displayed as the clock driver is loaded, linked and executed. If all goes well, the final message will be the Date and Time read from the clock followed by message that the B/P Bios Clock was Set Ok. + +Alternatively, a clock driver may be selected for automatic execution according to a specification on the command line. To use this mode, the `CLOCKS.DAT` file must either be in the currently-logged Drive and User, or on the current drive with the PUBlic Attribute bit set. the syntax for this method of setting the B/P Bios clock is: + +`SETCLOK nn` + +where "nn" is a number corresponding to one of the clocks in the `CLOCKS.DAT` file. This method of operation may be used to set the Bios clock within an alias script such as `STARTUP.COM` commonly used when the computer is first booted. + + +### 6.18.2 SETCLOK Error Messages + +Some of the errors in the SETCLOK utility are generated by the top-level program. These errors consist of: + +`+++ This is only for Z80 type computers!!!` + +This routine will only operate with Z80 or compatible processors since it is a B/P Bios utility which is also restricted to these types. + +`-- Error in locating Clock file` + +This routine could not find the `CLOCKS.DAT` Library. Insure that the library either exists in the currently-logged directory, can be found via the PUBlic feature, or is available along the DOS Path. + +Other errors are generated in the process of extracting and validating the driver selected from the `CLOCKS.DAT` library. Such errors consist of: + +`-- Error Opening : clockname` + +The Selected Clock driver in the Library could not be opened. This is most often due to corruption of the `CLOCKS.DAT` file. Restore it from your ZSDOS backup disks and try again. + +`-- Error Reading : fn.ft` + +An error occurred while reading the Clock code from the library. This also is most often due to corruption of the `CLOCKS.DAT` file. + +`-- Error in : clockname` + +An error occurred in the logical relocatable structure of the selected clock driver. + +`-- Error initializing DAT file` + +An error was encountered in initializing the `CLOCKS.DAT` Library. + +`-- Memory overflow in DAT file` + +A memory allocation error occurred in the Clock routine which caused the allocated memory to be exceeded. This should not occur in any of the library clock drivers, but may be experienced if the guidelines are not followed when developing a custom clock. + +Still other errors relate to the reading and linking of the selected clock routine whether it is from the Clock Library, or loaded as a Standalone driv- er. These errors include: + +`+++ Can't find : CLOCKS.DAT` + +SETCLOK could not find the referenced Clock file. This error will be seen if an attempt is made to use a standalone clock driver which could not be found in the current Drive/User, via the PUBlic attribute, or along the Dos path. + +`+++ Error on file open` + +An error occurred while trying to open a standalone clock file. Insure that the file was correctly assembled and try again. + +`+++ Error sizing : fn.ft` + +The selected clock file contained erroneous or invalid sizing information. If this is reported from the `CLOCKS.DAT` file, reload the file from your ZSDOS backup disk and try again. If it is reported while loading a standalone clock, it is most often due to incorrect specifications of the CSEG/DSEG/Named Common areas within the Clock template. Insure that the clock specifications were followed, reassemble the driver and try again. + +`+++ Link Error : nn in file : fn.ft` + +An error occurred while linking the relocatable code from a clock driver. The "nn" reported is an indicator to the exact nature of the error. Consult the authors if you cannot resolve the error. + +The final two errors are indicators that errors occurred after the clock driver has been loaded, linked, and validated. If either of these occurs, it is most often due to selection of an incorrect clock driver, problems with the hardware controlling the selected clock, or alterations to the B/P Bios code which altered the specified interface. + +`-- Clock Not Ticking --` + +The selected clock driver could not detect an active clock. This is most often the result of selecting the incorrect driver, or setting incorrect values when asked for specific addresses or values when activated. + +`-- Error Setting B/P Bios Clock !!` + +The Bios reported an error while attempting to set the B/P Bios clock. This is most often caused by errors when modifying the module `CLK.Z80`. + + +## 6.19 SHOWHD - Partition Display Utility + +SHOWHD is a utility which is furnished with the B/P Bios package as an aid in converting existing systems to B/P Bios without losing data, particularly on Hard Drives. It is not specific to B/P Bios and should properly execute on any CP/M 2.2-compatible system. Its purpose is to display the current Hard Drive Partition settings so that you may configure a B/P Bios in either source code, or image form (with BPCNFG) to reflect the same partitioning data. + + +### 6.19.1 Using SHOWHD + +This routine is a basic utility which is normally infrequently, so frills were not added. It expects no arguments and only operates in an interactive mode. To execute it, simply enter: + +`SHOWHD` + +You will be prompted to enter a drive letter. When entered, you will be presented with a display listing the logical parameters for the drive. A sample of execution is: + +```generic +/---------------------------------------------------------------------------\ +| Show Hard Drive Partition Data - 2 Nov 91 | +| | +| Enter Drive Letter [A..P] : C | +| | +| Drive: C | +| DPH Info BPCNFG Info | +| | +| | +| Sectors/Track = 64 (same) | +| Blk Shift Fctr = 5 4k/Block | +| Block Mask = 31 | +| Extent Mask = 1 | +| Disk Blocks-1 = 4999 20000k Total (2500 Tracks) | +| Max Dirs - 1 = 1023 1024 Dir Entries | +| Alloc bytes = FFH, 00H | +| Check Size = 0 | +| Track Offset = 3500 (same) | +| _ | +\---------------------------------------------------------------------------/ +``` + +### 6.19.2 SHOWHD Error Message + +Only one message may be displayed from the utility. It is: + +`+++ Invalid Drive : d` + +The Drive Letter selected was not a valid drive within the Bios. + + +## 6.20 SPINUP - Hard Disk Motor Control Utility + +SPINUP is a generic B/P utility to directly control the heads and motors of newer SCSI drives. It moves the heads on the specified hard drive unit to the designated shipping or park zone and may turn the drive motor off if called to Stop the unit and that feature exists in the drive. If called to Start the unit, the drive motor is turned on (if applicable) for the specified drive unit and the heads are positioned to Cylinder 0. This routine may be used as a power conservation feature where operation can be continued for periods of time from RAM or Floppy drives without need to access the hard drive unit. Attempts to access a unit which has been "spun down" with SPINUP will result in an error. This routine is essentially a generic version of PARK (see 6.17) and is furnished in source code form to demonstrate methods of interfacing to Hard Drives from Application Programs. + + +### 6.20.1 Using SPINUP + +This utility was written for use primarily in battery-operated systems where power conservation is desired. Generally, only the newer SCSI drives respond to the Stop/Start Unit commands by controlling the drive motors and positioning the heads over the designated "Landing Zone". SPINUP is Command-Line driven and expects an argument consisting of a valid Unit Number for the physical Hard Drive unit (see 5.2.1, `CONFIG+61`). Valid Unit Numbers are "0", "1" and "2". + +Stopping the unit is indicated by preceding the Unit Number with a minus sign as: + +`SPINUP -0` + +which will cause Unit 0 to park the heads and remove power from the drive motor if possible. Starting the unit is indicated by simply passing the Unit Number as an argument as: + +`SPINUP 0` + +Whether starting or stopping a Hard Drive Unit, SPINUP monitors the unit status after issuing the command and reports the status of the drive when results of the operation are received. Results are returned as; the unit is Stopped, Started, or an error has occurred (see 6.20.2 below). + +Prior to using SPINUP to stop a hard drive, you must insure that accesses to any logical drive on that unit will not occur while the unit is stopped by either exchanging logical drives with BPSWAP (see 6.5) or altering the Command Processor and Dos Search Paths with the ZSDOS Utility ZPATH. For example, if your system includes a partition on the subject Hard Drive as Drive A:, you have logged onto a RAM Drive as M: and the unit is stopped, ZCPR3 and ZSDOS may attempt to find a file on drive A: which will result in a Read Error. In this example, you may either swap drive A: with M:, insuring that M: is not in either Path, or set both paths to exclude drive A: + + +### 6.20.2 SPINUP Error Messages + +`+++ Not B/P Bios ... aborting +++` + +An attempt was made to execute SPINUP under a Bios other than B/P, or modifications made to the Bios altered the locations or values needed to correctly identify the system. + +`+++ Can't handle this Controller Type! +++` + +The Controller Type within the Bios cannot handle the "Stop/Start Unit" SCSI Commands. + +`**** SCSI Block Length Error !` + +The Bios does not support the Extended Commands necessary to turn the drive on and off using the "Stop Unit" and "Start Unit" SCSI Functions. This is most probably due to changes during an edit/assembly of the Bios which altered either the Command Descriptor Block size, or the Hard Drive function which returns the values. + +`**** Invalid Unit # !` + +The specified unit number was not "0", "1" or "2". Only three physical Hard Drive units are recognized in B/P Bios. + + +## 6.21 TDD - SmartWatch Support Utility + +TDD is a customized version of the ZSDOS utility TD. With ZSDOS2 systems, it used to display, set or update the B/P Bios clock. This latter capability only exists with the Dallas SmartWatch (DS-1216E) or JDR No-Slot-Clock in the Ampro Little Board, SB180 or YASBEC. + + +### 6.21.1 Using TDD + +TDD obtains the system Time and Date with a DOS Function 98 and displays the information on your console. Your system Must have an installed clock driver to use this utility. If the clock driver supports a set function, TDD can set the Date and Time using DOS Function 99. When setting the clock, TDD will allow you to operate in either an Interactive or Command Line driven mode. + +TDD responds to the standard Help request described in Section 1.7. You may obtain a brief usage description by entering: + +`TDD //` + +You may obtain the current Date and Time from the system clock by simply entering the program name as: + +`TDD` + +If you are using a Dallas 1216E-based clock, you can set the B/P Bios clock directly by entering: + +`TDD U` + +A continuous display may be obtained which will update every second until any key is depressed by entering: + +`TDD C` + +The system clock may be set in the Interactive mode by entering the program name followed by the "S" parameter as: + +`TDD S` + +You will then be asked to enter the date. The prompt will display the format in which the date will be accepted (US or European) as either: + +`Enter today's date (MM/DD/YY):` (US) + +or + +`Enter today's date (DD.MM.YY):` (European) + +Date fields (month, day, and year) may be either one or two digits in each position. Invalid entries such as an invalid day for the entered month will cause the prompt to be re-displayed for a new entry. + +When a valid date has been entered, you will be prompted for the current time. + +The prompt will vary depending on whether you are using a Real Time Clock, or the Relative counter substitute for a clock. The two prompts are: + +`Enter the time (HH:MM:SS):` (Real Time Clock) +`Enter the relative time (+XXXX):` (Relative Counter) + +Time is assumed to be in 24 hour format when a Real Time Clock is being used. Seconds may be omitted when setting the clock. When the relative clock is used, a '+' must prefix the count to which you wish to set the Relative Counter. Counts from +0 to +9999 are permitted. + +When the time entry is ended with a carriage return, the date and time will not be automatically set. A message will prompt you to press any key. At this point, the next key depression (other than shift and control) will set the clock. This procedure allows you to accurately synchronize the time with one of the many accurate time sources. + +Command Line setting of the clock is initiated by entering the program name followed by the date and optional time. The date must be in the correct form (US or European) for the configured TDD. If an error is detected in a Command Line clock set, TDD switches to the interactive mode and prompts for date and time as described above. + + +### 6.21.2 Configuring TDD + +TDD can be configured to present the time in either the US format of month, day, year as: Sep 18, 1988, or the European and military style as: 18 Sep 1988. Likewise, the set function accepts a US format of MM/DD/YY or the European DD.MM.YY. The default may be set with Al Hawley's ZCNFG utility using data contained in the TDD.CFG file on the distribution disk. + + +### 6.21.3 TDD Error Messages + +Error messages for TDD are simple and are mostly self-explanatory. For clarity, however, they are covered here. + +`SORRY! ZSDOS or ZDDOS is required to run this program!` + +You tried to run this with someone else's DOS. Use ZSDOS or ZDDOS. This error aborts to the Command Processor. + +`*** NO Clock Driver installed!!!` + +You tried to read a clock which does not exist. Install a clock with SETUPZST and try again. This error aborts to the Command Processor. + +`*** Clock does NOT Support SET!!!` + +The clock driver on your computer will not permit you to set the time with TDD. This error aborts to the Command Processor. + +`*** Must have B/P Bios to use!!!` + +This utility only functions under B/P Bios. If you are using B/P Bios and this message appears, it is most probably due to edit/reassembly of the Bios source which altered critical values in the data structures. + +`*** Hardware Type Not Supported ! ***` + +Since TDD is integrally tied to specified hardware platforms, it will only function if the running computer is one of the types for which the correct code has been implemented. This error should not appear unless the "U" or "S" command is issued. + +`++ Insufficient Memory! ++` + +The base of available memory has been reduced below that needed for the portion of TDD which is relocated to high memory. The most common cause of this is the addition of Resident System Extensions (RSXs) which cause the top of the TPA to be reported as below 8100H. + +`*** Error in Data Input` + +An invalid character or number was entered when trying to set the date and time. This error will cause the Interactive mode to be entered and issue a prompt to re-enter correct date/time. + +`*** Must be wheel to set clock!` + +An attempt was made to set the clock without Wheel access. Use ZSCONFIG (ZSDOS 1) or ZSCFG2 (ZSDOS2) to set a valid Wheel byte, or disable it (see 6.22 for ZSCFG2 or the ZSDOS 1 manual for ZSCONFIG). This error aborts to the Command Processor. + +`*** Must have Z180 Processor!!!` + +This error may be received if the ID tag identifies the Bios for a computer with a Z180/HD64180, but the check for this CPU failed. It is probably due to incorrect porting of the Bios or manipulation of the header structure. + +`*** Must have Z180 to Set No-Slot-Clock!!!` + +Similar to the error above, but will appear when trying to set the clock under al altered system. + +`**** Can't find No-Slot-Clock!` + +The JDR No-Slot-Clock/Dallas DS-1216E SmartWatch could not be validated in the system. This message will be seen if TDD is executed without the clock installed, or the clock has failed for some reason. + + +### 6.21.4 NOTES Spring 2001 + +TDD has been extended to more clocks than the DS-1216E cited in this manual. It handles the clocks in all supported B/P BIOS versions. + + +## 6.22 ZSCFG2 - ZSDOS2 Configuration Utility + +ZSCFG2 is a program to configure various parameters of a ZSDOS2 Operating System. It is included in this manual due to the close interaction of all parts of an operating system, particularly the Banked and Portable BIOS. ZSCFG2 operates in either an interactive (novice) or command line driven (expert) mode for maximum flexibility and ease of use. If your computer is running ZCPR3, the Z3 Environment is automatically detected and ZSCFG2 will use video attributes such as reverse video and cursor addressing to enhance the display. + +As in all of our support routines, a brief on-line help message is available by entering the name followed by two slashes as: + +`ZSCFG2 //` + +This configuration tool automatically tailors itself to the ZSDOS2 system, and all messages, from Help to Interactive prompts will accurately reflect the options and status for the running configuration of ZSDOS2. + + +### 6.22.1 ZSCFG2 Interactive Use + +To start ZSCFG2 in the interactive mode, simply enter the program name as: + +`ZSCFG2` + +If a valid ZCPR3 environment is located, the screen is cleared, and you will see a screen containing needed addresses from the environment, and a tabular display of the current settings within the operating ZSDOS2 system. Reverse video is used to enhance the display if available. If you are using a computer which is not equipped with ZCPR3, or cannot support direct cursor addressing, the information (less ZCPR3 addresses) is simply scrolled up the screen, one line at a time. The only content differences between the two displays is that no data on the ZCPR3 environment will be displayed. An example of a ZSDOS2 display is: + +```generic +/---------------------------------------------------------------------------\ +| ...Configuring ZSDOS Ver 2.0 Z3 Environment at : FE00H | +| ZCPR Path Address : FDF4H | +| Wheel Byte at : FDFFH | +| | +| 1 - Public Files : YES | +| 2 - Pub/Path Write Enable : NO | +| 3 - Read-Only Vector : YES | +| 4 - Fast Fixed Disk Log : YES | +| 5 - Disk Change Warning : NO | +| 6 - Path w/o System Attr : YES | +| 7 - DOS Search Path : Enabled - Internal | +| 8 - Wheel Byte Protect : Enabled Addr = FDFFH | +| T - Time Routine (Clock) : F168H | +| A - Stamp Last Access Time : Disabled | +| C - Stamp Create Time : EEB2H | +| M - Stamp Modify Time : EEBCH | +| | +| Entry to Change ("X" to EXIT) : _ | +\---------------------------------------------------------------------------/ +``` + +The type of Operating system and version number are first displayed, followed by any ZCPR3 Environment information needed. If no environment is located, you will see a message to that effect. In such a case, certain options will be restricted as covered later in detailed descriptions. + +Interactive operation consists simply of entering the number or letter in the left of each line to select a function. If you select numbers between one and six, the option is changed from OFF to ON or vice versa, and the menu and status are again displayed. If you select any of the other items, you will be asked for more detailed information. Section 6.22.2 below contains a detailed description of all options. + + +### 6.22.2 ZSCFG2 Command Line (Expert Mode) Use + +Command line entry (or Expert Mode) provides the ability to dynamically set ZSDOS options within STARTUP scripts, ZCPR Alias files, Submit files, or directly from the your console. This permits the operating system parameters to be tailored to specific applications, and restored upon completion. For example, a submit or alias command might feature the following sequence: + +```generic +Disable/Enable ZSDOS features and set addresses +...Process application programs +Restore ZSDOS features and addresses and return +``` + +Tailoring of ZSDOS in this sequence would be via a call to ZSCFG with arguments passed on the command line within the script. In this fashion, you do not have to constantly attend the computer to change DOS parameters. + +Settings are passed to ZSCFG as groups of characters separated by one or more tabs, spaces or commas. Each group of characters begins with a Command character which identifies the setting to be changed. In the case of the items related to time and date, a two-character sequence is used. A "+" sign identifies the Command as a Clock, or Time Stamp-related function, and the following Command character tells which parameter of the six is to be changed. Command Identifiers for ZSDOS are: + +| Option | Description | +| :---: | :--- | +| `P` | Public File Support | +| `W` | Public/Path Write Enable | +| `R` | Read-Only Drive Sustain | +| `F` | Fast Hard Disk Relog | +| `!` | Disk Change Warning | +| `S` | Path without SYStem Attribute | +| `>` | ZSDOS Search Path | +| `*` | Wheel Byte Write Protect | +| `C` | Clock Routine Address | +| `+A` | Stamp Access Time | +| `+C` | Stamp Create Time | +| `+M` | Stamp Modify Time | + +Options which are simply On/Off toggles require no arguments. You enable them merely by entering the Command Identifier(s). To disable such options, you simply append a minus sign ("-") to the end of the Identifier. For example, a command line entry to activate the Fast Relog capability for hard disks, turn PUBlic bit capability on, and disable the Disk Change warning would be: + +`ZSCFG2 F,!-` + +Certain options require additional parameters which are handled by a secondary prompt in the interactive mode. Since no prompt can be issued in the Command Line entry mode, the added parameters are passed by appending them to the Command Identifier. An example to set the Wheel Byte Write Protect to be the same as the ZCPR3 Wheel Byte, Activate the Internal path and set the Clock address to the standard B/P Bios Clock Vector is: + +`ZSCFG2 *Z,>I,CB` + +You must remember that NO spaced or other delimiters (spaces, tabs and commas) are permitted between the Command Identifier and added arguments. An "Invalid" error will generally be the result if you forget. When entering ad- dresses or numbers as arguments, they are always in Hexadecimal (base 16) with optional leading zeros. The algorithm used to interpret the number entered only retains up to four digits. Therefore, if you enter the sequence "0036C921045", it would be interpreted as 1045H. + +The following section describes each option and what alternatives are available to optimize it for your system. + + +### 6.22.3 ZSCFG2 Option Descriptions + +The two tools which permit tailoring of a ZSDOS2 system to your specific needs, INSTAL12 and ZSCFG, both present the same interactive display. This section, therefore, is applicable to installation as well as "on the fly" customization with ZSCFG2. Each option will also include specific arguments for Command Line entry of the option. Options will be covered in their order of appearance in the INSTAL12 and ZSCFG2 interactive menus. + + +#### 6.22.3.1 Public Files + +| | Description | +| ---: | :---: | +| Interactive Prompt: | 1 - Public Files | +| | (toggle) | +| Command Line Character: | P | +| Enable | P | +| Disable | P- | + +This flag controls recognition of the Plu*Perfect PUBlic attribute bit (Bit 7 of the second letter in the file name). When set to YES or activated, any file having this bit set will be accessible from any user area on the disk. This means that a search for the file will locate it on the first try, regardless of which User Area is currently selected (see 2.9.4, Public Access). If set to NO, the file will be private and can only be found if the user area matches that of the file. The default setting for this option is YES, to recognize PUBlic files. + + +#### 6.22.3.2 Public/Path Write Enable + +| | Description | +| ---: | :---: | +| Interactive Prompt: | 2 - Pub/Path Write Enable | +| | (toggle) | +| Command Line Character: | W | +| Enable | W | +| Disable | W- | + +When set to YES or activated in Command Line mode, ZSDOS2 will permit write operations to Public files, and in the case of ZSDOS2, files located along the Path. When set to NO or disabled, attempts to write to the file will result in a "Read-Only" error. The default setting for this option is NO. + + +#### 6.22.3.3 Read-Only Vector Sustain + +| | Description | +| ---: | :---: | +| Interactive Prompt: | 3 - Read-Only Vector | +| | (toggle) | +| Command Line Character: | R | +| Enable | R | +| Disable | R- | + +When set to YES or activated, the normal Write Protect vector set by ZSDOS2 function call 28 will not be cleared on a warm boot as with CP/M and ZRDOS. If set to NO or disabled, the Write Protect vector will function as in CP/M and ZRDOS. The default setting for this option is YES. + + +#### 6.22.3.4 Fast Fixed Disk Relog + +| | Description | +| ---: | :---: | +| Interactive Prompt: | 4 - Fast Fixed Disk Log | +| | (toggle) | +| Command Line Character: | F | +| Enable | F | +| Disable | F- | + +When set to YES or enabled, the allocation bit map for a fixed drive (one in which the WACD buffer is zero) will not be rebuilt after the initial drive logon. This results in much faster operation for systems with Hard Disks and RAM disks. If set to NO or disabled, the allocation map will be rebuilt each time fixed disk drives are initially selected after a warm boot. The default setting for this option is YES. + + +#### 6.22.3.5 Disk Change Warning + +| | Description | +| ---: | :---: | +| Interactive Prompt: | 5 - Disk Change Warning | +| | (toggle) | +| Command Line Character: | ! | +| Enable | ! | +| Disable | !- | + +When set to YES or enabled, a warning will be printed whenever ZSDOS2 detects that a disk in a removable-media drive (normally floppy disk drives) has been changed. If you press any key other than Control-C, ZSDOS2 will automatically log in the new disk and continue. If set to NO or disabled, no warning will be given, and the disk will be automatically logged, and the operation in progress will continue. The default setting for this option is NO, for no displayed message. + + +#### 6.22.3.6 Path Without System Attribute + +| | Description | +| ---: | :---: | +| Interactive Prompt: | 6 - Path w/o System Attr | +| | (toggle) | +| Command Line Character: | S | +| Enable | S | +| Disable | S- | + +When set to YES or enabled, Public files on drives along the Path will be found without the System Attribute being set (see 2.9.2, Path Directory Access mode). If this option is set to NO or disabled, Public files on drives addressed along the Path will not be found unless the System Attribute Bit (bit 7 of the second character in the filetype) is set (see 2.9.3, Path File Access mode). The default setting for this option is NO or Disabled, requiring the Public bit Set on accessible files. + + +#### 6.22.3.7 DOS Search Path + +| | Description | +| ---: | :---: | +| Interactive Prompt: | 7 - DOS Search Path | +| Options | (D)isable | +| | (S)et addr | +| | (I)nternal | +| | (Z)CPR3 (only if running ZCPR3) | +| Command Line Character: | > | +| Enable | >addr | +| | >I | +| | >Z (only if running ZCPR3) | +| Disable | >- | + +When this option is selected from the Interactive mode, you will be prompted for one of the three options. Contrary to the earlier ZSDOS1 configuration, a ZCPR3 style Environment Descriptor is required, so the following prompt will always be displayed: + +`DOS Path [(D)isable, (S)et, (I)nternal, (Z)CPR3] :` + +Operating ZSCFG2 in the Command Line mode permits you to select the same options directory from the command line as summarized above. No additional characters are required for Disable, Internal or ZCPR3 path selection. If you choose the (S)et option, you will be prompted for a Hexadecimal address with: + +`Enter PATH Address :` + +If you Disable the DOS Path option, ZSDOS2 functions just as CP/M 2.2 and ZRDOS for file searches. Requests for files will access only the currently logged disk and user, modified only by the Public capability, if active. This results in the familiar requirement to install utilities such as compilers, word processors and data base management systems to tell them where to go to find their overlays. + +Proper use of the DOS Path overcomes the limitation in finding program overlays and other files by simply setting the DOS Path to the drive and user area where the relevant overlays and other files are stored. The Path may be set in three ways. + +The first way is to assign a fixed address using the (S)et option from the Interactive Mode, or by appending the address to the Command Character in the Command Line mode. You will be responsible for insuring that any path at that address conforms to proper ZCPR3 path definitions. + +The second way to set a DOS Path is to use the three element Internal path by selecting the (I)nternal option from the Interactive Mode, or adding an "I" after the Command Character in the Command Line mode. As distributed, ZSDOS contains a single path entry of "A0:" to direct path searches to User Area 0 on Drive A. An alternative way to activate the Internal Path is with the `ZPATH.COM` utility made available with ZSDOS1. ZPATH will enable you to change the default path, and define up to three drive/user search elements. + +The final method of setting a DOS Path is only available if you are operating a ZCPR3 system. It is chosen by selecting the (Z)CPR3 option from the Interactive Mode, or following the Command Character with a "Z" in the Command Line mode. This Path mode will probably see little use, but is made available for systems which need more than three elements in a path. + +The principal disadvantage of using the ZCPR3 path is that requests from the command prompt (e.g. `A0>`) may result in n-squared searches where n is the number of elements in the path. The reason is that ZCPR3 will select the first path element, and ZSDOS will sequentially search along the entire path if the file is not found, returning to ZCPR3 with a "file not found" error. ZCPR3 will then select the second element with ZSDOS again searching along the entire file. This situation does not occur once an application program is started, since the ZCPR3 Command Processor is no longer active. + +The default setting for the DOS Path is "Internal". + + +#### 6.22.3.8 Wheel Byte Write Protect + +| | Description | +| ---: | :---: | +| Interactive Prompt: | 8 - Wheel Byte Protect | +| Options | (D)isable | +| | (S)et addr | +| | (Z)CPR3 | +| Command Line Character: | * | +| Enable | *addr | +| | *Z | +| Disable | *- | + +When you select this option from the Interactive mode of ZSCFG, you will presented with an additional lines containing available choices as: + +`Wheel [(D)isable, (S)et, (Z)CPR3] :` + +Selecting the (D)isable option by entering a "D" or disabling the Wheel Byte with the "*-" parameter string in the Command Line mode will cause ZSDOS2 to assume that the Wheel byte is always ON giving the user full privileges in file control (Writes, Renames and Erasures). Entering an "S" for (S)et from the Interactive mode will allow you to enter a Hexadecimal address for a Wheel Byte. It is your responsibility to insure that the byte is protected as necessary from unintentional alteration. Setting a Wheel Byte address from the Command line simply requires appending a Hexadecimal address after the Wheel Command Character. Entering a "Z" from the Interactive mode, or a "*Z" parameter string in the Command Line mode will set the address to the address defined for the Wheel byte in the ZCPR3-compatible B/P environment. The default for this option is OFF or Disabled to assume that the user has full privileges. + + +#### 6.22.3.9 Time Routine (Clock Driver) + +| | Description | +| ---: | :---: | +| Interactive Prompt: | T - Time Routine (Clock) | +| Options | (D)isable | +| | (S)et addr | +| Command Line Character: | C | +| Enable | C addr | +| Disable | C- | + +This option allows the user to enter the address of a clock driver routine conforming to ZSDOS standards, or disable an existing clock routine. When you enter a "T" at the prompt in the Interactive mode, the following appears: + +`Time (Clock) Routine [(D)isable, (S)et, (B)ios+4EH] :` + +Entering a "D" in the Interactive mode or the Command Line sequence "C-" will disable any existing clock. The primary effect of this is to cause an error return to DOS function calls 104 and 105 as well as disabling Date/Time Stamping functions. If you enter an "S" at this point in the Interactive mode, you will be further prompted for a Hexadecimal address of a clock driver. The same effect of setting a Clock Driver address is achieved in the Command Line mode by entering the "C" Command character followed by a valid Hexadecimal address beginning with a Number. Selecting "B", or entering "CB" as a command line argument, will Set the Dos Clock Driver address to the base of B/P Bios offset by 4EH which corresponds to the Jump Table entry for the B/P ZSDOS-compatible Clock driver. Do NOT enter unknown values since unpredictable results can occur! + + +#### 6.22.3.10 Stamp Last Accessed Time + +| | Description | +| ---: | :---: | +| Interactive Prompt: | A - Stamp Last Access Time | +| Options | (D)isable | +| | (E)nable | +| Command Line Character: | +A | +| Enable | +A | +| Disable | +A- | + +This option is only available with DateStamper type of Date/ Time Stamps. For P2DOS, the function is not defined and is ignored within ZSDOS2. As stated in Section 3.4.4.2, Unless you have a definite need to retain a record of the last time files are accessed, we recommend that you disable this option to reduce unnecessary overhead. To Select the Last Access Time option, enter an "A" at the Interactive main prompt. This will display the following prompt: + +`Stamp Last Access Time Routine [(D)isable, (E)nable] :` + +If you enter a "D" at this point in the Interactive mode or disable the function with the sequence "+A-" in the Command Line mode, no times will be entered in the "Last Accessed" field in the DateStamper file. This option may be re-enabled by selecting the "E" option in the Interactive mode from this secondary prompt, or the sequence "+A" from the Command Line mode. + + +#### 6.22.3.11 Stamp Create Time + +| | Description | +| ---: | :---: | +| Interactive Prompt: | C - Stamp Create Time | +| Options | (D)isable | +| | (E)nable | +| Command Line Character: | +C | +| Enable | +C addr | +| Disable | +C- | + +Entry of a "C" from the main menu in the Interactive mode will allow you to enable or disable the Create Time stamping feature. A secondary prompt will be displayed as: + +`Stamp Create Time Routine [(D)isable, (E)nable] :` + +To disable the Create time, enter a "D" from the secondary prompt, or the sequence "+C-" in the Command Line mode. To enable stamping of Create Times, enter an "E" from the secondary prompt from the Interactive mode, or by entering the Argument Sequence "+C" from the Command Line mode. + + +#### 6.22.3.12 Stamp Modify Time + +| | Description | +| ---: | :---: | +| Interactive Prompt: | M - Stamp Modify Time | +| Options | (D)isable | +| | (E)nable | +| Command Line Character: | +M | +| Enable | +M | +| Disable | +M- | + +The time of last Modification of a file is probably the most valuable of the times offered in a ZSDOS system. As such, you will probably never have a need to disable this feature. Should the need arise, however, enter an "M" at the Interactive main prompt. You will then be presented with: + +`Stamp Modify Time Routine [(D)isable, (E)nable] :` + +If you enter a "D" at this point in the Interactive mode or disable the function with the sequence "+M-" in the Command Line mode, no times will be stored in the "Modify" field of any active Time Stamp activity. + +This option may be re-enabled by selecting the "E" option in the Interactive mode from this secondary prompt, or the sequence "+M" from the Command Line mode. + + +### 6.22.4 ZSCFG2 Error Messages + +Only two error messages exist in ZSCFG2. For the most part, any error you see will deal with invalid parameters or entry mistakes. The two error messages are: + +`-- Invalid --` + +An invalid address or character was entered in a parameter. + +`*** ERROR: DOS is not ZSDOS2!` + +An attempt was made to run ZSCFG2 on an Operating system which was not ZSDOS2. This program cannot function under any other operating system. + + +## 6.23 ZXD - File Lister Utility for ZSDOS2 + +ZXD Version 1.66 is a modification of an earlier version released with our ZSDOS 1 package. It is the ZSDOS Extended Directory listing program derived from the ZCPR3 tool XD III written by Richard Conn and now modified to properly return disk sizing information from a banked ZSDOS 2 Operating System. Many additional capabilities were added over the original XD III, not the least of which is the ability to display time stamps for each file in a variety of formats. ZXD can display file Dates and times from DateStamper, P2DOS, and Plu*Perfect Systems' DosDisk stamp methods. In ZCPR3 systems, the Wheel byte is used to disable some functions as a security precaution in remote access systems. + + +### 6.23.1 Using ZXD + +ZXD is activated by entering its name at the command prompt, and may be followed by optional drive and user specifications to obtain the directory of another drive or user area. It may also be followed by various parameters which alter the format and/or content of the display. If options are listed without being preceded with a File Specification (drive, user, file name), then they must be preceded by the standard option character, a slash. A help message may be obtained in the standard manner by entering: + +`ZXD //` + +ZXD accepts directions in a natural form popularized with the ZCPR series of Command Processor replacements. Using the conventions described in Section 1.2, the syntax is summarized by: + +`ZXD [dir:][afn] [/][options]` + +If ZXD is called with no arguments, a display of only those files satisfying built-in default conditions will be displayed. Normally these defaults select only non-system files in the current drive and user. The default selections may be modified by option parameters detailed below. If option parameters are desired without drive, user or file specifications, then the options must be prefixed with a slash. The slash is optional if any redirection or file specifications are entered. + + +### 6.23.2 ZXD Options + +Option parameters, consisting of one or two characters, allow you to obtain selected information from files on a disk, or to tailor the display to your particular needs. Each of these options is also reflected as a permanent default. After deciding which parameters you use most by using the command line options, we recommend configuring ZXD to reflect those parameters as defaults. The results will be the requirement to enter fewer keystrokes, and consequently faster operation when a directory scan is required. + +The option characters are described in alphabetical order in the following sections. + + +#### 6.23.2.1 Select Files by Attribute + +In order to avoid cluttering a directory display with unwanted file names, ZXD features a flag which controls addition of those files marked with the SYStem Attribute Bit. The A Option controls this feature. It requires a second character of S, N, or A. Control offered by these characters is: + +| Option | Description | +| :---: | :--- | +| `S` | Include Only Files marked with the SYStem Attribute | +| `N` | Include Only Files Not marked with the SYStem Attribute (this is the defalt condition) | +| `A` | Include All Files | + +Since listing of all Non-SYStem files is the default condition, you will probably not use the N option very often. The A option, on the other hand, offers a simple way of viewing All files within the current directory, including SYStem files which are normally invisible due to the Attribute bit. + +In a ZCPR3 system where Wheel access has not been granted (Wheel byte is Off), this option is forced to Non-SYStem files only and the A option character is not permitted. + + +#### 6.23.2.2 Date Display Format + +The Dates for a ZXD display may be displayed in either US form of MM/DD/YY or European form of DD.MM.YY. You may override the default form with the D option. Here is an example of the two types of date displays: + +US Form: + +```generic +ZXD Ver 1.66 3 Apr 1993 15:43:17 +Filename.Typ Size Modified Filename.Typ Size Modified +-------- --- ---- -------- -------- --- ---- -------- +INITDIR .COM 4k 07:01-09/17/88 ZPATH .COM 4k 07:50-09/17/88 +ZXD .COM 8k 08:01-09/17/88 + C2: -- 3 Files Using 16K (324K Free) +``` + +European Form: + +```generic +ZXD Ver 1.66 3 Apr 1993 15:43:11 +Filename.Typ Size Modified Filename.Typ Size Modified +-------- --- ---- -------- -------- --- ---- -------- +INITDIR .COM 4k 07:01-17.09.88 ZPATH .COM 4k 07:50-17.09.88 +ZXD .COM 8k 08:01-17.09.88 + C2: -- 3 Files Using 16K (324K Free) +``` + + +#### 6.23.2.3 Disable Date (NoDate) Display + +While the display of date and time information is the default mode of ZXD, this may be disabled with the N option to display more file names on a screen. + + +#### 6.23.2.4 Output Control Option + +The O option controls ZXD's printer or screen output, and requires a second character which adds additional control to output formats. The second characters recognized are: + +| Option | Description | +| :---: | :--- | +| `F` | Send a Form Feed character at the end of the list | +| `H` | Toggle Horizontal/Vertical display of sorted listing | + + +#### 6.23.2.5 Output to Printer + +Option P controls output to the printer. When this option is given, the sorted directory listing is sent to both the console screen and the printer. This option is disabled and not available in a ZCPR3 system where Wheel access has not been granted (Wheel byte is Off). + + +#### 6.23.2.6 Sort by Name or Type + +The default sort condition for ZXD is to first sort by File Name, then by File Type within matching Names. Option S reverses the sequence. + + +#### 6.23.2.7 Primary DateStamp + +ZXD features an algorithm which will attempt to find one of several types of Date/Time Stamps for each file. The default conditions tell ZXD to first attempt to locate DateStamper type of Stamps. If that fails, a search is made for DosDisk stamps from MS/PC-DOS disks, and finally to check for P2DOS type stamps. The T option causes the DateStamper checks to be bypassed, thereby speeding response if DateStamper type stamping is never used. + + +#### 6.23.2.8 All User Areas + +The distribution version of ZXD will only search a single User area, either the currently logged or the explicitly stated area, for files. The U option will locate files in all user areas on the disk. Combining the U with the AA options will list all files in all user areas, both system and non-system, on a disk. This option is disabled and not available in a ZCPR3 system where Wheel access has not been granted (Wheel byte is Off). + + +#### 6.23.2.9 Wide Display + +ZXD only displays the "Last Modified" Date/Time Stamp. This may be reversed by appending the W option to the Command Line, which generates a Wide of all available Stamps. Only DateStamper has provisions for all three stamp categories; P2DOS contains only Created and Modified stamps, while the single MS/PC-DOS stamp accessed through DosDisk best corresponds to "Modified". A display created with this option is: + +```generic +Filename.Typ Size Created Last Access Modified +-------- --- ---- ------- ---- ------ -------- +BU16 .COm 8k 17:26-06/12/88 08:42-08/21/88 17:26-06/12/88 +COPY .COM 8k 15:06-09/17/88 15:06-09/17/88 +ZPATH .COM 4k 07:50-09/17/88 15:02-09/17/88 07:50-09/17/88 +ZXD .COM 8k 08:00-09/17/88 08:01-09/17/88 +``` + + +### 6.23.3 Customizing ZXD + +The configuration utility ZCNFG.COM is used to alter the default settings in ZXD. Settings and text prompts for ZXD are contained in the file ZXD.CFG which must be accessible to ZCNFG for any configuration change. All options are simple ON/OFF, or reversible settings and correspond to the options discussed in Section 6.23.2 above. See Section 4.8 of the ZSDOS 1.0 User Manual or ZCNFG documentation on the Ladera Z-Node for details on using ZCNFG. + + +## 6.24 Additional Utilities (NOTES Spring 2001) + +Several of the utilities documented in this manual have also matured over the years, and some new ones added. Some of the more significant are: + +**HASHINI.COM** - This utility prepares a fresh directory for file accesses via the ZSDOS2 hash algorithm implemented in ZS203.ZRL. See the built-in help for more details on use. + +**SIZERAM.COM** - Examine and report memory statistics in a Banked system. This utility uses the inter-bank data movement features of a Banked BPBIOS system and will not execute in a non-banked system. + +**TURBO.COM** - When using the Z8S180 CPU, this utility allows you to switch the internal divide-by-two circuit in and out of operation resulting in a doubling or halving of the processor speed. + diff --git a/Doc/CPM/BPBIOS/BPBIOS_7_ZSDOS2.md b/Doc/CPM/BPBIOS/BPBIOS_7_ZSDOS2.md new file mode 100644 index 00000000..efc80a13 --- /dev/null +++ b/Doc/CPM/BPBIOS/BPBIOS_7_ZSDOS2.md @@ -0,0 +1,37 @@ +# 7 ZSDOS Version 2 + +Version 2 of ZSDOS is currently in a developmental phase. The version provided with this package is preliminary and should not be considered a final work. Be sure you back up any files which you don't mind sacrificing, and please let us know in as much detail as possible any problems you experience. + +In addition to the ZSDOS Version call (Function 48) returning 20H signifying ZSDOS2, three new Operating System functions have been added. They are: + +| Function 46 | Return Disk Free Space | +| ---: | :--- | +| Enter: | C = 46 (function #) | +| | E = Drive # (A=0..P=15) | +| Exit: | A = 0 if Ok, <>0 if Error | +| | Disk Free Space in kilobytes is placed in DMA+0 (LSB) thru DMA+3 (MSB) | + +This function returns Disk Free Space from fully-banked systems where the ALV buffers are not directly accessible by applications programs. It **MUST** be used to reliably determine free space since there is no way for programs to ascertain which System Bank (if more than one) contains the Allocation Bit Map. For most reasonably-sized systems, only the lower two or three bytes will be used, but four bytes are allocated to accommodate a maximally-sized system. + +| Function | Return Environment Descriptor Address | +| ---: | :--- | +| Enter: | C = 49 (function #) | +| Exit: | HL = Address of Env Desc. | + +This function returns the address of a ZCPR 3.4 "type" Environment Descriptor needed in B/P Bios systems. Rather than rely on the Command Processor inserting the ENV address into application programs upon execution, this function may be used to reliably acquire the ENV address at any time. + +| Function 152 | Parse File Name | +| ---: | :--- | +| Enter: | C = 152 (function #) | +| | DE = Pointer to dest FCB | +| | DMA --> start of parse string | +| Exit: | A = Number of "?" in fn.ft | +| | DE = points to delimiter | +| | FCB+15 will be 0 if parse Ok, 0FFH if errors occurred | + +This function may be used to replace Z3LIB library routines in a more robust manner and produce consequently smaller applications programs. It is fully compliant with ZCPR 3.4 parse specifications. + + +## 7.1 NOTES Spring 2001 + +The versions of ZSDOS2 (the Banked Z-System DOS) and Z4x Banked Command Processor Replacement have been modified over the years. The manual may refer to specific versions, or by generic names. As of the Spring 2001 release under the GNU General Public License, Two versions of ZSDOS2 are provided; `ZS203.ZRL` which contains code for hashed directories, and `ZS227G,ZRL` which does not. diff --git a/Doc/CPM/BPBIOS/BPBIOS_8_ZCPR4.md b/Doc/CPM/BPBIOS/BPBIOS_8_ZCPR4.md new file mode 100644 index 00000000..f3162af2 --- /dev/null +++ b/Doc/CPM/BPBIOS/BPBIOS_8_ZCPR4.md @@ -0,0 +1,10 @@ +# 8 ZCPR Version 4 + +`Z40.ZRL` is a consolidation of ZCPR34 and many of the RCP features commonly in use, modified by the need to bank as much of the Command Processor as possible. When Z40 is used in a Fully-Banked system, you may not need much of, or any Resident Command Processor with your system. Z40 relys on ZSDOS2 and will **NOT** work without it since the Command Line Parser and disk free space calculations have been removed in favor of ZSDOS2 services. Additionally, the prompt line displays the time and will only function correctly if he ZSDOS2 clock is enabled. Comments on how these new System components work would be appreciated. + +More complete documentation is provided in the `Z40.HLP` files included with the distribution diskettes, and a list of active functions is available with the H command at the prompt. To read the On-line help files, use `HELP.COM` available for downloading from any Z-Node. + + +## 8.1 NOTES Spring 2001 + +The versions of ZSDOS2 (the Banked Z-System DOS) and Z4x Banked Command Processor Replacement have been modified over the years. The manual may refer to specific versions, or by generic names. As of the Spring 2001 release under the GNU General Public License, the latest version of the Z4x Processor Replacement is `Z41.ZRL` which features a small amount of tailoring. A new utility; **`CONFZ4.COM`** is available for this purpose. diff --git a/Doc/CPM/BPBIOS/BPBIOS_9_Glossary.md b/Doc/CPM/BPBIOS/BPBIOS_9_Glossary.md new file mode 100644 index 00000000..326043fd --- /dev/null +++ b/Doc/CPM/BPBIOS/BPBIOS_9_Glossary.md @@ -0,0 +1,100 @@ +# GLOSSARY + +**Application Programs** +In contrast to utility programs (see), application programs or applications are larger programs such as word processors which function interactively with the user. + +**BDOS** +Basic Disk Operating System. The machine-independent, but usually processor-dependent, program which controls the interface between application programs and the machine-dependent hardware devices such as printers, disk drives, clocks, etc. It also establishes the concept of files on media and controls the opening, reading, writing, and closing of such constructs. + +**BGii** +BackGrounder ii from Plu*Perfect Systems, a windowing task-switching system for CP/M users with hard or RAM disks. + +**BIOS** +Basic Input/Output System. Machine-dependent routines which perform actual peripheral device control such as sending and receiving characters to the console, reading and writing to disk drives, etc. + +**Bit** +BInary digiT. An element which can have only a single on or off state. + +**Bit Map** +An array of bits used to represent or map large arrays of binary information in a compact form. + +**Boot** +The term used for the starting sequence of a computer. Generally applies to starting from a "Cold," or power-off state, and includes the loading of Operating System, and configuration steps. + +**Byte** +A grouping of eight bits. + +**CPR** +Command Processor Replacement. Replaces CCP (see below). Example: ZCPR + +**CCP** +Console Command Processor. The portion of the operating system that interprets user's commands and either executes them directly or loads application programs from disk for execution. The CCP may be overwritten by applications, and is reloaded by the "Warm Boot" function of the BIOS. + +**Checksum** +An value which arithmetically summarizes the contents of a series of memory locations, and used to check the current contents for errors. + +**Clock Driver** +A software link between a Non-banked ZSDOS and the clock on your system. The clock driver allows ZSDOS and its utilities to read the clock which is normally inherent in the B/P Bios. + +**Command Script** +Sometimes called simply scripts, command scripts allow you to create a single command which issues other commands to perform a unique set of actions. CP/M submit files are one kind of command script familiar to all CP/M users. ZCPR also offers more sophisticated types of scripts such as aliases and command files (e.g., ALIAS.CMD). + +**DateStamper** +A software package developed by Plu*Perfect Systems to allow time and date stamping of files. The Boot System uses an external module in the file LDDS.COM to implement DateStamper, while ZSDOS2 automatically supports this stamping method. DateStamper is unique among file stampers for microcomputers for two reasons: first, it maintains all file stamps within a file; second, it maintains stamps for create, access, and modify time/date for each file. + +**DDT** +Dynamic Debugging Tool. A utility distributed with CP/M 2.2 which can display, disassemble, or alter disk files or areas of memory using opcodes or hexadecimal values. + +**DOS** +Disk Operating System. Often used term for the BDOS, but generally refers to the aggregate of CCP, BDOS and BIOS. + +**DosDisk** +A software package from Plu*Perfect Systems which allows users of CP/M and compatible computers to write and read files directly to and from standard 5-1/4" 40-track Double-Sided, Double-Density MS-DOS format diskettes. This is the standard "360k" disk format used in IBM-PC compatible computers. + +**FCB** +File Control Block. A standard memory structure used by CP/M and compatible operating systems to regulate disk file operations. + +**File Attributes** +Also known as file attributes, reserved bits stored along with file names in disk directories which control how the files are accessed. + +**Hexadecimal** +A base-16 numbering system consisting of the numbers 0-9 and letters A-F. Often used to represent bytes as two digits (00 to FF). Use of Hexadecimal numbers is usually represented by suffixing the number with an "H" as in "01H". + +**IOBYTE** +Input/Output Byte. A reserved byte at location 3 which is used by some CP/M BIOS's to redirect input and output between devices such as terminals and printers. + +**K** +Usually refers to Kilobyte or 1024 (2^10th power) bytes. + +**P2D** +P2Dos Datestamps. An alternative form of file stamping used in HAJ Ten Brugge's P2DOS. P2D stamps are compatible with CP/M Plus time and date stamps. This format is supported in a B/P Boot system with the LDP2D.COM Stamp module, and automatically in ZSDOS2. + +**RAM** +Random Access Memory. As opposed to Read Only Memory (ROM) the area of a computer's memory which may be both read from and written to. + +**RSX** +Resident System Extension. A program module complying with a standard developed by Plu*Perfect Systems for extending the functionality of a CP/M 2.2 compatible Operating System. The module must be loaded at the top of the Transient Program Area, and below the Console Command Processor. + +**System Prompt** +The familiar A> prompt which appears soon after CP/M computersare started up. + +**TPA** +Transient Program Area. That addressable memory space from the lowest available address to the highest available address. Usually this extends from 100H to the base of the BDOS (assuming that the Command Processor is overwritten), or the base of the lowest RSX. + +**Utility Programs** +In contrast to application programs (see), utility programs or utilities are shorter programs, such as directory programs, which accept a single command from the user. + +**Wheel Byte** +Taking its name from the colloquial "Big Wheel," the Wheel byte controls security under ZCPR and ZSDOS. When the byte is set to a non-zero value, the user has "Wheel status" and may execute commands unavailable to other users. + +**Word** +In the computer context, a fixed number of bytes. For 8- bit microcomputers, a word is usually two bytes, or 16 bits. + +**Z-System** +An operating system which completely replaces CP/M by substituting ZCPR for Digital Research's command processor and ZSDOS for Digital Research's disk operating system. ZCPR and ZSDOS complement one another in several ways to enhance performance. + +**ZCPR** +Z80 Command Processor Replacement. Originally developed as a group effort of the Special Interest Group for Microcomputers (SIG/M), but refined by Richard Conn to ZCPR version 3.0 and Jay Sage to versions 3.3 and 3.4. + +**ZRL** +A form of Relocatable file image using specified "Named Common" bases. For ZSDOS, files of this type are MicroSoft-compatible REL files using only the Common Relative segment "_BIOS_". diff --git a/Doc/ChangeLog.txt b/Doc/ChangeLog.txt index 666e1442..407f55e3 100644 --- a/Doc/ChangeLog.txt +++ b/Doc/ChangeLog.txt @@ -11,6 +11,7 @@ Version 3.6 - WBW: Added enhanced Hi-Tech C Compiler files from Ladislau Szilagyi - WBW: Added boundary check to ram/rom disk driver - WBW: Per Peter Onion, switch KERMIT default file xfer mode to binary +- J?L: Source for ZSDOS2 and BPBIOS Utilities (from disassembly) Version 3.5.1 ------------- diff --git a/Doc/RomWBW Applications.pdf b/Doc/RomWBW Applications.pdf index 589e9ab7..f4da6b27 100644 Binary files a/Doc/RomWBW Applications.pdf and b/Doc/RomWBW Applications.pdf differ diff --git a/Doc/RomWBW Disk Catalog.pdf b/Doc/RomWBW Disk Catalog.pdf index 113715b5..a033c65d 100644 Binary files a/Doc/RomWBW Disk Catalog.pdf and b/Doc/RomWBW Disk Catalog.pdf differ diff --git a/Doc/RomWBW Hardware.pdf b/Doc/RomWBW Hardware.pdf index 47012b2f..c0dc8b29 100644 Binary files a/Doc/RomWBW Hardware.pdf and b/Doc/RomWBW Hardware.pdf differ diff --git a/Doc/RomWBW Introduction.pdf b/Doc/RomWBW Introduction.pdf index 8c7a2ec8..43b00cad 100644 Binary files a/Doc/RomWBW Introduction.pdf and b/Doc/RomWBW Introduction.pdf differ diff --git a/Doc/RomWBW System Guide.pdf b/Doc/RomWBW System Guide.pdf index 20c04a78..4461d2db 100644 Binary files a/Doc/RomWBW System Guide.pdf and b/Doc/RomWBW System Guide.pdf differ diff --git a/Doc/RomWBW User Guide.pdf b/Doc/RomWBW User Guide.pdf index 9be352a1..6ad61973 100644 Binary files a/Doc/RomWBW User Guide.pdf and b/Doc/RomWBW User Guide.pdf differ diff --git a/ReadMe.md b/ReadMe.md index 1eb673b8..46bfe989 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -7,7 +7,7 @@ **RomWBW Introduction** \ Version 3.6 \ Wayne Warthen ([wwarthen@gmail.com](mailto:wwarthen@gmail.com)) \ -08 Jun 2025 +16 Jun 2025 # Overview @@ -343,6 +343,9 @@ let me know if I missed you! - Rob Gowin created an online documentation site via MkDocs, and contributed a driver for the Xosera FPGA-based video controller. +- Jörg Linder has contributed disassembled and nicely commented source + for ZSDOS2 and the BPBIOS utilities. + ## Related Projects Outside of the hardware platforms adapted to RomWBW, there are a variety diff --git a/ReadMe.txt b/ReadMe.txt index 5adcae8f..1670f092 100644 --- a/ReadMe.txt +++ b/ReadMe.txt @@ -1,6 +1,6 @@ RomWBW Introduction Wayne Warthen (wwarthen@gmail.com) -08 Jun 2025 +16 Jun 2025 @@ -350,6 +350,9 @@ let me know if I missed you! - Rob Gowin created an online documentation site via MkDocs, and contributed a driver for the Xosera FPGA-based video controller. +- Jörg Linder has contributed disassembled and nicely commented source + for ZSDOS2 and the BPBIOS utilities. + Related Projects diff --git a/Source/BPBIOS/@WBW Issues.txt b/Source/BPBIOS/@WBW Issues.txt index ae68d9a6..99649c81 100644 --- a/Source/BPBIOS/@WBW Issues.txt +++ b/Source/BPBIOS/@WBW Issues.txt @@ -15,8 +15,7 @@ as needed. The RomWBW ASSIGN command is not supported. BPBIOS will boot from the first hard disk unit number you assign and always from the first slice. -BPBIOS does not yet understand the 1024 directory entry -hard disk format. You must use the 512 directory entry -format images. +BPBIOS is hard-coded to use the 1024 directory entry hard disk +format (hd1k). The hd512 format is not supported at all. ---WBW 1:25 PM 10/7/2021 \ No newline at end of file +--WBW 5:04 PM 6/16/2025 \ No newline at end of file diff --git a/Source/BPBIOS/Build.cmd b/Source/BPBIOS/Build.cmd index b83df0c4..7460512e 100644 --- a/Source/BPBIOS/Build.cmd +++ b/Source/BPBIOS/Build.cmd @@ -2,6 +2,7 @@ setlocal pushd ZCPR33 && call Build || exit /b & popd +pushd UTIL && call Build || exit /b & popd set TOOLS=..\..\Tools set PATH=%PATH%;%TOOLS%\zxcc;%TOOLS%\cpmtools; diff --git a/Source/BPBIOS/Clean.cmd b/Source/BPBIOS/Clean.cmd index c0174859..69ed8e43 100644 --- a/Source/BPBIOS/Clean.cmd +++ b/Source/BPBIOS/Clean.cmd @@ -11,3 +11,4 @@ if exist *.bak del *.bak if exist def-ww.lib del def-ww.lib pushd ZCPR33 && call Clean.cmd & popd +pushd UTIL && call Clean.cmd & popd diff --git a/Source/BPBIOS/Makefile b/Source/BPBIOS/Makefile index fd405b9f..15a600d7 100644 --- a/Source/BPBIOS/Makefile +++ b/Source/BPBIOS/Makefile @@ -13,7 +13,7 @@ OTHERS = zcpr33.rel bp*.prn bp*.rel \ TOOLS = ../../Tools -SUBDIRS = ZCPR33 +SUBDIRS = ZCPR33 UTIL include $(TOOLS)/Makefile.inc zcpr33.rel: diff --git a/Source/BPBIOS/UTIL/Build.cmd b/Source/BPBIOS/UTIL/Build.cmd new file mode 100644 index 00000000..6a94b476 --- /dev/null +++ b/Source/BPBIOS/UTIL/Build.cmd @@ -0,0 +1,55 @@ +@echo off +setlocal + +set TOOLS=..\..\..\Tools +set PATH=%PATH%;%TOOLS%\zxcc;%TOOLS%\cpmtools; +set CPMDIR80=%TOOLS%/cpm/ + +zxcc Z80ASM -BPBUILD/RFS || exit /b +zxcc SLRNK -BPBUILD/N,/A:100,/D:23E0,BPBUILD,B:SLINK0,B:VLIBS/S,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b + +zxcc Z80ASM -BPCNFG/RFS || exit /b +zxcc SLRNK -BPCNFG/N,/A:100,/D:3A55,BPCNFG,B:VLIBS/S,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b + +zxcc Z80ASM -BPSWAP/RFS || exit /b +zxcc SLRNK -BPSWAP/N,/A:100,/D:0854,BPSWAP,B:VLIBS/S,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b + +zxcc Z80ASM -BPSYSGEN/RFS || exit /b +zxcc SLRNK -BPSYSGEN/N,/A:100,/D:08CD,BPSYSGEN,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b + +zxcc Z80ASM -CONFZ4/RFS || exit /b +zxcc SLRNK -CONFZ4/N,/A:100,/D:080A,CONFZ4,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b + +zxcc Z80ASM -HASHINI/RFS || exit /b +zxcc SLRNK -HASHINI/N,/A:100,/D:09E5,HASHINI,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b + +zxcc Z80ASM -LDSYS/RFS || exit /b +zxcc SLRNK -LDSYS/N,/A:100,/D:0CF8,LDSYS,B:VLIBS/S,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b + +zxcc Z80ASM -SHOWHD/RFS || exit /b +zxcc SLRNK -SHOWHD/N,/A:100,/D:064D,SHOWHD,B:SYSLIBS/S,/E || exit /b + +zxcc Z80ASM -SIZERAM/RFS || exit /b +zxcc SLRNK -SIZERAM/N,/A:100,/D:0750,SIZERAM,B:VLIBS/S,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b + +zxcc Z80ASM -ZSCFG2/RFS || exit /b +zxcc SLRNK -ZSCFG2/N,/A:100,/D:145E,ZSCFG2,B:VLIBS/S,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b + + + + + + + + + + + + + + + + + +:: zxcc Z80ASM +:: zxcc ZMAC -zcpr33.z80 -/P || exit /b diff --git a/Source/BPBIOS/UTIL/Clean.cmd b/Source/BPBIOS/UTIL/Clean.cmd new file mode 100644 index 00000000..96451c7d --- /dev/null +++ b/Source/BPBIOS/UTIL/Clean.cmd @@ -0,0 +1,6 @@ +@echo off +setlocal + +if exist *.com del *.com +if exist *.lst del *.lst +if exist *.rel del *.rel diff --git a/Source/BPBIOS/UTIL/Makefile b/Source/BPBIOS/UTIL/Makefile new file mode 100644 index 00000000..22f50800 --- /dev/null +++ b/Source/BPBIOS/UTIL/Makefile @@ -0,0 +1,40 @@ +OBJECTS = bpbuild.com bpcnfg.com bpswap.com bpsysgen.com confz4.com hashini.com \ + ldsys.com showhd.com sizeram.com zscfg2.com +TOOLS = ../../../Tools +# DEST = .. +OTHERS = *.rel + +include $(TOOLS)/Makefile.inc + +%.rel: %.z80 + @$(ZXCC) $(CPM)/Z80ASM -$(basename $<)/RFS + +bpbuild.com : bpbuild.rel + $(ZXCC) slrnk -bpbuild/n,/a:100,/d:23e0,bpbuild,b:slink0,b:vlibs/s,b:z3libs/s,b:syslibs/s,/e + +bpcnfg.com : bpcnfg.rel + $(ZXCC) slrnk -bpcnfg/n,/a:100,/d:3a55,bpcnfg,b:vlibs/s,b:z3libs/s,b:syslibs/s,/e + +bpswap.com : bpswap.rel + $(ZXCC) slrnk -bpswap/n,/a:100,/d:0854,bpswap,b:vlibs/s,b:z3libs/s,b:syslibs/s,/e + +bpsysgen.com : bpsysgen.rel + $(ZXCC) slrnk -bpsysgen/n,/a:100,/d:08cd,bpsysgen,b:z3libs/s,b:syslibs/s,/e + +confz4.com : confz4.rel + $(ZXCC) slrnk -confz4/n,/a:100,/d:080a,confz4,b:z3libs/s,b:syslibs/s,/e + +hashini.com : hashini.rel + $(ZXCC) slrnk -hashini/n,/a:100,/d:09e5,hashini,b:z3libs/s,b:syslibs/s,/e + +ldsys.com : ldsys.rel + $(ZXCC) slrnk -ldsys/n,/a:100,/d:0cf8,ldsys,b:vlibs/s,b:z3libs/s,b:syslibs/s,/e + +showhd.com : showhd.rel + $(ZXCC) slrnk -showhd/n,/a:100,/d:064d,showhd,b:syslibs/s,/e + +sizeram.com : sizeram.rel + $(ZXCC) slrnk -sizeram/n,/a:100,/d:0750,sizeram,b:vlibs/s,b:z3libs/s,b:syslibs/s,/e + +zscfg2.com : zscfg2.rel + $(ZXCC) slrnk -zscfg2/n,/a:100,/d:145e,zscfg2,b:vlibs/s,b:z3libs/s,b:syslibs/s,/e diff --git a/Source/BPBIOS/UTIL/bpbuild.z80 b/Source/BPBIOS/UTIL/bpbuild.z80 new file mode 100644 index 00000000..e427b741 --- /dev/null +++ b/Source/BPBIOS/UTIL/bpbuild.z80 @@ -0,0 +1,2357 @@ + TITLE "B/P Bios Build System Image" +;************************************************************************ +;* B P B U I L D * +;* Create a system image file containing B/P Bios * +;* by Harold F. Bower and Cameron W. Cotrill * +;*----------------------------------------------------------------------* +;* Disassembly: jxl Jan 2025 * +;* public release 1.0 Apr 2025 * +;* see remarks at the end * +;*----------------------------------------------------------------------* +;* LINK with Version 4 libraries: VLIB, Z3LIB, SYSLIB * +;* and SLINK0.REL module (as included in ZSDOS v1 GNU public release) * +;* * +;* A>Z80ASM BPBUILD/RS * +;* A>SLRNK BPBUILD/N,/A:100,/D:23E0,BPBUILD,SLINK0,VLIBS/S,Z3LIBS/S,SYSLIBS/S,/E * +;************************************************************************ + +VER EQU 10 +REV EQU ' ' + +DATE MACRO + DEFB '31 Aug 92' + ENDM + + +CTRLC EQU 03H ; Control-C character +BEL EQU 07H ; Bell character +TAB EQU 09H ; Tab character +LF EQU 0AH ; Line Feed character +CR EQU 0DH ; Carriage Return character +ESC EQU 1BH ; Escape character + +CPMBDOS EQU 5 ; CP/M BDOS entry point (JP) +CPMFCB EQU 5CH ; CP/M standard FCB #1 (+1 filename, +9 filetype) +CPMDMA EQU 80H ; CP/M standard DMA buffer + + +; SLINK0 M-Rel linker module + EXTRN LINK ; get + PUBLIC @GBYTE ; make visible + +; From VLIB Get.. + EXTRN Z3VINIT, GXYMSG, VPRINT, EREOL, TINIT, DINIT, CLS, GOTOXY + +; From Z3LIB Get.. + EXTRN GETNAME, PRTNAME, ZFNAME, GZMTOP, WHRENV + +; From SYSLIB Get.. + EXTRN PUTUD, RETUD, SETDMA, INITFCB, BLINE, CRLF, CAPINE, CAPIN, PFN1, PFN3 + EXTRN F$EXIST, F$MOPEN, F$CLOSE, F$DELETE, F$OPEN, F$READ, F$RENAME, F$WRITE + EXTRN PADC, PHLFDC, PHL4HC, COUT, EVAL10, EVAL16, ISALNUM, CODEND + + +;::::: PROGRAM START + + ORG 100H + CSEG + + +BPBUILD: JP START ; bypass header + DEFB 'Z3ENV' ; this is a ZCPR3 utility + DEFB 1 ; show external environment + +ENVADR: DEFW 0 ; addr of Z3 environment + +START: LD HL,(CPMBDOS) ; ##### BUG: should rather be CPMBDOS+1 + CALL WHRENV ; find Z3 Environment Descriptor + LD (ENVADR),HL ; store ENV ptr locally + CALL Z3VINIT ; ..and init for VLIB/Z3LIB routines + CALL TINIT ; init terminal characteristics + CALL GETNAME ; get actual program name + CALL GETQFLG ; get quiet flag + AND A ; check if verbose mode + JR NZ,START0 ; ..if not, skip over (= quiet) + + CALL VPRINT + DEFB 1,'B/P System Build',2,' V',VER/10+'0','.',VER MOD 10 + '0',REV,' ' + DATE + DEFB ' ',CR,LF + DEFB 0 + +START0: CALL GZMTOP ; get top of memory (first byte _not_ to be used) + DEC HL ; -1 + EX DE,HL ; save temporarily + CALL CODEND ; get available page after code end (WSPC area) + EX DE,HL ; swap regs back + XOR A ; reset C-Flag + SBC HL,DE ; calc remaining TPA size + EX DE,HL ; use DE as counter + +CLRTPA: LD (HL),0 ; clear TPA memory + INC HL ; ..from end of program to top of memory + DEC DE + LD A,E + OR D ; counter = zero ? + JR NZ,CLRTPA ; ..loop till done + + LD (STACK),SP ; set local stackpointer + LD SP,STACK + CALL RETUD ; get current drive (B) and user (C) + LD (OLDDU),BC ; ..and store + + ; evaluate command line + LD A,(CPMFCB+1) ; get first char of command line (in FCB #1) + CP '/' ; is this a help request ? + JP Z,HELP ; ..if so, jump display help and exit + CP ' ' ; is file name blank ? + JR Z,INITRAM ; ..if so, jump to ask for manual input + + ; a file name was specified (= image file), attempt to read header + LD HL,CPMFCB+9 ; check file type + LD A,(HL) + CP ' ' ; is first char ? + JR NZ,RDFILE ; ..if not, skip over + EX DE,HL ; else, swap regs + LD HL,FTYPES+3 ; ptr to standard file type 'IMG' + LD BC,3 ; ..and copy 3 chars + LDIR +RDFILE: LD HL,CPMFCB+1 ; ptr to file name in standard FCB #1 + LD DE,IMGFN_I ; ptr to default file name for system image + LD BC,11 ; copy 11 chars from FCB to IMG Header area + LDIR + CALL CODEND ; get addr WSPC + CALL RDHDR ; read first page of IMG file + OR A ; check if successful + JR NZ,RDFILE0 ; ..if not, jump to display msg + CALL CODEND ; get addr WSPC + LD DE,IMGHD_I ; point to area for IMG file header + JR RDFILE1 ; ..and jump to continue +RDFILE0: CALL VPRINT + DEFB CR,LF,"+++ Can't Read...any key to continue w/defaults +++" + DEFB 0 + CALL CAPINE ; get input (any key) + CALL CODEND ; get addr WSPC + EX DE,HL ; swap regs + LD HL,IMGHD_I ; point to area for IMG file hdr + +RDFILE1: LD BC,0100H ; bytes to copy (1 page) + LDIR ; ..from hdr to WSPC (no file, or read error) + ; or from WSPC to hdr (file read successfully) + + ; initialize ram storage +INITRAM: LD HL,CCPFCB + XOR A ; nullify A + LD B,IMGFCB+36-CCPFCB ; B= 179 +INITRM0: LD (HL),A ; clear variables + INC HL ; with (180 bytes) + DJNZ INITRM0 + LD BC,11 ; bytes to copy + PUSH BC + LD HL,CFNAM_I ; copy ZCPR file name + LD DE,CCPFCB+1 + LDIR + POP BC ; restore # bytes + PUSH BC + LD HL,DFNAM_I ; copy ZSDOS file name + LD DE,DOSFCB+1 + LDIR + POP BC ; restore # bytes + PUSH BC + LD HL,BFNAM_I ; copy B/P Bios file name + LD DE,BIOSFCB+1 + LDIR + POP BC ; restore # bytes + LD HL,IMGFN_I ; copy IMG file name + LD DE,IMGFCB+1 + LDIR + + +;::::: MAIN MENU + +M0MAIN: CALL M0SHOW ; display menu + CALL MSELECT ; get user for input + CP ' ' ; is it ? + JP Z,MKSYS ; ..build new system + CP CR ; ? + JP Z,MKSYS ; ..build new system + CP ESC ; ? + JP Z,M$ABORT ; ..quit program + CP CTRLC ; ? + JP Z,M$ABORT ; ..quit program + CP '1' ; '1' ? + JR Z,M0GOM1 ; ..go to Files menu + CP '2' ; '2' ? + JP Z,M0GOM2 ; ..go to Bios config menu + CP '3' ; '3' ? + JP Z,M0GOM3 ; ..go to Environment menu + JR M0MAIN + +M0GOM1: CALL M1FILE + JR M0MAIN + +M0GOM2: CALL M2BIOS + JR M0MAIN + +M0GOM3: CALL M3ENV + JR M0MAIN + + +;::::: MAKE (build) NEW SYSTEM + +MKSYS: CALL CLS + CALL VPRINT + DEFB CR,LF,'..building system..',CR,LF,LF + DEFB 0 + + + ;----- Pre-run to determine addr/size of linked system segments + + ; determine CPR size/addr + LD HL,0 + LD (COMTB6),HL ; clear org B2RAM Common + LD (COMTB5),HL ; clear org BANK2 Common + LD DE,CCPFCB + LD HL,COMTBL + CALL LNKDSZ ; determine CCP segment sizes + LD (CCNBSZ),HL ; store CCP CSEG Non-banked size + ADD HL,BC ; add DSEG size + CALL ALIGN ; ..align to next sector boundary + LD (CNBSZ_I),HL ; ..and store CCP Non-banked total size + LD HL,(COMTB6) ; get B2RAM Common + LD (CDBKSZ),HL ; ..and store CCP DSEG Banked size + EX DE,HL + LD HL,(COMTB5) ; get BANK2 Common + LD (CCBKSZ),HL ; ..and store CCP CSEG Banked size + ADD HL,DE ; add values + CALL ALIGN ; ..align to next sector boundary + LD (CBKSZ_I),HL ; ..and store as CCP Banked total size + CALL PB2ADR ; display addr's + + ; determine DOS size/addr + LD DE,DOSFCB + LD HL,COMTBL + CALL LNKDSZ ; determine DOS segment sizes + LD (DCNBSZ),HL ; store DOS CSEG Non-banked size + ADD HL,BC ; add DSEG size + CALL ALIGN ; ..align to next sector boundary + LD (DNBSZ_I),HL ; ..and store DOS Non-banked total size + LD HL,(COMTB6) ; get B2RAM Common + LD (DDBKSZ),HL ; ..and store DOS DSEG Banked size + EX DE,HL + LD HL,(COMTB5) ; get BANK2 Common + LD (DCBKSZ),HL ; ..and store DOS CSEG Banked size + ADD HL,DE ; add values + CALL ALIGN ; ..align to next sector boundary + LD (DBKSZ_I),HL ; ..and store as DOS Banked total size + CALL PB2ADR ; display addr's + + ; determine B/P BIOS size/addr + LD DE,BIOSFCB + LD HL,COMTBL + CALL LNKDSZ ; determine BIOS segment sizes + LD (BCNBSZ),HL ; store BIOS CSEG Non-banked size + ADD HL,BC ; add DSEG size + CALL ALIGN ; ..align to next sector boundary + LD (BNBSZ_I),HL ; ..and store BIOS Non-banked total size + LD HL,(COMTB6) ; get B2RAM Common + LD (BDBKSZ),HL ; ..and store BIOS DSEG Banked size + EX DE,HL + LD HL,(COMTB5) ; get BANK2 Common + LD (BCBKSZ),HL ; ..and store BIOS CSEG Banked size + ADD HL,DE ; add values + LD (BBKSZ_I),HL ; ..and store as BIOS Banked total size + CALL PB2ADR ; display addr's + LD HL,(COMTB7) ; get org RESVD Common + LD (BRSVDO),HL ; ..and store it + + + ;----- Auto-size system segments + +AUTOSZ: LD HL,(Z3ENV_I+63) ; get start addr CCP from ENV + LD (CNBADR),HL + LD HL,(Z3ENV_I+66) ; " DOS from ENV + LD (DNBADR),HL + LD HL,(Z3ENV_I+69) ; " BIOS from ENV + LD (BNBADR),HL + + CALL VPRINT + DEFB CR,LF,'Auto-size system ([Y]/N)? : ' + DEFB 0 + CALL CAPIN ; get user input (capitalized) + CALL EXITRQ ; quit program ? + CALL YESNO ; get (Y)es/no input + CP 'N' ; entered 'N' ? + LD A,0FFH ; prepare indicator byte for 'Yes' + JR NZ,PRELINK ; ..if not 'N', skip over + XOR A ; else, clear A (indicator byte for 'No') + + + ;----- Prelink BIOS + +PRELINK: LD (AUTOSIZ),A ; ..and store indicator + CALL VPRINT + DEFB CR,LF,'-- Pre-linking Bios for Info --' + DEFB 0 + LD HL,(Z3ENV_I+27) ; get addr Env Descriptor + LD (COMTB1),HL ; ..and store in org _ENV_ Common + LD HL,0 + LD (COMTB0),HL ; set org _BIOS_ Common to zero + LD HL,(COMTB5) ; get BIOS BANK2 Common (= Banked CSEG size) + LD DE,(DBKSZ_I) ; DOS Banked size + ADD HL,DE ; add values + LD (COMTB5),HL ; ..and store as org BANK2 Common + ; (BIOS Banked CSEG addr) + LD DE,(BCBKSZ) ; BIOS Banked CSEG size + ADD HL,DE ; add values + LD (COMTB6),HL ; ..and store as org B2RAM Common + ; (BIOS Banked DSEG addr) + + ; prepare alt. registers for linking + ; BC'= offset to add to CSEG, DE'= offset to add to DSEG + ; ( HL'= dest. addr bitmap -- not used ) + EXX + LD BC,(BNBAD_I) ; BIOS Non-banked addr + LD HL,(BCNBSZ) ; BIOS Non-banked CSEG size + ADD HL,BC ; calc Non-banked DSEG start + EX DE,HL ; ..keep in DE + EXX + + CALL CODEND ; get addr WSPC + LD DE,0100H ; move beyond header (1 page) + ADD HL,DE + LD B,H + LD C,L ; ..store addr in BC + LD (LPHYADR),HL ; ..and in local var for link module + LD HL,(BNBSZ_I) ; get BIOS Non-banked size + ADD HL,BC ; calc BIOS phys. load location CSEG + LD (COMTB5+2),HL ; (in BANK2 Common) + LD DE,(BCBKSZ) ; get BIOS Banked CSEG addr + ADD HL,DE ; calc BIOS phys. load location DSEG + LD (COMTB6+2),HL ; (in B2RAM Common) + LD HL,(BCNBSZ) ; get BIOS Non-Banked CSEG size + ADD HL,BC ; add to dest. addr + LD DE,BIOSFCB ; ptr to BIOS FCB + + ; link file with BC= phys. addr CSEG, HL= phys. addr DSEG, DE= addr FCB + CALL LNKFILE + + LD HL,(LPHYADR) ; get dest. addr (start of linked file) + LD DE,128 ; offset to OPTF1 (option flag) + ADD HL,DE ; in B/P Bios config area + LD A,(HL) ; get byte + LD (OPTF1),A ; store it + AND 00001000B ; mask bit 3 (ALV/CSV in TPA, or in bank) + LD (BNKDSYS),A ; store indicator + JR NZ,PRELNK0 ; ..if bit 3= 1 (in bank), skip over + CALL VPRINT ; else, display 'Non-Banked' + DEFB '(Non-Banked)' + DEFB 0 + JR CALCSIZ + +PRELNK0: CALL VPRINT + DEFB '(Banked)' + DEFB 0 + + + ;----- Calculate addr/size of System Segments + +CALCSIZ: LD HL,(BNBSZ_I) ; get BIOS Non-banked size + LD DE,(BBKSZ_I) ; ..and Banked size + ADD HL,DE ; calc total size + LD C,L ; move in BC + LD B,H + LD HL,(LPHYADR) ; dest. addr + LD E,L ; in DE + LD D,H + INC DE ; move ptr fwd + LD (HL),0 ; ..and clear memory + LDIR + LD A,(AUTOSIZ) ; get indicator for auto-sizing + OR A ; check if zero (= no) + PUSH AF + CALL NZ,CALCASZ ; ..if auto-sizing, calc base addr's + ; of Non-banked system segments + + POP AF + JR Z,STNDSZ ; ..if no auto-sizing, jump to continue + LD HL,(CNBADR) ; CCP Non-banked start addr + LD (Z3ENV_I+63),HL ; write to ENV + EX DE,HL + LD HL,(DNBADR) ; start addr DOS + LD (Z3ENV_I+66),HL ; write to ENV + XOR A + SBC HL,DE ; calc CCP size (in bytes) + ADD HL,HL ; and convert to 128-byte records + LD A,H + LD (Z3ENV_I+65),A ; write # records to ENV + LD HL,(BNBADR) ; BIOS Non-banked start addr + LD (Z3ENV_I+69),HL ; write to ENV + LD DE,(Z3ENV_I+66) ; get start addr DOS + XOR A + SBC HL,DE ; calc DOS size (in bytes) + ADD HL,HL ; and convert to 128-byte records + LD A,H + LD (Z3ENV_I+68),A ; write # records to ENV + JR SIZDONE ; then, jump to continue + + + ; Use Standard Sizes ? +STNDSZ: CALL VPRINT + DEFB CR,LF,'Set to "Standard" if possible? (Y/[N]) : ' + DEFB 0 + CALL CAPIN ; get user input + CALL EXITRQ ; quit program ? + CALL NOYES ; get yes/(N)o input + CP 'Y' ; is it 'Y' ? + CALL Z,CALCSSZ ; ..if so, set standard sizes for segments + + + ;----- Sizing done - addr/size of Non-banked System Segments determined + +SIZDONE: CALL PSYSNB ; display base addr's of system (Non-banked) + + ; transfer base addr's from ENV to IMG hdr + LD DE,(Z3ENV_I+69) ; base addr BIOS from ENV + LD (BNBAD_I),DE ; to IMG hdr + LD DE,(Z3ENV_I+66) ; base addr DOS from ENV + LD (DNBAD_I),DE + LD DE,(Z3ENV_I+63) ; base addr CCP from ENV + LD (CNBAD_I),DE + LD A,(OPTF1) ; get OPTF1 flag from linked BIOS + AND 00000001B ; mask bit 0 (0= unbanked, 1= banked Bios) + JR Z,ENV2COM + BIT 7,D ; check CCP base addr >32k + JP NZ,ENV2COM ; start addr of CCP in banked system must be above 32k + CALL VPRINT + DEFB CR,LF,BEL,'+++ CPR Starting Addr Too Low (<8000H) +++',CR,LF + DEFB 0 + JP AUTOSZ ; loop, ask for auto-sizing + + + ; Transfer addr's from Z3ENV to COMMON table (logical 'ORG') +ENV2COM: LD HL,(Z3ENV_I+27) ; addr Z3ENV (env. descriptor) + LD (COMTB1),HL ; org _ENV_ Common + LD HL,(Z3ENV_I+69) ; addr BIOS (start NZBIO) + LD (COMTB0),HL ; org _BIOS_ Common + LD HL,(Z3ENV_I+34) ; addr Z3MSG (msg buffer) + LD (COMTB2),HL ; org _MSG_ Common + LD HL,(Z3ENV_I+36) ; addr EXTFCB (external FCB) + LD (COMTB3),HL ; org _FCB_ Common + LD HL,(Z3ENV_I+24) ; addr Z3CL (cmd line buffer) + LD (COMTB4),HL ; org _MCL_ Common + LD HL,(Z3ENV_I+30) ; addr SHSTK (shell stack) + LD (COMTB8),HL ; org _SSTK_ Common + LD HL,(Z3ENV_I+38) ; addr EXTSTK (external stack) + LD (COMTB9),HL ; org _XSTK_ Common + + ; ##### CHECK: top of mem not used (HL immediately overwritten) + CALL GZMTOP + + ; init phys. load location addr's in COMMON table + LD HL,0080H + LD (COMTB0+2),HL + LD (COMTB1+2),HL + LD (COMTB2+2),HL + LD (COMTB3+2),HL + LD (COMTB4+2),HL + LD (COMTB7+2),HL + LD (COMTB8+2),HL + LD (COMTB9+2),HL + + + ;----- Link files + + ; link CCP + LD HL,(CNBSZ_I) ; CCP Non-banked total size + ; (make room for Non-banked CCP to.. + ; ..copy from SYS Bank to TPA Bank) + INC H ; +100H + LD (COMTB5),HL ; store as CCP Banked CSEG start (org BANK2 Common) + LD (CBKAD_I),HL ; ..and as CCP Banked base addr + EX DE,HL + LD HL,(CCBKSZ) ; CCP Banked CSEG addr + ADD HL,DE ; add to Banked base addr + LD (COMTB6),HL ; ..store as CCP Banked DSEG start (org B2RAM Common) + + ; ##### CHECK: obsolete? contents of HL and DE overwritten after EXX/EXX anyway + LD HL,(CBKSZ_I) ; CCP Banked total size + ADD HL,DE + + ; prepare alt. registers for linking + ; BC'= offset to add to CSEG, DE'= offset to add to DSEG + ; ( HL'= dest. addr bitmap -- not used ) + EXX + LD BC,(CNBAD_I) ; CCP Non-banked base addr + LD HL,(CCNBSZ) ; CCP Non-banked CSEG size + ADD HL,BC ; add (= DSEG start) + EX DE,HL ; swap into DE + EXX + + CALL CODEND ; get addr WSPC + LD DE,0100H ; move beyond header (1 page) + ADD HL,DE ; add (= destination) + LD C,L + LD B,H ; copy addr in BC + LD (LPHYADR),HL ; ..and store in var for link module + LD HL,(CNBSZ_I) ; CCP Non-banked total size + ADD HL,BC ; add to dest location + LD (COMTB5+2),HL ; ..set CCP Banked CSEG phys. load location + ; (in BANK2 Common) + LD DE,(CCBKSZ) ; CCP Banked CSEG addr + ADD HL,DE ; add to dest + LD (COMTB6+2),HL ; ..set CCP Banked DSEG phys. load location + ; (in B2RAM Common) + LD HL,COMTBL ; addr of COMMON's table + LD (LTBLADR),HL ; store in var for linker + LD HL,(CCNBSZ) ; CSEG size CCP unbanked + ADD HL,BC ; add (= dest DSEG) + LD DE,CCPFCB + + ; link file with BC= phys. addr CSEG, HL= phys. addr DSEG, DE= addr FCB + CALL LNKFILE + + ; link DOS + LD HL,(COMTB5) ; get org BANK2 Common (= CCP Banked base addr) + LD DE,(CBKSZ_I) ; CCP Banked total size + ADD HL,DE ; add + LD (COMTB5),HL ; ..store as DOS Banked CSEG addr (org BANK2 Common) + LD (DBKAD_I),HL ; ..and as DOS Banked base addr + LD DE,(DCBKSZ) ; DOS Banked CSEG size + ADD HL,DE ; add to base addr + LD (COMTB6),HL ; ..store as DOS Banked DSEG addr (org B2RAM Common) + + ; prepare alt. registers for linking + EXX + LD BC,(DNBAD_I) ; DOS Non-banked base addr + LD HL,(DCNBSZ) ; DOS Non-banked CSEG size + ADD HL,BC ; add (= DSEG start) + EX DE,HL ; swap into DE + EXX + + LD BC,(LPHYADR) ; destination addr (WSPC + 0x100) + LD HL,(CNBSZ_I) ; CCP Non-banked total size + ADD HL,BC + LD DE,(CBKSZ_I) ; CCP Banked total size + ADD HL,DE + LD C,L + LD B,H ; new dest. addr in BC + LD (LPHYADR),HL ; ..and update var for link module + + ; ##### CHECK: already done when linking CCP - obsolete ? + LD HL,COMTBL ; addr of COMMON's table + LD (LTBLADR),HL ; store in var for linker + ; ###### + + LD HL,(DNBSZ_I) ; DOS Non-banked total size + ADD HL,BC ; add to dest location + LD (COMTB5+2),HL ; ..set DOS Banked CSEG phys. load location + ; (in BANK2 Common) + LD DE,(DCBKSZ) ; DOS Banked CSEG size + ADD HL,DE ; add to dest + LD (COMTB6+2),HL ; ..set DOS Banked DSEG phys. load location + ; (in B2RAM Common) + LD HL,(DCNBSZ) ; DOS Non-banked CSEG size + ADD HL,BC ; add (= dest DSEG) + LD DE,DOSFCB + + ; link file with BC= phys. addr CSEG, HL= phys. addr DSEG, DE= addr FCB + CALL LNKFILE + + ; link BIOS + LD HL,(COMTB5) ; get org BANK2 Common (= DOS Banked base addr) + LD DE,(DBKSZ_I) ; DOS Banked total size + ADD HL,DE ; add + LD (COMTB5),HL ; ..store as BIOS Banked CSEG addr (org BANK2 Common) + LD (BBKAD_I),HL ; ..and as BIOS Banked base addr + LD DE,(BCBKSZ) ; BIOS Banked CSEG size + ADD HL,DE ; add to base addr + LD (COMTB6),HL ; ..store as BIOS Banked DSEG addr (org B2RAM Common) + + ; prepare alt. registers for linking + EXX + LD BC,(BNBAD_I) ; BIOS Non-banked base addr + LD HL,(BCNBSZ) ; BIOS Non-banked CSEG size + ADD HL,BC ; add (= DSEG start) + EX DE,HL ; swap into DE + EXX + + LD BC,(LPHYADR) ; destination addr (begin DOS) + LD HL,(DNBSZ_I) ; DOS Non-banked total size + ADD HL,BC + LD DE,(DBKSZ_I) ; DOS Banked total size + ADD HL,DE + LD C,L + LD B,H ; new dest. addr in BC + LD (LPHYADR),HL ; ..and update var for link module + LD HL,(BNBSZ_I) ; BIOS Non-banked total size + ADD HL,BC ; add to dest location + LD (COMTB5+2),HL ; ..set BIOS Banked CSEG phys. load location + ; (in BANK2 Common) + LD DE,(BCBKSZ) ; BIOS Banked CSEG size + ADD HL,DE ; add to dest + LD (COMTB6+2),HL ; ..set BIOS Banked DSEG phys. load location + ; (in B2RAM Common) + LD DE,(BDBKSZ) ; BIOS Banked DSEG size + ADD HL,DE ; add (= end addr in WSPC) + LD (SYSEADR),HL ; ..and store in var + LD HL,(BCNBSZ) ; BIOS Non-Banked CSEG size + ADD HL,BC ; add (= dest DSEG) + LD DE,BIOSFCB + + ; link file with BC= phys. addr CSEG, HL= phys. addr DSEG, DE= addr FCB + CALL LNKFILE + + ;----- Link finished + + LD DE,(SYSEADR) ; end addr of linked system in WSPC + CALL CODEND ; addr start of WSPC + EX DE,HL + XOR A + SBC HL,DE ; calc length in bytes + CALL ALIGN ; ..and align to next sector boundary + + ; divide by 8 (dump lower bits 6..0) + LD A,L ; move low byte to A + LD L,H ; move high byte to L + LD H,0 ; and dump high byte + RLC A ; rotate MSB to C-Flag + ADC HL,HL ; double HL plus C-Flag + LD (SYSBLKS),HL ; ..store system length (in blocks) in var + PUSH HL + CALL UPDINFO ; update 'k Bios' info + POP HL + + CALL VPRINT + DEFB CR,LF,' Total ' + DEFB 0 + LD DE,IMGFCB+1 ; ptr to IMG file name + CALL PFN3 ; ..display it + CALL VPRINT + DEFB ' size = ' + DEFB 0 + CALL PHL4HC + CALL VPRINT + DEFB 'H sectors',CR,LF + DEFB 0 + + + ;----- Update Z3ENV <---> B/P Bios (vice versa) + + LD DE,(LPHYADR) ; get last dest. addr (BIOS) + LD HL,152 ; offset to Env. Descriptor (CONFIG+26) + ADD HL,DE ; move ptr fwd + LD BC,(Z3ENV_I+27) ; addr Z3ENV (env. descriptor) + LD (HL),C ; ..store actual addr Z3ENV + INC HL + LD (HL),B + LD BC,4 + ADD HL,BC ; move ptr to CPU Clock Rate (CONFIG+31) + LD A,(HL) ; get value + LD (Z3ENV_I+43),A ; ..and store in ENV + LD HL,67 ; offset to BIOS fn #22 (get addr DRVTBL) + ADD HL,DE ; move ptr forward + LD A,(HL) + INC HL + LD H,(HL) ; get addr of fn call in HL + LD L,A + LD BC,(BNBAD_I) ; BIOS Non-banked base addr in BC + OR A + SBC HL,BC ; ..calc difference + ADD HL,DE ; ..set ptr to start of fn in WSPC memory + INC HL ; move ptr beyond opcode 0x21 (LD HL,nnnn) + LD A,(HL) + INC HL + LD H,(HL) ; addr of drive table in HL + LD L,A + OR A + SBC HL,BC ; calc diff to BIOS base addr + ADD HL,DE ; ..and set ptr to location in WSPC memory + LD B,16 ; counter (16 drives, A..P) + LD DE,0 + DEC HL ; prior to loop, set ptr back + + ; create bit mask for drive vector +MKDRVEC: INC HL + LD A,(HL) ; check if high byte + INC HL + OR (HL) ; .and low byte are zero + JR Z,MKDRVE0 ; ..if so, skip drive + SCF ; else, set C-Flag for existing byte +MKDRVE0: RR D ; and rotate bit into position + RR E + DJNZ MKDRVEC ; loop till done + LD (Z3ENV_I+52),DE ; set DRVEC (drive vector) + LD HL,(UNBAD_I) + LD (Z3ENV_I+60),HL ; set USRSP addr (resident user space) + LD A,(UNBSZ_I) + LD (Z3ENV_I+59),A ; set remaining user space + LD (Z3ENV_I+62),A ; ..and size of user space + + + ;----- Write IMG file to disk + + ; copy IMG header to workspace (0x100 bytes before linked new system) + CALL CODEND ; get addr WSPC + EX DE,HL ; dest in DE + LD HL,IMGHD_I ; src addr (IMG hdr) in HL + LD BC,0100H ; bytes to copy + LDIR + + ; save file + LD BC,(SYSBLKS) ; # of sectors to write + CALL CODEND ; addr WSPC + CALL WRFILE ; write IMG file + JP NC,EXIT ; ..if ok, jump and exit program + CALL VPRINT + DEFB CR,LF,'..Error Writing output file..',BEL,CR,LF + DEFB 0 + JP EXIT + + +;::::: SUPPORT FUNCTIONS + + ; check if user requested to abort program ( or entered) + ; in: A= char +EXITRQ: CP ESC ; is it ? + JR Z,EXITRQ0 ; ..if so, jump forward and abort + CP CTRLC ; ? + RET NZ ; ..if not, return + ; else, fall through and abort +EXITRQ0: CALL CRLF + +M$ABORT: CALL VPRINT + DEFB ' ...aborting...',CR,LF + DEFB 0 + JP EXIT + + +;::::: HELP SCREEN + +HELP: CALL VPRINT + DEFB CR,LF,1 + DEFB 0 + CALL PRGNAME + CALL VPRINT + DEFB 2,' builds banked and non-banked parts of a B/P Bios.',CR,LF + DEFB ' It operates with layered Menus and supports tailoring of defaults.',CR,LF + DEFB ' Starting locations of BIOS, DOS and CPR may be automatically computed',CR,LF + DEFB ' or Specified. If ZSDOS2 is the selected Dos, Bit Allocation buffers',CR,LF + DEFB ' for Hard Drives are located in the System Bank.',CR,LF,LF + DEFB 'Syntax:',CR,LF,' ' + DEFB 0 + CALL PRGNAME + CALL VPRINT + DEFB ' - Generate system w/defaults',CR,LF,' ' + DEFB 0 + CALL PRGNAME + CALL VPRINT + DEFB ' fn[.ft] - Make/Modify a specific system',CR,LF + DEFB ' (Default type is .IMG)',CR,LF + DEFB ' ' + DEFB 0 + CALL PRGNAME + CALL VPRINT + DEFB ' // - Display this Message',CR,LF + DEFB 0 + + +;::::: EXIT PROGRAM + +EXIT: LD SP,(STACK) ; restore stackpointer + CALL DINIT ; de-init terminal characteristics + LD BC,(OLDDU) + CALL PUTUD ; log initial Drive/User + RET + + + ; display main menu +M0SHOW: CALL CLS + CALL VPRINT + DEFB CR,LF,1,' Main ',2,CR,LF,CR,LF,LF + DEFB TAB,1,' 1 ',2,' File Names',CR,LF,LF + DEFB TAB,1,' 2 ',2,' BIOS Configuration',CR,LF,LF + DEFB TAB,1,' 3 ',2,' Environment' + DEFB 0 + RET + + +;::::: MENU 1 - FILES + +M1FILE: CALL CLS + CALL VPRINT + DEFB CR,LF,1,' Files (1.1) ',2,CR,LF,CR,LF,LF + DEFB TAB,1,' 1 ',2,' Command Processor File : ' + DEFB 0 + LD DE,CCPFCB+1 ; ptr file name in CCP FCB + CALL PFN1 ; ..display file name + type + CALL VPRINT + DEFB CR,LF,LF,TAB,1,' 2 ',2,' Operating System File : ' + DEFB 0 + LD DE,DOSFCB+1 ; ptr file name in DOS FCB + CALL PFN1 + CALL VPRINT + DEFB CR,LF,LF,TAB,1,' 3 ',2,' B/P Bios Source File : ' + DEFB 0 + LD DE,BIOSFCB+1 ; ptr file name in BIOS FCB + CALL PFN1 + CALL VPRINT + DEFB CR,LF,LF,TAB,1,' 4 ',2,' B/P Executable Image : ' + DEFB 0 + LD DE,IMGFCB+1 ; ptr file name in IMG FCB + CALL PFN1 + + CALL MSELECT ; get user input + CP ' ' ; is it ? + RET Z ; ..return + CP CR ; ? + RET Z ; ..return + CP ESC ; ? + JP Z,M$ABORT ; ..quit program + CP CTRLC ; ? + JP Z,M$ABORT ; ..quit program + CP '4'+1 ; is it above '4' ? + JP NC,M1FILE ; ..if so, display Files menu again + ; else, fall through + LD DE,CCPFCB + LD HL,CFNAM_I ; ZCPR FCB+name ptr's + CP '1' ; option '1' ? + JR Z,M1FNAME ; ..if so, jump to continue + LD DE,DOSFCB + LD HL,DFNAM_I ; ZSDOS FCB+name ptr's + CP '2' ; option '2' ? + JR Z,M1FNAME ; ..if so, jump to continue + LD DE,BIOSFCB + LD HL,BFNAM_I ; B/P Bios FCB+name ptr's + CP '3' ; option '3' ? + JR Z,M1FNAME ; ..if so, jump to continue + LD DE,IMGFCB ; else, set IMG FCB+name ptr's + LD HL,IMGFN_I ; ..and fall through + + ; enter file name +M1FNAME: LD (MSELOPT),A ; store selected option + PUSH HL ; save HL regs + CALL VPRINT + DEFB CR,LF,TAB,TAB,' FileName[.Typ] : ' + DEFB 0 + CALL CINPUTL ; get user input (line editor) + PUSH DE + LD DE,CPMFCB ; ptr to standard FCB #1 + CALL INITFCB ; init FCB + CALL ZFNAME ; ..and parse user input as fn/ft into FCB + POP DE ; restore regs + POP HL + OR A ; check if file name is unambiguous + JR Z,M1FCB ; ..if so, jump to continue + + ; error, file name invalid +M1FNERR: LD A,BEL ; else, send to CON: + CALL COUT + JP M1FILE ; ..and loop, ask for new input + + ; file name ok, init FCB +M1FCB: LD A,(CPMFCB+1) ; check first char of file name + CP ' ' ; is it ? + JR Z,M1FNERR ; ..if so, file name is invalid + ; jump, alert and ask for new input + PUSH HL ; save regs + LD A,(CPMFCB+9) ; get first char of file type + CP ' ' ; is it ? + JR NZ,M1FCB1 ; ..if not, jump to continue + LD A,(MSELOPT) ; get selected menu option (to set file type) + PUSH DE + LD DE,CPMFCB+9 + LD BC,3 ; bytes to copy + LD HL,FTYPES+3 ; prepare ptr for .IMG file type + CP '4' ; was option '4' (image file) selected ? + JR Z,M1FCB0 ; ..if so, jump to continue + LD HL,FTYPES+6 ; prepare ptr for .REL file type + CP '3' ; was option '3' (B/P Bios file) selected ? + JR Z,M1FCB0 ; ..if so, jump to continue + LD HL,FTYPES+9 ; else, set ptr to .ZRL file type + +M1FCB0: LDIR ; ..and copy + POP DE ; DE= ptr to respective FCB in temp area + ; (Stack)= ptr to file name in IMG file header area +M1FCB1: LD HL,CPMFCB ; ptr to standard FCB #1 + LD BC,15 ; copy 15 bytes to FCB in temp area + LDIR + POP DE + LD HL,CPMFCB+1 ; ptr to file name in standard FCB #1 + LD BC,11 ; copy 11 bytes (fn.ft) to IMG file hdr + LDIR + JP M1FILE ; ..and loop + + +;::::: MENU 2 - BIOS CONFIG + +M2BIOS: CALL CLS + CALL VPRINT + DEFB 1,' Environment (2.1) ',2 + DEFB 0 + CALL GXYMSG ; display w/ positioning + DEFB 3,3,'COMMON (Bank 0) MEMORY BANK 2 MEMORY' + DEFB 0 + CALL GXYMSG + DEFB 4,2,'---------------------- ------------------------' + DEFB 0 + CALL GXYMSG ; col 2 (on the left) + DEFB 5,2,1,' A ',2,' Common BIOS - ' + DEFB 0 + CALL GXYMSG + DEFB 6,2,' Size - ' + DEFB 0 + CALL GXYMSG + DEFB 7,2,1,' B ',2,' Common BDOS - ' + DEFB 0 + CALL GXYMSG + DEFB 8,2,' Size - ' + DEFB 0 + CALL GXYMSG + DEFB 9,2,1,' C ',2,' Command Proc - ' + DEFB 0 + CALL GXYMSG + DEFB 10,2,' Size - ' + DEFB 0 + CALL GXYMSG + DEFB 11,2,1,' D ',2,' User Space - ' + DEFB 0 + CALL GXYMSG + DEFB 12,2,' Size - ' + DEFB 0 + CALL GXYMSG ; col 34 (on the right) + DEFB 5,34,1,' E ',2,' Banked BIOS - ' + DEFB 0 + CALL GXYMSG + DEFB 6,34,' Size - ' + DEFB 0 + CALL GXYMSG + DEFB 7,34,1,' F ',2,' Banked BDOS - ' + DEFB 0 + CALL GXYMSG + DEFB 8,34,' Size - ' + DEFB 0 + CALL GXYMSG + DEFB 9,34,1,' G ',2,' Command Proc - ' + DEFB 0 + CALL GXYMSG + DEFB 10,34,' Size - ' + DEFB 0 + CALL GXYMSG + DEFB 11,34,1,' H ',2,' User Space - ' + DEFB 0 + CALL GXYMSG + DEFB 12,34,' Size - ' + DEFB 0 + + ; display BIOS addr and size + LD HL,0516H ; row 5 / col 22 + CALL GOTOXY ; position cursor + LD HL,(Z3ENV_I+69) ; ptr to start addr BIOS in ENV + CALL PHLXH ; display as hex + 'H' + EX DE,HL ; keep value + LD HL,0616H ; row 6 / col 22 + CALL GOTOXY + PUSH DE + CALL ENVLOW ; lowest addr of ENV component in HL + POP DE + LD BC,(UNBAD_I) ; get addr User Space in IMG hdr + LD A,B ; check if invalid (= zero) + OR C + CALL NZ,MINHLBC ; ..if not, get the lower of both addr's in HL + OR A + SBC HL,DE ; calc size [lowest ENV] - [start addr BIOS] + ADD HL,HL ; *2 + LD A,L ; check for page boundary + OR A ; (low byte = zero) + JR Z,M2ADRSZ ; ..if so, skip over + INC H ; else, increase before displaying + + ; display addr and size of other system segments +M2ADRSZ: LD A,H + CALL PSPCAD ; display + value as dec (size high byte) + LD HL,0716H ; row 7 / col 22 + LD DE,Z3ENV_I+66 ; ptr start addr DOS in Z3ENV + CALL PSEGXY ; print Segment addr/size at coordinates + LD HL,0916H ; row 9 / col 22 + LD DE,Z3ENV_I+63 ; ..start addr ZCPR in Z3ENV + CALL PSEGXY + LD HL,0B16H ; row 11 / col 22 + LD DE,UNBAD_I ; ..addr User Space in IMG hdr + CALL PSEGXY + LD HL,0536H ; row 5 / col 54 + LD DE,BBKAD_I ; ..base addr BIOS Banked in IMG hdr + CALL PSEGXY + LD HL,0736H ; row 7 / col 54 + LD DE,DBKAD_I ; ..base addr DOS Banked in IMG hdr + CALL PSEGXY + LD HL,0936H ; row 9 / col 54 + LD DE,CBKAD_I ; ..base addr ZCPR Banked in IMG hdr + CALL PSEGXY + LD HL,0B36H ; row 11 / col 54 + LD DE,UBKAD_I ; ..addr User Space Banked (RESVD ??) in IMG hdr + CALL PSEGXY + + ; select option from Menu 2 Bios Config +M2SELCT: CALL MSELECT ; get user input + CP ' ' ; is it ? + RET Z ; ..return + CP CR ; ? + RET Z ; ..return + CP ESC ; ? + JP Z,M$ABORT ; ..quit program + CP CTRLC ; ? + JP Z,M$ABORT ; ..quit program + + LD HL,Z3ENV_I+69 + CP 'A' ; 'A' (Common Bios) ? + JR Z,M2EXEC + LD HL,Z3ENV_I+66 + CP 'B' ; 'B' (Common BDOS) ? + JR Z,M2EXEC + LD HL,Z3ENV_I+63 + CP 'C' ; 'C' (Common ZCPR) ? + JR Z,M2EXEC + LD HL,UNBAD_I + CP 'D' ; 'D' (Common User Space) ? + JR Z,M2EXEC + LD HL,BBKAD_I + CP 'E' ; 'E' (Banked Bios) ? + JR Z,M2EXEC + LD HL,DBKAD_I + CP 'F' ; 'F' (Banked BDOS) ? + JR Z,M2EXEC + LD HL,CBKAD_I + CP 'G' ; 'G' (Banked ZCPR) ? + JR Z,M2EXEC + LD HL,UBKAD_I + CP 'H' ; 'H' (Banked User Space) ? + + JR NZ,M2SELCT + +M2EXEC: CALL PHLXSIZ ; execute selected option (display addr and size, + ; ask for new values, convert) + JP M2BIOS ; ..then loop, display again + + +;::::: SUPPORT FUNCTIONS (Menu 2 - Bios Config) + + ; return the lower of HL and BC ("min" function) + ; in: BC, HL = values to compare + ; out: HL= the lower of both values +MINHLBC: LD A,H ; test high byte first + SUB B + RET C ; if borrowed from C-Flag, return (HL < BC) + JR NZ,MINHLB0 ; if delta <> zero, jump (HL > BC) + LD A,L ; ..else, test low byte too + SUB C + RET C ; if borrowed from C-Flag, return (BC > HL) +MINHLB0: LD L,C ; ..else, copy contents of BC into HL + LD H,B + RET + + +;::::: MENU 3 - ENVIRONMENT + +M3ENV: CALL CLS + CALL VPRINT + DEFB 1,' Environment (3.1) ',2 + DEFB 0 + CALL GXYMSG + DEFB 3,2,1,' A ',2,' - Environment - ' + DEFB 0 + CALL GXYMSG + DEFB 4,2,' Size (# recs)- ' + DEFB 0 + CALL GXYMSG + DEFB 5,2,1,' B ',2,' - Flow Ctrl Pkg - ' + DEFB 0 + CALL GXYMSG + DEFB 6,2,' Size (# recs)- ' + DEFB 0 + CALL GXYMSG + DEFB 7,2,1,' C ',2,' - I/O Package - ' + DEFB 0 + CALL GXYMSG + DEFB 8,2,' Size (# recs)- ' + DEFB 0 + CALL GXYMSG + DEFB 9,2,1,' D ',2,' - Res Cmd Proc - ' + DEFB 0 + CALL GXYMSG + DEFB 10,2,' Size (# recs)- ' + DEFB 0 + CALL GXYMSG + DEFB 11,2,1,' E ',2,' - Command Line - ' + DEFB 0 + CALL GXYMSG + DEFB 12,2,' Size (bytes) - ' + DEFB 0 + CALL GXYMSG + DEFB 3,34,1,' F ',2,' - Named Dirs - ' + DEFB 0 + CALL GXYMSG + DEFB 4,34,' # of Entries - ' + DEFB 0 + CALL GXYMSG + DEFB 5,34,1,' G ',2,' - External Path - ' + DEFB 0 + CALL GXYMSG + DEFB 6,34,' # of Entries - ' + DEFB 0 + CALL GXYMSG + DEFB 7,34,1,' H ',2,' - Shell Stack - ' + DEFB 0 + CALL GXYMSG + DEFB 8,34,' # of Entries - ' + DEFB 0 + CALL GXYMSG + DEFB 9,34,' Entry Size - ' + DEFB 0 + CALL GXYMSG + DEFB 10,34,1,' I ',2,' - Msg Buffer - ' + DEFB 0 + CALL GXYMSG + DEFB 11,34,1,' J ',2,' - Ext. FCB - ' + DEFB 0 + CALL GXYMSG + DEFB 12,34,1,' K ',2,' - Ext. Stack - ' + DEFB 0 + + ; display addr and size of ENV components + ; stored as (16-bit) (8-bit) + LD HL,0318H ; row 3 / col 24 + LD DE,Z3ENV_I+27 ; ptr addr Z3ENV (ZCPR3 Environment Descriptor) + CALL PSEGXY ; print Segement addr/size at coordinates + LD HL,0518H ; row 5 / col 24 + LD DE,Z3ENV_I+18 ; ptr addr FCP (Flow Cmd Pkg) + CALL PSEGXY + LD HL,0718H ; row 7 / col 24 + LD DE,Z3ENV_I+15 ; ptr addr IOP (I/O Pkg) + CALL PSEGXY + LD HL,0918H ; row 9 / col 24 + LD DE,Z3ENV_I+12 ; ptr addr RCP (Resident Cmd Pkg) + CALL PSEGXY + LD HL,0B18H ; row 11 / col 24 + LD DE,Z3ENV_I+24 ; ptr addr Z3CL (ZCPR3 cmd line buffer) + CALL PSEGXY + LD HL,0339H ; row 3 / col 57 + LD DE,Z3ENV_I+21 ; ptr addr Z3NDIR (named dir buffer) + CALL PSEGXY + LD HL,0539H ; row 5 / col 57 + LD DE,Z3ENV_I+9 ; ptr addr EXPATH (external path) + CALL PSEGXY + LD HL,0739H ; row 7 / col 57 + LD DE,Z3ENV_I+30 ; ptr addr SHSTK (shell stack) + CALL PSEGXY + + ; single value entries (8-bit or 16-bit) + LD HL,0939H ; row 9 / col 57 + CALL GOTOXY + LD A,(Z3ENV_I+33) ; SHSIZE (size of a shell stack entry) + CALL PSPCAD ; display + value as dec + LD HL,0A39H ; row 10 / col 57 + CALL GOTOXY + LD HL,(Z3ENV_I+34) ; addr Z3MSG (ZCPR3 message buffer) + CALL PHLXH ; display as hex + 'H' + LD HL,0B39H ; row 11 / col 57 + CALL GOTOXY + LD HL,(Z3ENV_I+36) ; addr EXTFCB (external File Control Block) + CALL PHLXH + LD HL,0C39H ; row 12 / col 57 + CALL GOTOXY + LD HL,(Z3ENV_I+38) ; addr EXTSTK (external stack) + CALL PHLXH + +M3SELCT: CALL MSELECT + CP ' ' ; is it ? + RET Z ; ..return + CP CR ; ? + RET Z ; ..return + CP ESC ; ? + JP Z,M$ABORT ; ..quit program + CP CTRLC ; ? + JP Z,M$ABORT ; ..quit program + CP 'A' ; 'A' (ENV) ? + JR C,M3SELCT ; ..if below ascii 'A', loop ask for new input + + LD HL,Z3ENV_I+27 ; ptr to addr of ZCPR3 Env Descriptor + JR Z,M3EXEC1 + LD HL,Z3ENV_I+18 ; ..of FCP + CP 'B' + JR Z,M3EXEC1 + LD HL,Z3ENV_I+15 ; ..of IOP + CP 'C' + JR Z,M3EXEC1 + LD HL,Z3ENV_I+12 ; ..of RCP + CP 'D' + JR Z,M3EXEC1 + LD HL,Z3ENV_I+24 ; ..of Z3CL (cmd line buffer) + CP 'E' + JR Z,M3EXEC1 + LD HL,Z3ENV_I+21 ; ..of Z3NDIR (named dir buffer) + CP 'F' + JR Z,M3EXEC2 + LD HL,Z3ENV_I+9 ; ..of EXPATH (external path) + CP 'G' + JR Z,M3EXEC2 + LD HL,Z3ENV_I+30 ; ..of SHSTK + CP 'H' + JR Z,M3EXEC4 + LD HL,Z3ENV_I+34 ; ..of Z3MSG (msg buffer) + CP 'I' + JR Z,M3EXEC3 + LD HL,Z3ENV_I+36 ; ..of EXTFCB + CP 'J' + JR Z,M3EXEC3 + LD HL,Z3ENV_I+38 ; ..of EXTSTK + CP 'K' + JR Z,M3EXEC3 + + JP M3ENV + + + ; ##### CHECK: redundant JR C loop in case of error, + ; because called routines handle errors +M3EXEC1: CALL PHLXSIZ ; print addr and size + get input (converted) + JR C,M3EXEC1 +M3EXEC: JP M3ENV ; ..and loop + +M3EXEC2: CALL PHLXENT ; print addr and # entries + get input (converted) + JR C,M3EXEC2 + JR M3EXEC + +M3EXEC3: CALL PHLXCIN ; print (only) addr + get input (converted) + JR C,M3EXEC3 + JR M3EXEC + +M3EXEC4: CALL PADENSZ ; print addr, # entries, and size + get input (converted) + JR C,M3EXEC4 + JR M3EXEC + + +;::::: SUPPORT FUNCTIONS (all Menus) + + ; select an option from menu (validate user input) +MSELECT: CALL VPRINT + DEFB CR,LF,LF + DEFB 0 +MSELCT0: CALL VPRINT + DEFB CR,TAB,TAB,'Selection : ' + DEFB 0 + CALL EREOL ; clear end of line + CALL CAPIN ; get input and capitalize it + CP ' ' ; is it ? + RET Z ; ..return + CP CR ; ? + RET Z ; ..return + CP ESC ; ? + RET Z ; ..return + CP CTRLC ; ? + RET Z ; ..return + CP '0' ; is it a control char (below ascii '0') ? + JR C,MSELCT0 ; ..then loop and ask for new input + CP '9'+1 ; is it an ascii number ? + JR C,MSELCT1 ; ..if so, jump to display + CP 'A' ; is it below ascii 'A' ? + JR C,MSELCT0 ; ..then loop and ask for new input + CP 'Z'+1 ; is it above ascii 'Z' ? + JR NC,MSELCT0 ; ..then loop and ask for new input +MSELCT1: JP COUT ; display on CON: and let return from there + + + ; validate input for (Y)/N query, and echo + ; Yes is default + ; in: A= char (capitalized) +YESNO: CP 'N' ; is it 'N' ? + JR Z,YESNO0 ; ..if so, skip over + LD A,'Y' ; else, set 'Y' for any other char +YESNO0: JP COUT ; print on CON: and let return from there + + ; validate input for Y/(N) query, and echo + ; No is default + ; in: A= char (capitalized) +NOYES: CP 'Y' ; is it 'Y' ? + JR Z,YESNO0 ; ..if so, jump to display + LD A,'N' ; else, set 'N' for any other char + JR YESNO0 ; and jump to display + + + ; determine CSEG and DSEG sizes of linked file + ; (SLINK0 linker module provides a dedicated sizing function) + ; in: DE= ptr FCB + ; HL= addr COMTBL + ; out: BC= DSEG size + ; HL= CSEG size +LNKDSZ: LD (LFCBADR),DE ; store addr of FCB + LD (LTBLADR),HL ; store addr of COMMON table + PUSH DE + INC DE + CALL PFN1 ; display file name + POP DE + CALL INITFCB ; init FCB + CALL F$EXIST ; check if file exists + OR A + JP Z,E$NFND ; ..if not, jump and let return from there + CALL INITFCB ; init FCB + CALL F$OPEN ; open file + OR A + JP NZ,E$OPEN ; ..if error, jump and let return from there + LD A,128 + LD (LBYTPOS),A ; set byte pos for @GBYTE function (= initiate load) + XOR A ; clear A (= just sizing info) + LD HL,(LTBLADR) ; set ptr COMMON table + + CALL LINK + + OR A ; check error status + JP NZ,E$LINK ; ..if not ok, jump + PUSH BC ; save DSEG size + PUSH DE ; save CSEG size + PUSH BC + PUSH DE + LD DE,(LFCBADR) ; get FCB addr + CALL F$CLOSE ; close file + CALL VPRINT + DEFB ' - CSEG=' + DEFB 0 + POP HL ; restore CSEG size + CALL PHL4HC ; ..and display as hex + CALL VPRINT + DEFB 'H, DSEG=' + DEFB 0 + POP HL ; restore DSEG size + CALL PHL4HC ; ..and display as hex + CALL VPRINT + DEFB 'H',CR,LF + DEFB 0 + POP HL ; restore CSEG size in HL + POP BC ; restore DSEG size in BC + RET + + + ; print addr's of BANK2 and B2RAM Common +PB2ADR: LD HL,(COMTB6) ; get org B2RAM Common + LD A,H ; check if zero + OR L + LD HL,(COMTB5) ; prepare, and get org BANK2 Common + JR NZ,PB2ADR0 ; ..if addr <> zero, jump to continue + LD A,H ; else, check org BANK2 Common + OR L ; if also zero + RET Z ; ..if so, return + ; else, fall through and print +PB2ADR0: CALL VPRINT + DEFB ' Bank2=' + DEFB 0 + LD HL,(COMTB5) ; get org BANK2 Common + CALL PHL4HC + CALL VPRINT + DEFB 'H B2Ram=' + DEFB 0 + LD HL,(COMTB6) ; get org B2RAM Common + CALL PHL4HC + CALL VPRINT + DEFB 'H',CR,LF + DEFB 0 + RET + + + ; Standard sizes - calculate base addr's of system segments Non-banked + ; in: - + ; out: - (addr's in ram storage locations) +CALCSSZ: LD DE,(CNBSZ_I) ; compare CCP Non-banked size + LD HL,0800H ; with CP/M standard 2.0 kB + OR A + SBC HL,DE + JR C,E$LARGE ; ..if too large, jump error + LD DE,(DNBSZ_I) ; compare DOS Non-banked size + LD HL,0E00H ; with CP/M standard 3.5 kB + SBC HL,DE + JR C,E$LARGE ; ..if too large, jump error + CALL ENVLOW ; addr of lowest ENV component in HL + CALL USPCSZ ; size of User Space in DE + JR NZ,CALCSS0 ; ..if User Space size <> zero, skip over + LD HL,0 ; else, nullify HL before calc +CALCSS0: OR A ; reset C-Flag + SBC HL,DE ; calc User Space base addr + LD (UNBAD_I),HL ; ..and store it + LD HL,(Z3ENV_I+69) ; start addr BIOS (from ENV) + LD (BNBADR),HL ; ..and store in var (BIOS Non-banked addr) + LD DE,0E00H ; DOS standard size + SBC HL,DE ; calc base addr + LD (Z3ENV_I+66),HL ; store in ENV + LD (DNBADR),HL ; ..and in var (DOS Non-banked addr) + LD A,1CH ; DOS standard size in 128-byte recs + LD (Z3ENV_I+68),A ; ..store in ENV + LD DE,0800H ; CCP standard size + SBC HL,DE ; calc base addr + LD (Z3ENV_I+63),HL ; store in ENV + LD (CNBADR),HL ; ..and in var (CCP Non-banked addr) + LD A,10H ; CCP standard size in 128-byte recs + LD (Z3ENV_I+65),A ; store in ENV + RET + + ; too large +E$LARGE: CALL VPRINT + DEFB CR,LF,BEL,TAB,TAB,'+++ CPR or DOS too Large +++',CR,LF + DEFB 0 + JP AUTOSZ ; loop, ask for auto-sizing + + + ; link file (using SLINK0 LINK routine) + ; in: DE= ptr FCB, BC= phys. addr CSEG, HL= phys. addr DSEG + ; alt. registers set, addr of COMMON table in var + ; out: BC= size DSEG, DE= size CSEG +LNKFILE: PUSH BC + PUSH HL + LD (LFCBADR),DE ; store addr of FCB + CALL INITFCB ; init FCB + CALL F$EXIST ; check if file exists + OR A + JR Z,E$NFND0 ; ..if not, jump and let return from there + CALL INITFCB ; init FCB + CALL F$OPEN ; open file + OR A + JR NZ,E$OPEN0 ; ..if error, jump and let return from there + LD A,128 + LD (LBYTPOS),A ; set ptr for @GBYTE function (= initiate load) + LD A,00000001B ; set flag to link (bit 0= 1), no bitmap (bit 1= 0) + LD HL,(LTBLADR) ; set addr COMMON table + POP DE ; restore DSEG addr + POP BC ; restore CSEG addr + CALL LINK ; ..and link + OR A + JR NZ,E$LINK ; ..if error, jump error and exit + RET + + + ; error messages + +E$NFND0: POP HL ; clear stack + POP HL ; ..then fall through +E$NFND: CALL VPRINT + DEFB '..not found..' + DEFB 0 + JP CRLF + +E$OPEN0: POP HL + POP HL +E$OPEN CALL VPRINT + DEFB '..Open Error..' + DEFB 0 + LD DE,(LFCBADR) ; addr of FCB + CALL F$CLOSE ; close file + JP CRLF + +E$LINK: PUSH AF + CALL VPRINT + DEFB CR,LF,BEL,'..Link Error..' + DEFB 0 + POP AF + CP 'A' + JR NC,E$INFIL + CALL PADC + LD A,' ' + +E$INFIL: CALL COUT + CALL VPRINT + DEFB ' in ' + DEFB 0 + LD DE,(LFCBADR) ; addr of FCB + INC DE ; move ptr to file name + CALL PFN3 + DEC DE + CALL F$CLOSE ; close file + JP EXIT + + +;::::: SLINK0 MODULE SUPPORT FUNCTION AND COMMONs TABLE + + ; get one byte from input file + ; used by SLINK0 linker module + ; (saves all registers) +@GBYTE: PUSH BC ; save regs + PUSH DE + PUSH HL + LD A,(LBYTPOS) ; check pos for file read + CP 128 + JR C,GBYTE0 ; while below 128, bypass reading a sector + LD HL,CPMDMA ; input buffer starts here + CALL SETDMA ; set file DMA buffer + LD DE,(LFCBADR) ; addr of FCB + CALL F$READ ; ..read one sector (sequential) + OR A + SCF ; set C-Flag in case of error + JR NZ,GBYTE1 ; jump w/ error code C-Flag set + + ; valid data is in sector buffer, get a byte and move ptr fwd +GBYTE0: LD E,A ; set ptr for offset + LD D,0 ; high byte is zero + LD HL,CPMDMA ; start from base + ADD HL,DE + INC A ; move ptr fwd + LD (LBYTPOS),A ; ..and save + LD A,(HL) ; get a byte + OR A ; set return status OK (NC) +GBYTE1: POP HL ; restore regs + POP DE + POP BC + RET + + + ; table of Named COMMONs + ; for the various system segments + ; used by SLINK0 linker module + ; (12 bytes per entry) +COMTBL: DEFB '_BIOS_',80H,0 ; name (1-7 char, 80H terminated) - 8 byte field +COMTB0: DEFW 0 ; logical load location ('ORG') of segment + DEFW 0 ; phys. load location of segment + DEFB '_ENV_',80H,0,0 +COMTB1: DEFW 0FE00H + DEFW 0 + DEFB '_MSG_',80H,0,0 +COMTB2: DEFW 0 + DEFW 0 + DEFB '_FCB_',80H,0,0 +COMTB3: DEFW 0 + DEFW 0 + DEFB '_MCL_',80H,0,0 +COMTB4: DEFW 0 + DEFW 0 + DEFB 'BANK2',80H,0,0 +COMTB5: DEFW 0 + DEFW 0 + DEFB 'B2RAM',80H,0,0 +COMTB6: DEFW 0 + DEFW 0 + DEFB 'RESVD',80H,0,0 +COMTB7: DEFW 0 + DEFW 0 + DEFB '_SSTK_',80H,0 +COMTB8: DEFW 0 + DEFW 0 + DEFB '_XSTK_',80H,0 +COMTB9: DEFW 0 + DEFW 0 + DEFB 80H ; end-of-table mark + + + + ; update info string w/ size information "k Bios" + ; in linked BIOS +UPDINFO: LD DE,(LPHYADR) ; last destination addr (BIOS) in WSPC + LD HL,(SYSEADR) ; end addr of linked system in WSPC + XOR A + SBC HL,DE ; calc length in bytes + LD C,L ; and move to BC + LD B,H ; (# of bytes to scan) + EX DE,HL + + ; find string 'k Bios' in linked Bios + ; (similar to Z3LIB's CHKENV routine) +UPDFND: LD DE,S$KBIOS ; point to string to search for ('k Bios') + LD A,(DE) ; do a quick scan for first char in string + CPIR + RET PO ; ..if not found, return + PUSH BC ; save count and addr + PUSH HL + CALL UPDFND0 ; and check remaining chars in string + POP HL + POP BC + JR NZ,UPDFND ; ..if no match, loop + + ; string is stored as "60.00k Bios" + LD DE,-6 ; move 6 bytes back to first digit char + ADD HL,DE + EX DE,HL ; swap regs (ptr in DE) + LD A,(BNBAD_I+1) ; get high byte base addr BIOS Non-banked + ADD A,6 ; ??? # recs User Space ??? + PUSH AF + RRA ; divide by 4 + RRA ; (1.024 = 256 *4 = 0x100 *4) + AND 00111111B ; mask off upper bits + + ; divide by subtraction + LD BC,10 ; B= 0, C= 10 +UPDDIV: SUB C ; A= A-10 + JR C,UPDPAT ; ..if negative, exit loop and write to memory + INC B ; B= B+1 + JR UPDDIV ; continue division + + ; patch new info string +UPDPAT: ADD A,10 ; compensate underflow + LD C,A ; B contains 10's, C contains 1's + LD HL,3030H ; HL= ascii '0' '0' + ADD HL,BC ; convert digits to ascii (add '0') + EX DE,HL ; swap digits/ptr + LD (HL),D ; store 1st digit char + INC HL + LD (HL),E ; store 2nd digit char + INC HL ; move ptr to decimal places + INC HL + EX DE,HL ; and swap regs again + POP AF ; restore AF + AND 00000011B ; mask bits 1 and 0 + LD HL,S$KDECPL ; ptr to list of strings for decimal places + ADD A,A ; strings of 2 bytes each (pos *2) + CALL ADDHLA ; move ptr forward + LDI ; ..and copy 2 bytes + LDI + RET + + ; string 'k Bios' +S$KBIOS: DEFB 'k Bios' + + ; check remaining chars in string +UPDFND0: LD BC,5 ; chars remaining in string + LD DE,S$KBIOS+1 ; find this string +UPDFND1: LD A,(DE) + CPI + RET NZ ; ..if no match, return + INC DE ; move source ptr fwd + JP PE,UPDFND1 ; ..if not yet done, continue checking + RET + + ; strings for decimal places +S$KDECPL: DEFB '00','25','50','75' + + + ; read IMG file header + ; in: file name in standard FCB #1 +RDHDR: LD DE,CPMFCB + CALL F$OPEN ; attempt to open file + OR A ; check if successful + JR NZ,RDHDR0 ; ..if not, jump + CALL CODEND ; get addr WSPC + CALL SETDMA ; ..and set as buffer addr + LD DE,CPMFCB + CALL F$READ ; read file sequentially + JR NZ,RDHDR0 ; ..if error, jump + LD DE,128 ; else, move forward + ADD HL,DE ; by 1 sector + CALL SETDMA ; set file buffer addr + LD DE,CPMFCB + CALL F$READ ; read another sector + RET Z ; ..if successful, return + ; else, fall through +RDHDR0: OR 0FFH ; set Z-Flag + SCF ; and C-Flag (error status) + RET + + + ; write IMG file to disk + ; in: HL= addr IMG in memory + ; BC= # sectors to write + ; out: C-Flag reset (NC) if successful (will not return from error, anyway) +WRFILE: PUSH BC + PUSH HL + LD DE,IMGFCB + CALL INITFCB ; init FCB + CALL F$EXIST ; check if file exists + JR Z,WRFIL0 ; ..if not, jump to continue + LD HL,IMGFCB ; else, try to rename existing file + LD DE,CPMFCB + LD BC,9 ; bytes to copy + LDIR + LD HL,FTYPES ; ptr to standard file type 'BAK' + LD BC,3 ; bytes to copy + LDIR + LD DE,CPMFCB + CALL INITFCB ; init FCB + CALL F$DELETE ; delete an existing .BAK file + EX DE,HL ; HL= ptr to FCB (old file name) + LD DE,IMGFCB ; ptr to FCB (new file name) + CALL F$RENAME ; try to rename + JR Z,E$IMGREN ; ..if error, jump error and exit + +WRFIL0: LD DE,IMGFCB + CALL INITFCB ; init FCB + CALL F$MOPEN ; open file (create if not exists) + POP HL ; clear stack and fall through + POP BC +WRFIL1: PUSH BC ; save regs + PUSH HL + CALL SETDMA ; set file buffer addr + CALL F$WRITE ; write one 128-byte sector + POP HL ; restore regs + POP BC + OR A ; check error status + JR NZ,E$IMGWRI ; ..if error, jump error and exit + PUSH DE + LD DE,128 ; move forward by 1 sector + ADD HL,DE + POP DE + DEC BC ; reduce counter + LD A,B + OR C ; counter = zero ? + JR NZ,WRFIL1 ; ..if not, loop + CALL F$CLOSE ; close file + OR A ; set C-Flag (status = ok) + RET + + + ; error messages + +E$IMGREN: CALL VPRINT + DEFB CR,LF,BEL,' +++ ..Error Renaming: ' + DEFB 0 + +E$IMGFIL: LD DE,IMGFCB+1 ; ptr to file name in IMG FCB + CALL PFN1 ; display it + CALL CRLF + JP EXIT + +E$IMGWRI: CALL VPRINT + DEFB CR,LF,BEL,' +++ ..Error Writing to: ' + DEFB 0 + JR E$IMGFIL + + + ; ##### unreferenced code (not used) +JUMPHL JP (HL) + ; ##### + + + ; get Quiet Flag from Z3 Environment + ; in: - + ; out: A= Quiet Flag, defaults to A= 0 (not quiet) +GETQFLG: LD HL,(ENVADR) ; get local ENVPTR + LD A,H ; check if invalid (= zero) + OR L + RET Z ; ..if so, return + LD A,40 ; else, move ptr forward to Quiet Flag + CALL ADDHLA + LD A,(HL) ; get value + RET + + + ; print program name on CON: device + ; (either the actual name, or fallback to default) + ; only used by HELP +PRGNAME: LD A,(ENVADR+1) ; get high byte of local ENVPTR + OR A ; check if valid (<> zero) + JP NZ,PRTNAME ; ..if so, display actual name + ; ..and let return from there + CALL VPRINT ; else, display default + DEFB 'BPBUILD' + DEFB 0 + RET + + + ; ##### unreferenced code (not used) + LD B,8 +UNUSED1 + INC HL + LD A,(HL) + AND 01111111B + CP ' ' + CALL NZ,COUT + DJNZ UNUSED1 + RET + ; ##### + + + ; add A to HL (result in HL) +ADDHLA: ADD A,L ; add L + LD L,A ; store result in L + RET NC ; ..if no overflow, return + INC H ; else, increment H + RET + + + ; align addr to next 128-byte boundary + ; in: HL= addr + ; out: HL= aligned addr +ALIGN: LD DE,7FH ; add offset for partial 128-byte block + ADD HL,DE + LD A,L ; get low byte + AND 80H ; sector alignment + LD L,A + RET + + + ; Auto-sizing - calculate base addr's of system segments Non-banked + ; in: - + ; out: - (addr's in ram storage locations) +CALCASZ: CALL ENVLOW ; addr of lowest ENV component in HL + CALL VPRINT + DEFB CR,LF,'Sizing from lowest ENV element = ' + DEFB 0 + CALL PHL4HC + CALL USPCSZ ; User Space size (USPCS) in bytes + OR A + SBC HL,DE ; calc User Space start addr + LD (UNBAD_I),HL ; ..and store in IMG hdr + LD A,(BNKDSYS) ; get banking indicator (0= Non-banked) + OR A + JR NZ,CALCAS0 ; ..if Non-banked, skip over + LD DE,(BRSVDO) ; get org RESVD Common + XOR A ; reset flags + SBC HL,DE ; ..and calc base addr +CALCAS0: LD DE,(BNBSZ_I) ; BIOS Non-banked total size + XOR A ; reset flags + SBC HL,DE ; ..and calc BIOS Non-banked base addr + LD L,0 ; align to page boundary + LD (BNBADR),HL ; store it + LD DE,(DNBSZ_I) ; DOS Non-banked total size + SBC HL,DE ; ..calc base addr + LD (DNBADR),HL + LD DE,(CNBSZ_I) ; CCP Non-banked total size + SBC HL,DE ; ..calc base addr + LD (CNBADR),HL + RET + + + ; print base addr's of System (Non-banked Segments) on CON: + ; in: - +PSYSNB: LD HL,(UNBAD_I) ; base addr User Space (from IMG hdr) + LD A,H + OR L ; check if zero + JR NZ,PSYSNB0 ; ..and branch accordingly + CALL VPRINT + DEFB CR,LF,' ' + DEFB 0 + JR PSYSNB1 +PSYSNB0: CALL VPRINT + DEFB CR,LF,' Base of Usr Sp = ' + DEFB 0 + CALL PHL4HC ; display HL as hex +PSYSNB1: CALL VPRINT + DEFB CR,LF,' Base of Bios = ' + DEFB 0 + LD HL,(BNBADR) ; BIOS Non-banked base addr (from var) + CALL PHL4HC ; ..display as hex + CALL VPRINT + DEFB CR,LF,' Base of Dos = ' + DEFB 0 + LD HL,(DNBADR) ; DOS Non-banked base addr (from var) + CALL PHL4HC + CALL VPRINT + DEFB CR,LF,' Base of Cpr = ' + DEFB 0 + LD HL,(CNBADR) ; CCP Non-banked base addr (from var) + JP PHL4HC ; ..display and let return from there + + + ; size of User Space in bytes + ; in: - + ; out: DE= size, Z-Flag set if size = 0 +USPCSZ: LD DE,UNBSZ_I ; User Space # records in IMG hdr + LD A,(DE) + LD D,A ; convert to 16-bit word + LD E,0 ; ..and multiply by 256 + SRL D ; /2 (blocks * 128 = size in bytes) + RR E + OR A ; if User Space size = zero, set Z-Flag + RET + + + ; get lowest addr in Z3ENV + ; ( from offs. +9 EXPAT to +30 SHSTK = 8x 16-/8-bit value combo + ; from offs. +34 Z3MSG to +38 EXTSTK = 3x 16-bit value ) + ; in: - + ; out: HL= lowest addr of Z3ENV components +ENVLOW: LD HL,Z3ENV_I ; ptr to Z3ENV base + LD DE,9 ; start w/ offset to addr EXPATH (ext. path) + ADD HL,DE + LD C,(HL) ; get addr in BC + INC HL + LD B,(HL) + DEC HL ; move ptr back prior to loop + LD A,8 ; 8 entries (from EXPATH to SHSTK) +ENVLOW0: PUSH AF + CALL ADRLOWC ; find the lower of two addresses + INC HL ; skip byte following the addr + POP AF + DEC A ; decrease counter + JR NZ,ENVLOW0 ; ..loop till done + LD A,3 ; 3 entries (from Z3MSG to EXTSTK) +ENVLOW1: PUSH AF + CALL ADRLOWS ; find the lower of two addresses + POP AF + DEC A ; decrement counter + JR NZ,ENVLOW1 ; ..loop till done + INC HL ; skip Quiet flag + CALL ADRLOWS ; check also Z3WHL addr + LD L,C ; finally, copy lowest addr to HL + LD H,B + RET + + + ; returns lowest addr of Z3ENV components w/ 16-/8-bit value combo (e.g. RCP, IOP) + ; in: HL= ptr to current addr + ; BC= lowest addr so far + ; out: BC= lowest addr +ADRLOWC: LD E,(HL) ; get low byte + INC HL + LD D,(HL) ; ..and high byte + INC HL + LD A,D + OR E ; check if high = low = zero + RET Z ; ..if so, return + LD A,(HL) ; get high byte again + OR A ; check if zero + RET Z ; ..if so, return + LD A,E ; get low byte again + SUB C + LD A,D ; get high byte again + SBC A,B ; ..and check against lowest addr so far + RET NC ; ..no C-Flag means, old addr is lower + LD C,E ; else, copy current addr + LD B,D + RET + + + ; returns lowest addr of Z3ENV components w/ 16-bit value (e.g. Z3MSG) + ; in: HL= ptr to byte ahead of current addr + ; BC= lowest addr so far + ; out: BC= lowest addr +ADRLOWS: INC HL ; move ptr fwd to addr + LD A,(HL) ; get low byte + INC HL + OR (HL) ; check if high = low = zero + RET Z ; ..if so, return + DEC HL ; move ptr back + LD A,(HL) ; get low byte again + INC HL + SUB C + LD A,(HL) ; get high byte again + SBC A,B ; ..and check against lowest addr so far + RET NC ; ..no C-Flag means, old addr is lower + LD B,(HL) ; else, copy current addr + DEC HL + LD C,(HL) + INC HL + RET + + + ; print HL as four-digit hex + closing bracket + ; then get user input and convert to number + ; in: HL= 16-bit value + ; A= 0 no conversion, <> 0 convert to number + ; out: DE= converted number +PHLXCNV: PUSH HL ; save regs + CALL PHL4HC ; display as hex + LD A,'H' ; display additional 'H' + CALL COUT + POP DE ; prepare for no input (restore value in DE) + CALL PRBRCIN ; display closing bracket and get user input + RET Z ; ..if input empty, return + JP EVAL16 ; else, convert as hexadecimal + ; ..and let return from there + + + + ; print HL as decimal + closing bracket + ; then get user input and convert to number + ; in: HL= 16-bit value + ; A= 0 no conversion, <> 0 convert to number + ; out: DE= converted number +PHLDCNV: PUSH HL ; save regs + CALL PHLFDC ; display as dec + POP DE ; prepare for no input (restore value in DE) + CALL PRBRCIN ; display closing bracket and get user input + RET Z ; ..if input empty, return + JP EVAL10 ; else, convert as decimal number + ; ..and let return from there + + + ; print right (closing) bracket, then fall through to get user input +PRBRCIN: CALL VPRINT + DEFB ']',TAB,': ' + DEFB 0 + + + ; get console input (based based on line editor) + ; in: - + ; out: HL= ptr to first char of nul-terminated input string + ; ##### CHECK: buffer location could interfere with STACK +CINPUTL: LD HL,CINBUF ; set ptr to buffer + LD (HL),30 ; set buffer size + INC HL + LD (HL),0 ; init char count (filled by BLINE) + INC HL + LD (HL),0 ; init first char (filled by BLINE) + DEC HL ; move ptr back to start of buffer + DEC HL + OR 0FFH ; set flag to capitalize + JP BLINE ; get line input, and let return from there + + + ; ##### unreferenced code (not used) +UNUSED2 + CALL BASEROW + LD L,10 + CALL GOTOXY + CALL VPRINT + DEFB 'Selection (ESC/Ctrl-C Aborts) : ' + DEFB 0 + CALL CAPINE + CP ESC + RET Z + CP CTRLC + RET Z + CALL ISALNUM + JR NZ,UNUSED2 + RET + ; ##### + + + ; print segment information - addr, # entries, and size + ; ask for new values and convert, replacing old values at orig. location + ; in: HL= ptr to 16-bit value (addr), + ; followed by 8-bit values (entries, size) +PADENSZ: CALL PHLXENT ; print addr and # entries, get input (converted) + PUSH HL ; save ptr + CALL BASEROW + INC HL ; row 4 from bottom + JR PHLXSZ1 ; ..jump to continue displaying size + + + ; print string "Address" and 16-bit value as hex on CON: + ; ask for new value, convert it, and store at original addr + ; then print "Size" and following byte, ask for new value, + ; convert it, and store at original addr + ; in: HL= ptr to 16-bit value (addr), followed by 8-bit value (entries) +PHLXSIZ: CALL PHLXCIN ; print addr, get input and convert +PHLXSZ0: PUSH HL ; save ptr + CALL BASEROW ; row 5 from bottom +PHLXSZ1: INC H ; 2* row down + INC H + LD L,16 ; col 16 + CALL GOTOXY ; position cursor + CALL VPRINT + DEFB 'Size',TAB,' [' + DEFB 0 + POP HL ; restore ptr + LD A,(HL) ; get byte + PUSH HL + LD L,A ; copy byte to L + LD H,0 ; set high byte to zero + CALL PHLDCNV ; ..display as dec and get user input (converted) + POP HL ; restore ptr + JR NC,PHLXSZ2 ; ..if conversion successful, skip over + LD A,BEL ; else, send to CON: + CALL COUT + JR PHLXSZ0 ; ..and loop + +PHLXSZ2: LD A,E ; copy converted number to A + LD (HL),A ; ..and store at orig. location + RET + + + ; print string "Address" and 16-bit value as hex on CON: + ; ask for new value, convert it, and store at original addr + ; then print "Entries" and following byte, ask for new value, + ; convert it, and store at original addr + ; in: HL= ptr to 16-bit value (addr), followed by 8-bit value (entries) +PHLXENT: CALL PHLXCIN ; print addr, get input and convert +PHLXEN0: PUSH HL ; save ptr + CALL BASEROW ; row 5 from bottom + INC H ; 2* row down + INC H + LD L,16 ; col 16 + CALL GOTOXY ; position cursor + CALL VPRINT + DEFB '# Entries [' + DEFB 0 + POP HL ; restore ptr + LD A,(HL) ; get byte + PUSH HL + LD L,A ; copy byte to L + LD H,0 ; set high byte to zero + CALL PHLDCNV ; ..display as dec and get user input (converted) + POP HL ; restore ptr + JR NC,PHLXSZ2 ; ..if conversion successful, jump to continue + LD A,BEL ; else, send to CON: + CALL COUT + JR PHLXEN0 ; ..and loop + + + ; print string "Address" and 16-bit value as hex on CON: + ; in row 4 from bottom, col 15 + ; then ask for new value, convert it, and store at original addr + ; in: HL= ptr to 16-bit value +PHLXCIN: PUSH HL + CALL BASEROW ; row 5 from bottom + INC H ; row down + LD L,15 ; col 15 + CALL GOTOXY ; position cursor + CALL VPRINT ; ..and display + DEFB 'Address',TAB,'[' + DEFB 0 + POP HL ; restore ptr in HL + LD E,(HL) ; get 16-bit value in DE + INC HL + LD D,(HL) + DEC HL + PUSH HL ; save ptr again + EX DE,HL ; swap regs + CALL PHLXCNV ; display hex value and get user input (converted) + POP HL ; restore ptr + JR NC,PHLXCI0 ; check for overflow in number conversion + ; ..if not, jump + ; else, fall through + LD A,BEL ; alert user (send to CON:) + CALL COUT + JR PHLXCIN ; ..and loop + +PHLXCI0: LD (HL),E ; store converted number in DE + INC HL ; at orig. location + LD (HL),D + INC HL + RET + + + ; print addr and value of segment to CON: at xy coordinates + ; in: HL= row/col + ; DE= ptr to addr (value byte follows) +PSEGXY: CALL GOTOXY ; position cursor + PUSH HL ; save coordinates + LD A,(DE) ; get low byte + INC DE ; move ptr fwd + LD L,A + LD A,(DE) ; get high byte + INC DE ; ptr fwd + LD H,A + CALL PHLXH ; display 16-bit value as hex and 'H' + POP HL ; restore coordinates + INC H ; row +1 + CALL GOTOXY ; position cursor + LD A,(DE) ; get byte + JR PSPCAD ; display + value as dec, return from there + + + ; print addr in HL as four-digit hex and append 'H' + ; in: HL= addr +PHLXH: CALL PHL4HC ; display as 4-digit hex + LD A,'H' ; append 'H' + JP COUT ; ..and let return from there + + + ; ###### unreferenced code (not used) +UNUSED3: CALL ALIGN ; align to next sector boundary + ADD HL,HL + LD A,H + ; ##### + + ; print and A as decimal +PSPCAD: PUSH AF ; save regs + LD A,' ' ; send to CON: + CALL COUT + POP AF ; restore A + JP PADC ; display as decimal, let return from there + + + ; returns row # of 5 lines above bottom of screen + ; in: - + ; out: H= row (max. row -5) +BASEROW: PUSH DE ; save regs + LD HL,(ENVADR) ; get ptr to ENV + LD DE,50 ; offset to number of rows (CRT) + ADD HL,DE ; move ptr + LD H,(HL) ; get value + DEC H ; -5 + DEC H + DEC H + DEC H + DEC H + POP DE ; restore regs + RET + + +;::::: Standard file types + +FTYPES: DEFB 'BAK','IMG','REL','ZRL' + DEFS 23 + + +;::::: HEADER OF IMAGE FILE (all labels end with "_I") + + ; area for building the IMG file header + ; if an image file was specified on the command line, the header is read + ; and copied here, else default values are used and updated accordingly +IMGHD_I: JP 0 + +UNBAD_I: DEFW 0E900H ; addr User Space Non-banked +UNBSZ_I: DEFB 6 ; # recs +UBKAD_I: DEFW 0 ; addr User Space Banked + DEFS 8 + +CFNAM_I: DEFB 'ZCPR33 REL' ; default name ZCPR file +CNBAD_I: DEFW 0 ; Non-banked base addr +CNBSZ_I: DEFW 0 ; " size +CBKAD_I: DEFW 0 ; Banked base addr +CBKSZ_I: DEFW 0 ; " size + DEFS 13 + +DFNAM_I: DEFB 'ZSDOS ZRL' ; default name ZSDOS file +DNBAD_I: DEFW 0 +DNBSZ_I: DEFW 0 +DBKAD_I: DEFW 0 +DBKSZ_I: DEFW 0 + DEFS 13 + +BFNAM_I: DEFB 'B/P-18 REL' ; default name B/P Bios file +BNBAD_I: DEFW 0 +BNBSZ_I: DEFW 0 +BBKAD_I: DEFW 0 +BBKSZ_I: DEFW 0 + DEFS 13 + +IMGFN_I: DEFB 'BPSYS IMG' ; default name system image file + DEFS 5 + + +;::::: Z3ENV DESCRIPTOR (in IMG header) + +Z3ENV_I: JP 0 ; Leading jump (address is CBIOS when NZCOM) + DEFB 'Z3ENV' ; Environment ID + DEFB 81H ; Env type (=>80H means extended) + ; ##### should rather be 90H for B/P Bios + + ; offset + ; (dec / hex) + DEFW 0FDF4H ; EXPATH 9 / 09 + DEFB 05H + DEFW 0F200H ; RCP 12 / 0C + DEFB 10H + DEFW 0EC00H ; IOP 15 / 0F + DEFB 0CH + DEFW 0FA00H ; FCP 18 / 12 + DEFB 04H + DEFW 0FC00H ; Z3NDIR 21 / 15 + DEFB 0EH + DEFW 0FF00H ; Z3CL 24 / 18 + DEFB 0CBH + DEFW 0FE00H ; Z3ENV 27 / 1B + DEFB 02H + DEFW 0FD00H ; SHSTK 30 / 1E + DEFB 04H + DEFB 20H + DEFW 0FD80H ; Z3MSG 34 / 22 + DEFW 0FDD0H ; EXTFCB 36 / 24 + DEFW 0FFD0H ; EXTSTK 38 / 26 + DEFB 00H ; Quiet Flag 40 / 28 + DEFW 0FDFFH ; Z3WHL 41 / 29 + DEFB 4 ; Proc. Speed (MHz) 43 / 2B + + DEFB 'P'-'@' ; Max Disk Letter + DEFB 31 ; Max User Number + DEFB 1 ; DU flag + DEFB 0 ; CRT Selection + DEFB 0 ; Printer Selection + DEFB 80 ; CRT 0: Width (# Columns) + DEFB 24 ; # of Lines + DEFB 22 ; # of Text Lines + + DEFW 0001000011111111B ; DRVEC (valid drives) 52 / 34 + DEFB 0 ; + + DEFB 80 ; PRT 0: Width (# Columns) + DEFB 66 ; # of Lines + DEFB 58 ; # of Text Lines + DEFB 1 ; FF Flag + + ; storage for Resident User Space Vectors (replaces PRT1 definitions) + DEFB 06H ; remaining free recs 59 / 3B + DEFW 0E900H ; base addr (xx00H/xx80H) 60 / 3C + DEFB 06H ; size in 128-byte recs 62 / 3E + + DEFW 0BE00H ; CPR 63 / 3F + DEFB 10H + DEFW 0C600H ; DOS 66 / 42 + DEFB 1CH + DEFW 0D400H ; BIOS 69 / 45 + + DEFB 'SH ' ; Shell variable filename + DEFB 'VAR' ; Shell variable filetype + DEFB ' ' ; File 1 + DEFB ' ' ; + DEFB ' ' ; File 2 + DEFB ' ' ; + DEFB ' ' ; File 3 + DEFB ' ' ; + DEFB ' ' ; File 4 + DEFB ' ' ; + DEFB 0 ; Public Drive Area (ZRDOS +) + DEFB 0 ; Public User Area (ZRDOS +) + + ; *** end of Z3ENV descriptor and IMG header *** + + +;::::::::::::::::::::::::::::::::::::::::::::::::::::: +; LINK - 0x1980 +; VLIB - 0x1bfb +; Z3LIB - 0x1e3a +; SYSLIB - 0x20f4 +; end addr 0x23e0 (begin DSEG) +;::::::::::::::::::::::::::::::::::::::::::::::::::::: + + +;::::: RAM STORAGE + + DSEG + +MSELOPT: DEFB 0 ; selected Menu option + + ; room for FCB's of system segments +CCPFCB: DEFS 36 ; CCP (ZCPR) +DOSFCB: DEFS 36 ; (ZS)DOS +BIOSFCB: DEFS 36 ; (B/P) BIOS + +CCNBSZ: DEFW 0 ; CCP CSEG Non-banked Size (in TPA bank) +DCNBSZ: DEFW 0 ; DOS CSEG Non-banked Size +BCNBSZ: DEFW 0 ; BIOS CSEG Non-banked Size +BCBKSZ: DEFW 0 ; BIOS CSEG Banked Size (org 'BANK2', in System bank) +BDBKSZ: DEFW 0 ; BIOS DSEG Banked Size (org 'B2RAM') +DCBKSZ: DEFW 0 ; DOS CSEG Banked Size ('BANK2') +DDBKSZ: DEFW 0 ; DOS DSEG Banked Size ('B2RAM') +CCBKSZ: DEFW 0 ; CCP CSEG Banked Size ('BANK2') +CDBKSZ: DEFW 0 ; CCP DSEG Banked Size ('B2RAM') + +SYSBLKS: DEFW 0 ; Size of new system in 128-byte blocks (# sectors) +AUTOSIZ: DEFB 0 ; Auto-sizing flag (0= no, 0xFF= yes) +BNKDSYS: DEFB 0 ; Banked system flag (bit 3 of OPTF1 = indicator ALV/CSV in bank) +OPTF1: DEFB 0 ; OPTF1 option flag of linked BIOS +BRSVDO: DEFW 0 ; BIOS org RESVD common +BNBADR: DEFW 0 ; BIOS Non-banked base addr +DNBADR: DEFW 0 ; DOS Non-banked base addr +CNBADR: DEFW 0 ; CCP Non-banked base addr + +LPHYADR: DEFW 0 ; phys. destination addr when linking system segment (from WSPC onwards) +SYSEADR: DEFW 0 ; end addr of new system in WSPC (total of all segments) + +IMGFCB: DEFS 36 ; room for FCB of image file + + ; used by linker related fn's +LBYTPOS: DEFB 0 ; byte ptr @GBYTE function +LFCBADR: DEFW 0 ; addr current FCB +LTBLADR: DEFW 0 ; addr COMTBL + +CINBUF: ; console input buffer + DEFS 60H ; room for stack +STACK: DEFW 0 ; stack storage location +OLDDU: DEFW 0 ; logged Drive/User at program start + + END + + +;************************************************************************ +; Remarks jxl: +; BPBUILD.COM, included in available B/P Bios package(s), was dis- +; assembled and extensively commented. Labels are up to seven chars long +; to comply with M-REL standards. However, it is recommended to use SLR +; tools that support labels up to sixteen chars. +; In its current state, the compiled/linked file matches exactly the +; original ZSCFG2.COM, i.e. no changes to the source were made. Possible +; optimisations detected during disassembly are marked with "#####" in the +; comment. +; +; The program makes use of linker module which was included in the +; distributed package of ZSDOS v1 sources (SLINK0.Z80/.REL), to generate +; its output from M-REL files - an interesting piece of software! +; The embedded Image header and Z3 Environment descriptor could be +; externalised in .LIB files. However, this was not done (yet) to provide +; the complete source code "as is." +;************************************************************************ diff --git a/Source/BPBIOS/UTIL/bpcnfg.z80 b/Source/BPBIOS/UTIL/bpcnfg.z80 new file mode 100644 index 00000000..4e8476fc --- /dev/null +++ b/Source/BPBIOS/UTIL/bpcnfg.z80 @@ -0,0 +1,4539 @@ + TITLE "Change B/P Bios Configuration Settings" +;************************************************************************ +;* B P C O N F I G * +;* Set user-configurable parameters in a B/P Bios * +;* by Harold F. Bower and Cameron W. Cotrill * +;*----------------------------------------------------------------------* +;* Disassembly: jxl Nov 2024 * +;* public release 1.0 Apr 2025 * +;* see remarks at the end * +;*----------------------------------------------------------------------* +;* LINK with Version 4 libraries: VLIB, Z3LIB, SYSLIB * +;* * +;* A>Z80ASM BPCNFG/RS * +;* A>SLRNK BPCNFG/N,/A:100,/D:3A55,BPCNFG,VLIBS/S,Z3LIBS/S,SYSLIBS/S,/E * +;************************************************************************ + +VER EQU 21 +REV EQU 'a' + +DATE MACRO + DEFB '21 Apr 97' + ENDM + + +CTRLC EQU 03H ; Control-C character +BEL EQU 07H ; Bell character +BS EQU 08H ; Backspace character +TAB EQU 09H ; Tab character +LF EQU 0AH ; Line Feed character +CR EQU 0DH ; Carriage Return character +CTRLZ EQU 1AH ; Control-Z character (end of file) +ESC EQU 1BH ; Escape character + +CPMBIOS EQU 0 ; CP/M BIOS warm boot (JP) +CPMBDOS EQU 5 ; CP/M BDOS entry point (JP) +CPMFCB EQU 5CH ; CP/M standard FCB #1 (+1 filename, +9 filetype) +CPMFCB2 EQU 6CH ; CP/M standard FCB #2 + + +; For SYSLIB make visible... + PUBLIC CIN + +; From VLIB Get.. + EXTRN Z3VINIT, VPRINT, CLS, VPSTR, EREOL + +; From Z3LIB Get.. + EXTRN WHRENV, GETNAME, PRTNAME, ZFNAME, FCB1CHK, Z3LOG + +; From SYSLIB Get.. + EXTRN RETUD, LOGUD, CODEND, COUT, CRLF, PAFDC, PHLFDC, PHL4HC, PAFDC, PFN3, EVAL + EXTRN CAPIN, CAPINE, INLINE, SETDMA, F$EXIST, F$OPEN, R$READ, F$WRITE, F$CLOSE, F$READ + + +;::::: PROGRAM START + + ORG 100H + CSEG + + +BPCNFG: JP START ; bypass header + DEFB 'Z3ENV' ; this is a ZCPR3 utility + DEFB 1 ; show external environment + +ENVADR: DEFW 0h ; addr of Z3 environment + DEFW BPCNFG ; type 4 filler + DEFB 'BPCNFG ' ; configuration name + DEFB 0 +FTYPE: DEFB 'IMG' ; standard file types + DEFB 'CNF' + +START: LD (STACK),SP ; save stack pointer + LD SP,STACK ; ..and set local stack + CALL RETUD ; get currently logged drive/user + LD (OLDDU),BC ; ..store + CALL CODEND ; determine begin of WSPC + LD (WSPCBEG),HL ; ..store + LD (WRKSTRT),HL ; ..plus a copy to work with + EX DE,HL ; clear workspace area up to 0x8000 + LD HL,8000H + OR A + SBC HL,DE ; calc length + LD C,L + LD B,H + DEC BC ; actual bytecount is one less + LD L,E ; restore HL + LD H,D + INC DE ; move fwd + LD (HL),0 ; set first byte to 0x00 + LDIR ; ..clear + + ; save 2nd token of cmdline (script file) + LD HL,CPMFCB2 ; ptr to 2nd token of cmdline + LD DE,CFFCB ; ptr to local FCB + LD BC,16 ; copy 16 bytes + LDIR + CALL CFINFT ; add standard filetype, if necessary + + ; find/init Z3 Environment + LD HL,(CPMBDOS+1) + CALL WHRENV ; locate Env descriptor + LD (ENVADR),HL ; ..save addr + CALL Z3VINIT ; and init for VLIB/Z3LIB routines + CALL GETNAME ; get actual program name + CALL GETQFLG ; get quiet flag + AND A + JR NZ,START0 ; ..if quiet, skip over + + ; display message (verbosely) + CALL VPRINT + DEFB CR,LF,1,'B/P CONFIG Utility',2,' V' + DEFB VER/10+'0','.',VER MOD 10 + '0',REV,' ' + DATE + DEFB CR,LF,' Copyright 1991-3 by H.F.Bower/C.W.Cotrill',CR,LF + DEFB 0 + + ; init BIOS shortcuts and evaluate cmdline (FCB #1) +START0: LD HL,(CPMBIOS+1) ; ptr to BIOS WBOOT JP + LD A,8*3 ; ..skip 8 JP's + CALL ADDHLA ; HL= ptr to JP of BIOS fn #9 (SELDSK) + LD DE,BIOSELD ; target addr + LD BC,8*3 ; make local copies of 8 fn jumps + LDIR + LD A,(CPMFCB+1) ; get first cmdline token from FCB + CP '/' ; is this a help request ? + JP Z,HELP ; ..if so, show help screen + CP '?' ; is it an ambiguous filename ? (option '*' is expanded) + LD C,'M' + JR Z,CHKMOD1 ; ..if so, jump to (M)emory config + CP ' ' ; ? + LD C,'I' + JP NZ,CHKMOD6 ; ..if not, jump to (I)mage config + LD A,(CPMFCB) ; else get drive + OR A ; is it zero ? + JR Z,CHKMODE ; ..if so, jump to display options + ADD A,40H ; else, convert to ascii letter + LD C,'D' + JR CHKMOD4 ; ..and jump to (D)isk config + + ; --- Check running mode +CHKMODE: CALL VPRINT + DEFB CR,LF,' Configure Memory (M), Disk (D), or Image (I) ? : ' + DEFB 0 + CALL GETINP + LD C,A ; keep user input + CP 'M' ; is it 'M' ? + JR NZ,CHKMOD2 ; ..if not, jump to next + +CHKMOD1: LD A,C ; restore user input + LD (RUNMODE),A ; save (confirmed) mode + CALL RDMEM ; read B/P Bios of running system + JP CHKMOD9 + +CHKMOD2: CP 'D' ; is it 'D' ? + JR NZ,CHKMOD5 ; ..if not, jump to next + CALL VPRINT +CHKMOD3: DEFB CR,LF,TAB,'Disk Drive Letter (A..P) : ' + DEFB 0 + CALL GETINP ; get input + CALL CHKDLTR ; is a valid drive letter ? ('A'..'P') + JR C,CHKMOD3 ; ..if not, ask for new input +CHKMOD4: PUSH AF ; save AF + LD A,C ; restore user input + LD (RUNMODE),A ; save (confirmed) mode + POP AF ; restore AF (drive) + CALL RDDSK ; read system tracks and find B/P Bios + JR CHKMOD9 + +CHKMOD5: CP 'I' ; is it 'I' ? + JP NZ,CHKMODE ; ..if not, loop ask user again + CALL VPRINT + DEFB CR,LF,TAB,'Image File to Configure : ' + DEFB 0 + CALL CINPUTL ; get input (inline editor) + JP Z,EXIT + LD DE,CPMFCB ; ptr to CP/M standard FCB #1 + CALL ZFNAME ; parse FCB + OR A + JR NZ,CHKMOD7 ; ..if error, display msg and quit program +CHKMOD6: LD A,C ; restore user input + LD (RUNMODE),A ; save (confirmed) mode + CALL FCB1CHK ; check 1st cmdline token + JR Z,CHKMOD8 ; ..if valid filename, skip over + +CHKMOD7: CALL E$MSG + CALL VPRINT + DEFB 'Error in File Name Parse !' + DEFB 0 + JP EXIT +CHKMOD8: CALL RDIMG ; read image file + + ; fall through and try to open script file +CHKMOD9: XOR A + LD (CFBYTE),A ; clear current byte + LD A,(CFFCB+1) ; get first char of script file name + CP ' ' ; is it ? + CALL NZ,CFINOPN ; ..if not, open script file + + ; * + + +;::::: MENU 0 - MAIN + + +M0MAIN: LD SP,STACK ; reset SP to local stack + XOR A ; clear A + LD (CFMENU),A ; ..and store as indicator + CALL CLS + CALL VPRINT + DEFB CR,LF,'Main Menu - Configuring ' + DEFB 0 + + ; eval user selection + ; configure (M)emory, (D)isk, or default to (I)mage + LD A,(RUNMODE) + CP 'M' + JR NZ,M0MAIN1 + CALL VPRINT + DEFB 'Running Memory' + DEFB 0 + JR M$BVER +M0MAIN1: CP 'D' + JR NZ,M0MAIN2 + CALL VPRINT + DEFB 'Drive ' + DEFB 0 + LD A,(DISKNO) ; get disk number + ADD A,40H ; ..convert to ascii letter for display + CALL COUT + LD A,':' + CALL COUT + CALL VPRINT + DEFB ' Boot Sectors' + DEFB 0 + JR M$BVER +M0MAIN2: CALL VPRINT + DEFB 'Image File [' + DEFB 0 + LD BC,(IMGDU) + LD A,B + ADD A,'A' + CALL COUT + LD A,C + CALL PAFDC ; print byte in A as 1-3 decimal chars + LD A,':' + CALL COUT + LD DE,CPMFCB+1 ; filename in CP/M standard FCB + CALL PFN3 ; display fn/ft on CON: + LD A,']' + CALL COUT + + ; msg B/P Bios Vers x.x +M$BVER: CALL VPRINT + DEFB CR,LF,' Bios Ver ' + DEFB 0 + LD A,(BPVERS) ; get version # + PUSH AF ; save AF + RRCA ; reverse nybbles in A + RRCA + RRCA + RRCA + CALL PLOWAX ; print lower nybble as hex + LD A,'.' + CALL COUT + POP AF ; restore AF + CALL PLOWAX ; ..and print lower nybble as hex + + ; display Main menu + CALL VPRINT + DEFB CR,LF,LF,' ',1,' 1 ',2,' System Options' + DEFB CR,LF,LF,' ',1,' 2 ',2,' Character IO Options' + DEFB CR,LF,LF,' ',1,' 3 ',2,' Floppy Subsystem Options' + DEFB CR,LF,LF,' ',1,' 4 ',2,' Hard Disk Subsystem Options' + DEFB CR,LF,LF,' ',1,' 5 ',2,' Logical Drive Layouts' + DEFB CR,LF,LF,' ',1,' 6 ',2,' Configure from Script File' + DEFB 0 + +M0SLCT: LD A,'6' ; max. possible option in this menu as ascii number + CALL MSELECT + OR A + JR Z,WRCONF + CP '1' + JP Z,M1SYS + CP '2' + JP Z,M2CIO + CP '3' + JP Z,M3FD + CP '4' + JP Z,M4HD + CP '5' + JP Z,M5DL + CP '6' + JP Z,M6CNF + CALL CFEVAL ; eval script file input + JR M0SLCT ; loop + + ; write configuration +WRCONF: CALL VPRINT + DEFB CR,LF,'..Writing New Configuration to ' + DEFB 0 + LD A,(RUNMODE) ; get mode + CP 'D' ; config mode (D)rive ? (system tracks) + JR NZ,WRCONF1 ; ..if not, jump to next + + CALL VPRINT + DEFB 'Drive : ' + DEFB 0 + LD A,(DISKNO) ; get disk number + ADD A,40H ; convert to ascii letter for display + CALL COUT + CALL WRDSK ; write to disk + JR WRCONF3 ; ..and exit +WRCONF1: CP 'M' ; config mode (M)emory ? (running system) + JR NZ,WRCONF2 ; ..if not, jump to next + + CALL VPRINT + DEFB 'Memory..' + DEFB 0 + CALL WRMEM ; write to memory + JR WRCONF3 ; ..and exit +WRCONF2: CALL VPRINT ; config mode (I)mage + DEFB ' : ' + DEFB 0 + LD DE,CPMFCB+1 ; filename in CP/M standard FCB + CALL PFN3 ; display fn.ft on CON: + CALL VPRINT + DEFB '..' + DEFB 0 + CALL WRIMG ; write to image file +WRCONF3: LD BC,(OLDDU) + CALL LOGUD ; restore previously logged DU: + CALL CRLF + JP EXIT + + ; * + + +;::::: MENU 1 - SYSTEM OPTIONS (display) + + +M1SYS: LD A,1 + LD (CFMENU),A ; store flag (sub-)menu entered + CALL CLS + CALL VPRINT + DEFB CR,LF,'Menu 1 - System Options' + DEFB CR,LF,LF,LF,' ',1,' 1 ',2,' System Drive = ' + DEFB 0 + LD A,7FH ; offset to SYSDRV in Config area + CALL WSPCPTR ; set ptr + LD A,(HL) ; get system drive # + ADD A,'A' ; ..convert to ascii letter + CALL COUT ; display it + CALL VPRINT + DEFB ':',CR,LF,LF,' ',1,' 2 ',2,' Startup Command = "' + DEFB 0 + LD A,8EH ; offset to AUTOCMD in Config area + CALL WSPCPTR ; set ptr + INC HL ; get past leading 'DEFB 8' + CALL VPSTR ; ..and display nul-terminated string + CALL VPRINT + DEFB '"',CR,LF,LF,' ',1,' 3 ',2,' Reload Constant = ' + DEFB 0 + LD A,9FH ; offset to RELOD0 in Config area (const counter/timer) + CALL WSPCPTR ; set ptr + LD A,(HL) ; get low byte of 16-bit value + INC HL ; ptr fwd + LD H,(HL) ; get high byte + LD L,A + CALL PHLFDC ; display value in HL as dec + CALL VPRINT + DEFB ' (' + DEFB 0 + CALL PHL4HC ; ..and as hex + CALL VPRINT + DEFB 'H)', + DEFB LF,CR,LF,' ',1,' 4 ',2,' Processor Speed = ' + DEFB 0 + LD A,9DH ; offset to SPEED in Config area + CALL WSPCPTR ; set ptr + LD A,(HL) ; get processor speed + CALL PAFDC ; ..and display it + CALL VPRINT + DEFB ' MHz' + DEFB CR,LF,LF,' ',1,' 5 ',2,' Memory Waits = ' + DEFB 0 + LD A,9EH ; offset to WAITS in Config area (MEM + IO combined) + CALL WSPCPTR ; set ptr + LD A,(HL) ; get value + RRCA ; reverse nybbles in A + RRCA + RRCA + RRCA + AND 00001111B ; mask off upper nybble + CALL PAFDC ; ..and display value + CALL VPRINT + DEFB ', IO Waits = ' + DEFB 0 + LD A,(HL) ; get value + AND 00001111B ; mask off upper nybble + CALL PAFDC ; ..and display value + LD A,'6' ; max. possible option in this menu as ascii number + ; (hidden option 6: Menu 1.1 System Banks) + CALL MSELECT + OR A + JP Z,M0MAIN + + +;::::: MENU 1 - SYSTEM OPTIONS (configure) + + ; subsequent labels start with "SY_" +M1CFG: CP '1' ; option '1' selected ? + JR NZ,SY_CMD ; ..if not, jump to next + CALL CRLF + + ; --- option 1 System Drive +SY_DRV: CALL VPRINT + DEFB CR,TAB,TAB,'System Drive Letter',TAB,TAB,'[' + DEFB 0 + LD A,7FH ; offset to SYSDRV in Config area + CALL WSPCPTR ; set ptr + LD A,(HL) ; get system drive # + ADD A,'A' ; ..convert to ascii letter + CALL COUT ; display it + CALL VPRINT + DEFB ']',TAB,': ' + DEFB 0 + CALL EREOL ; clear CON: to end of line + CALL GETINP + JP Z,M1SYS ; ..if no input, jump display menu again + CP CR ; entered ? + JP Z,M1SYS ; ..if so, jump display menu + CALL CHKDLTR ; check is drive letter A..P ? + JR NC,SY_DRV1 ; ..if so, jump to continue + CALL CFEVAL ; eval script file input + JR SY_DRV ; loop (ask for new input) +SY_DRV1: SUB 'A' ; convert ascii to number + LD C,A + LD A,7FH ; offset to SYSDRV in Config area + CALL WSPCPTR ; set ptr in WSPC + LD (HL),C ; store new SYSDRV value + JP M1SYS ; loop, jump to display menu + + ; --- option 2 Startup Command +SY_CMD: CP '2' ; option 2 selected ? + JR NZ,SY_TMR ; ..if not, jump to next + CALL CRLF +SY_CMD1: CALL VPRINT + DEFB CR,TAB,TAB,'Enter New Startup Command : ' + DEFB 0 + CALL EREOL ; clear CON: to end of line + CALL CINPUTL ; get input (inline editor) + JR Z,SY_CMD1 ; ..if empty, jump ask for new input + EX DE,HL ; DE= ptr input buffer + LD A,8EH ; offset to AUTOCMD in Config area + CALL WSPCPTR ; set ptr in WSPC + INC HL ; move past leading 'DEFB 8' + EX DE,HL ; swap pointers + LD B,8 ; copy up to 8 chars +SY_CMD2: LD A,(HL) ; get char from input buffer + OR A ; is it a ? (= end) + JR Z,SY_CMD3 ; ..if so, exit loop + LD (DE),A ; store char in AUTOCMD + INC HL ; move ptr's fwd + INC DE + DJNZ SY_CMD2 ; ..and loop til done + JR SY_CMD5 ; at this point, 8 chars were copied + ; no filling up with +SY_CMD3: EX DE,HL ; swap pointers (HL= AUTOCMD) +SY_CMD4: LD (HL),' ' ; fill remaining bytes with + INC HL + DJNZ SY_CMD4 +SY_CMD5: JP M1SYS ; loop, display menu + + ; --- option 3 Timer Reload Value +SY_TMR: CP '3' ; option 3 selected ? + JR NZ,SY_PRC ; ..if not, jump to next + CALL CRLF +SY_TMR1: CALL VPRINT + DEFB CR,TAB,TAB,'Timer Reload Value',TAB,'[' + DEFB 0 + CALL EREOL ; clear CON: to end of line + LD A,9FH ; offset to RELOD0 in Config area + CALL WSPCPTR ; set ptr + LD E,(HL) ; get low-byte of 16-bit value + INC HL + LD D,(HL) ; ..and high-byte + PUSH HL ; save ptr + EX DE,HL ; swap regs + CALL PHLDCNV ; display value and ask for input + POP HL ; restore ptr + JR NC,SY_TMR2 ; ..if input is valid, skip over + CALL CFEVAL ; eval script file input + JR SY_TMR1 ; loop (ask for input) +SY_TMR2: LD (HL),D ; store high-byte of new value + DEC HL ; move ptr back + LD (HL),E ; ..and low-byte + JR SY_CMD5 ; jump to display menu again + ; (use of two consecutive JR's saves one byte) + + + ; --- option 4 Processor Speed +SY_PRC: CP '4' ; was option 4 selected ? + JP NZ,SY_WT ; ..if not, jump to next + CALL CRLF +SY_PRC1: CALL VPRINT + DEFB CR,TAB,TAB,'Processor Speed in MHz',TAB,'[' + DEFB 0 + CALL EREOL ; clear CON: to end of line + LD A,9DH ; offset to SPEED in Config area + CALL WSPCPTR ; set ptr + LD E,(HL) ; get Processor Speed + LD D,0 + PUSH HL ; save ptr + EX DE,HL ; swap regs + CALL PHLDCNV ; display value and ask for input + POP HL ; restore ptr + JR C,SY_PRC2 ; ..if input is invalid, jump + LD A,D ; else, evaluated input in DE + OR A ; high-byte must be zero + JR Z,SY_PRC3 ; ..if zero, jump to continue +SY_PRC2: CALL CFEVAL ; eval script file input + JR SY_PRC1 ; loop (ask for input) +SY_PRC3: LD D,(HL) ; get new Processor Speed + LD (HL),E ; ..and store value + PUSH DE ; also save it + CALL VPRINT + DEFB CR,LF,TAB,TAB,' Scale Timer Constant?',TAB,'([Y]/N) : ' + DEFB 0 + CALL GETINP ; get input + CP 'N' ; entered 'N' ? + POP DE + JP Z,M1SYS ; ..if so, exit and display menu again + LD A,9FH ; offset to RELOD0 in Config area + CALL WSPCPTR ; set ptr + LD A,(HL) ; get low-byte of 16-bit value + INC HL + LD H,(HL) ; ..and high-byte + LD L,A ; HL= constant for counter/timer refresh + LD C,D ; Processor Speed in C + LD B,0 ; prepare BC as divisor + INC C ; check if Processor Speed = 0 + DEC C + JP Z,M1SYS ; ..if so, exit and display menu + PUSH DE ; else, save Processor Speed + LD DE,0 ; DE is quotient + OR A ; clear Flags +SY_PRC4: SBC HL,BC ; division by subtraction + JR C,SY_PRC5 ; ..if below zero, exit loop + INC DE ; increase counter (quotient) + JR SY_PRC4 ; and loop +SY_PRC5: POP BC ; restore Processor Speed in BC + LD HL,0 ; set initial value +SY_PRC6: ADD HL,DE ; multiply by addition + DEC C ; decrease counter + JR NZ,SY_PRC6 ; ..loop till done + EX DE,HL ; swap regs (DE= new RELOD0 value) + LD A,9FH ; offset to RELOD0 in Config area + CALL WSPCPTR ; set ptr + INC HL ; move ptr fwed + JP SY_TMR2 ; ..and re-use code to store value in DE + + ; --- option 5 Memory Waits +SY_WT: CP '6' ; option 6 selected ? + JP Z,M11ASK ; ..if so, jump to continue + CALL CRLF ; else, must be config of waits +SY_WT1: CALL VPRINT + DEFB CR,TAB,TAB,'Number of Memory Waits',TAB,'[' + DEFB 0 + CALL EREOL + LD A,9EH ; offset to WAITS in Config area + CALL WSPCPTR ; set ptr + LD A,(HL) ; get value + RRCA ; shift upper nybble to lower + RRCA ; WAITS combines Mem (bits 7-4) + RRCA ; and IO (bits 3-0) wait states + RRCA + AND 00001111B ; mask off higher nybble + LD L,A ; Mem wait states in HL + LD H,0 + CALL PHLDCNV ; display value and ask for input + JR C,SY_WT2 ; ..if input is not valid, jump + LD A,D ; evaluated input in DE + OR A ; high-byte must be zero + JR NZ,SY_WT2 ; ..if not, jump + LD A,E + CP 00010000B ; check if value exceeds limit + JR C,SY_WT3 ; ..if not, skip over +SY_WT2: CALL CFEVAL ; eval script file input + JR SY_WT1 ; loop (ask for new input) +SY_WT3: RLCA ; move new value to high nybble + RLCA + RLCA + RLCA + LD C,A ; ..and remember it + CALL CRLF +SY_WT4: CALL VPRINT ; now IO waits + DEFB CR,TAB,TAB,'Number of IO Waits',TAB,'[' + DEFB 0 + CALL EREOL + LD A,9EH ; offset to WAITS in Config area + CALL WSPCPTR ; set ptr + LD A,(HL) ; get value + PUSH HL ; save ptr + AND 00001111B ; mask off high nybble (bits 3-0 = IO waits) + LD L,A ; get value in HL + LD H,0 + CALL PHLDCNV ; display value and ask for input + POP HL ; restore ptr + JR C,SY_WT5 ; ..if input not valid, jump + LD A,D ; evaluated input in DE + OR A ; high-byte must be zero + JR NZ,SY_WT5 ; ..if not, jump + LD A,E + CP 00010000B ; check if value exceeds limit + JR C,SY_WT6 ; ..if not, skip over +SY_WT5: CALL CFEVAL ; eval script file input + JR SY_WT4 ; loop (ask for new input) +SY_WT6: OR C ; combine values (C= Mem waits, A= IO waits) + LD (HL),A ; store new value + JP M1SYS ; ..loop, display menu + + ; * + + + ; --- option 6 System Banks (hidden menu 1.1) +M11ASK: CALL VPRINT ; ask for confirmation before entering menu + DEFB CR,LF,TAB,'-- This is DANGEROUS...Proceed? (Y/[N]) : ' + DEFB 0 + CALL GETINP ; get input + CP 'Y' ; entered 'Y' ? + JP NZ,M1SYS ; ..if not, jump display main menu again + ; else, fall through + + +;::::: MENU 1.1 - SYSTEM BANK NUMBERS (display) + + +M11BNK: CALL CLS + CALL VPRINT + DEFB CR,LF,'Menu 1.1 - System Bank Numbers' + DEFB CR,LF,LF,LF,' ',1,' 1 ',2,' TPA Bank # = ' + DEFB 0 + LD A,82H ; offset to TPABANK in Config area + CALL WSPCPTR ; set ptr + LD A,(HL) ; get TPABANK # + CALL PAFDC ; ..display as decimal + CALL VPRINT + DEFB CR,LF,LF,' ',1,' 2 ',2,' System Bank # = ' + DEFB 0 + LD A,83H ; offset to SYSBNK in Config area + CALL WSPCPTR ; set ptr + LD A,(HL) ; get SYSBNK # + CALL PAFDC ; ..and display + CALL VPRINT + DEFB CR,LF,LF,' ',1,' 3 ',2,' User Bank # = ' + DEFB 0 + LD A,81H ; offset to UABNK in Config area + CALL WSPCPTR ; set ptr + LD A,(HL) ; get UABNK # + CALL PAFDC ; ..and display + CALL VPRINT + DEFB CR,LF,LF,' ',1,' 4 ',2,' RAM Drive Bank # = ' + DEFB 0 + LD A,84H ; offset to RAMBNK in Config area + CALL WSPCPTR ; set ptr + LD A,(HL) ; get RAMBNK # + CALL PAFDC ; ..and display + CALL VPRINT + DEFB CR,LF,LF,' ',1,' 5 ',2,' Maximum Bank # = ' + DEFB 0 + LD A,85H ; offset to MAXBNK in Config area + CALL WSPCPTR ; set ptr + LD A,(HL) ; get MAXBNK # + CALL PAFDC ; ..and display + LD A,'5' ; max. possible option in this menu as ascii number + CALL MSELECT + OR A ; valid option selected ? + JP Z,M1SYS ; ..if not, jump to display system menu + ; else, fall through + + +;::::: MENU 1.1 - SYSTEM BANKS (configure) + +M11CFG: CALL CRLF + SUB '1' ; convert input (ascii) to zero-based index + LD HL,BKOTBL ; ptr lookup table of offset values + CALL ADDHLA ; adjust ptr + LD A,(HL) ; ..and get offset + CALL SB_BNK ; configure + JP M11BNK ; loop, display menu + + ; Lookup table for offsets in config area + ; to the different RAM banks +BKOTBL: DEFB 82H ; TPABNK + DEFB 83H ; SYSBNK + DEFB 81H ; UABNK + DEFB 84H ; RAMBNK + DEFB 85H ; MAXBNK + + + ; --- configure System Banks +SB_BNK: LD (SELBNK),A ; store offset +SB_BNK1: CALL VPRINT + DEFB CR,TAB,' Enter Bank Number',TAB,'[' + DEFB 0 + CALL EREOL ; clear CON: to end of line + LD A,(SELBNK) ; get offset value for selected RAM bank + CALL WSPCPTR ; ..and set ptr in WSPC + LD E,(HL) ; bank # + LD D,0 + PUSH HL ; save ptr + EX DE,HL ; swap regs + CALL PHLDCNV ; display value and ask for input + POP HL ; restore ptr + JR C,SB_BNK1 ; ..if input not value, loop + LD A,D ; evaluated number in DE + OR A ; high-byte must be zero + JR NZ,SB_BNK1 ; ..if not, loop ask for new input + LD (HL),E ; else, store new value + RET + + ; * + + +;::::: MENU 2 - CHARACTER I/O (display) + + +M2CIO: LD A,1 + LD (CFMENU),A ; store flag (sub-)menu entered + CALL CLS + CALL VPRINT + DEFB CR,LF,'Menu 2 - Character IO Options' + DEFB CR,LF,LF,LF,' ',1,' 1 ',2,' IOBYTE Assignment:' + DEFB CR,LF,TAB,TAB,'Console = ' + DEFB 0 + LD A,7EH ; offset IOBYT in Config area + CALL WSPCPTR ; set ptr + LD A,(HL) ; get IO Byte + PUSH AF ; ..and save + CALL PIOASSG ; display name of assigned device + CALL VPRINT + DEFB CR,LF,TAB,TAB,'Auxiliary = ' + DEFB 0 + POP AF ; restore IOBYT + PUSH AF + RRCA ; shift bits 3-2 to position 1-0 + RRCA + CALL PIOASSG ; display name of assigned device + CALL VPRINT + DEFB CR,LF,TAB,TAB,'Printer = ' + DEFB 0 + POP AF ; restore IOBYT + RLCA ; ..and shift bits 7-6 to pos 1-0 (other direction) + RLCA + CALL PIOASSG ; display name of assigned device + XOR A ; nullify A + LD (DEVASSG),A ; clear temp data storage +M2CIO1: CALL IO_PTR ; ptr to DEVCFG table + LD A,(HL) ; get byte + OR A ; is it ? + JR Z,M2CFG ; ..if so, exit loop + LD (DEVTBL),HL ; else, save addr + LD A,(DEVASSG) + INC A ; counter +1 + LD (DEVASSG),A ; ..store + CP 6 ; display additional for first five devices + CALL C,CRLF + CALL VPRINT + DEFB CR,LF,' ',1,' ' + DEFB 0 + LD A,(DEVASSG) + ADD A,'1' ; convert number to ascii + CALL COUT ; ..display + CALL VPRINT + DEFB ' ',2,' ' + DEFB 0 + LD HL,(DEVTBL) ; ptr to DEVCFG (Char IO device table) + CALL PIOPARM ; display parameters + JR M2CIO1 ; ..loop + + +;::::: MENU 2 - CHARACTER I/O (configure) + + ; subsequent labels start with "IO_" +M2CFG: LD A,(DEVASSG) ; get last device # + ADD A,'1' ; convert to ascii + LD (DEVLAST),A ; ..and store it (later used as max. option in this menu) + LD A,(BPVERS) ; get B/P Bios version + CP 20H ; less than 2.0 ? + LD A,(DEVLAST) + JR C,IO_ASS ; ..if <2.0, swap devices not possible + CALL VPRINT + DEFB CR,LF,LF,' ',1,' ' + DEFB 0 + LD A,(DEVASSG) ; get last device # (num) + ADD A,'2' ; ..convert to ascii +1 (adjust for menu option) + CALL COUT + CALL VPRINT + DEFB ' ',2,' Swap Devices' + DEFB 0 + LD A,(DEVLAST) ; get last device # (ascii) + INC A ; make max. possible option in this menu as ascii number + + ; --- configure IO Device Assignment (IOBYT) +IO_ASS: CALL MSELECT + OR A ; input not valid ? + JP Z,M0MAIN ; ..if so, jump to main menu + CP '1' ; else, option 1 selected ? + JP NZ,IO_SWP ; ..if not, jump to next + CALL VPRINT + DEFB CR,LF,TAB,'Set [C]onsole, [A]uxiliary, or [P]rinter : ' + DEFB 0 +IO_ASS1: CALL CAPINE ; get input + CP CR ; is it ? + JP Z,M2CIO ; ..if so, display menu 2 again + CP 'C' ; assign (C)onsole ? + JR NZ,IO_ASS2 ; ..if not, jump + CALL CIOASSG ; configure CON IO Dev Assignment + JP C,M2CIO ; ..if error, display menu again + LD C,11111100B ; set bit mask + JR IO_ASS5 ; ..and finish +IO_ASS2: CP 'A' ; assign (A)uxiliary ? + JR NZ,IO_ASS3 ; ..if not, jump + CALL CIOASSG ; configure AUX IO Dev Assignment + JP C,M2CIO ; ..if error, display menu again + RLC B ; device number in B + RLC B ; ..shift bits to position 3-2 + LD A,B ; copy to bits 5-4 by multiplication + ADD A,A ; *2 + ADD A,A ; *4 + ADD A,B ; *5 + LD B,A ; B= AUX Out (bits 5-4) and In (bits 3-2) + LD C,11000011B ; set bit mask + JR IO_ASS5 ; ..and finish +IO_ASS3: CP 'P' ; assign (P)rinter ? + JR Z,IO_ASS4 ; ..if so, jump + CP ' ' ; else, entered ? + JP Z,M2CIO ; ..then display menu again + CP ESC ; or ? + JP Z,M2CIO ; ..then also display menu again + CALL CFEVAL ; eval script file input + CALL VPRINT ; notify user, and loop + DEFB BEL,BS + DEFB 0 + JR IO_ASS1 +IO_ASS4: CALL CIOASSG ; configure PRT IO Dev Assignment + JP C,M2CIO ; ..if error, display menu again + RRC B ; device in B + RRC B ; shift bits from pos 1-0 to 7-6 + LD C,00111111B ; set bit mask + ; ..and fall through + + ; set new IO Dev Assignment +IO_ASS5: LD A,7EH ; offset to IOBYT in Config area + CALL WSPCPTR ; set ptr + LD A,(HL) ; get IOBYT + AND C ; apply bit mask + OR B ; combine with new assignment + LD (HL),A ; ..and store back + JP M2CIO ; loop display menu + + ; --- Swap Device Assignment +IO_SWP: PUSH AF + LD A,(DEVLAST) ; get last device # (ascii) + INC A ; increase + LD C,A ; this menu option is created dynamically + POP AF + CP C ; so check if selection matches + JP NZ,IO_CFG ; ..if not, jump + CALL VPRINT + DEFB CR,LF,TAB,'Swap [2..' + DEFB 0 + LD A,(DEVLAST) ; get last device # (ascii) + CALL COUT ; ..display + CALL VPRINT + DEFB '] : ' + DEFB 0 +IO_SWP1: CALL GETINP ; get input + JP Z,M2CIO ; ..if empty, jump display menu again + CP '2' ; entered value below '2' ? + JR C,IO_SWP2 ; ..if so, jump and loop + LD HL,DEVLAST + DEC A + CP (HL) ; else, also check above max. + JR C,IO_SWP3 ; ..if not, jump to continue + ; else, fall through and loop +IO_SWP2: CALL VPRINT ; notify user (), and remove char () + DEFB BS,BEL + DEFB 0 + CALL CFEVAL ; eval script file input + JR IO_SWP1 ; loop (ask for new input) +IO_SWP3: SUB '1' ; convert ascii to number (already reduced by 1 before) + LD (DEV1SWP),A ; ..store it + CALL VPRINT + DEFB ' with [2..' + DEFB 0 + LD A,(DEVLAST) ; get ascii number of last device + CALL COUT ; ..and display it + CALL VPRINT + DEFB '] : ' + DEFB 0 +IO_SWP4: CALL GETINP ; get input + JP Z,M2CIO ; ..if empty, jump display menu again + CP '2' ; check if input is below '2' + JR C,IO_SWP5 ; ..if so, jump and loop + LD HL,DEVLAST + DEC A + CP (HL) ; else, check if input is above max. + JR C,IO_SWP6 ; ..if not, jump + ; else, fall through and loop +IO_SWP5: CALL VPRINT ; remove char () and notify user () + DEFB BS,BEL + DEFB 0 + CALL CFEVAL ; eval script file input + JR IO_SWP4 ; loop (ask for new input) +IO_SWP6: SUB '1' ; convert ascii to number (already reduced by 1, so only -'1') + LD (DEVASSG),A ; ..and store + CALL IO_PTR ; get ptr to entry in DEVCFG + PUSH HL ; save + LD A,(DEV1SWP) ; get device to swap + LD (DEVASSG),A ; ..and store + CALL IO_PTR ; get ptr to entry in DEVCFG + POP DE ; restore 1st ptr + LD B,16 ; length of an entry in DEVCFG + ; (swap is only displayed for version above 2.0 + ; no additional check/adjustment of length needed) + + ; perform device swapping (copy bytes from one entry to the other) +IO_SWP7: LD C,(HL) ; get byte from entry #1 + LD A,(DE) ; get byte from entry #2 + EX DE,HL ; swap regs (ie. ptr's) + LD (DE),A ; save bytes to other entry + LD (HL),C + EX DE,HL ; ..swap pointers back + INC HL ; move fwd + INC DE + DJNZ IO_SWP7 ; loop till done + JP M2CIO ; finally, jump to display menu again + + + ; --- Configure Char IO Device + ; menu option entries are created dynamically according to existing devices + ; A= selected option ('1' is fixed, so devices start with '2') +IO_CFG: SUB '2' ; convert selected option to device # (num) + LD (DEVASSG),A ; ..store + CALL IO_PTR ; display, and get ptr in DEVCFG + PUSH HL ; move ptr to IX + POP IX + LD A,(HL) ; check if entry is valid (<> zero) + OR A + JR NZ,IO_CFG1 ; ..if so, jump to continue + CALL VPRINT ; else, display msg and loop + DEFB BEL,CR,LF,'-- Nothing There !! --' + DEFB 0 + CALL CFEVAL ; eval script file input + JP M2CIO ; loop, display Char IO menu again + + + ; IX= ptr to first byte of entry in DEVCFG table + ; +4 baud rate, +5 data transmission, +6 input data mask, +7 output data mask +IO_CFG1: CALL VPRINT + DEFB CR,LF,TAB,'Configuring ' + DEFB 0 + CALL P4CHRS ; display name of device + LD A,' ' ; and + CALL COUT + CALL PIOIO ; display In/Out configuration of device + LD A,':' ; and colon + CALL COUT + + ; configure baud rate + LD A,(IX+4) ; get baud rate + AND 11110000B ; check high nybble (capabilities) + JP Z,IO_FLW ; ..if none, jump + CALL VPRINT ; else, continue displaying + DEFB CR,LF,TAB,' Baud Rate ' + DEFB 0 + LD A,(IX+4) ; get baud rate + CPL ; complement + AND 11110000B ; check high nybble (capabilities) + JR Z,IO_BDR ; ..if zero, skip option 'Max' + CALL VPRINT + DEFB ' (Max=' + DEFB 0 + LD A,(IX+4) ; get baud rate + RRCA ; move high nybble to lower + RRCA + RRCA + RRCA + AND 00001111B ; mask off high nybble + LD (BAUDRT),A ; ..store value + CALL PIOBDRT ; and display it + CALL VPRINT + DEFB ') = ' + DEFB 0 +IO_BDR: CALL VPRINT + DEFB ' Selections are:' + DEFB 0 + LD A,1 ; set initial value + PUSH AF +IO_BDR1: DEC A ; insert + AND 3 ; after output of 4 values + JR NZ,IO_BDR2 + CALL VPRINT + DEFB CR,LF,TAB + DEFB 0 +IO_BDR2: LD A,TAB ; print + CALL COUT + POP AF ; restore counter + PUSH AF + CALL PAFDC ; display value + LD A,'-' + CALL COUT + POP AF ; restore counter again + PUSH AF + CALL PIOBDRT ; ..and display corresponding baud rate + POP AF + PUSH AF + LD HL,BAUDRT ; get value for max. baud rate + CP (HL) ; check if reached + JR NC,IO_BDR3 ; ..if so, exit loop + POP AF ; else, restore counter + INC A ; +1 + PUSH AF ; ..save again + JR IO_BDR1 ; loop +IO_BDR3: CALL CRLF +IO_BDR4: CALL VPRINT + DEFB CR,TAB,' Select',TAB,'[' + DEFB 0 + CALL EREOL ; clear CON: to end of line + LD A,(IX+4) ; get current baud rate + AND 00001111B ; mask off high nybble + LD L,A ; value in HL + LD H,0 + CALL PHLDCNV ; display and ask for input + JR C,IO_BDR5 ; ..if input is not valid, jump + LD A,D ; evaluated number in DE + OR A ; high-byte must be zero + JR NZ,IO_BDR5 ; ..if not, jump + LD A,E ; check if low-byte is zero + OR A + JR Z,IO_BDR5 ; ..if so, jump + DEC A ; make zero-based + LD HL,BAUDRT ; get value for max. baud rate + CP (HL) ; check if new value exceeds limit + JR C,IO_BDR6 ; ..if not, continue +IO_BDR5: CALL CFEVAL ; eval script file input + JR IO_BDR4 ; loop (ask for new input) +IO_BDR6: LD A,(IX+4) ; get current baud rate settings + AND 11110000B ; mask off low nybble + OR E ; combine with new value + LD (IX+4),A ; ..and store + + ; configure data bits + CALL VPRINT + DEFB CR,LF,TAB,' Data = ' + DEFB 0 + LD A,(IX+5) ; get Config Byte data transmission + CPL ; complement + BIT 3,A ; ..and test bit 3 (data bits) + CALL M$87BIT ; display # of bits and ask for change + JR NZ,IO_STP ; ..if no change, jump + LD A,00001000B ; else, mask bit 4 + XOR (IX+5) ; invert current state + LD (IX+5),A ; ..and save back + + ; configure stop bits +IO_STP: CALL VPRINT + DEFB CR,LF,TAB,' Stop Bits = ' + DEFB 0 + BIT 0,(IX+5) ; test bit 0 for stop bits (0= 2, 1= 1) + LD A,'1' ; prepare for '1' + JR NZ,IO_STP1 ; ..if not set, skip over + INC A ; else, increase to '2' +IO_STP1: CALL COUT ; display current setting + CALL M$BITS ; display string and ask for change + JR NZ,IO_PTY ; ..if no change, jump + LD A,00000001B ; else, mask bit 0 + XOR (IX+5) ; invert current state + LD (IX+5),A ; ..and save back + + ; configure parity +IO_PTY: CALL VPRINT + DEFB CR,LF,TAB,' Parity = ' + DEFB 0 + LD HL,PRTY$4 ; prepare ptr to string "None" + BIT 1,(IX+5) ; test bit 1 for Parity (0= no, 1= enabled) + JR Z,IO_PTY1 ; ..if not enabled, jump + LD HL,PRTY$2 ; else point to string "Odd" + BIT 2,(IX+5) ; test bit 2 for Parity (0= odd, 1= even) + JR Z,IO_PTY1 ; ..if odd, skip over + LD HL,PRTY$1 ; else, point to string "Even" +IO_PTY1: CALL VPSTR ; display string (ptr in HL) + CALL M$CHNG ; ask for change + JR NZ,IO_FLW ; ..if no change, jump + CALL VPRINT + DEFB CR,LF,TAB,TAB,'Enable Parity' + DEFB 0 + CALL ASKYN ; ask Yes (Z) / No (NZ) + RES 1,(IX+5) ; reset bit + JR NZ,IO_FLW ; ..if 'N' was entered, jump + SET 1,(IX+5) ; else, set bit and continue + CALL VPRINT + DEFB CR,LF,TAB,TAB,'Odd or Even? (O/[E]) : ' + DEFB 0 + CALL GETINP ; get input + SET 2,(IX+5) ; set bit (even) + CP 'O' ; check if 'O' was entered + JR NZ,IO_FLW ; ..if not, skip over + RES 2,(IX+5) ; else, reset bit (odd) and fall through + + ; configure flow control +IO_FLW: CALL VPRINT ; display output + DEFB CR,LF,TAB,' XON/XOFF Flow = ' + DEFB 0 + BIT 4,(IX+5) ; test bit 4 XON/XOFF (0= no, 1= yes) in Config. Byte + CALL PNOYES ; display No/Yes accordingly + CALL M$CHNG ; ..and ask if it shall be changed + JR NZ,IO_FLW1 ; ..if not 'Y', skip + LD A,00010000B ; else, take bit 4 + XOR (IX+5) ; ..invert it + LD (IX+5),A ; ..and write back +IO_FLW1: CALL VPRINT + DEFB CR,LF,TAB,' RTS/CTS Flow = ' + DEFB 0 + BIT 5,(IX+5) ; test bit 5 CTS/RTS control (0= no, 1= enabled) + CALL PNOYES ; display No/Yes accordingly + CALL M$CHNG ; ..and ask if it shall be changed + JR NZ,IO_MSK ; ..if not 'Y', skip + LD A,00100000B ; else, take bit 5 + XOR (IX+5) ; ..invert it + LD (IX+5),A ; ..and write back + + ; configure in/out and data masks +IO_MSK: LD A,(IX+5) ; get Config. Byte + AND 11000000B ; mask high bits + JR Z,IO_NONE ; ..if zero, exit (no input, no output) + BIT 6,(IX+5) ; test bit 6 Input (0= no, 1= dev can be read) Config. Byte + JR Z,IO_MSK1 ; ..if no Input, jump to output settings + CALL VPRINT ; else, display + DEFB CR,LF,TAB,' Input is ' + DEFB 0 + BIT 7,(IX+6) ; test bit 7 of data mask + CALL M$87BIT ; display # of bits and ask for change + JR NZ,IO_MSK1 ; ..if not 'Y', skip + LD A,10000000B ; else, take bit 7 + XOR (IX+6) ; ..invert it + LD (IX+6),A ; ..and write back +IO_MSK1: BIT 7,(IX+5) ; test bit 7 Output (0= no, 1= can write dev) Config. Byte + JR Z,IO_EXIT ; ..if no Output, jump exit + CALL VPRINT ; else, display + DEFB CR,LF,TAB,' Output is ' + DEFB 0 + BIT 7,(IX+7) ; test bit 7 of data mask + CALL M$87BIT ; display # of bits and ask for change + JR NZ,IO_EXIT ; ..if not 'Y', exit + LD A,10000000B ; else, take bit 7 + XOR (IX+7) ; ..invert it + LD (IX+7),A ; ..and write back + JR IO_EXIT ; then exit to display menu again + + ; nothing configurable +IO_NONE: CALL VPRINT + DEFB CR,LF,TAB,' -- Nothing Configurable...' + DEFB '[any key to continue] --' + DEFB 0 + CALL CFIN +IO_EXIT: JP M2CIO ; display menu again + + +;::::: SUPPORT FUNCTIONS - Char IO Device Config. + + ; get ptr to entry in DEVCFG + ; (length of an entry is 16 bytes, or 8 bytes prior to B/P Bios v1.1) + ; in: variable DEVASSG, bits 1-0 + ; out: HL= ptr to entry +IO_PTR: LD A,(BPVERS) ; check B/P Bios version + LD C,8 ; length of an entry + CP 11H ; is version prior to 1.1 ? + JR C,IO_PTR1 ; ..if so, jump + LD C,16 ; else, set length of entry to 16 byte +IO_PTR1: LD A,(DEVASSG) ; assignment bits 1-0 (from IOBYT) + LD B,A ; copy to B as counter + OR A ; is it zero ? + JR Z,IO_PTR3 ; ..if so, no more calculation + XOR A ; else, clear A +IO_PTR2: ADD A,C ; add length of an entry + DJNZ IO_PTR2 ; ..and loop +IO_PTR3: LD E,A ; offset into E + LD A,0DBH ; DEVCFG offset (after Config area) + CALL WSPCPTR ; calc ptr to DEVCFG + LD D,0 + ADD HL,DE ; add offset (ptr to first byte of entry) + RET + + + ; prints "No" or "Yes" to CON: + ; in: Z-Flag set= No, NZ= Yes +PNOYES: LD HL,PRTY$3 ; ptr to string "No" + JR Z,PNOYES0 ; ..if Z-Flag set, skip over + LD HL,PRTY$5 ; else, ptr to string "Yes" +PNOYES0: JP VPSTR ; display string, and let return from there + + + ; print name of assigned device + ; mask off upper bits, get ptr to assigned device in DEVCFG table + ; in: A= device (bits shifted from IOBYT to position 1-0) + ; out: HL= ptr to baud rate + ; dev assignment stored in DEVASSG +PIOASSG: AND 00000011B ; mask off upper bits 7-2 + LD (DEVASSG),A ; store encoded device assignment + PUSH DE + CALL IO_PTR ; HL= ptr to entry in DEVCFG + POP DE + LD B,4 ; name consists of 4 chars +PIOASS1: LD A,(HL) ; get char + CALL COUT ; ..display + INC HL ; move ptr fwd + DJNZ PIOASS1 ; loop till done + RET + + + ; configure IO Device assignment, display current setting and ask for input + ; out: A= new device number, B= A (copy) + ; C-Flag set if error (no input), NC ok +CIOASSG: CALL VPRINT + DEFB CR,LF,TAB,' Set ' + DEFB 0 + XOR A ; clear A + LD (DEVASSG),A ; ..and stored assignment +CIOASS1: CALL PIOASSG ; display device name (starting with COM1) + LD A,'[' + CALL COUT + LD A,(DEVASSG) ; get device number + INC A ; ..increase it + LD (DEVASSG),A + ADD A,'0' ; convert to ascii for display + CP '4' ; maximum reached ? + PUSH AF ; save regs + CALL COUT + LD A,']' + CALL COUT + POP AF + PUSH AF + LD A,',' + CALL C,COUT + LD A,' ' + CALL COUT + POP AF ; restore flags + JR C,CIOASS1 ; ..loop till done + CALL VPRINT + DEFB '? ' + DEFB 0 +CIOASS2: CALL GETINP ; get input + SCF ; set C-Flag (error) + RET Z ; ..if input is empty, return + SUB '1' ; else, convert ascii to number + LD B,A + JR C,CIOASS3 ; ..if input below '1', jump/loop + CP 4 ; check for max. device number + CCF ; invers C-Flag + RET NC ; if input '1' to '4', return with C-Flag cleared + ; ..else, fall through and loop + +CIOASS3: CALL VPRINT ; notify user (), remove char (), and ask for new input + DEFB BS,BEL + DEFB 0 + JR CIOASS2 + + + ; display parameters of Char IO Device on CON: + ; in: HL= ptr to first byte of entry in DEVCFG +PIOPARM: PUSH HL ; move ptr to IX + POP IX + LD A,(HL) + OR A ; check entry + JR NZ,PIOPAR1 ; ..if not empty, jump to continue + CALL VPRINT ; else, display msg and return + DEFB '-- Unavailable --' + DEFB 0 + RET + + ; device is valid, display name and baud rate +PIOPAR1: CALL P4CHRS ; display name of device + CALL VPRINT + DEFB ' - ' + DEFB 0 + EX DE,HL ; swap regs, DE= ptr first byte after name + LD A,(DE) ; get baud rate + INC DE ; move ptr fwd + CP 00010000B ; is a max. baud rate set ? (upper nybble) + JR C,PIOIO ; ..if so, jump + DEC DE ; else, move ptr back + CALL PIOBDRT + CALL VPRINT + DEFB ', ' + DEFB 0 + EX DE,HL ; swap regs + INC HL ; move ptr to config. byte for data transmission + LD A,'8' ; prepare to display '8' + BIT 3,(HL) ; check # of data bits (0= 8 bit data, 1= 7 bit data) + JR Z,PIOPAR2 ; ..if 8 bits, skip + DEC A ; else, adjust A + + ; display number of data bits +PIOPAR2: EX DE,HL ; swap regs + CALL COUT ; print char in A + CALL VPRINT + DEFB ' Data, ' + DEFB 0 + LD A,(DE) ; get config. byte for data transmission + BIT 0,A ; check # of stop bits (0= 2, 1= 1) + LD A,'1' ; prpare to display '1' + JR NZ,PIOPAR3 ; ..if 1 stop bit, skip + LD A,'2' ; else, adjust A + + ; display number of stop bits +PIOPAR3: CALL COUT ; print char in A + CALL VPRINT + DEFB ' Stop, ' + DEFB 0 + LD A,(DE) ; get config. byte for data transmission + LD HL,PRTY$3 ; ptr to string "No" + BIT 1,A ; check parity (0= no parity, 1= enabled) + JR Z,PIOPAR4 ; ..if no parity, jump to output + LD HL,PRTY$1 ; else, set ptr to string "Even" + BIT 2,A ; check parity setting (0= odd, 1= even) + JR NZ,PIOPAR4 ; ..if even, jump to output + LD HL,PRTY$2 ; else, set ptr to "Odd" + + ; display parity +PIOPAR4: CALL VPSTR ; display string, HL is ptr + CALL VPRINT + DEFB ' Parity, ' + DEFB 0 + + ; display Char IO Device In/Out settings on CON: + ; in: IX= ptr to first byte of an entry in DEVCFG +PIOIO: LD A,'[' ; print left bracket + CALL COUT + BIT 6,(IX+5) ; check Input setting (0= no input, 1= dev can be read) + ; IX+5 points to config. byte for data transmission + JR Z,PIOIO2 ; ..if no Input, jump + CALL VPRINT ; else, display + DEFB 'In' + DEFB 0 + LD A,'(' ; print left parenthesis + CALL COUT + BIT 7,(IX+6) ; check Input data mask (IX+6 points to mask byte) + LD A,'7' ; prepare to display '7' + JR Z,PIOIO1 ; ..if high bit not set, skip + INC A ; else, adjust A +PIOIO1: CALL COUT ; ..and display char in A + LD A,')' ; and display closing parenthesis + CALL COUT + LD A,(IX+5) ; get config. byte for data transmission + AND 11000000B ; mask high bits (7 Input, 8 Output) + CP 11000000B + JR NZ,PIOIO2 ; ..if not both bits are set, skip + LD A,'/' ; else, display '/' as separator + CALL COUT + +PIOIO2: BIT 7,(IX+5) ; check Output setting (0= no output, 1= can write dev) + ; IX+5 points to config. byte for data transmission + JR Z,PIOIO4 ; ..if no Output, jump + CALL VPRINT ; else, display + DEFB 'Out' + DEFB 0 + LD A,'(' ; print left parenthesis + CALL COUT + BIT 7,(IX+7) ; check Output data mask (IX+7 points to mask byte) + LD A,'7' ; prepare to display '7' + JR Z,PIOIO3 ; ..if high bit not set, skip + INC A ; else, adjust A +PIOIO3: CALL COUT ; display char in A + LD A,')' ; ..and closing parenthesis + CALL COUT +PIOIO4: LD A,']' ; print right bracket + JP COUT ; ..and let return from there + + ; parity options + ; nul-terminated strings +PRTY$1: DEFB 'Even',0 +PRTY$2: DEFB 'Odd',0 +PRTY$3: DEFB 'No',0 +PRTY$4: DEFB 'None',0 +PRTY$5: DEFB 'Yes',0 + + + ; print four chars (ptr in HL), used to display name of Char IO Device + ; in: HL= ptr to first byte of entry in DEVCFG (name) + ; IX= HL (not used in this routine) +P4CHRS: LD B,4 ; number of chars +P4CHR1: LD A,(HL) ; get char + INC HL ; move ptr fwd + CALL COUT ; send char in A to CON: + DJNZ P4CHR1 ; ..loop till done + RET + + + ; displays the baud rate on CON: + ; in: A= data rate setting + ; IX= ptr to first byte of an entry in DEVCFG +PIOBDRT: AND 00001111B ; mask lower nybble + LD HL,BDRT$1 ; ptr to 1st string + CP 00001110B ; check special cases + JR NC,PIOBDR1 + LD HL,BDRT$2 ; ptr to 2nd string + CP 00000001B + JR Z,PIOBDR1 + LD HL,BDRT$3 ; followings strings are 5 bytes long + SUB 2 ; calc offset, account for 2 special cases + LD B,A + ADD A,A ; *2 + ADD A,A ; *4 + ADD A,B ; *5 + CALL ADDHLA ; add offset + LD A,B + CP 9 ; check for entry number + JR C,PIOBDR1 ; ..and display "kpbs" or "bps" + CALL VPSTR ; print string, ptr in HL + CALL VPRINT + DEFB ' kbps' + DEFB 0 + JR PIOBDR2 +PIOBDR1: CALL VPSTR ; print string, ptr in HL + CALL VPRINT + DEFB ' bps' + DEFB 0 +PIOBDR2: LD A,(IX+4) ; get 'Data Rate Capabilities' byte in DEVCFG entry + AND 11110000B ; mask upper nybble + CP 11110000B ; all upper bits set ? + RET NZ ; ..if not, return + CALL VPRINT ; else, append string and then return + DEFB ' (fixed)' + DEFB 0 + RET + + ; baud rate options + ; nul-terminated strings, from BDRT$3 onwards = table w/ 5-byte entries + ; data rate is represented by upper/lower nybble +BDRT$1: DEFB '115.2',0 ; 1110 = 115200 +BDRT$2: DEFB '134.5',0 ; 0001 = 134.5 +BDRT$3: DEFB '50',0,0,0 ; 0010 = 50 + DEFB '75',0,0,0 ; 0011 = 75 + DEFB '150',0,0 ; 0100 = 150 + DEFB '300',0,0 ; 0101 = 300 + DEFB '600',0,0 ; 0110 = 600 + DEFB '1200',0 ; 0111 = 1200 + DEFB '2400',0 ; 1000 = 2400 + DEFB '4800',0 ; 1001 = 4800 + DEFB '9600',0 ; 1010 = 9600 + DEFB '19.2',0 ; 1011 = 19200 + DEFB '38.4',0 ; 1100 = 38400 + DEFB '76.8',0 ; 1101 = 76800 + DEFB '(fixed)',0 ; 1111 = Fixed + + + ; display '8' or '7' then fall through fo following msg's and get input + ; in: Z-Flag set= '7', NZ= '8' + ; out: Z-Flag set for 'Y' entered, else NZ +M$87BIT: LD A,'8' ; prepare to display '8' + JR NZ,M$87BI1 ; ..if Z-Flag cleared, display + DEC A ; else, adjust A +M$87BI1: CALL COUT ; print char in A + ; ..and fall through + + ; msg '-bits.' +M$BITS: CALL VPRINT ; display and fall through + DEFB '-bits.' + DEFB 0 + + ; msg 'Change' +M$CHNG: CALL VPRINT ; display and fall through + DEFB TAB,'Change' + DEFB 0 + + + ; ask for user input Y/[N] + ; out: Z-Flag set if 'Y' was entered, else NZ +ASKYN: CALL VPRINT ; display + DEFB '? (Y/[N]) : ' + DEFB 0 + CALL GETINP ; get input + CP 'Y' ; check if 'Y' was entered + RET ; ..and return, Z-Flag is set accordingly + + ; * + + +;::::: MENU 3 - FLOPPY DISK (display) + +M3FD: LD A,1 + LD (CFMENU),A ; store flag (sub-)menu entered + CALL CLS + CALL VPRINT + DEFB CR,LF,'Menu 3 - Floppy Disk Options' + DEFB CR,LF,LF,LF,' ',1,' 1 ',2,' Floppy Drive Characteristics:' + DEFB CR,LF,TAB,'Drv0 = ' + DEFB 0 + LD A,0A1H ; offset to FDCSPEC (floppy drv #1) in Config area + CALL PFDPARM ; display characteristics floppy #1 + CALL VPRINT + DEFB TAB,'Drv1 = ' + DEFB 0 + LD A,0A6H ; offset to FDCSPEC+5 (floppy drv #2) in Config area + CALL PFDPARM ; display characteristics floppy #2 + CALL VPRINT + DEFB TAB,'Drv2 = ' + DEFB 0 + LD A,0ABH ; offset to FDCSPEC+10 (floppy drv #3) in Config area + CALL PFDPARM ; display characteristics floppy #3 + CALL VPRINT + DEFB TAB,'Drv3 = ' + DEFB 0 + LD A,0B0H ; offset to FDCSPEC+15 (floppy drv #4) in Config area + CALL PFDPARM ; display characteristics floppy #4 + CALL VPRINT + DEFB CR,LF,' ',1,' 2 ',2,' Motor ON Time (Tenths-of-Seconds) : ' + DEFB 0 + LD A,0B5H ; offset to MONTIM in Config area + CALL WSPCPTR ; set ptr + LD A,(HL) ; get Motor On Time (in tenths-of-seconds) + CALL PAFDC ; ..and display it + CALL VPRINT + DEFB CR,LF,LF,' ',1,' 3 ',2,' Motor Spinup (Tenths-of-Seconds) : ' + DEFB 0 + LD A,0B6H ; offset to SPINUP in Config area + CALL WSPCPTR ; set ptr + LD A,(HL) ; get Spinup Delay (in tenths-of-seconds) + CALL PAFDC ; ..and display it + CALL VPRINT + DEFB CR,LF,LF,' ',1,' 4 ',2,' Times to Try Disk Operations : ' + DEFB 0 + LD A,0B7H ; offset to MXRTRY in config area + CALL WSPCPTR ; set ptr + LD A,(HL) ; get Max. # of Retries on Floppy Disks + CALL PAFDC ; ..and display + LD A,'4' ; max. possible option in this menu as ascii number + CALL MSELECT + OR A ; valid input ? + JP Z,M0MAIN ; ..if not, jump to display main menu + + +;::::: MENU 3 - FLOPPY DISK (configure) + + ; subsequent labels start with "FD_" +M3CFG: CALL CRLF + CP '1' ; option 1 (Phys. Unit) selected ? + JR NZ,FD_MOTR ; ..if not, jump to next + + ; configure Floppy Disk drive physical unit +FD_UNIT: CALL VPRINT + DEFB CR,TAB,' Configure which unit [0..3] : ' + DEFB 0 + CALL EREOL + CALL GETINP ; get input + CP ' ' ; is it ? + JR Z,FD_UN3 ; ..if so, jump done and display menu again + CP CR ; ? + JR Z,FD_UN3 ; ..if so, jump done and display menu again + SUB '0' ; else, convert ascii to number + JR C,FD_UN1 ; ..if less than '0', jump + CP 4 ; else, check upper limit + JR C,FD_UN2 ; ..if within range, skip over and continue +FD_UN1: CALL M$BEL ; else, notify user + JR FD_UNIT ; ..and ask for new input +FD_UN2: LD L,A ; copy unit # in HL + LD H,0 + ADD HL,HL ; *2 + ADD HL,HL ; *4 + CALL ADDHLA ; *5 (FDCSPEC entry = 5 bytes long) + EX DE,HL ; swap regs + LD A,0A1H ; offset to FDCSPEC in Config area + CALL WSPCPTR ; set ptr + ADD HL,DE ; add calculated offset + PUSH HL ; move ptr in IX + POP IX + CALL CFDUNIT ; ..and go configure the drive +FD_UN3: JP M3FD ; loop, display menu again + + ; configure Floppy Disk motor on time +FD_MOTR: CP '2' ; option 2 (Motor On) selected ? + JR NZ,FD_SPIN ; ..if not, jump to next +FD_MOT1: CALL VPRINT + DEFB CR,TAB,TAB,'Motor On Time in 1/10 Secs',TAB,'[' + DEFB 0 + CALL EREOL + LD A,0B5H ; offset to MONTIM in Config area + CALL PVALASK ; display current value, ask for input + JR C,FD_MOT2 ; ..if error, jump + LD A,D ; else, check if input is valid + OR A ; high-byte must be zero + JR NZ,FD_MOT2 ; ..if not, do not save value + OR E ; is the entered value zero ? + JR NZ,FD_MOT3 ; ..if not, jump save value +FD_MOT2: CALL M$BEL ; else, notify user + JR FD_MOT1 ; ..and ask for new input +FD_MOT3: LD (HL),E ; save new value + JP M3FD ; ..and display Floppy menu again + + ; configure Floppy Disk motor spinup time +FD_SPIN: CP '3' ; option 3 (Motor Spinup) selected ? + JR NZ,FD_RTRY ; ..if not, jump to next +FD_SP1: CALL VPRINT + DEFB CR,TAB,TAB,'Motor Spinup in 1/10 Secs',TAB,'[' + DEFB 0 + CALL EREOL ; clear CON: to end of line + LD A,0B6H ; offset to SPINUP in Config area + CALL PVALASK ; display current value, ask for input + JR C,FD_SP2 ; ..if error, jump + LD A,D ; else, check if input is valid + OR A ; high-byte must be zero + JR NZ,FD_SP2 ; ..if not, do not save value + OR E ; is the entered value zero ? + JR NZ,FD_SP3 ; ..if not, jump save value +FD_SP2: CALL M$BEL ; else, notify user + JR FD_SP1 ; ..and ask for new input +FD_SP3: LD (HL),E ; save new value + JP M3FD ; ..and display Floppy menu again + + ; configure Floppy Disk number of retries +FD_RTRY: CALL EREOL +FD_RTR1: CALL VPRINT + DEFB CR,TAB,TAB,'Times to try Disk Opns',TAB,'[' + DEFB 0 + CALL EREOL + LD A,0B7H ; pointer to MXRTRY in Config area + CALL PVALASK ; display current value, ask for input + JR C,FD_RTR2 ; ..if error, jump + LD A,D ; else, check if input is valid + OR A ; high-byte must be zero + JR NZ,FD_RTR2 ; ..if not, do not save + OR E ; is the entered value zero ? + JR NZ,FD_RTR3 ; ..if not, jump save value +FD_RTR2: CALL M$BEL ; else, notify user + JR FD_RTR1 ; ..and ask for new input +FD_RTR3: LD A,E + CP 11 ; new value greater than 10 ? + JR C,FD_RTR4 ; ..if not, jump save + CALL VPRINT ; else, ask for confirmation + DEFB CR,LF,TAB,TAB,TAB,'Do you REALLY mean ' + DEFB 0 + LD A,E ; get new value again + CALL PAFDC ; ..and display it + CALL VPRINT + DEFB ' tries? (Y/[N]) : ' + DEFB 0 + CALL CAPINE + CP 'Y' ; confirmed by user ? + JR Z,FD_RTR4 ; ..if so, save and exit + CALL M$BEL ; else, notify user + JR FD_RTRY ; ..and ask for new input +FD_RTR4: LD (HL),E ; save new value + JP M3FD ; display Floppy menu again + + +;::::: SUPPORT FUNCTIONS - Floppy Disk + + ; configure Floppy Disk Physical Unit + ; in: IX= ptr to entry in FDCSPEC +CFDUNIT: CALL CRLF + + ; floppy disk size +CFDSZ: CALL VPRINT + DEFB CR,TAB,TAB,'Size 8"(1), 5.25"(2), 3.5"(3)?',TAB,'[' + DEFB 0 + CALL EREOL + LD A,(IX+0) ; get FDCSPEC + AND 00000111B ; mask lower 3 bits (floppy size) + LD L,A ; ..and move to HL + LD H,0 + CALL PHLDCNV ; display value and ask for input + JR C,CFDSZ1 ; ..if input is not valid, jump + LD A,D ; evaluated input in DE + OR A ; high-byte must be zero + JR NZ,CFDSZ1 ; ..if not, jump + LD A,E ; else, check if low-byte is zero + OR A + JR Z,CFDSZ1 ; ..if so, jump + CP 4 ; check if value is within limit + JR C,CFDSZ2 ; ..if so, skip over and continue +CFDSZ1: CALL M$BEL ; else, notify user + JR CFDSZ ; ..and loop, ask for new input +CFDSZ2: LD B,A ; copy input + LD A,(IX+0) ; get FDCSPEC + AND 11111000B ; mask off lower bits + OR B ; combine with new value + LD (IX+0),A ; ..save it back + + ; single-/double-sided +CFDSSD: CALL VPRINT + DEFB CR,TAB,TAB,'Single or Double-Sided Drive ?',TAB,TAB,'(' + DEFB 0 + LD D,'S' ; prepare available options for output + LD E,'D' ; (S)ingle / (D)ouble + BIT 3,(IX+0) ; check bit 3 (0= single-sided, 1= double-sided) + CALL PDEOPTN ; show options + CALL VPRINT + DEFB ')',TAB,': ' + DEFB 0 + CALL EREOL ; clear CON: to end of line + CALL GETINP ; get input + CALL CHRSPCR ; is or ? + JR Z,CFDMCTR ; ..if so, jump + CP 'S' ; else, is it 'S' ? + JR Z,CFDSSD1 ; ..if so, jump to continue + CP 'D' ; or, 'D' entered ? + JR Z,CFDSSD1 ; ..if so, jump to continue + CALL M$BEL ; else, notify user + JR CFDSSD ; ..loop +CFDSSD1: CP 'D' ; check input again + SET 3,(IX+0) ; set bit 3 (= double-sided) + JR Z,CFDMCTR ; ..if 'D' entered, skip over + RES 3,(IX+0) ; else, reset bit 3 (= single-sided) + + ; motor control +CFDMCTR: CALL VPRINT + DEFB CR,LF,TAB,TAB,'Motor On/Off Control Needed ?',TAB,TAB,'(' + DEFB 0 + LD D,'Y' ; prepare available options for output + LD E,'N' ; (Y)es / (N)o + LD A,(IX+0) ; get FDCSPEC + CPL ; invers value (two's complement) + BIT 5,A ; check bit 5 (motor), now reversed meaning + CALL PDEOPTN ; display options + CALL VPRINT + DEFB ')',TAB,': ' + DEFB 0 + CALL GETINP ; get input + CALL CHRSPCR ; is it or ? + JR Z,CFDMCT1 ; ..if so, jump + CP 'N' ; else, is it 'N' ? + SET 5,(IX+0) ; set bit 5 (= motor drive control) + JR NZ,CFDMCT1 ; ..if not 'N' entered, skip over + RES 5,(IX+0) ; else, reset bit 5 (= motor always on) +CFDMCT1: LD A,(IX+0) ; get FDCSPEC + AND 00000111B ; mask lower 3 bits + DEC A ; -1 + JR Z,CFDMCT4 ; ..if 8", jump (cannot be hi-density) + CALL CRLF +CFDMCT2: CALL VPRINT + DEFB CR,TAB,TAB,'Motor Speed Standard or Hi-Density',TAB,'(' + DEFB 0 + LD D,'S' ; prepare available options for output + LD E,'H' ; (H)igh / (S)tandard Density + BIT 6,(IX+0) ; check bit 6 (max. speed, 0= 300 RPM, 1= 360 RPM) + CALL PDEOPTN ; display options + CALL VPRINT + DEFB ')',TAB,': ' + DEFB 0 + CALL EREOL ; clear CON: to end of line + CALL GETINP ; get input + CALL CHRSPCR ; is it or ? + JR Z,CFDTRK ; ..if so, jump + CP 'S' ; else, is it 'S' ? + JR Z,CFDMCT3 ; ..if so, jump to continue + CP 'H' ; or, 'H' entered ? + JR Z,CFDMCT3 ; ..if so, jump to continue + CALL M$BEL ; else, notify user + JR CFDMCT2 ; ..loop, ask for new input +CFDMCT3: RES 6,(IX+0) ; reset bit 6 (= for 8" and HD max speed) + CP 'H' ; check input again, 'H' entered ? + JR NZ,CFDTRK ; ..if not, skip over +CFDMCT4: SET 6,(IX+0) ; else, set bit 6 (= max speed 5.25") + + ; tracks per side +CFDTRK: CALL CRLF +CFDTRK1: LD A,(IX+0) ; get FDCSPEC + AND 00000111B ; mask lower 3 bits + DEC A ; -1 + LD A,77 ; prepare for 77 tracks + JR Z,CFDTRK3 ; ..if 8", jump + CALL VPRINT + DEFB CR,TAB,TAB,'Tracks-per-Side (35,40,80)',TAB,TAB,'[' + DEFB 0 + CALL EREOL ; clear CON: to end of line + LD L,(IX+4) ; get FDCSPEC+4 (tracks per side) + LD H,0 + CALL PHLDCNV ; display value and ask for input + JR C,CFDTRK2 ; ..if input not valid, jump + LD A,D ; evaluated input in DE + OR A ; high-byte must be zero + JR NZ,CFDTRK2 ; ..if not, jump + LD A,E ; check input value (tracks) + CP 35 + JR Z,CFDTRK3 ; ..if 35, jump to continue + CP 40 + JR Z,CFDTRK3 ; ..or 40, jump to continue + CP 80 + JR Z,CFDTRK3 ; ..or 80, jump to continue +CFDTRK2: CALL M$BEL ; else, notify user + JR CFDTRK1 ; loop, ask for new input +CFDTRK3: LD (IX+4),A ; save new value at FDCSPEC+4 (tracks) + + ; step rate +CFDSTP: CALL VPRINT + DEFB CR,TAB,TAB,'Step Rate in Milli-Seconds',TAB,TAB,'[' + DEFB 0 + CALL EREOL ; clear CON: to end of line + LD L,(IX+1) ; get FDCSPEC+1 (step rate in mS) + LD H,0 + CALL PHLDCNV ; display value and ask for input + JR C,CFDSTP1 ; ..if input not valid, jump + LD A,D ; evaluated input in DE + OR A ; high-byte must be zero + JR NZ,CFDSTP1 ; ..if not, jump + OR E ; else, is low-byte zero ? + JR NZ,CFDSTP2 ; ..if not, skip over and continue +CFDSTP1: CALL M$BEL ; else, notify user + JR CFDSTP ; loop, ask for new input +CFDSTP2: LD (IX+1),A ; store new value (step rate) + + ; head load/unload time +CFDHLD: CALL VPRINT + DEFB CR,TAB,TAB,'Head Load Time in Milli-Seconds',TAB,TAB,'[' + DEFB 0 + CALL EREOL ; clear CON: to end of line + LD L,(IX+2) ; get FDCSPEC+2 (head load time in mS) + LD H,0 + CALL PHLDCNV ; display value and ask for input + JR C,CFDHLD1 ; ..if input not valid, jump + LD A,D ; evaluated input in DE + OR A ; high-byte must be zero + JR NZ,CFDHLD1 ; ..if not, jump + OR E ; else, is low-byte zero ? + JR NZ,CFDHLD2 ; ..if not, skip over to continue +CFDHLD1: CALL M$BEL ; else, notify user + JR CFDHLD ; loop, ask for new input +CFDHLD2: LD (IX+2),A ; store new value (head load time) +CFDHLD3: CALL VPRINT + DEFB CR,TAB,TAB,'Head Unload Time in Milli-Seconds',TAB,'[' + DEFB 0 + CALL EREOL ; clear CON: to end of line + LD L,(IX+3) ; get FDCSPEC+3 (head unload time in mS) + LD H,0 + CALL PHLDCNV ; display value and ask for input + JR C,CFDHLD4 ; ..if input not valid, jump + LD A,D ; evaluated input in DE + OR A ; high-byte must be zero + JR NZ,CFDHLD4 ; ..if not, jump + OR E ; else, is low-byte zero ? + JR NZ,CFDHLD5 ; ..if not, skip over to continue +CFDHLD4: CALL M$BEL ; else, notify user + JR CFDHLD3 ; loop, ask for new input +CFDHLD5: LD (IX+3),A ; store new value (head unload time) + RET + + ; output to CON: and continue validating script file input +M$BEL: LD A,BEL ; + CALL COUT ; output char in A to CON: + JP CFEVAL ; eval script file input + ; ..and let return from there + + + ; display Floppy Drive parameters on CON: + ; in: A= offset to first byte of FDCSPEC drive entry +PFDPARM: CALL WSPCPTR ; set ptr + LD A,(HL) ; get Drive Characteristics + PUSH HL ; save regs + LD HL,FDSZ$5 ; ptr to "Unknown" + AND 00000111B ; mask lower bits + CP 00000100B ; check for unknown Disk Size + ; 000= Fixed / 001= 8" / 010= 5.25" / 011= 3.5" + JR NC,PFDPAR1 ; ..if unknown, jump to continue + LD HL,FDS$TBL ; else, ptr to vectors of Floppy Sizes + ADD A,A ; calculate offset in vector table + CALL GWRDHLA ; ..and get addr +PFDPAR1: CALL VPSTR ; display string (HL= ptr) + LD A,' ' + CALL COUT + POP HL ; restore ptr to Drive Characteristics + BIT 3,(HL) ; check if single-sided (0), or double-sided (1) + INC HL ; move ptr fwd + PUSH HL ; save + LD A,'S' ; prepare for output 'S' + JR Z,PFDPAR2 ; ..if bit 3 not set; jump + LD A,'D' ; else, output 'D' +PFDPAR2: CALL COUT + LD A,'S' + CALL COUT + CALL VPRINT ; display string (ptr on Stack), value Step Rate + DEFB ', ' + DEFB 0 + POP HL ; restore ptr + PUSH HL + INC HL ; move ptr fwd to Tracks per Side + INC HL + INC HL + LD A,(HL) ; get # of Tracks + CALL PAFDC ; ..and display it + CALL VPRINT + DEFB ' Trks/Side',CR,LF,TAB,TAB,'Step Rate = ' + DEFB 0 + POP HL ; restore ptr (to Step Rate) + LD A,(HL) ; get value + CALL PAFDC ; ..and display + CALL VPRINT + DEFB ' mS, Head Load = ' + DEFB 0 + INC HL ; move ptr fwd to Head Load Time + LD A,(HL) + CALL PAFDC ; ..and display + CALL VPRINT + DEFB ' mS, Unload = ' + DEFB 0 + INC HL ; move ptr fwd to Head Unload Time + LD A,(HL) + CALL PAFDC ; ..and display + CALL VPRINT + DEFB ' mS',CR,LF + DEFB 0 + RET + + ; Floppy Disk sizes + ; nul-terminated strings prefixed by a table of vectors +FDS$TBL: DEFW FDSZ$1 + DEFW FDSZ$4 + DEFW FDSZ$3 + DEFW FDSZ$2 +FDSZ$1: DEFB 'Fixed',0 +FDSZ$2: DEFB '3.5"',0 +FDSZ$3: DEFB '5.25"',0 +FDSZ$4: DEFB '8"',0 +FDSZ$5: DEFB 'Unknown',0 + + + ; ###### CHECK: unreferenced code (not used) +UNUSED1: LD A,']' + CALL COUT + CALL VPRINT + DEFB TAB,': ' + DEFB 0 + RET + ; ###### + + + ; display value at given offset in Config area, and ask user for new value + ; in: A= offset (base is B/P Bios page addr) + ; out: DE= evaluated number (user input) + ; HL= ptr in config area +PVALASK: CALL WSPCPTR ; set ptr + LD E,(HL) ; get value + LD D,0 + PUSH HL ; save regs + EX DE,HL ; swap + CALL PHLDCNV ; display current value and ask for user input + POP HL ; restore regs (ptr) + RET + + +;::::: MENU 4 - HARD DISK (config) + +M4HD: LD A,1 + LD (CFMENU),A ; store flag (sub-)menu entered + CALL CLS + CALL VPRINT + DEFB CR,LF,'Menu4 - Hard Disk Options' + DEFB CR,LF,LF,' ',1,' 1 ',2,' Hard Drive Controller = ' + DEFB 0 + LD A,0BAH ; offset to CNTRLR in Config area + CALL WSPCPTR ; set ptr + LD A,(HL) ; get controller type + LD (HDCTRLR),A ; ..and store it + LD (HDCTRL2),A + LD HL,HDCTR$A ; prepare ptr for "GIDE" + CP 80H ; is it GIDE ? + JR Z,M4HD1 ; ..if so, jump to contiinue + LD HL,HDCTRL2 ; else, clear copy + LD (HL),0 + CP 10 ; check for unknown controller type + LD HL,HDCTR$B+1 ; prepare for type "Unknown" + JR NC,M4HD1 ; ..if so, jump + LD HL,HDC$TBL ; else, ptr to vector table for strings + ADD A,A ; calculate offset + CALL GWRDHLA ; read addr and let HL point to string +M4HD1: CALL VPSTR ; display string (HL= ptr) + CALL VPRINT + DEFB CR,LF,LF,' ',1,' 2 ',2,' First Drive :' + DEFB 0 + LD A,0BBH ; offset to HDRV0 in Config area + CALL PHDPARM ; set ptr + CALL VPRINT + DEFB CR,LF,LF,' ',1,' 3 ',2,' Second Drive :' + DEFB 0 + LD A,0C4H ; offset to HDRV1 in Config area + CALL PHDPARM ; set ptr + CALL VPRINT + DEFB CR,LF,LF,' ',1,' 4 ',2,' Third Drive :' + DEFB 0 + LD A,0CDH ; offset to HDRV2 in Config area + CALL PHDPARM ; set ptr + LD A,'4' ; max. possible option in this menu as ascii number + CALL MSELECT ; get input + OR A + JP Z,M0MAIN ; if none, jump display main menu + + +;::::: MENU 4 - HARD DISK (configure) + + ; subsequent labels start with "HD_" +M4CFG: CP '2' ; option '2' selected ? + JR Z,HD_DRV1 ; ..if so, jump + CP '3' ; option '3' ? + JR Z,HD_DRV2 + CP '4' ; option '4' ? + JR Z,HD_DRV3 + CALL VPRINT + DEFB CR,LF,TAB,' Select Controller Type as:',CR,LF + DEFB 0 + XOR A ; clear A + LD C,A ; ..and C +M4CFG1: LD HL,HDC$TBL ; ptr to vector tables of strings + ADD A,A ; calc offset (2 bytes per entry) + CALL ADDHLA ; move ptr fwd + CALL PHDCNAM ; display option number and name of controller + INC C ; counter +1 + LD A,C + CP 10 ; check if max. number not exceeded + JR C,M4CFG1 ; ..show next controller type + LD A,0BAH ; offset to CNTRLR in Config area + CALL WSPCPTR ; set ptr + PUSH HL ; ..in IX + POP IX + LD A,'9'+1 ; max. possible option in this menu as ascii number + CALL MSELECT ; get input + JR Z,M4CFG3 ; if none, jump exit + SUB '0' ; convert ascii to number + CP 9 ; below 9 ? + JR C,M4CFG2 ; ..if so, skip over + LD A,80H ; else, must be GIDE (type 0x80) +M4CFG2: LD (IX+0),A ; set controller type +M4CFG3: JP M4HD ; ..and display hard disk menu again + + + ; configure HD drive + ; in: A= offset to HDRV0/1/2 + ; use injected opcode to skip over another offset being loaded +HD_DRV1: LD A,0BBH ; offset to HDRV0 in Config area + DEFB 21h ; injected opcode 0x21 (= LD HL,nnnn), and fall through +HD_DRV2: LD A,0C4H ; offset to HDRV1 in Config area + DEFB 21h +HD_DRV3: LD A,0CDH ; offset to HDRV2 in Config area + CALL WSPCPTR ; set ptr + CALL VPRINT + DEFB CR,LF,TAB,TAB,'Activate Drive ([Y]/N) ? ' + DEFB 0 + CALL CAPIN + RES 4,(HL) ; byte = combined Phys. Unit # and Log. Unit # + ; bit 4 indicates if active (0= inactive, 1= active) + CP 'N' ; 'N' entered ? + JP Z,HD_STP4 ; ..if so, jump exit + SET 4,(HL) ; else, set bit 4 to activate drive + CALL CRLF + + ; physical unit +HD_PUN: CALL VPRINT + DEFB CR,TAB,TAB,'Physical Unit (0..7)',TAB,TAB,'[' + DEFB 0 + CALL EREOL ; clear CON: to end of line + PUSH HL ; save HL (ptr to HDRV0/1/2) + LD A,(HL) ; get config. byte + AND 00000111B ; mask lower bits (physical device) + LD L,A ; ..and move to HL for display/input + LD H,0 + CALL PHLDCNV ; display current value and ask for user input + POP HL ; restore regs + LD A,D ; evaluated number in DE + OR A ; high-byte must not be zero + JR NZ,HD_PUN1 ; ..if so, jump + LD A,E ; else, get low-byte + CP 8 ; ..and check if above limit + JR C,HD_PUN2 ; ..if not, jump to continue +HD_PUN1: CALL CFEVAL ; eval script file input + JR HD_PUN ; loop +HD_PUN2: LD A,(HL) ; get Config. Byte + AND 11111000B ; mask off lower 3 bits + OR E ; ..combine with new value (input) + LD (HL),A ; ..and write back + LD C,A ; store Config. Byte in C + LD A,(HDCTRLR) ; get controller type + CP 80H ; is it GIDE ? + JR Z,HD_CYL ; ..if so, skip following options + CALL CRLF + + ; configure logical unit +HD_LUN: CALL VPRINT + DEFB CR,TAB,TAB,'Logical Unit Number (0..7)',TAB,'[' + DEFB 0 + CALL EREOL ; clear CON: to end of line + LD A,(HL) ; get Config. Byte + RLCA ; shift upper bits 7-5 to position 2-0 + RLCA + RLCA + AND 00000111B ; mask lower bits (= log. unit) + PUSH HL ; save regs + LD L,A ; copy to HL for display + LD H,0 + CALL PHLDCNV ; display current value and ask for user input + POP HL ; restore regs + LD A,D ; evaluated number in DE + OR A ; check if high-byte is zero + JR NZ,HD_LUN1 ; ..if not, jump + LD A,E ; else, get low-byte + CP 8 ; ..and check if above limit + JR C,HD_LUN2 ; ..if not, jump to continue +HD_LUN1: CALL CFEVAL ; else, eval script file input + JR HD_LUN ; loop (ask for new input) +HD_LUN2: RRCA ; shift bits back to position 7-5 + RRCA + RRCA + LD B,A ; save logical unit number in B + LD A,(HL) ; get Config. Byte + AND 00011111B ; mask off upper 3 bits + OR B ; ..combine with new value (input) + LD (HL),A ; write back + + ; configure cylinders +HD_CYL: INC HL ; move ptr to # of Cylinders in HDRV0/1/2 + PUSH HL ; ..copy to IX + POP IX + CALL VPRINT + DEFB CR,LF,TAB,TAB,'Number of Cylinders',TAB,TAB,'[' + DEFB 0 + LD L,(IX+0) ; current # of Cyl's in HL for output + LD H,(IX+1) + CALL PHLDCNV ; display current value and ask for user input + LD (IX+0),E ; evaluated number in DE + LD (IX+1),D ; ..write back + LD (HDCYLNO),DE ; ..and also store locally + CALL CRLF + + ; configure heads +HD_HEAD: CALL VPRINT + DEFB CR,TAB,TAB,'Number of Heads',TAB,TAB,TAB,'[' + DEFB 0 + CALL EREOL ; clear CON: to end of line + LD L,(IX+2) ; current # of Heads in HL for output + LD H,0 + CALL PHLDCNV ; display current value and ask for user input + LD A,D ; evaluated number in DE + OR A ; check if high-byte is zero + JR Z,HD_HED1 ; ..if so, jump to continue + CALL CFEVAL ; else, eval script file input + JR HD_HEAD ; loop (ask for new input) +HD_HED1: LD (IX+2),E ; write back new value (input) + LD A,(HDCTRLR) ; get controller type + CP 80H ; is it GIDE ? + JR NZ,HD_HED2 ; ..if not, continue w/ reduced write + CALL VPRINT ; else, continue w/ sectors per track + DEFB CR,LF,TAB,TAB,'Sectors Per Track',TAB,TAB,'[' + DEFB 0 + JR HD_RWRT +HD_HED2: CALL VPRINT + DEFB CR,LF,TAB,TAB,'Reduced Write Starting Cylinder',TAB,'[' + DEFB 0 + + ; configure Sectors per Track (GIDE) or Reduced Write Starting Cyl (SCSI) +HD_RWRT: LD L,(IX+3) ; current value in HL for output + LD H,(IX+4) + CALL PHLDCNV ; display current value and ask for user input + LD (IX+3),E ; write back evaluated number in DE + LD (IX+4),D + LD A,(HDCTRLR) ; get controller type + SUB 80H ; is it GIDE ? + ; Note: SUB 0x80 is used here, instead of CP + ; so A= 0 which is written as Step Rate value below + ; GIDE does not use a Step Rate + JP Z,HD_STP3 ; ..if so, skip following options + CALL VPRINT + DEFB CR,LF,TAB,TAB,'Write Precomp. Start Cylinder',TAB,'[' + DEFB 0 + LD L,(IX+5) ; get current Cyl # to start precompensation + LD H,(IX+6) ; ..to HL for output + CALL PHLDCNV ; display current value and ask for user input + LD (IX+5),E ; write back evaluated number in DE + LD (IX+6),D + LD A,(HDCTRLR) ; get controller type + CP 3 ; is it Owl/Adaptec/Xebec (first 3 options) ? + LD A,0 + JR NC,HD_STP3 ; ..if so, set Step Rate = 0 + + ; configure Step Rate (predefined values for specific SCSI controllers) +HD_STEP: LD A,(HDCTRLR) ; get controller type + LD HL,HDSTP$1 ; prepare ptr to Step Rate options #1 + LD C,3 ; number of options + DEC A ; is it Adaptec (#1) ? + JR Z,HD_STP1 ; ..if so, jump continue + LD HL,HDSTP$2 ; ptr Step Rate options #2 + LD C,4 ; number of options + DEC A ; is it Xebec ? + JR NZ,HD_STP4 ; ..if not, jump exit +HD_STP1: CALL VPSTR ; print string (HL= ptr) + CALL EREOL + LD L,(IX+7) ; get current value + INC L ; make it 1-based + LD H,0 + CALL PHLDCNV ; display current value and ask for user input + JR C,HD_STP2 ; ..if error, jump + LD A,D ; evaluated number in DE + OR A ; check if high-byte is zero + JR NZ,HD_STP2 ; ..if not, jump + LD A,E ; else, get low byte + DEC A ; ..make it 0-based + CP C ; and compare to possible # of options + JR C,HD_STP3 ; ..if within boundaries, continue +HD_STP2: CALL CFEVAL ; eval script file input + JR HD_STEP ; loop (ask for new input) +HD_STP3: LD (IX+7),A ; write Step Rate +HD_STP4: JP M4HD ; jump display HD menu + + ; Step Rate options + ; nul-terminated strings +HDSTP$1: DEFB CR,LF,TAB,TAB,'Step Rate:' + DEFB CR,LF,' 3mS(1), 28uS(2), 12uS(3)',TAB,TAB,'[' + DEFB 0 +HDSTP$2: DEFB CR,LF,TAB,TAB,'Step Rate: 3mS(1), ' + DEFB '200uS(2), 70uS(3), 40uS(4)',TAB,'[' + DEFB 0 + + +;::::: SUPPORT FUNCTIONS - Hard Disk (config) + + ; display option number and name of controller + ; in: C= current number (counter) + ; HL= entry in vector table of strings (names) +PHDCNAM: CALL VPRINT + DEFB CR,LF,TAB,TAB,'(' + DEFB 0 + LD A,C ; get number + ADD A,'0' ; make it ascii + CALL COUT ; ..and display + CALL VPRINT + DEFB ') ' + DEFB 0 + LD E,(HL) ; addr of string, low byte + INC HL ; ptr fwd + LD D,(HL) ; addr of string, high byte + EX DE,HL ; swap regs + JP VPSTR ; display string (HL= ptr), and return from there + + ; strings Hard Disk controllers + ; nul-terminated strings prefixed by a table of vectors +HDC$TBL: DEFW HDCTR$1 + DEFW HDCTR$2 + DEFW HDCTR$3 + DEFW HDCTR$4 + DEFW HDCTR$5 + DEFW HDCTR$6 + DEFW HDCTR$7 + DEFW HDCTR$8 + DEFW HDCTR$9 + DEFW HDCTR$A + DEFW HDCTR$B + +HDCTR$1: DEFB 'Owl',0 +HDCTR$2: DEFB 'Adaptec ACB-4000A',0 +HDCTR$3: DEFB 'Xebec 1410a/Shugart 1610-3',0 +HDCTR$4: DEFB 'Seagate SCSI',0 +HDCTR$5: DEFB 'Shugart 1610-4/Minimal SCSI',0 +HDCTR$6: DEFB 'Conner SCSI',0 +HDCTR$7: DEFB 'Quantum SCSI',0 +HDCTR$8: DEFB 'Maxtor SCSI',0 +HDCTR$9: DEFB 'Syquest SCSI',0 +HDCTR$A: DEFB 'GIDE (IDE/ATA)',0 +HDCTR$B: DEFB '--Unknown--',0 + + + ; display Hard Disk parameters + ; in: A= offset to HDRV0/1/2 +PHDPARM: CALL WSPCPTR ; set ptr + LD A,(HL) ; get Config. Byte + BIT 4,A ; is drive active ? (bit 4, 0= inactive, 1= active) + JR NZ,PHDPAR1 ; ..if active, continue + CALL VPRINT ; else, display msg and return + DEFB ' - inactive -' + DEFB 0 + RET +PHDPAR1: LD A,(HDCTRLR) ; get controller type + CP 80H ; is it GIDE ? + JR NZ,PHDPAR2 ; ..if not, jump + CALL VPRINT ; else, display msg + DEFB ' Unit ' + DEFB 0 + LD A,(HL) ; get Config. Byte + JR PHDPAR3 ; ..and skip several options + + ; for SCSI drives, show physical and locgical unit +PHDPAR2: CALL VPRINT + DEFB ' Physical Unit ' + DEFB 0 + LD A,(HL) ; get Config. Byte + AND 00000111B ; mask off bits 4-7 + CALL PAFDC ; ..display value (Phys. Unit) + CALL VPRINT + DEFB ', Logical Unit ' + DEFB 0 + LD A,(HL) ; get Config. Byte + RLCA ; rotate bits 7-5 to position 2-0 + RLCA + RLCA +PHDPAR3: AND 00000111B ; mask off bits 4-7 + CALL PAFDC ; ..display value (Log. Unit) + INC HL ; move ptr fwd (# Cyl) + PUSH HL ; ..into IX + POP IX + LD A,(HL) ; get # Cylinders + INC HL ; ..in HL + LD H,(HL) + LD L,A + OR H ; is value = zero ? + JP Z,PHDPARB ; ..if so, exit + LD (HDCYLNO),HL ; store # Cylinders + CALL VPRINT + DEFB CR,LF,TAB,' No. of Cylinders = ' + DEFB 0 + CALL PHLFDC ; display value (# Cyl) + CALL VPRINT + DEFB ',',TAB,'No. of Heads = ' + DEFB 0 + LD A,(IX+2) ; get # Heads + CALL PAFDC ; ..and display + LD A,(HDCTRLR) ; get controller type + CP 80H ; is it GIDE ? + JR NZ,PHDPAR4 ; ..if not, jump + CALL VPRINT ; else, display Sect. per Track + DEFB CR,LF,TAB,' Sectors-Per-Track= ' + DEFB 0 + LD L,(IX+3) ; get word - for GIDE Sect./Track are stored here + LD H,(IX+4) ; (instead of Cyl. to start Reduced Write) + JP PHLFDC ; ..diplay, and let return from there + + ; more parameters shown for certain SCSI controllers +PHDPAR4: CP 3 ; is controller type # less than 3 ? + RET NC ; ..if not, return (type <> Owl, Adaptec, Xebec) + CALL VPRINT ; else, display more parameters + DEFB CR,LF,TAB,' Red. Write Cyl = ' + DEFB 0 + LD E,(IX+3) ; get word, Cyl. # to start Reduced Write + LD D,(IX+4) + LD HL,(HDCYLNO) ; get total # of Cylinders + OR A ; clear C-Flag + SBC HL,DE ; subtract + EX DE,HL ; swap regs + JR NZ,PHDPAR5 ; ..if not zero, jump + CALL VPRINT ; else, no Reduced Write + DEFB 'None' + DEFB 0 + JR PHDPAR6 ; skip over +PHDPAR5: CALL PHLFDC ; display value (Cyl. to start Reduced Write) +PHDPAR6: CALL VPRINT + DEFB ',',TAB,'Precomp. @ Cyl = ' + DEFB 0 + LD E,(IX+5) ; get word, Cyl. # to start Precompensation + LD D,(IX+6) + LD HL,(HDCYLNO) ; get total # of Cylinders + OR A ; clear C-Flag + SBC HL,DE ; subtract + EX DE,HL ; swap regs + JR NZ,PHDPAR7 ; ..if not zero, jump + CALL VPRINT ; else, no Precompensation + DEFB 'None' + DEFB 0 + JR PHDPAR8 ; skip over +PHDPAR7: CALL PHLFDC ; display value (Cyl. to start Precompensation) +PHDPAR8: LD A,(HDCTRLR) ; get controller type + OR A ; is it zero ? (= Owl) + RET Z ; ..if so, return + CP 3 ; else, check if type # is less than 3 ? + RET NC ; ..if not, return + + ; Step Rate parameters only for Adaptec and Xebec SCSI controllers + CALL VPRINT + DEFB CR,LF,TAB,' Drive Step Rate = ' + DEFB 0 + LD HL,HDSTP$A ; prepare ptr + DEC A ; is it Adaptec controller ? + JR Z,PHDPAR9 ; ..if so, skip over + LD HL,HDSTP$X ; else, ptr to Xebec controller strings +PHDPAR9: LD A,(IX+7) ; get Step Rate + AND 00000011B ; mask off bits 2-7 (max. 4 values possible) + LD B,A + ADD A,A ; *2 + ADD A,A ; *4 + ADD A,B ; *5 (each entry is 5 bytes long) + CALL ADDHLA ; set ptr to string + LD B,5 ; 5 chars to display +PHDPARA: LD A,(HL) ; get char + INC HL ; move ptr fwd + CALL COUT ; ..and display char in A + DJNZ PHDPARA ; loop till done + RET + + ; parameter not defined, exit +PHDPARB: CALL VPRINT + DEFB CR,LF,TAB,'-- Not Defined --' + DEFB 0 + RET + +; Step Rate options - Adaptec controller +; 5 bytes per entry +HDSTP$A: DEFB '3mS ' + DEFB '28uS ' + DEFB '12uS ' + DEFB '??? ' +; Step Rate options - Xebec controller +; 5 bytes each entry +HDSTP$X: DEFB '3mS ' + DEFB '200uS' + DEFB '70uS ' + DEFB '40uS ' + + ; * + + +;::::: MENU 5 - DRIVE LAYOUT (display) + +M5DL: LD A,1 + LD (CFMENU),A ; store flag (sub-)menu entered + LD HL,(WSPCBEG) ; addr start WSPC area + LD DE,22*3+1 ; offset to Bios fn #22 DRVTBL (addr drive table) + ADD HL,DE + LD E,(HL) ; get low byte + INC HL + LD D,(HL) ; get high byte + EX DE,HL ; ..and swap + CALL CNVADDR ; convert to addr in WSPC area + INC HL ; move ptr past 0x21 LD HL,.... + LD E,(HL) ; get low byte + INC HL + LD D,(HL) ; get high byte + EX DE,HL ; ..and swap + CALL CNVADDR ; convert to addr in WSPC area + LD (DRTBL),HL ; store addr (in WSPC) of drive table +M5DL1: CALL CLS + CALL VPRINT + DEFB CR,LF,'Menu 5 - Logical Drive Layout',CR,LF,LF + DEFB 0 + XOR A ; clear A + LD B,16 ; max. number of drives +M5DL2: PUSH BC + PUSH AF + ADD A,'A' ; convert to ascii letter (0 -> 'A') + CALL COUT ; ..and display + CALL VPRINT + DEFB ': = ' + DEFB 0 + POP AF ; restore drive number + PUSH AF + CALL PDLPARM ; display drive parameters + CALL CRLF + POP AF + POP BC + INC A ; next drive number + DJNZ M5DL2 ; loop + CALL VPRINT + DEFB CR,LF,' ' + DEFB 1,' 1 ',2,' Swap Drives, ' + DEFB 1,' 2 ',2,' Configure Partition' + DEFB 1,' 3 ',2,' Show Drive Allocations' + DEFB 0 + LD A,'3' ; max. possible option in this menu as ascii number + CALL MSELECT ; get input + OR A + JP Z,M0MAIN ; ..if none, display Main menu + + +;::::: MENU 5 - DRIVE LAYOUT (configure) + + ; subsequent labels start with "DL_" +M5CFG: CP '1' ; option 1 selected ? + JP NZ,DL_PRTT ; ..if not, jump to next + + ; --- Swap Drives (option 1) + CALL VPRINT + DEFB CR,LF,' Swap drive [A..P] : ' + DEFB 0 +DL_SWP: CALL GETINP ; get input + CP ' '+1 ; is it a Control char or ? + JP C,M5DL1 ; ..if so, go back and display options again + CALL CKDLTR ; is it a valid drive letter ? + JR C,DL_SWP ; ..if not, loop + LD (DR1SWP),A ; else, store number of 1st drive + CALL VPRINT + DEFB ' with drive [A..P] : ' + DEFB 0 +DL_SWP1: CALL GETINP ; get input + CP ' '+1 ; is it a Control char or ? + JP C,M5DL1 ; ..if so, go back and display options again + CALL CKDLTR ; is it a valid drive letter ? + JR C,DL_SWP1 ; ..if not, loop + ADD A,A ; double the number (drive table entries are 16-bit) + LD HL,(DRTBL) ; addr of DRVTBL + LD E,L ; ..into DE + LD D,H + CALL ADDHLA ; add offset + EX DE,HL ; ..swap + LD A,(DR1SWP) ; # of 1st drive + ADD A,A ; *2 + CALL ADDHLA ; add offset + LD A,(DE) ; byte of table entry 1st drive (HL= ptr) + LD B,(HL) ; byte of table entry 2nd drive (DE= ptr) + EX DE,HL ; swap pointers + LD (HL),B ; ..and write bytes to swapped locations + LD (DE),A + INC DE ; both pointers fwd + INC HL + LD A,(DE) ; ..and repeat read/write + LD B,(HL) + EX DE,HL + LD (HL),B + LD (DE),A + LD HL,(DRTBL) ; get addr of DRVTBL + LD B,16 ; number of drives + LD DE,0 + DEC HL ; move ptr back + ; ..and fall through + + ; build drive vector (bitmap of available drives) in DE +DL_VECT: INC HL ; move ptr fwd + LD A,(HL) ; get byte + INC HL ; ptr fwd + OR (HL) ; is it zero ? (no drive) + JR Z,DL_VEC1 ; ..if so, skip + SCF ; else, set C-Flag +DL_VEC1: RR D ; rotate bits through DE + RR E ; ..existing drives are marked with a 1-bit + DJNZ DL_VECT ; loop till done + LD A,(RUNMODE) ; get program running mode + LD BC,34H ; offset drive vector in Z3ENV Descriptor + LD HL,(WRKEND) ; addr of WSPC end + CP 'I' ; config mode 'I'mage ? + JR Z,DL_VEC2 ; ..if so, jump + LD HL,(ENVADR) ; else, get addr of Environment + CP 'M' ; config mode 'M'emory ? + JR Z,DL_VEC2 ; ..if so, jump + LD HL,(WRKZ3E) ; else, Disk mode, get addr of Environment + LD A,H ; is it valid ? + OR L + JR Z,DL_VEC3 ; ..if not, jump exit +DL_VEC2: ADD HL,BC ; add offset + LD (HL),E ; ..and store new drive vector + INC HL + LD (HL),D +DL_VEC3: JP M5DL1 + + ; --- Configure Partition (option 2) +DL_PRTT: CP '2' ; option 2 selected ? + JP NZ,DL_ALOC ; ..if not, jump to next + LD A,(RUNMODE) ; get program running mode + CP 'M' ; config mode 'M'emory ? + JR NZ,DL_PRT1 ; ..if not, jump to coninue + CALL VPRINT ; else, show message + DEFB CR,LF,TAB,"--- Can't Configure Running System ! ---" + DEFB 0 + CALL CFEVAL ; eval script file input + JP DL_ALO7 ; ..and jump exit +DL_PRT1: CALL VPRINT + DEFB CR,LF,TAB,'Configure which Drive [A..P] : ' + DEFB 0 +DL_PRT2: CALL GETINP ; get input + CP CR ; is it ? + JP Z,M5DL1 ; ..if so, jump display DL menu again + CALL CKDLTR ; else, convert to drive number + JR C,DL_PRT2 ; ..if not valid, get new input + LD (DRNO),A ; store drive number + CALL GDPHDPB ; addr of DPH and DPB in WSPC area + LD A,D ; is DPH addr valid ? + OR E + JP Z,M5DL1 ; ..if not, jump to display menu + DEC DE ; move ptr back (in XPDH, located before standard DPH) + DEC DE + LD A,(DE) ; get driver ID + LD (DRVRID),A ; ..store it + CP 2 ; is it a Hard Disk ? + JR Z,DL_PRT3 ; ..if so, continue + CP 3 ; or is it RAM Disk ? + JR Z,DL_PRT3 ; ..then continue + LD A,BS ; else, clear char (send ) + CALL COUT + CALL CFEVAL ; eval script file input + JR NZ,DL_PRT2 ; loop (ask for new input) +DL_PRT3: CALL CRLF + + ; partition allocation size +DL_ALSZ: CALL VPRINT + DEFB TAB,'Allocation Size (1, 2, 4, 8, 16, 32k)',TAB,'[' + DEFB 0 + LD A,(DRNO) ; get drive number + CALL GDPHDPB ; HL= addr of DPB + LD E,(HL) ; Sect/Trk into DE + INC HL + LD D,(HL) + INC HL + SRL D ; divide DE by 2 + RR E + SRL D ; /4 + RR E + SRL D ; /8 + RR E + LD (ALSIZKB),DE ; store allocation size (kB) + LD A,(HL) ; get block shift factor (BSH) + LD (DRBSH),A ; ..and store + CALL GBLS ; get Block Size (BLS) + LD L,A ; ..in HL for output + LD H,0 + CALL PHLDCNV ; display value and ask for input + LD A,1 ; start with 1 + LD B,6 ; max. 6 valid allocation sizes +DL_ALS1: CP E ; evaluated number in DE (single digit range - check E) + JR Z,DL_ALS2 ; ..if match, jump + ADD A,A ; else, double value + DJNZ DL_ALS1 ; ..and loop + LD A,7 ; entered value is invalid + CALL COUT + CALL CFEVAL ; eval script file input + JR DL_ALSZ ; loop (ask for new input) +DL_ALS2: CALL GBSHP ; get ptr to BSH that corresponds with block size + LD (DRBSTBL),HL ; ..and store it + + ; partition number of dir entries +DL_DIRE: CALL VPRINT + DEFB TAB,TAB,'Number of Dir Entries',TAB,'[' + DEFB 0 + LD A,(DRNO) ; get drive number + CALL GDPHDPB ; HL= addr of DPB + LD DE,7 ; offset to 'Dir Max -1' + ADD HL,DE + LD A,(HL) ; get DirMax value + INC HL ; ..into HL + LD H,(HL) + LD L,A + INC HL ; +1 + CALL PHLDCNV ; display value and ask for input + LD HL,(DRBSTBL) ; ptr to BSH lookup table + INC HL ; move fwd to BLM + LD A,(HL) ; get Block Mask (BLM) + SCF + RLA ; A= A*2+1 + SCF + RLA ; A= A*2+1 + AND E ; compare input with max. possible number + JR Z,DL_TROF ; ..if ok, jump to continue + CALL VPRINT ; else, display error and ask for new input + DEFB BEL,' +++ Illegal Number of Entries +++',CR,LF + DEFB 0 + CALL CFEVAL ; eval script file input + JR DL_DIRE ; loop (ask for new input) + + ; partition track offset (start of directory) +DL_TROF: LD (DRDIRMX),DE ; store new Max Dir value + CALL VPRINT + DEFB TAB,TAB,'Starting Track Number',TAB,'[' + DEFB 0 + LD A,(DRNO) ; get drive number + CALL GDPHDPB ; HL= addr of DPB + LD DE,13 ; offset to 'Trk Offset' + ADD HL,DE + LD A,(HL) ; get 'Trk Offset' + INC HL ; ..into HL + LD H,(HL) + LD L,A + CALL PHLDCNV ; display value and ask for input + LD (DROFFS),DE ; store entered value + CALL VPRINT + DEFB TAB,TAB,'# Tracks in Logical Drv',TAB,'[' + DEFB 0 + LD A,(DRNO) ; get drive number + CALL GDPHDPB ; HL= addr of DPB + LD DE,5 ; offset to 'Disk Size -1' + ADD HL,DE + LD E,(HL) ; get Disk Size + INC HL ; ..into DE + LD D,(HL) + INC DE ; +1 + LD A,(DRBSH) ; get current Block Shift Factor (BSH) + EX DE,HL ; swap regs (HL= Disk Size) + SUB 3 ; reduce BSH + LD B,A ; ..for use as counter + LD DE,(ALSIZKB) ; get allocation size (kB) + LD A,0 + JR Z,DL_TRN1 ; ..if A already zero (BSH= 3), don't loop + + ; partition number of tracks (total) +DL_TRNO: ADD HL,HL ; 'Disk Size' is measured in BLS units (allocation blocks) + ADC A,0 ; ..so double it [BSH-3] times + DJNZ DL_TRNO +DL_TRN1: CALL DIVHLDE ; calculate disk capacity in tracks + LD L,C ; copy result in HL + LD H,B + CALL PHLDCNV ; display value and ask for input + LD (DRTRKS),DE ; store entered value (# tracks) + LD A,(DRNO) ; get drive number + CALL GDPHDPB ; DE= addr DPH, HL= addr DPB + PUSH HL ; save HL (DPB) + EX DE,HL ; swap regs + DEC HL ; move ptr backwards + PUSH HL ; save HL (ptr DPH-1, Phys. Unit #) + LD L,(HL) ; get Phys. Unit number + LD H,0 + CALL VPRINT + DEFB TAB,TAB,'Physical Unit Number',TAB,'[' + DEFB 0 + CALL PHLDCNV ; display value and ask for input + POP HL ; restore ptr (DPH-1, Phys. Drive #) + LD (HL),E ; ..and store entered value + EX DE,HL ; swap regs + INC DE ; move ptr fwd to DPH + POP HL ; restore HL (DPB) + LD A,(DRVRID) ; get driver ID + CP 2 ; is it Hard Disk ? + JR Z,DL_UNIT ; ..if so, jump to continue + INC HL ; else, move ptr fwd to DPB+2 (BSH) + INC HL + JR DL_UN1 ; ..and skip over + + ; partition physical unit + ; for Hard Disk, set fixed Sect/Trk (DEFW 64) and Alloc. Size (8k) +DL_UNIT: LD (HL),64 ; set number of sectors per track + INC HL ; ptr fwd + LD (HL),0 + INC HL + LD DE,8 ; allocation size + LD (ALSIZKB),DE ; ..store it +DL_UN1: LD DE,(DRBSTBL) ; ptr to BSH in internal lookup table + EX DE,HL ; swap regs + LDI ; copy BSH and BLM over + LDI + EX DE,HL ; swap regs back + PUSH HL ; save HL (ptr to DPB+4, extent mask) + LD A,(DE) ; get BLS from internal lookup table + LD E,A ; ..into DE + LD D,0 + LD HL,(DRTRKS) ; # of tracks (disk capacity) + LD A,(ALSIZKB) ; allocation size in kB (Sect/Trk) + SRL A ; shift right through C-Flag + LD B,A ; after initial SRL, reg B will be used + XOR A ; clear A and C-Flag + + ; multiply # of tracks according to Allocation Size + ; 1k= *2, 2k= *4, 4k= *8 and so forth +DL_UN2: ADD HL,HL ; double value + ADC A,0 ; test C-Flag + SRL B ; shift right through C-Flag + JR NC,DL_UN2 ; ..loop if more to do + CALL DIVHLDE ; then divide by BLS (from internal lookup table) + LD A,E ; BLS into A (value: 1, 2, 4, 8, 16, or 32) + LD L,0 + SRL A ; shift LSB out + JR Z,DL_UN4 ; ..if A= 0, jump +DL_UN3: SCF ; else, set Carry + RL L ; ..and set as LSB in L + SRL A ; shift next LSB out + JR NZ,DL_UN3 ; ..and continue until A= 0 + ; reg L contains a mask with lower bits set + ; representing BLS value (1= 00000000, 2= 00000001, 4= 00000011 ...) + LD A,B ; get high-byte of quotient (disk capacity / BLS) + OR A ; is it zero ? + JR Z,DL_UN4 ; ..if so, skip over + SRL L ; else, extent bit mask once more +DL_UN4: LD A,L ; bit mask into A + POP HL ; restore HL (ptr DPB+4, extent mask) + LD (HL),A ; ..store EXM + INC HL ; ptr fwd + DEC BC ; disk size -1 + LD (HL),C ; ..store value + INC HL + LD (HL),B + INC HL ; ptr to DPB+7 'Dir Max -1' + LD BC,(DRDIRMX) ; get Dir Max value + DEC BC ; -1 + LD (HL),C ; ..and store + INC HL + LD (HL),B + INC HL + PUSH HL ; save HL (ptr DPB+9, Alloc0) + LD L,C ; copy 'Dir Max -1' to HL + LD H,B + INC HL + LD B,5 ; set counter +DL_UN5: SRL H ; divide HL by 32 (5 times /2) + RR L + DJNZ DL_UN5 ; loop + XOR A + CALL DIVHLDE ; divide by BLS + LD B,C ; ..use result as counter + LD HL,0 +DL_UN6: SCF ; set Carry + RR H ; ..and build bit mask + RR L ; starting from MSB this time + ; (see B/P Bios manual, p. 57) + DJNZ DL_UN6 ; loop + EX DE,HL ; swap regs, bit mask in DE + POP HL ; restore HL (ptr DPB+9, Alloc0) + LD (HL),D ; ..store value + INC HL + LD (HL),E + INC HL + LD (HL),0 ; set 'Check Size' (DPB+11) to zero + INC HL + LD (HL),0 + INC HL ; move ptr to 'Trk Offset' + LD DE,(DROFFS) ; get start of Dir + LD (HL),E ; ..and store + INC HL + LD (HL),D + JP M5DL1 ; jump back to display menu + + ; display allocation (option 3) +DL_ALOC: CALL VPRINT + DEFB CR,LF,' Display Allocations for which Hard Drive [0..2] : ' + DEFB 0 +DL_ALO1: CALL GETINP ; get input + CP CR ; is it ? + JP Z,M5DL1 ; ..if so, jump to display DL menu + SUB '0' ; else, convert to number + JR C,DL_ALO1 ; ..if less than ascii '0', ask for new input + CP 3 + JR NC,DL_ALO1 ; ..if greater than '3', ask for new input + LD C,A ; remember user input (number) + LD HL,(WRKEND) ; addr of WSPC end + INC H ; +100h + LD B,16 ; set initial value to avoid underflow +DL_ALO2: LD A,16 + SUB B + PUSH HL + PUSH BC + CALL GDPHDPB ; DE= addr DPH, HL= addr DPB + POP BC + LD A,D ; check if DPH is valid (<> zero) + OR E + JR Z,DL_ALO5 ; ..if not valid, jump + DEC DE ; move ptr to XDPH (DPH-2= Driver ID) + DEC DE + LD A,(DE) + CP 2 ; is Hard Drive ? (ID= 2) + JR NZ,DL_ALO5 ; ..if not, jump + INC DE ; ptr fwd + LD A,(DE) ; get Phys. Drive # + CP C ; matches user input ? + JR NZ,DL_ALO5 ; ..if not, jump + EX DE,HL ; else, swap regs (DE= DPB) + POP HL ; restore addr WSPC end + LD A,16 + SUB B ; calc drive # + ADD A,'A' ; convert to ascii letter + LD (HL),A ; store it (WSPC end) + INC HL ; ptr fwd + PUSH BC ; save regs + PUSH DE + PUSH HL + LD HL,13 ; offset to 'Track Offset' (DPB+13) + ADD HL,DE ; adjust ptr + LD C,(HL) ; get track offset (16-bit) + INC HL + LD B,(HL) + POP HL ; restore ptr (WSPC end) + LD (HL),C ; ..and store TrkOffs value + INC HL + LD (HL),B + INC HL ; ptr fwd + PUSH HL ; save regs + PUSH BC + INC DE ; move ptr to DPB+2 + INC DE + LD A,(DE) ; get block shift factor (BSH) + INC DE ; move ptr to 'Disk Size -1' + INC DE + INC DE + EX DE,HL ; swap regs + LD E,(HL) ; 'Disk Size -1' into DE + INC HL + LD D,(HL) + EX DE,HL ; swap regs back + INC HL ; Disk Size (measured in BLS units) + SUB 3 ; reduce BSH + JR Z,DL_ALO4 ; ..if zero, don't loop + LD B,A ; else, use as counter + XOR A ; clear A +DL_ALO3: ADD HL,HL ; 'Disk Size' is measured in BLS units (allocation blocks) + ADC A,0 ; ..so double it [BSH-3] times + DJNZ DL_ALO3 +DL_ALO4: LD DE,8 ; 8 sectors (of 128 bytes) = 1kB + CALL DIVHLDE ; divide (result in BC) + POP HL ; restore HL= 'Track Offset' + POP DE ; DE= ptr WSPC end + DEC BC ; [Disk Size in kB]-1 + ADD HL,BC ; calc in HL + EX DE,HL ; swap regs + LD (HL),E ; ..and store value in WSPC area + INC HL + LD (HL),D + INC HL ; move ptr fwd + POP DE ; clear stack + POP BC + PUSH HL ; save ptr WSPC +DL_ALO5: POP HL + LD (HL),0 ; (zero) marks end of string + DJNZ DL_ALO2 ; loop, collect data of all partitions of that drive + CALL CLS + CALL VPRINT + DEFB 'Partition Data Hard Drive Unit : ' + DEFB 0 + LD A,C + ADD A,'0' + CALL COUT + CALL VPRINT + DEFB CR,LF,LF,' Drv',TAB,'Start Trk',TAB,'End Trk',CR,LF + DEFB 0 + LD HL,(WRKEND) ; addr of WSPC end + INC H ; +100h (scratch area w/ collected data) + LD A,(HL) ; check first byte, zero = nothing to display + OR A + JR NZ,DL_ALO6 ; ..if not zero, jump to continue + CALL VPRINT + DEFB CR,LF,TAB,'-- No Assignments --' + DEFB 0 + JR DL_ALO7 ; jump to exit + + ; loop through collected data and display it +DL_ALO6: CALL VPRINT + DEFB CR,LF,TAB + DEFB 0 + LD A,(HL) ; ascii letter of drive + INC HL + CALL COUT + LD A,TAB + CALL COUT + LD E,(HL) ; get start track + INC HL + LD D,(HL) + INC HL + EX DE,HL ; swap regs + CALL PHLFDC ; ..display value + EX DE,HL ; and swap back + CALL VPRINT + DEFB TAB,TAB + DEFB 0 + LD E,(HL) ; get end track + INC HL + LD D,(HL) + INC HL + EX DE,HL ; swap regs + CALL PHLFDC ; ..display value + EX DE,HL ; and swap back + LD A,(HL) ; end of data (= zero) ? + OR A + JR NZ,DL_ALO6 ; ..if not, loop + CALL CRLF ; else, fall through + +DL_ALO7: CALL VPRINT + DEFB TAB,'[any key to continue]' + DEFB 0 + CALL GETINP ; get input + JP M5DL1 ; display DL menu again + + +;::::: SUPPORT FUNCTIONS - Drive Layout + + ; check if input is a valid drive letter, and convert to number + ; in: A= ascii letter (user input) + ; out: A= number ('A' = 0 .. 'P' = 15) + ; ##### another version of this routine is implemented as CHKDLTR + ; with slightly different functionality + ; THIS routine is only used by "DL_" (Drive Layout) +CKDLTR: CP 'A' ; min. 'A' + JP C,CFEVAL ; ..if not, jump + CP 'P'+1 ; max. 'P' + CCF + JP C,CFEVAL ; ..if not, jump + SUB 'A' ; convert ascii letter to number ('A' -> 0) + RET + + + ; display drive layout parameters on CON: + ; (for drives other than HD, only a short msg is displayed) + ; in: A= drive number (0 = 'A:') +PDLPARM: CALL GDPHDPB ; DE= addr DPH, HL= addr DPB + LD A,E ; check if valid (<> zero) + OR D + JP Z,M$NODRV ; ..if not valid, display message and let return from there + DEC DE ; else, move ptr to XDPH area (DPH-2) + DEC DE + LD A,(DE) ; get Driver ID + CP 2 ; is it Hard Disk ? + JP NZ,M$FLPPY ; ..if not, jump to display type and let return from there + INC DE ; else, move ptr to Phys. Drive # + CALL VPRINT + DEFB 'Unit ' + DEFB 0 + LD A,(DE) ; get Unit (Phys. Drive #) + CALL PAFDC ; ..and display + CALL VPRINT + DEFB ', ' + DEFB 0 + LD E,(HL) ; Sectors per Track in DE + INC HL + LD D,(HL) + LD (DRSECTT),DE ; store value + INC HL + EX DE,HL ; swap regs + CALL PHLFDC ; ..display value + EX DE,HL ; and swap back + LD A,(HL) ; get Block Shift Factor (BSH) + PUSH AF ; ..save + CALL VPRINT + DEFB ' Sctrs/Trk, ' + DEFB 0 + CALL GBLS ; get Block Size (BLS) for that BSH + CALL PAFDC ; ..display as decimal + CALL VPRINT + DEFB 'k/Blk, ' + DEFB 0 + LD E,(HL) ; 'Disk Size -1' in DE + INC HL + LD D,(HL) + INC HL + EX DE,HL ; swap regs + INC HL ; +1 (HL= Disk Size in BLS units) + POP AF ; restore AF + SUB 3 ; reduce BSH for use as counter + LD B,A + JR Z,PDLPAR2 ; ..if already zero, don't loop + XOR A ; else, clear A +PDLPAR1: ADD HL,HL ; 'Disk Size' is measured in BLS units (allocation blocks) + ADC A,A ; ..so double it [BSH-3] times + JP C,M$BIG ; overflow ? then exit loop + DJNZ PDLPAR1 ; else, continue loop +PDLPAR2: PUSH DE + PUSH AF + PUSH HL + CALL PDISKSZ ; display capacity + CALL VPRINT + DEFB 'k (' + DEFB 0 + LD DE,(DRSECTT) ; get Sectors/Track + LD B,3 +PDLPAR3: SRL D ; divide by 8 (sectors to kB) + RR E + DJNZ PDLPAR3 ; loop + POP HL ; restore regs (HL= Disk Size in kB) + POP AF + CALL DIVHLDE ; Disk Size / Sectors-per-Tracks (both in kB) + LD L,C ; result into HL + LD H,B + CALL PHLFDC ; ..and display value + CALL VPRINT + DEFB ' Trks), ' + DEFB 0 + POP HL ; restore DPB+8 'Dir Max -1' + LD E,(HL) ; get value + INC HL + LD D,(HL) + EX DE,HL ; swap regs + INC HL ; +1 for display + CALL PHLFDC + CALL VPRINT + DEFB ' Dirs' + DEFB 0 + RET + + ; msg "No Drive" +M$NODRV: CALL VPRINT + DEFB ' -- No Drive --' + DEFB 0 + RET + + ; for drives other than Hard Disks, only the type is displayed +M$FLPPY: CP 1 ; check Driver ID + JR NZ,M$RAM ; ..if not Floppy (1), jump next + CALL VPRINT + DEFB 'Floppy ' + DEFB 0 + INC DE ; move DPH ptr fwd + LD A,(DE) ; get Unit (Phys. Drive #) + ADD A,'0' ; convert to ascii + JP COUT ; ..display, and let return from there + +M$RAM: CP 3 ; check Driver ID + JR NZ,M$UKNWN ; ..if not RAM (3), jump to next + CALL VPRINT ; else, just display and return + DEFB 'RAM' + DEFB 0 + RET + +M$UKNWN: CALL VPRINT ; unknown type + DEFB '??? (' + DEFB 0 + INC DE ; move DPH ptr fwd + ; ##### BUG: LD A,(DE) missing ? value not retrieved before output + CALL PAFDC ; display byte in A as 1-3 decimal chars + LD A,')' + JP COUT + + ; msg "Too Big" +M$BIG: CALL VPRINT + DEFB '+++ Too Big +++' + DEFB 0 + RET + + + ; 16-bit division + ; in: HL= dividend + ; DE= divisor + ; out: BC= result +DIVHLDE: OR A ; clear C-Flag + LD BC,-1 ; set initial value for counter +DIVHLD1: INC BC ; increase counter + SBC HL,DE ; divide by subtraction + SBC A,0 ; test C-Flag + JR NC,DIVHLD1 ; ..and loop while more to go + RET + + + ; get ptr to BSH (Block Shift Factor) in internal lookup table + ; in: A= BLS + ; out: HL= points to BSH value +GBSHP: PUSH BC ; save BC + LD B,6 ; # entries in lookup table + LD HL,BSTBL+2 ; ptr to first BLS +GBSHP1: CP (HL) ; BLS found ? + JR Z,GBSHP2 ; ..if so, exit loop + INC HL ; else, ptr to next BLS + INC HL + INC HL + DJNZ GBSHP1 ; ..and loop +GBSHP2: DEC HL ; move ptr back (= BLM) + DEC HL ; ..and once more (= BSH) + POP BC ; restore BC + RET + + + ; get BLS (Block Size) for given BSH (Block Shift Factor) + ; in: HL= ptr to BSH (in DPB) + ; out: A= BLS, or 0x00 if no valid BSH was found +GBLS: LD B,6 ; # entries in lookup table + LD DE,BSTBL ; ptr to lookup table +GBLS1: PUSH HL ; save HL + LD A,(DE) ; get BSH from table + CP (HL) ; ..and compare + INC HL ; move pointers fwd + INC DE + JR NZ,GBLS2 ; ..if no match, jump + LD A,(DE) ; else, get BLM + CP (HL) ; ..and compare to value in DPB +GBLS2: POP HL ; restore HL + INC DE ; move table ptr fwd + JR Z,GBLS3 ; ..if match, jump + INC DE ; else move table ptr fwd + DJNZ GBLS1 ; loop till done + XOR A ; clear A (not found) + JR GBLS4 ; ..and exit +GBLS3: LD A,(DE) +GBLS4: INC HL + INC HL + INC HL + RET + + ; lookup table for related values of + ; BSH (block shift factor) / BLM (block mask) / BLS (block size) + ; 3 bytes per entry +BSTBL: DEFB 3 ; BSH= 3 + DEFB 7 ; BLM= 7 + DEFB 1 ; BLS= 1 (1 kB) + DEFB 4 ; BSH= 4 / BLM= 15 / BLS= 2 kB + DEFB 15 + DEFB 2 + DEFB 5 ; BSH= 5 / BLM= 31 / BLS= 4 kB + DEFB 31 + DEFB 4 + DEFB 6 ; BSH= 6 / BLM= 63 / BLS= 8 kB + DEFB 63 + DEFB 8 + DEFB 7 ; BSH= 7 / BLM= 127 / BLS= 16 kB + DEFB 127 + DEFB 16 + DEFB 8 ; BSH= 8 / BLM= 255 / BLS= 32 kB + DEFB 255 + DEFB 32 + + + ; get addr's of DPH and DPB for given drive number + ; in: A= drive number + ; out: DE= addr of DPH, HL= addr of DPB + ; or Z-Flag set if no drive +GDPHDPB: LD HL,(DRTBL) ; addr of DRVTBL in WSPC area + ADD A,A ; offset is 2* drive # + CALL GWRDHLA ; get 16-bit value from offset addr + LD D,H ; ..into DE + LD E,L + OR H ; addr invalid (= zero) ? + RET Z ; ..if so, exit with Z-Flag set + CALL CNVADDR ; convert to addr in WSPC + EX DE,HL ; swap regs + LD HL,10 ; offset from to addr DPB in DPH + ADD HL,DE + LD A,(HL) ; get addr + INC HL + LD H,(HL) + LD L,A ; ..and fall through, convert addr to WSPC + + + ; convert addr in B/P Bios to addr in WSPC area + ; in/out: HL= addr +CNVADDR: LD BC,(BIOSADR) ; B/P Bios page addr + OR A ; clear flags + SBC HL,BC ; calculate offset + LD BC,(WSPCBEG) ; ..and add to addr of start WSPC + ADD HL,BC + RET + + + ; print disk size to CON: (capacity in kB) + ; output as decimal with provision for 3-byte values - see ZXD21.Z80 PRBIG + ; in: A,H,L= 24-bit value + ; (Stack)= DE, AF, HL in that order +PDISKSZ: PUSH DE ; save regs + PUSH BC + EX AF,AF' ; swap AF + PUSH AF ; save + EX AF,AF' ; ..and swap back + LD B,0 + LD C,-1 ; set initial result + LD DE,86A0H ; 100,000 = 0x0186A0, set lower 2 bytes + OR A ; clear C-Flag +PDISKS1: INC C ; accumulate count + SBC HL,DE ; subtract lower 2 bytes + SBC A,1 ; ..and upper byte + JR NC,PDISKS1 ; loop till done + ADD HL,DE ; adjust underflow + ADC A,1 + CALL PHLD2 + LD DE,10000 ; print 10000's + CALL PHLD + LD DE,1000 ; print 1000's + CALL PHLD + LD DE,100 ; print 100's + CALL PHLD + LD DE,10 ; print 10's + CALL PHLD + LD A,L ; print 1's + CALL PHLD3 + POP AF ; restore AF + EX AF,AF' ; ..and swap + POP BC ; restore regs + POP DE + RET + + + ; print content of HL to CON: as decimal + ; divide HL by DE, convert remainder to ascii digit and print it + ; (similar to SYSLIB's PHLFDC/PHDC1 - see ZXD21.Z80 DECDSP) + ; in: HL= value, DE= divisor +PHLD: LD C,-1 ; set initial count + OR A ; clear C-Flag +PHLD1: INC C ; accumulate count + SBC HL,DE ; divide by subtraction + SBC A,0 + JR NC,PHLD1 ; ..and loop while more to go + ADD HL,DE ; compensate for underflow + ADC A,0 +PHLD2: EX AF,AF' ; swap AF regs (retain flags) + LD A,C ; get result (quotient) + OR A ; is it zero ? + JR NZ,PHLD3 ; ..if not, skip over + OR B ; get prior digit print flag + JR Z,PHLD4 ; ..if anything printed yet, jump + XOR A ; else, print a zero +PHLD3: ADD A,'0' ; convert to ascii + LD B,A ; remember for next loop + CALL COUT ; ..and display it +PHLD4: EX AF,AF' ; swap AF regs back + RET + + ; * + + +;::::: IMAGE FILE + + ; --- Read IMG file +RDIMG: LD DE,CPMFCB+9 ; filetype in CP/M standard FCB #1 + LD A,(DE) ; get byte + CP ' ' ; is it ? + JR NZ,RDIMG1 ; ..if not, skip over + LD HL,FTYPE ; else, point to standard filetype 'IMG' + LD BC,3 ; copy 3 bytes + LDIR +RDIMG1: LD HL,(WRKSTRT) ; start of workspace area + LD (WRKDMA),HL ; ..set as DMA buffer addr + CALL SETDMA + LD DE,CPMFCB + CALL Z3LOG ; log into given DU (eval as ZCPR3 XFCB) + CALL F$EXIST ; check file exists (Z= not found) + JR NZ,RDIMG2 ; ..if so, jump to continue + CALL E$MSG ; else, display error and exit + CALL VPRINT + DEFB 'File Not Found!' + DEFB 0 + JP EXIT + +RDIMG2: CALL F$OPEN ; open image file + JR Z,RDIMG3 ; ..if no error, jump to continue + CALL E$MSG ; else, dipslay error and exit + CALL VPRINT + DEFB "Can't Open!" + DEFB 0 + JP EXIT + + ; image file found and opened, read into memory +RDIMG3: LD HL,0 ; read record #0 + CALL R$READ ; random read from file (DE=FCB, HL=record) + JP NZ,RDIMERR + LD HL,(WRKSTRT) ; ptr workspace area (= current DMA) + LD DE,29 ; offset ZCPR Non-banked Size (at offset 29d) + ADD HL,DE ; adjust ptr + LD DE,0100H ; length of img file header + CALL ADDDHPT ; add values, DE = DE + (HL) + INC HL ; ptr fwd + INC HL + INC HL ; ZCPR Banked Size (at offset 33d) + CALL ADDDHPT ; add values + LD BC,27 ; move ptr fwd + ADD HL,BC ; ZSDOS Non-banked Size (at offset 61d) + CALL ADDDHPT ; add values + INC HL ; move ptr fwd + INC HL + INC HL ; ZSDOS Banked Size (at offset 66d) + CALL ADDDHPT ; add values + LD BC,25 ; move ptr fwd + ADD HL,BC ; B/P Bios base addr (at offset 91d) + LD C,(HL) ; get low byte + INC HL + LD B,(HL) ; ..and high byte + LD (BIOSADR),BC ; store B/P Bios page addr + EX DE,HL ; swap regs, HL= offset to Bios start in img file + ADD HL,HL ; *2 + LD A,H ; high byte in A + LD (BPOFFS),A ; store offset sector # + LD L,H ; ..and set as start value + LD H,0 + LD DE,CPMFCB + + ; read 20 sectors (20 * 128 = 2560 bytes) + LD B,20 +RDIMSEC: CALL R$READ ; read file sector (randomly, DE= FCB, HL= sector #) + JR NZ,RDIMERR ; ..if error, jump + PUSH HL ; save regs + PUSH BC + LD HL,(WRKDMA) ; get current DMA addr + LD BC,128 ; ..and increase by 128 bytes + ADD HL,BC + LD (WRKDMA),HL ; store new addr + CALL SETDMA ; ..and set as DMA buffer addr + POP BC ; restore regs + POP HL + INC HL ; next sector + DJNZ RDIMSEC ; ..loop til done + LD HL,(WRKDMA) ; get end of workspace area + LD (WRKEND),HL ; ..save + CALL CHKBP ; check for "B/P" signature string + JP C,EXIT ; ..if not found, exit + + PUSH DE + LD HL,(WRKSTRT) ; get addr start WSPC + PUSH HL + LD DE,91 ; offset to B/P Bios page addr + ADD HL,DE ; ..adjust ptr + LD E,(HL) ; get low byte + INC HL + LD D,(HL) ; ..and high byte of Bios page addr + LD HL,(BIOSADR) ; offset from file start + EX DE,HL ; swap regs + OR A ; clear flags + SBC HL,DE ; calc difference + POP DE ; addr WSPC (now in DE) + ADD HL,DE ; ..add to ptr + LD DE,10 ; ..and move another 10 bytes fwd + ADD HL,DE + LD A,(HL) ; get byte + LD (BPVERS),A ; ..and save it (Bios version #) + CALL RETUD ; currently logged drive in B, and user in C + LD (IMGDU),BC ; ..store DU: of IMG file + POP DE + LD HL,(WRKEND) ; addr of workspace end + CALL SETDMA ; set DMA transfer address (in HL) + LD HL,1 ; read sector #1 + CALL R$READ ; read file sector (DE= FCB, HL= sector #) + RET Z + + ; error while reading image file +RDIMERR: CALL E$MSG + CALL VPRINT + DEFB 'Error Reading : ' + DEFB 0 + JR PIMGFN ; display filename and close file + ; ..let return from there + + + ; ADD DE,(HL), add 16-bit value addressed by HL to DE + ; in: DE= 16-bit value + ; HL= ptr to 2nd 16-bit value + ; uses: BC, DE, HL +ADDDHPT: LD C,(HL) ; get low byte in C + INC HL ; move ptr to next byte + LD B,(HL) ; get high byte in B + EX DE,HL ; swap regs + ADD HL,BC ; add values + EX DE,HL ; ..and swap back + RET + + ; --- Write IMG file +WRIMG: LD HL,(WRKSTRT) ; addr start of WSPC + LD (WRKDMA),HL ; ..set as DMA buffer addr + CALL SETDMA + LD BC,(IMGDU) ; drive and user of IMG file + CALL LOGUD ; set DU: for following operations + LD DE,CPMFCB + CALL Z3LOG ; log DU (eval as ZCPR3 XFCB) + LD A,(BPOFFS) ; get offset sector # to start writing + LD L,A + LD H,0 + + ; write 20 records (20 * 128 = 2560 bytes) + LD B,20 +WRIMSEC: CALL F$WRITE ; write file sector (randomly, DE= FCB, HL= sector #) + JR NZ,WRIMERR ; ..if not successful, jump + PUSH HL ; save regs + PUSH BC + LD HL,(WRKDMA) ; get current DMA addr + LD BC,128 ; ..and increase by 128 bytes + ADD HL,BC + LD (WRKDMA),HL ; store new addr + CALL SETDMA ; ..and set as DMA addr + POP BC + POP HL + INC HL ; next sector + DJNZ WRIMSEC ; ..loop til done + LD HL,(WRKEND) ; addr end of workspace + CALL SETDMA ; set as DMA buffer addr + LD HL,1 ; sector #1 + CALL F$WRITE ; write to file + JR Z,CLSIMG ; ..if successful, jump to close file + + +; error while writing image file +WRIMERR: CALL F$CLOSE ; close file (DE= ptr FCB) + CALL E$MSG ; ..and display error msg + CALL VPRINT + DEFB 'Error Writing : ' + DEFB 0 + +; Display IMG filename +PIMGFN: LD DE,CPMFCB+1 ; fn in CP/M standard FCB #1 + CALL PFN3 ; display fn.ft + JP CRLF + +; --- Close IMG file +CLSIMG: CALL F$CLOSE ; close file (DE= ptr FCB) + CALL VPRINT ; ..and inform user + DEFB CR,LF,TAB,'...File Closed.' + DEFB 0 + RET + + ; * + + +;::::: MEMORY + + ; --- Read running B/P Bios from memory (using BIOS fn #30) +RDMEM: LD HL,(CPMBIOS+1) ; addr warm boot (BION fn #1) + LD L,30*3 ; adjust ptr to fn #30 + LD A,(HL) ; check byte at ptr location + CP 0C3H ; is it opcode 0xC3 (JP) ? + JP NZ,E$BPBIO ; ..if not, jump error and let return from there + CALL JUMPHL ; else "call" B/P Bios fn #30 (RETBIO) + LD (BPVERS),A ; store version of B/P Bios + LD (BIOSADR),BC ; " base addr + LD (CNFGADR),DE ; " config area addr + EX DE,HL ; swap regs (HL= ptr Config area) + CALL CHKSYS ; check for signature string + JP NZ,E$BPBIO ; ..if not found, jump error and let return from there + LD DE,(WSPCBEG) ; addr WSPC + LD L,C ; Bios page addr in HL + LD H,B + LD BC,2560 ; number of bytes + LDIR ; ..and copy + LD (WRKEND),DE ; store end of WSPC area + RET + + ; --- Write new configuration to memory, replace running system +WRMEM: LD HL,(WSPCBEG) ; addr WSPC start + LD DE,(BIOSADR) ; B/P Bios page addr + LD BC,2560 ; bytes to copy + LDIR + LD HL,(BIOSADR) ; B/P Bios page addr + LD L,21*3 ; offset to BIOS fn #21 (DEVINI, init IO devices) + CALL JUMPHL ; ..and "call" BIOS directly + CALL VPRINT + DEFB CR,LF,LF,TAB,'..New Configuration Installed..',CR,LF + DEFB 0 + RET + + ; * + + +;::::: DISK (System Tracks) + + ; --- Read System Tracks + ; and find addr's of system segments + ; in: A= drive letter (already checked it is A..P) +RDDSK: SUB 40H ; convert ascii to number + LD (DISKNO),A ; ..and store it + CALL DSKINDR ; ask user to place disk in drive + LD A,(DISKNO) ; get disk number + LD HL,(WSPCBEG) ; addr start WSPC + CALL RDSTRK ; read sys tracks into WSPC + JP C,ERREXIT ; ..if error, jump exit + LD A,(OLDDU+1) ; get previously logged drive + JP SELDSK ; ..select and let return from there + + ; --- Write System Tracks +WRDSK: LD A,(DISKNO) ; get disk number + CALL SELDSK1 ; ..select + LD BC,(SECTNO) ; counter outer loop + LD DE,(SYSSECT) ; # sectors w/ system tracks + PUSH BC ; save regs + PUSH DE + CALL BIOSTTR ; set track for subsequent write + POP BC ; restore regs + POP DE + LD A,(SCTBOOT) ; # of sectors w/ system (after boot code) + LD B,A + LD HL,(WRKSTRT) ; addr start WSPC +WRDSK1: PUSH DE ; save regs + PUSH BC + PUSH HL + LD DE,(XLTADR) ; addr XLT (sector translation table) + CALL BIOSTRN ; translate logical to physical sector + LD B,H ; ..in BC + LD C,L + CALL BIOSTSE ; set sector for subsequent write + POP BC ; addr WSPC + PUSH BC + CALL BIOSTDM ; set DMA buffer + LD C,0 + CALL BIOWRIT ; ..write one sector + OR A + JP NZ,E$WRITE ; if not successful, jump error and exit + POP HL ; addr WSPC + LD DE,128 ; ..move forward by 128 bytes (1 sector) + ADD HL,DE + POP BC ; restore regs / clear stack + POP DE + DEC B ; reduce counter + JR NZ,WRDSK2 ; ..if not finished, skip over + LD C,1 ; else, force writing + JP BIOWRIT ; ..and write final sector (returning from there) + +WRDSK2: INC C ; counter +1 + LD A,(SECTTRK) ; check if sectors/track (DPB) limit reached + CP C + JR NZ,WRDSK1 ; ..if not, write sector + INC DE ; else, increase track # + LD C,0 ; ..clear counter + PUSH DE + PUSH BC + PUSH HL + LD B,D ; track # in BC + LD C,E + CALL BIOSTTR ; ..and set track + POP HL + POP BC + POP DE + JR WRDSK1 ; loop + + + ; read system tracks + ; in: A= drive number + ; HL= addr of WSPC start + ; out: Z-Flag set if error, NZ if ok +RDSTRK: LD (WRKSTRT),HL ; store copy of WSPC addr (to work with) + CALL SELDSK1 ; select disk (A= #) + JP Z,E$SRC ; ..if error, jump error and exit + LD E,(HL) ; HL= addr of DPH + INC HL ; get addr of XLT (sector translation table) + LD D,(HL) ; in DE + LD (XLTADR),DE ; ..and store it + LD A,9 ; move ptr to DPB addr + CALL ADDHLA + LD E,(HL) ; addr of DPB in DE + INC HL + LD D,(HL) + EX DE,HL ; swap regs + LD E,(HL) ; get Sectors/Track from DPB + INC HL + LD D,(HL) + LD (SECTTRK),DE ; ..and save + LD A,12 ; move ptr to Trk Offset + CALL ADDHLA + LD E,(HL) ; get # of system tracks + INC HL + LD A,(HL) + AND A ; high byte must be zero + JP NZ,E$NOSYS ; ..if not, jump error and exit + OR E ; check if # of system tracks is zero + JP Z,E$NOSYS ; ..if so, jump error and exit + LD (SYSTRK),A ; store # of system tracks + LD HL,(SECTTRK) ; get Sectors/Track + LD DE,46 ; # of sectors (= 0x1700) + ; ##### CHECK: bpboot codes approx. 0x1700 -- 46d/0x2E sectors + LD C,0 + XOR A ; clear flags + SBC HL,DE ; enough space in one track ? + JR NC,RDSTRK2 ; ..if so, jump to continue + ADD HL,DE ; else, restore initial value + EX DE,HL ; swap regs + XOR A ; clear flags +RDSTRK1: SBC HL,DE ; divide by subtraction + INC C ; increase counter (quotient) + JR NC,RDSTRK1 ; ..more to go + ADD HL,DE ; compensate underflow + DEC C ; and correct quotient + EX DE,HL ; swap back +RDSTRK2: LD B,0 + LD A,E ; check if DE= 0 + OR D + JR Z,RDSTRK3 ; ..if so, skip + DEC DE ; else, decrease DE +RDSTRK3: LD (SECTNO),BC ; store loop counter + LD (SYSSECT),DE ; store # of sys sectors + PUSH BC ; save regs + PUSH DE + LD A,(SYSTRK) ; # of system tracks + LD DE,(SECTTRK) ; sectors/track + LD HL,0 +RDSTRK4: ADD HL,DE ; accumulate count + DEC A ; decrease counter + JR NZ,RDSTRK4 ; ..loop till done + LD DE,-45 ; adjust for boot code + ADD HL,DE + LD A,L + LD (SCTBOOT),A ; save # of sectors after boot code + CALL BIOSTTR ; set track for subsequent read + POP BC + POP DE + LD A,(SCTBOOT) ; get # of sectors + LD B,A + LD HL,(WRKSTRT) ; addr start WSPC +RDSTRK5: PUSH DE ; save regs + PUSH BC + PUSH HL + LD DE,(XLTADR) ; addr of XLT + CALL BIOSTRN ; translate sector # (log. to phys.) + LD B,H + LD C,L + CALL BIOSTSE ; set sector for subsequent read + POP BC ; restore addr in WSPC + PUSH BC + CALL BIOSTDM ; set as DMA buffer + CALL BIOREAD ; ..and read one sector + OR A + JP NZ,E$READ ; ..if error, jump error and exit + POP HL ; restore addr in WSPC + LD DE,128 ; move fwd by 128 bytes (1 sector) + ADD HL,DE + LD (WRKEND),HL ; store as WSPC end addr + POP BC ; restore regs + POP DE + DEC B ; decrease counter (# of sectors) + JR Z,RDSTRK6 ; ..if done, exit loop + INC C ; counter +1 + LD A,(SECTTRK) ; check if sectors/track (DPB) limit reached + CP C + JR NZ,RDSTRK5 ; ..if not, loop + INC DE ; else, increase track # + LD C,0 ; ..clear counter + PUSH DE + PUSH BC + PUSH HL + LD B,D ; track # in BC + LD C,E + CALL BIOSTTR ; ..and set it + POP HL + POP BC + POP DE + JR RDSTRK5 ; then start all over again +RDSTRK6: CALL CHKBP ; search for B/P signature string in WSPC + JP C,EXIT ; ..if not found, exit program + ; else, fall through + + ; --- Find System Segments + ; search for B/P Bios fn #30 RETBIO in the just loaded system + ; start addr is at known offset in WSPC + ; byte pattern: 0x01 0x00 ... 0x11 ... ... 0x21 ... ... 0x3E ... + ; LD BC,..00 LD DE,.... LD HL,.... LD A,.. + ; page addr config area dev table version + LD HL,0 +FNDSYS: LD (WRKZ3E),HL ; clear variable + LD HL,(WSPCBEG) ; addr start WSPC area + LD DE,30*3+1 ; offset to B/P Bios fn #30 RETBIO + ADD HL,DE + LD C,(HL) ; get addr of function + INC HL + LD B,(HL) + LD E,C ; ..low byte only + LD D,0 + LD HL,(WSPCBEG) ; reset ptr to start WSPC again + ADD HL,DE ; move ptr to first byte of fn +FNDSYS1: PUSH HL ; ..and save ptr + LD A,(HL) ; get byte at ptr location + CP 01H ; is it 0x01 ? (LD BC,...) + JR NZ,FNDSYS2 ; ..if not, move to next memory page + INC HL ; else, move ptr fwd + LD A,(HL) ; get byte + OR A ; is it 0x00 ? + JR NZ,FNDSYS2 ; ..if not, move to next mem page + INC HL ; else, move ptr fwd + LD A,(HL) ; get byte (high byte of possible B/P Bios page addr) + ADD A,D ; add to current offset in WSPC area + CP B ; match w/ addr of fn #30 ? + JR Z,FNDSYS3 ; ..if so, code found, jump to continue +FNDSYS2: POP HL ; else, restore ptr in WSPC + INC D ; move both ptr's fws by 0x100 bytes + INC H + LD A,D ; fn must be within first 0x600 bytes + CP 6 ; so check + JR C,FNDSYS1 ; ..if within limit, continue searching + LD HL,0 ; else, clear addr and exit + JR FNDSYS8 + + ; code signature of fn #30 found, extract data +FNDSYS3: PUSH HL ; save regs + PUSH DE + LD DE,8 ; offset to version # (LD A,..) + ADD HL,DE ; adjust ptr + LD A,(HL) ; get byte + LD (BPVERS),A ; ..and store it + POP DE + POP HL ; HL= ptr to high byte of B/P Bios page addr + LD A,(HL) ; get it + POP HL ; clear stack + LD H,A ; copy Bios page addr in HL + LD L,0 + PUSH HL ; ..and save it + + ; search for Z3ENV Environment descriptor + LD DE,(WSPCBEG) ; addr start WSPC area + LD HL,(WRKEND) ; addr end WSPC area + OR A ; clear C-Flag + SBC HL,DE ; calculate size of WSPC area + LD C,L ; ..copy to BC + LD B,H + EX DE,HL ; swap regs + LD DE,Z3ENV$ ; ptr to "Z3ENV" +FNDSYS4: LD A,(DE) ; get letter from string to search for + CPIR + JP PO,FNDSYS7 ; ..if not found, exit + PUSH HL ; else, save regs + PUSH DE + PUSH BC + LD B,4 ; number of remaining letters +FNDSYS5: INC DE ; move to next letter to search + LD A,(DE) ; ..and get it + CP (HL) ; compare with found place + JR NZ,FNDSYS6 ; ..if no match, jump + INC HL ; else, move ptr fwd + DJNZ FNDSYS5 ; ..and loop for next letter + XOR A ; set Z-Flag (= found) and fall through +FNDSYS6: POP BC ; restore regs + POP DE + POP HL + JR NZ,FNDSYS4 ; Z-Flag not set, continue searching + LD DE,-4 ; correct addr, set to beginning of Z3ENV + ADD HL,DE + LD (WRKZ3E),HL ; ..and store it +FNDSYS7: POP HL ; restore regs + OR A ; clear flags +FNDSYS8: LD (BIOSADR),HL ; store B/P Bios page addr + RET +Z3ENV$: DEFB 'Z3ENV' + + + ; search for signature string "B/P" within first 3 sectors in workspace + ; in: WRKSTRT set to start addr + ; out: if found, Z-Flag is set and C-Flag is reset (NC) + ; else display error msg and C-Flag set +CHKBP: LD HL,(WRKSTRT) ; addr start of WSPC + LD (WSPCBEG),HL ; ..retain copy + LD B,2 ; set counter (# of attempts) +CHKBP0: LD HL,(WSPCBEG) ; addr start WSPC + LD A,7EH ; offset to Config area (from sector start) + CALL ADDHLA ; adjust ptr + CALL CHKSYS ; ..and check for signature + RET Z ; if found, return + LD HL,(WSPCBEG) ; else, get addr of WSPC + LD DE,128 ; ..and move fwd by 1 sector (128 bytes) + ADD HL,DE + LD (WSPCBEG),HL ; store new addr + DJNZ CHKBP0 ; ..and loop + JP E$BPBIO ; not found, display err msg and let return from there + ; ..with C-Flag set + + +;::::: HELP + +HELP: CALL VPRINT + DEFB CR,LF,1 + DEFB 0 + CALL PPRGNAM + CALL VPRINT + DEFB 2,' - Alter parameters in a B/P Bios Image file, Boot Tracks or Memory.' + DEFB CR,LF,' The program may be interactive with screen attributes under ZCPR3' + DEFB CR,LF,' or take input from a text Configuration file.' + DEFB CR,LF,LF,'Syntax:',CR,LF,' ' + DEFB 0 + CALL PPRGNAM + CALL VPRINT + DEFB ' //',TAB,TAB,'<-- Display this message',CR,LF,' ' + DEFB 0 + CALL PPRGNAM + CALL VPRINT + DEFB TAB,TAB,'<-- Run interactively',CR,LF,LF + DEFB ' The following forms may be followed by an optional Config file',CR,LF + DEFB ' from which to draw parameters to set. There must be a space',CR,LF + DEFB ' between the first argument shown and the filename.',CR,LF,LF,' ' + DEFB 0 + CALL PPRGNAM + CALL VPRINT + DEFB ' *',TAB,TAB,'<-- Configure Memory Image',CR,LF,' ' + DEFB 0 + CALL PPRGNAM + CALL VPRINT + DEFB ' d:',TAB,TAB,'<-- Configure drive d: Boot Tracks',CR,LF,' ' + DEFB 0 + CALL PPRGNAM + CALL VPRINT + DEFB ' [du:]fn[.ft]',TAB,'<-- Configure Image File',CR,LF,' ' + DEFB 0 + CALL PPRGNAM + CALL VPRINT + DEFB ' [du:]fn[.ft] [du:]fn[.ft] <-- Configure Image file (1st ',CR,LF + DEFB ' filespec) using Config file (2nd filespec).',CR,LF + DEFB ' Default Type of Config File is .CNF.',CR,LF + DEFB 0 + + +;::::: EXIT PROGRAM +EXIT: LD SP,(STACK) ; restore stack pointer + JP 0 ; initiate warm boot + +EXIT1: CALL VPRINT + DEFB CR,LF,TAB,'.. aborted ..',CR,LF + DEFB 0 + JR EXIT + + + ; return quiet flag from ENV, or Z-Flag set if error + ; (shorter than SYSLIB's GETQUIET) +GETQFLG: LD HL,(ENVADR) ; get ENV addr + LD A,H ; check if valid (<> zero) + OR L + RET Z ; ..if not, return with Z-Flag set + LD A,28H ; offset to quiet flag + CALL ADDHLA ; ..adjust ptr + LD A,(HL) ; get flag + RET + + + ; print program name on CON: device + ; (either the actual name, or fallback to default) + ; only used by HELP +PPRGNAM: LD A,(ENVADR+1) ; get high byte of ENVPTR + OR A ; check if valid (<> zero) + JP NZ,PRTNAME ; ..if so, display actual name + ; and let return from there + CALL VPRINT ; else, display default + DEFB 'BPCNFG' + DEFB 0 + RET + + + ; #### CHECK: unreferenced code (not used) + ; print filename (?), deleting spaces + LD B,8 ; up to eight chars +UNUSED2: INC HL ; move ptr forward + LD A,(HL) ; get char + AND 7FH ; mask MSB + CP ' ' ; is it ? + CALL NZ,COUT ; ..if not, print to CON: + DJNZ UNUSED2 ; count down + RET + ; ##### + + + ; check if running under B/P Bios + ; in: HL= ptr to possible B/P Bios CONFIG area + ; out: Z-Flag set if B/P Bios, NZ= not ok +CHKSYS: PUSH HL ; save regs + DEC HL ; move ptr 6 bytes backward + DEC HL ; (signature string) + DEC HL + DEC HL + DEC HL + DEC HL + LD A,(HL) ; get byte + CP 'B' ; is it 'B' ? + JR NZ,CHKSYS1 ; ..if not, jump error + INC HL ; ptr fwd + LD A,(HL) ; get byte + CP '/' ; is it '/' ? + JR NZ,CHKSYS1 ; ..if not, jump error + INC HL ; ptr fwd + LD A,(HL) ; get byte + CP 'P' ; is it 'P' + ; ..if so, fall trhough w/ Z-Flag set +CHKSYS1: POP HL ; restore regs + RET + + + ; select disk using direct BIOS call + ; in: A= disk drive # (one-based) + ; out: Z-Flag set if error, NZ= ok +SELDSK1: DEC A ; A -1, and fall through + + ; in: A= disk drive # (zero-based) +SELDSK: LD C,A ; C= drive (0= A ... 15= P) + LD E,0 ; ##### CHECK: not needed under B/P Bios + CALL BIOSELD + LD A,H ; HL= 0 if no drive + OR L ; ..set Z-Flag (status indicator) + RET + + + ; #### CHECK: unreferenced code (not used) +UNUSED3: PUSH BC + PUSH DE + PUSH HL + CALL CPMBDOS + INC A + POP HL + POP DE + POP BC + RET + ; ##### + + +;::::: MENU SELECTION + + ; evaluate selected option, or exit program (on / ) + ; function combines manual input and reading script file (CNF) + ; in: A= max. possible option (as ascii number) + ; out: Z-Flag set if error, NZ= ok +MSELECT: INC A ; upper limit +1 + LD E,A ; ..store value + CALL VPRINT + DEFB CR,LF,LF,LF,TAB,'Enter Selection : ' + DEFB 0 +MSELCT1: CALL CFIN ; get input + CP ' ' ; is it ? + JR Z,MSELCT3 ; ..jump return + CP CR ; ? + JR Z,MSELCT3 ; ..jump return + CP CTRLC ; ? + JP Z,EXIT ; ..exit program + CP ESC ; ? + JP Z,EXIT ; ..exit program + CP '1' ; is it ascii number ? + JR C,MSELCT2 ; ..if not, jump error + CP E ; else, compare with limit + CCF ; reverse C-Flag + JR C,MSELCT2 ; ..if out of range, jump error + CALL COUT ; else, print char and return + RET +MSELCT2: LD A,BEL ; error, notify user + CALL COUT + CALL CFEVAL ; if running script, opt change to interactive mode + JR MSELCT1 ; ..and loop +MSELCT3: XOR A ; set Z-Flag + RET + + + ; get input - either from script file, or manual (CAPINE uses injected CIN) + ; *** A CENTRAL FUNCTION *** + ; out: A= char + ; Z-Flag set if , exit program if or +GETINP: CALL CAPIN ; get char in A and capitalize + CP ' ' ; is it a control char ? + CALL NC,COUT ; ..if not, echo on console + CP ESC ; ? + JR Z,GETINP1 ; ..if so, jump exit program + CP 3 ; ? +GETINP1: JP Z,EXIT ; ..if so, exit program + CP ' ' ; is it ? return w/ Z-Flag set + RET + + + ; check for and + ; in: A= char to check + ; out: Z-Flag set if true +CHRSPCR: CP ' ' ; is it a ? + RET Z ; ..if so, return w/ Z-Flag set + CP CR ; ? + RET ; return, Z-Flag is set accordingly + + + ; #### CHECK: unreferenced code (not used) +UNUSED4: PUSH HL + CALL PHL4HC ; display hex number + JR PHLDCN1 ; ... and get input + ; ##### + + + ; print HL as decimal + closing bracket + ; then get user input and convert to number + ; in: HL= 16-bit value + ; out: DE= converted number, or original value if no input + ; HL= ptr after string + ; Z-Flag set if no input +PHLDCNV: PUSH HL ; save regs + CALL PHLFDC ; display as dec +PHLDCN1: POP DE ; get orig. value in DE + CALL VPRINT + DEFB ']',TAB,': ' + DEFB 0 + CALL CINPUTL ; line input + RET Z ; ..if no input, return + JP EVAL ; else, parse input string as Bin/Oct/Dec/Hex + + + ; print 2 options the user can choose from as "[D]/E" or "D/[E]" + ; in: DE= ascii chars to display + ; Z-Flag set= "D" in brackets, NZ= "E" in brackets +PDEOPTN: CALL Z,PLBR ; ..if Z, print left bracket + LD A,D ; print char in D + CALL COUT + CALL Z,PRBR ; ..if Z, print right bracket + LD A,'/' ; print slash + CALL COUT + CALL NZ,PLBR ; ..if NZ, print left bracket + LD A,E ; print char in E + CALL COUT + RET Z ; ..if Z, return (no closing bracket) +PRBR: LD A,']' ; print right bracket + JP COUT ; ..and let return from there +PLBR: LD A,'[' ; print left bracket + JP COUT ; ..and let return from there + + + ; #### CHECK: unreferenced code (not used) +UNUSED5: CALL CINPUTL + JP EVAL ; HL points to string to be parsed for Bin/Oct/Dec/Hex + ; ##### + + + ; get line input + ; through SYSLIB's INLINE fn, with injected code to read script file + ; out: HL= ptr to string buffer + ; Z-Flag set if nothing entered +CINPUTL: LD HL,INLBUF ; set buffer addr + LD (HL),0 ; prepare for empty string ( terminator) + OR 0FFH ; echo ON + CALL INLINE ; single line editor for CON: + LD A,(HL) ; check for empty string + OR A + RET + + + ; get pointer in WSPC area + ; (used to return addr in Config area) + ; in: A= offset + ; out: HL= ptr to byte at WSPC + offset +WSPCPTR: LD HL,(WSPCBEG) ; addr start WSPC area + ; ..and fall through + + ; add A to HL (result in HL) +ADDHLA: ADD A,L ; add L + LD L,A ; store result in L + RET NC ; ..if no overflow, return + INC H ; else, increment H + RET + + + ; get word (16-bit value) indirectly + ; in: HL= base addr + ; A= offset + ; out: HL= 16-bit value at offset addr +GWRDHLA: CALL ADDHLA ; add offset + LD A,(HL) ; get low byte + INC HL ; ptr fwd + LD H,(HL) ; get high byte in H + LD L,A ; ..and low byte in L + RET + + + ; check drive letter is valid ('A'..'P') + ; in: A= letter to check + ; out: C-Flag set if error, NC= ok + ; ##### another version of this routine is implemented as CKDLTR + ; with slightly different functionality +CHKDLTR: CP 'A' ; below ascii letter 'A' ? + RET C ; ..return with C-Flag set + CP 'P'+1 ; greater than ascii letter 'P' ? + CCF ; ..reverse C-Flag and return + RET + + + ; ask user to place disk in drive + ; in: DISKNO contains disk # +DSKINDR: CALL VPRINT + DEFB CR,LF,'Place disk in drive ' + DEFB 0 + LD A,(DISKNO) ; get disk number + ADD A,40H ; ..convert to ascii for display + CALL COUT + CALL VPRINT + DEFB ': and press return to continue...' + DEFB 0 +DSKIND0: CALL CFIN ; get input (console or script file) + CP CTRLC ; is it ? + JP Z,EXIT1 ; ..if so, quit program + CP CR ; ? + JR NZ,DSKIND0 ; ..if not, loop + JP CRLF ; else, output newline and let return from there + + +;::::: ERROR MESSAGES + + ; entry points for various error messages + ; in most cases, the program is terminated after display +E$BPBIO: CALL E$MSG + CALL VPRINT + DEFB 'Not B/P Bios +++',CR,LF + DEFB 0 + SCF + RET + +E$READ: CALL VPRINT + DEFB BEL,'*** Read Error' + DEFB 0 + JR ERREXIT + +E$SRC: CALL VPRINT + DEFB BEL,'*** Bad source!' + DEFB 0 + JR ERREXIT + +E$WRITE: CALL VPRINT + DEFB BEL,'*** Write Error' + DEFB 0 + JR ERREXIT + +E$DEST: CALL VPRINT + DEFB BEL,'*** Bad destination!' + DEFB 0 + JR ERREXIT + +E$NOSYS: CALL VPRINT + DEFB BEL,'*** No System!' + DEFB 0 + JR ERREXIT + +E$OPEN: CALL VPRINT + DEFB BEL,"*** Can't open source file!" + DEFB 0 + +ERREXIT: CALL CRLF + LD HL,0 ; load HL= 0 (warm boot) + ; ..and fall through + + ; "called" as a pseudo-routine that returns to caller + ; in: HL= target addr +JUMPHL: JP (HL) ; jump to addr in HL regs + + + ; every output of an error message begins + ; with this sequence of and "+++ " +E$MSG: CALL VPRINT + DEFB CR,LF,BEL,'+++ ' + DEFB 0 + RET + + + ; print lower nybble in A as hex on CON: + ; in: A= number to display +PLOWAX: AND 00001111B ; mask off high nybble, keep lower + ADD A,90H ; conversion to hex + DAA ; (same as SYSLIB @B2HL) + ADC A,40H + DAA + JP COUT ; send to CON: and let return from there + + ; * + + +;::::: MENU 6 - CNF SCRIPT FILE + +M6CNF: CALL VPRINT + DEFB CR,LF,LF,' Enter Config File (default type = .CNF) : ' + DEFB 0 + CALL CINPUTL + LD HL,INLBUF ; ptr to input buffer + LD DE,CFFCB ; ptr to script file FCB + CALL ZFNAME ; parse specified token into an FCB + CALL CFINFT ; add standard filetype 'CNF', if necessary + CALL CFINOPN ; open file (check if exists) + JP M0MAIN + + + ; read config file (script) byte-wise + ; interpret special chars (comment, end-of-line etc.) + ; convert closing brackets and commas to + ; all other chars fall through and are returned as read +CIN: +CFIN: LD A,(CFBYTE) ; get current byte + OR A ; is it zero ? + JR Z,CINPUT ; ..if so, manual input mode is active + CALL CFINCHR ; else, get next byte from config file + JR C,CFIN ; if error occurred, loop and fall through to manual input + CP ';' ; is it a semi-colon ? + JR NZ,CFIN1 ; ..if not, jump to check of end of line + + ; comment, skip over chars until an error occurred or end of line is reached +CFIN0: CALL CFINCHR ; get next char + JR C,CFIN ; ..if error occured, loop and fall through to manual input + CP CR ; is it a ? + JR Z,CFIN ; ..if so, get next byte from config file + CP LF ; follows ? + JR NZ,CFIN0 ; ..if not, get next byte + LD A,(CFLNNO) ; else, get line counter + INC A ; ..increase it + LD (CFLNNO),A ; ..and save back + JR CFIN ; loop + + ; end of line ? +CFIN1: CP CR ; is it ? + JR Z,CFIN ; ..if so, get next byte + CP LF ; follows ? + JR NZ,CFIN2 ; ..if not, jump to check special chars + LD A,(CFLNNO) ; else, get line counter + INC A ; ..increase it + LD (CFLNNO),A ; ..and save back + JR CFIN ; loop + + ; check for special characters +CFIN2: CP ' ' ; is it ? + JR Z,CFIN ; ..if so, get next byte + CP TAB ; ? + JR Z,CFIN ; ..get next byte + CP '[' ; is it an opening bracket ? + JR Z,CFIN ; ..get next byte + CP ']' ; is it a closing bracket ? + JR Z,CFIN3 ; ..exit routine + CP ',' ; is it a comma ? + RET NZ ; ..if not, return with Z-Flag cleared +CFIN3: LD A,CR ; else return a in A + RET + + + ; get one char from console + ; (using direct call to BIOS CONIN) +CINPUT: PUSH HL + PUSH DE + PUSH BC + LD HL,(CPMBIOS+1) ; HL= warm boot addr of BIOS jump (fn #1) + LD L,3*3 ; adjust target addr to fn #3 (after 0xC3 JP) + CALL JUMPHL ; ..and "call" into BIOS + POP BC + POP DE + POP HL + RET + + + ; get next char from config file + ; in: - + ; out: byte stored in data segment + ; or A= 0 and C-Flag set if error +CFINCHR: PUSH HL ; save regs + LD HL,CFDMA ; addr DMA transfer buffer + LD A,(CFPOS) ; get last reading position + OR A ; reset flags + INC A ; ..move forward + CALL M,CFINRD ; if negative (high-bit set), read next sector + JR C,CFINCH0 ; ..if end reached, jump + LD (CFPOS),A ; else, remember reading position + CALL ADDHLA ; HL= ptr to byte in DMA buffer + LD A,(HL) ; ..get it + CP CTRLZ ; is it (EOF) ? + SCF + CCF ; clear C-Flag, set return status Ok (NC) + JR NZ,CFINCH0 ; ..if not EOF, return Ok + XOR A ; else, clear A + LD (CFBYTE),A ; ..and store zero byte + SCF ; set C-Flag (= error) +CFINCH0: POP HL ; restore regs + RET + + ; reads next sector from config file +CFINRD: PUSH HL + PUSH DE + LD HL,CFDMA ; addr DMA transfer buffer + CALL SETDMA ; ..set + LD DE,CFFCB ; local FCB + CALL Z3LOG ; ..log into DU: given in FCB + CALL F$READ ; read one sector of file sequentially + CALL NZ,CFINCLS ; close file again + POP DE + POP HL + RET + + ; open config file +CFINOPN: LD HL,CFDMA ; addr DMA transfer buffer + CALL SETDMA ; ..set + LD DE,CFFCB ; local FCB + CALL Z3LOG ; ..log into DU: given in FCB + CALL F$EXIST ; does the file exist ? + JR NZ,CFINOP0 ; ..if yes, try to open it + CALL E$MSG ; else, display msg and switch to interactive mode + CALL VPRINT + DEFB 'Not Found' + DEFB 0 +CFINERR: CALL VPRINT + DEFB '..using Console Input!',CR,LF,' [press any key to continue]' + DEFB 0 + CALL CINPUT + XOR A + LD (CFBYTE),A + RET +CFINOP0: CALL F$OPEN ; try to open config file + JR Z,CFINOP1 ; ..if ok, jump + CALL E$MSG ; else, display error + CALL VPRINT + DEFB "Can't Open" + DEFB 0 + JR CFINERR ; ..and switch to interactive mode + + ; set parameters for subsequent read +CFINOP1: LD A,1 ; line # + LD (CFLNNO),A + LD A,0FFH ; current byte + LD (CFBYTE),A + DEC A ; set byte pos in DMA buffer + LD (CFPOS),A ; ..to initiate reading next sector automatically + XOR A ; clear A + LD (CFFCB+32),A ; set sector count in FCB + RET + + ; close file +CFINCLS: LD DE,CFFCB ; local FCB + CALL Z3LOG ; ..log into DU: given in ZCPR3 FCB + CALL F$CLOSE ; and close file + XOR A + LD (CFBYTE),A + SCF ; set Carry + RET + + ; add standard file type 'CNF' if none was specified +CFINFT: LD A,(CFFCB+9) ; get first char of filetype + CP ' ' ; is it ? + JR NZ,CFINFT0 ; ..if not, skip over + LD DE,CFFCB+9 ; else, ptr to filetype in FCB + LD HL,FTYPE+3 ; ..ptr to default type 'CNF' + LD BC,3 ; copy 3 bytes + LDIR +CFINFT0: LD DE,CFFCB ; ptr to FCB + RET + + ; evaluate script file, checks if current byte is zero + ; if so, an error occured and user may switch to manual input +CFEVAL: PUSH AF ; save regs + LD A,(CFBYTE) ; get current byte + OR A ; is is zero ? + JP Z,CFEVL0 ; ..if so, jump exit + PUSH BC ; else, save other regs too + PUSH DE + PUSH HL + CALL CFINCLS ; close config file + CALL VPRINT + DEFB CR,LF,BEL,'+++ Error in : ' + DEFB 0 + LD DE,CFFCB+1 ; ptr to fn in FCB + CALL PFN3 ; print FCB-type fn.ft to CON: + CALL VPRINT + DEFB ', Line : ' + DEFB 0 + LD A,(CFLNNO) ; print line number + CALL PAFDC ; as decimal + CALL VPRINT + DEFB ' ..aborting to Keyboard..',CR,LF,' [press any key to continue]' + DEFB 0 + CALL CINPUT ; get pressed key + CP CTRLC ; is it ? + JP Z,0 ; ..if so, exit program w/ warm boot + CP ESC ; ? + JP Z,0 ; ..exit program w/ warm boot + CALL CRLF + POP HL ; restore regs + POP DE + POP BC +CFEVL0: POP AF ; restore AF + RET + + +;::::: BIOS JUMPS (for direct calls) + +; area is filled with actual jumps at runtime +; to call BIOS fn's directly +BIOSELD: JP 0 ; fn #9 SELDSK select disk +BIOSTTR: JP 0 ; fn #10 SETTRK set track +BIOSTSE: JP 0 ; fn #11 SETSEC set sector +BIOSTDM: JP 0 ; fn #12 SETDMA set buffer addr +BIOREAD: JP 0 ; fn #13 READ read one sector +BIOWRIT: JP 0 ; fn #14 WRITE write one sector + JP 0 ; fn #15 LISTST list status (not used) +BIOSTRN: JP 0 ; fn #16 SECTRN sector translation + + + +;::::::::::::::::::::::::::::::::::::::::::::::::::::: +; VLIB - 0x318C +; Z3LIB - 0x33AD +; SYSLIB - 0x3653 +; end addr 0x3A55 (begin DSEG) +;::::::::::::::::::::::::::::::::::::::::::::::::::::: + + +;::::: RAM STORAGE + + DSEG + + ; --- RAM (menu 1.1) + DEFB 0 ; not used + DEFB 0 ; not used +SELBNK: DEFB 0 ; selected RAM bank (offset in CONFIG area) + DEFB 0 ; not used + DEFB 0 ; not used + + ; --- Char IO Device (menu 2) +BAUDRT: DEFB 0 ; baud rate / max. capabilities +DEVASSG: DEFB 0 ; device assignment (current #, 2 bits IOBYT) +DEVTBL: DEFW 0 ; addr of Char IO device table (DEVCFG) +DEVLAST: DEFB 0 ; # of last/highest device as ascii +DEV1SWP: DEFB 0 ; # first device to swap + + ; --- Hard Disk (menu 4) +HDCYLNO: DEFW 0 ; # of cylinders +HDCTRLR: DEFB 0 ; SCSI/HD controller type +HDCTRL2: DEFB 0 ; " (copy) + + ; --- Drive Layout (menu 5) +DRBSH: DEFB 0 ; BSH block shift factor (from DPB) +DRNO: DEFB 0 ; # drive to configure +DRBSTBL: DEFW 0 ; ptr to internal lookup table (vector), +0 = BSH, +1 = BLM +DRDIRMX: DEFW 0 ; max. directory entries +DROFFS: DEFW 0 ; track offset (start of directory) +DRTRKS: DEFW 0 ; number of tracks (disk capacity) +DRSECTT: DEFW 0 ; sectors per track (tmp storage when iterating over HD's) +DRTBL: DEFW 0 ; addr of DRVTBL in workspace area +DR1SWP: DEFB 0 ; # first drive to swap +DRVRID: DEFB 0 ; driver ID (1= Floppy, 2= HD, 3= RAM) +ALSIZKB: DEFW 0 ; allocation size in kB (sect/trk divided by 8) + + ; --- CNF Script File +CFBYTE: DEFB 0 ; current byte +CFMENU: DEFB 0 ; indicator when entering a new menu (##### CHECK: not used?) + DEFB 0 ; not used +CFLNNO: DEFB 0 ; # line (counter) +CFPOS: DEFB 0 ; pos of current byte (in DMA buffer) +CFFCB: DEFS 24H ; local FCB of CNF script file +CFDMA: DEFS 80H ; transfer buffer + + ; 'other' +BPVERS: DEFB 0 ; B/P Bios version # +WSPCBEG: DEFW 0 ; addr begin of workspace (WSPC) +CNFGADR: DEFW 0 ; addr Config. area +BIOSADR: DEFW 0 ; addr Bios base + + DEFS 64H ; room for stack (100 bytes) +STACK: DEFW 0 ; stack storage location + + ; ..and more 'other' +RUNMODE: DEFB 0 ; program running mode (config Memory/Disk/Image) +OLDDU: DEFW 0 ; logged Drive/User at program start +IMGDU: DEFW 0 ; Drive/User of image file +INLBUF: DEFS 20H ; buffer for INLINE routine (SYSLIB single line editor) +DISKNO: DEFB 0 ; # of disk (in config mode Disk) +WRKSTRT: DEFW 0 ; addr begin of WSPC (copy) +WRKDMA: DEFW 0 ; addr of transfer buffer +WRKEND: DEFW 0 ; addr end of WSPC + + ; config mode Disk (system tracks) +SECTTRK: DEFW 0 ; sectors per track (from DPB) +XLTADR: DEFW 0 ; addr of XLT (from DPH) +SECTNO: DEFW 0 ; counter for sectors, if track capacity less than 0x1700 bytes +SYSSECT: DEFW 0 ; # of sectors containing system tracks +SCTBOOT: DEFB 0 ; # of sectors after boot code +SYSTRK: DEFB 0 ; # of system tracks +WRKZ3E: DEFW 0 ; addr of Z3ENV descriptor in WSPC +BPOFFS: DEFB 0 ; offset (in # of sectors) to start writing B/P Bios in IMG file + + END + + +;************************************************************************ +; Remarks jxl: +; BPCNFG.COM, included in available B/P Bios package(s), was dis- +; assembled and extensively commented. Labels are up to seven chars long +; to comply with M-REL standards. However, it is recommended to use SLR +; tools that support labels up to sixteen chars. +; In its current state, the compiled/linked file *almost* matches the +; original BPCNFG.COM file. Some SYSLIB routines are located at other +; absolute addresses. Apparently, a different version of SYSLIB was used +; for the original BPCNFG.COM. Reproducing an exactly matching copy was +; not possible. However, only the order of routines within SYSLIB seem +; to have changed, not their code/functionality. (see BPCNFG.SYM) +; +; The program is the most complex of tools distributed with B/P Bios. +; It supports configuration of the running system in memory, of an image +; file, and of system tracks; requiring an exhaustive tool chest (and +; code). Configuration can be done manually/interactively or using a +; script file. Programmatically, this has been intertwined, i.e. user +; input and script input are handled in the same routine. Therefore, a +; local implementation replaces SYSLIB's CIN routine, letting all calls +; go through that local routine which can read console and file input. +; +; From the structure and coding styles (let alone the size!) it can +; be concluded, that the original code was divided up into several +; files, worked on by different persons. As a byproduct of this approach +; (and the technical limitations in those days), some unreferenced code +; portions were found. Those are marked with "#####" in the comment, as +; well as some other places that could be optimised. Of course, further +; code refactoring would be possible. +; Similar patterns can be found for every menu displayed on screen: +; Display, configure, support functions, and messages/strings. The +; source code above is structured accordingly, also attemting to use +; a common naming scheme for labels. It seems very likely that first +; .REL files were produced for the different code portions before +; linking them together. Not exposing all labels as public gives more +; freedom in naming them. To provide the source code in its entirety, +; for now it was not split up. Perhaps in a later version... +;************************************************************************ diff --git a/Source/BPBIOS/UTIL/bpswap.z80 b/Source/BPBIOS/UTIL/bpswap.z80 new file mode 100644 index 00000000..a966b9b9 --- /dev/null +++ b/Source/BPBIOS/UTIL/bpswap.z80 @@ -0,0 +1,483 @@ + TITLE "Swap drives under B/P Bios" +;************************************************************************ +;* B P S W A P * +;* Swap two drive letters in a running B/P Bios system * +;* by Harold F. Bower and Cameron W. Cotrill * +;*----------------------------------------------------------------------* +;* Disassembly: jxl Dec 2024 * +;* public release 1.0 Apr 2025 * +;* see remarks at the end * +;*----------------------------------------------------------------------* +;* LINK with Version 4 libraries: VLIB, Z3LIB, SYSLIB * +;* * +;* A>Z80ASM BPSWAP/RS * +;* A>SLRNK BPSWAP/N,/A:100,/D:0854,BPSWAP,VLIBS/S,Z3LIBS/S,SYSLIBS/S,/E * +;************************************************************************ + +VER EQU 10 +REV EQU ' ' + +DATE MACRO + DEFB '31 Aug 92' + ENDM + + +CTRLC EQU 03H ; Control-C character +BEL EQU 07H ; Bell character +TAB EQU 09H ; Tab character +LF EQU 0AH ; Line Feed character +CR EQU 0DH ; Carriage Return character + +CPMBIOS EQU 0 ; CP/M BIOS warm boot (JP) +CPMBDOS EQU 5 ; CP/M BDOS entry point (JP) +CPMFCB EQU 5CH ; CP/M standard FCB #1 (+1 filename, +9 filetype) +CPMDMA EQU 80H ; CP/M standard DMA buffer + + +; From VLIB Get.. + EXTRN VPRINT, Z3VINIT + +; From Z3LIB Get.. + EXTRN GETNAME, PRTNAME, WHRENV + +; From SYSLIB Get.. + EXTRN CRLF, CAPINE, COUT + + +;::::: PROGRAM START + + ORG 100H + CSEG + + +BPSWAP: JP START ; bypass header + DEFB 'Z3ENV' ; this is a ZCPR3 utility + DEFB 1 ; show external environment + +ENVADR: DEFW 0 ; addr of Z3 environment + +START: LD HL,(CPMBDOS) ; ##### BUG: should be CPMBDOS+1 ? + CALL WHRENV ; find Z3 Environment Descriptor + LD (ENVADR),HL ; store addr + CALL Z3VINIT ; ..and init for Z3LIB routines + CALL GETNAME ; get actual program name + CALL GQFLAG + AND A ; running in quiet mode ? + JR NZ,START0 ; ..if so, skip over + CALL VPRINT + DEFB 1,'B/P Drive Swap',2,' V',VER/10+'0','.',VER MOD 10 + '0',', ' + DATE + DEFB CR,LF + DEFB 0 + +START0: LD (STACK),SP + LD SP,STACK + + ; get first token from command line (in FCB #1) + LD A,(CPMFCB+1) ; get char + CP '/' ; is this a help request ? + JP Z,HELP ; ..if so, show help screen + LD HL,(CPMBIOS+1) ; get warm boot addr (BIOS fn #1) + LD L,30*3 ; adjust ptr to fn #30 + LD A,(HL) ; check byte at ptr location + CP 0C3H ; is it opcode 0xC3 (JP) ? + JR NZ,E$BPBIO ; ..if not, jump error and exit + CALL JUMPHL ; else, "call" B/P Bios fn #30 (RETBIO) + LD (BPBASE),BC ; store B/P Bios base addr + LD HL,-6 ; move ptr 6 bytes backward + ADD HL,DE ; (signature string) + LD A,(HL) ; get byte + CP 'B' ; is it 'B' ? + JR NZ,E$BPBIO ; ..if not, error and exit + INC HL ; ptr fwd + LD A,(HL) ; get byte + CP '/' ; is it '/' ? + JR NZ,E$BPBIO ; ..if not, error and exit + INC HL ; ptr fwd + LD A,(HL) ; get byte + CP 'P' ; is it 'P' ? + JR Z,EVALCMD ; ..if so, jump to continue + ; else, fall through (error and exit) + +E$BPBIO: CALL VPRINT + DEFB CR,LF,BEL,'+++ Not B/P Bios ... aborting +++',CR,LF + DEFB 0 + JP EXIT + + + ; evaluate command line +EVALCMD: LD HL,CPMDMA ; ptr to standard DMA buffer (holds command line) + LD A,(HL) ; get length of first token + INC HL ; +1 + CALL ADDHLA ; move ptr fwd + LD (HL),0 ; set terminator + LD HL,CPMDMA+1 ; set ptr to start of string + CALL FINDDRV ; find letter of first drive + JR C,RUNIMOD ; ..if invalid/not found, switch to interactive mode + LD (DRV1ST),A ; else, store # of first drive + LD A,(HL) ; get following byte + CALL EVALSEP ; is it a separator char ? + JP C,M$ABORT ; ..if not, abort program + CALL FINDDRV ; find letter of second drive + JR C,RUNIM0 ; ..if invalid/not found, switch to interactive mode + LD (DRV2ND),A ; else, store # of second drive + LD A,(HL) ; get following byte + CALL EVALSEP ; is it a separator char ? + JP C,M$ABORT ; ..if not, abort program + JR SWAPDRV ; else, jump to continue + + + ; run in interactive mode +RUNIMOD: CALL VPRINT + DEFB ' First Drive to Swap [A..P] : ' + DEFB 0 + CALL CAPINE ; get input + CALL CRLF + CP CTRLC ; is it ? + JP Z,M$ABORT ; ..if so, abort program + CALL EVALDRV ; check if drive letter is valid (A..P) + JR C,RUNIMOD ; ..if not, loop ask for new input + LD (DRV1ST),A ; else, store drive # +RUNIM0: CALL VPRINT + DEFB ' Second Drive to Swap [A..P] : ' + DEFB 0 + CALL CAPINE ; get input + CALL CRLF + CP CTRLC ; is it ? + JP Z,M$ABORT ; ..if so, abort program + CALL EVALDRV ; check if drive letter is valid (A..P) + JR C,RUNIM0 ; ..if not, loop ask for new input + LD (DRV2ND),A ; else, store drive # + + +;::::: PROCESS + +SWAPDRV: LD HL,(BPBASE) ; get B/P Bios base addr + LD L,22*3 ; adjust ptr to fn #22 (DRVTBL) + CALL JUMPHL ; ..and "call" fn + PUSH HL ; save ptr to DRVTBL + LD A,(DRV1ST) ; get # of first drive + ADD A,A ; *2 for 16-bit entries + CALL ADDHLA ; ..and move ptr fwd + EX DE,HL ; swap regs + POP HL ; restore ptr to DRVTBL + LD A,(DRV2ND) ; get # of second drive + ADD A,A ; *2 + CALL ADDHLA ; ..and move ptr fwd + + ; DE= addr DPH first drive + ; HL= addr DPH second drive + LD C,(HL) ; swap addr's in DRVTBL using + LD A,(DE) ; regs DE, HL as pointers + LD (HL),A ; and regs A, C holding bytes to copy + LD A,C + LD (DE),A + INC HL + INC DE + LD C,(HL) + LD A,(DE) + LD (HL),A + LD A,C + LD (DE),A + LD HL,0 + LD (PDRVVCT),HL ; init new Drive Vector (pos) with 0x0000 + DEC HL + LD (NDRVVCT),HL ; init new Drive Vector (neg) with 0xFFFF + LD HL,(ENVADR) ; get ENV addr + LD DE,52 ; offset to Drive Vector + ADD HL,DE ; move ptr + PUSH HL ; ..and save it + LD E,(HL) ; get Drive Vector in DE + INC HL + LD D,(HL) + LD A,(DRV1ST) ; get # of first drive + CALL MKDRMSK ; get bit mask for first drive + LD C,L ; ..and move it to BC + LD B,H + LD A,(DRV2ND) ; get # of second drive + CALL MKDRMSK ; get bit mask for second drive + EX DE,HL ; ..and move it to DE + CALL MKVCMSK ; update new Drive Vector for first drive + PUSH BC ; swap BC and DE + PUSH DE + POP BC + POP DE + CALL MKVCMSK ; update new Drive Vector for second drive + + ; (Stack) = addr of Drive Vector in ENV - PUSH HL + ; HL= current Drive Vector, DE= bit mask first drive, BC= bit mask second drive + EX DE,HL ; swap regs (save current Drive Vector in DE) + ADD HL,BC ; add/merge bit masks + EX (SP),HL ; put merged mask on stack - used by SWAPDRX + ; get addr of Drive Vector in ENV + PUSH HL ; ..and save it + EX DE,HL ; swap regs back (current Drive Vector in HL) + LD BC,(PDRVVCT) ; get new Drive Vector (pos) + LD DE,(NDRVVCT) ; and (neg) + LD A,L ; low byte of current Drive Vector + AND E ; reset bit (neg) + OR C ; set bit (pos) + LD E,A ; ..and store result in E + LD A,H ; high byte of current Drive Vector + AND D ; reset bit (neg) + OR B ; set bit (pos) + LD D,A ; ..and store result in D + POP HL ; get addr of Drive Vector in ENV + LD (HL),E ; store new Drive Vector (low byte) + INC HL + LD (HL),D ; ..and high byte + CALL GQFLAG + OR A ; check quiet flag + JR NZ,SWAPDRX ; ..if quiet mode, skip over + CALL VPRINT + DEFB ' ...Drives ' + DEFB 0 + LD A,(DRV1ST) ; get # of first drive + ADD A,'A' ; make ascii letter + CALL COUT ; ..and display it + CALL VPRINT + DEFB ': and ' + DEFB 0 + LD A,(DRV2ND) ; get # of second drive + ADD A,'A' ; make ascii letter + CALL COUT ; ..and display it + CALL VPRINT + DEFB ': exchanged',CR,LF + DEFB 0 + + ; exit function +SWAPDRX: POP DE ; restore merged bit masked 1st+2nd drive + LD C,37 ; BDOS fn #37 Reset Drive(s) + CALL CPMBDOS + JP EXIT + + +M$ABORT: CALL VPRINT + DEFB ' ...aborting...',CR,LF + DEFB 0 + JP EXIT + + +;::::: HELP SCREEN + +HELP: CALL VPRINT + DEFB CR,LF,1 + DEFB 0 + CALL PPRGNAM + CALL VPRINT + DEFB 2,' exchanges the logical definition ' + DEFB 'of two physical disk drives',CR,LF + DEFB ' or partitions. Drive letters must be ' + DEFB 'in the range of "A"-"P".',CR,LF + DEFB ' The program is re-executable under ' + DEFB 'ZCPR with the "GO" command',CR,LF,LF + DEFB ' Syntax: ' + DEFB 0 + CALL PPRGNAM + CALL VPRINT + DEFB ' [:] [:]',CR,LF,LF + DEFB ' Examples:',CR,LF,' ' + DEFB 0 + CALL PPRGNAM + CALL VPRINT + DEFB ' A: E: - Exchange E drive with A',CR,LF + DEFB ' ' + DEFB 0 + CALL PPRGNAM + CALL VPRINT + DEFB ' D,H - Exchange D drive with H',CR,LF + DEFB ' ' + DEFB 0 + CALL PPRGNAM + CALL VPRINT + DEFB ' // - display this message',CR,LF + DEFB 0 + + +;::::: EXIT PROGRAM + +EXIT: LD SP,(STACK) ; restore stack + RET ; ..and return to system + + +;::::: SUPPORT FUNCTIONS + + ; "called" as a pseudo-routine that returns to caller + ; in: HL= target addr +JUMPHL: JP (HL) ; jump to addr in HL regs + + + ; parse nul-terminated string skipping separator chars + ; then fall through and check/convert drive letter + ; in: HL= ptr to string + ; out: A= drive number (or if invalid letter) + ; HL= ptr to byte after end of string + ; C-Flag set if (end of string) reached +FINDDRV: LD A,(HL) ; get byte + INC HL ; move ptr fwd + OR A ; check if (zero) = end of string + SCF ; prepare status indicator (C-Flag set) + RET Z ; ..if byte, return + CALL EVALSEP ; check if byte is a separator + JR NC,FINDDRV ; ..if so, get next char + ; else, fall through and check if letter is valid + + + ; evaluate if letter is a valid drive (A..P) and return as number + ; in: A= letter to check + ; out: A= drive number + ; C-Flag set if error, NC= ok +EVALDRV: CP 'A' ; is it lower than ascii 'A' ? + RET C ; ..return with C-Flag already set + CP 'P'+1 ; is it greater than ascii 'P' ? + CCF ; ..reverse C-Flag to set correct status + RET C ; and return + SUB 'A' ; else, convert to number + RET + + + ; evaluate char in register A whether it is a separator + ; (space, comma, colon, tab, zero) + ; in: A= char + ; out: C-Flag set if not separator, NC= char is separator +EVALSEP: CP ' ' ; is it ? + RET Z + CP ',' ; Comma ? + RET Z + CP ':' ; Colon ? + RET Z + CP TAB ; ? + RET Z + OR A ; (zero) ? + RET Z + SCF ; set C-Flag + RET + + + ; make bit mask for specified drive # + ; position of 1-bit represents drive in 16-bit word (similar to Drive Vector) + ; in: A= drive number + ; out: HL= bit mask +MKDRMSK: LD HL,1 ; set bit 0 + INC A ; ahead of loop, increase A +MKDRMS0: DEC A ; decrease A + RET Z ; ..if zero, finished + ADD HL,HL ; *2 (shift 1-bit to next position) + JR MKDRMS0 ; loop + + + ; make bit masks for new Drive Vector + ; maintaining a positive (bits set) map, and a negate version (bits reset) + ; in: HL= current Drive Vector (from ENV) + ; BC= bit mask w/ old position + ; DE= bit mask w/ new position +MKVCMSK: PUSH BC ; save regs + LD A,B + AND H ; mask high byte + LD B,A ; ..and store result back in B + LD A,C + AND L ; mask low byte + OR B ; check if invalid (= zero), ie. not mapped in Vector + POP BC ; restore regs + JR Z,MKVCMS0 ; if invalid drive, jump + + ; drive at new position exists in Drive Vector - set bit + PUSH HL + LD HL,(PDRVVCT) + LD A,H ; high byte first + OR D ; ..merge with new position + LD H,A ; and store result back in H + LD A,L ; low byte + OR E ; ..merge with new position + LD L,A ; and store result back in L + LD (PDRVVCT),HL ; save final result + POP HL + RET + + ; drive at new position does _not_ exist in Drive Vector - reset bit +MKVCMS0: PUSH HL + LD HL,(NDRVVCT) + LD A,D ; get high byte of new position + CPL ; invert it + AND H ; reset corresponding bit + LD H,A ; ..and store result in H + LD A,E ; get low byte of new position + CPL ; invert it + AND L ; reset corresponding bit + LD L,A ; ..and store result in L + LD (NDRVVCT),HL ; save final result + POP HL + RET + + + ; get Quiet Flag from Z3 Environment + ; in: - + ; out: A= Quiet Flag, defaults to A= 0 (not quiet) +GQFLAG: LD HL,(ENVADR) ; get ENV addr + LD A,H ; check if invalid (= zero) + OR L + RET Z ; ..if so, return + LD A,40 ; else, move ptr forward + CALL ADDHLA ; to Quiet Flag + LD A,(HL) ; get value + RET ; ..and return + + + ; add A to HL (result in HL) +ADDHLA: ADD A,L ; add L + LD L,A ; store result in L + RET NC ; ..if no overflow, return + INC H ; else, increment H + RET + + + ; print program name on CON: device + ; (either the actual name, or fallback to default) + ; only used by HELP +PPRGNAM: LD A,(ENVADR+1) ; get high byte of ENVPTR + OR A ; check if valid (<> zero) + JP NZ,PRTNAME ; ..if so, display actual name + ; and let return from there + CALL VPRINT ; else, display default + DEFB 'BPSWAP' + DEFB 0 + RET + + +;::::::::::::::::::::::::::::::::::::::::::::::::::::: +; VLIB - 0x0536 +; Z3LIB - 0x0757 +; SYSLIB - 0x0805 +; end addr 0x0854 (begin DSEG) +;::::::::::::::::::::::::::::::::::::::::::::::::::::: + + +;::::: RAM STORAGE + + DSEG + +PDRVVCT: DEFW 0 ; new Drive Vector + ; (positive notation, bit _set_ for existing drives) +NDRVVCT: DEFW 0 ; new Drive Vector + ; (negative notation, bits _reset_ for existing drives) +BPBASE: DEFW 0 ; B/P Bios base addr +DRV1ST: DEFB 0 ; # of first drive +DRV2ND: DEFB 0 ; # of second drive + + DEFS 40H ; room for stack +STACK: DEFW 0 ; stack storage location + + END + + +;************************************************************************ +; Remarks jxl: +; BPSWAP.COM, included in available B/P Bios package(s), was dis- +; assembled and extensively commented. Labels are up to seven chars long +; to comply with M-REL standards. However, it is recommended to use SLR +; tools that support labels up to sixteen chars. +; In its current state, the compiled/linked file matches exactly the +; original BPSWAP.COM, i.e. no changes to the source were made. There +; seems to be one bug (marked with "##### BUG") at the beginning of the +; program. +;************************************************************************ diff --git a/Source/BPBIOS/UTIL/bpsysgen.z80 b/Source/BPBIOS/UTIL/bpsysgen.z80 new file mode 100644 index 00000000..aebf8fe0 --- /dev/null +++ b/Source/BPBIOS/UTIL/bpsysgen.z80 @@ -0,0 +1,636 @@ + TITLE "Write B/P Bios System to system tracks of a disk" +;************************************************************************ +;* B P S Y S G E N * +;* Copy B/P Bios based Operating System to system tracks * +;* by Harold F. Bower and Cameron W. Cotrill * +;*----------------------------------------------------------------------* +;* Disassembly: jxl Dec 2024 * +;* public release 1.0 Apr 2025 * +;* see remarks at the end * +;*----------------------------------------------------------------------* +;* LINK with Version 4 libraries: VLIB, Z3LIB, SYSLIB * +;* * +;* A>Z80ASM BPSYSGEN/RS * +;* A>SLRNK BPSYSGEN/N,/A:100,/D:08CD,BPSYSGEN,Z3LIBS/S,SYSLIBS/S,/E * +;************************************************************************ + +VER EQU 10 +REV EQU ' ' + +DATE MACRO + DEFB '31 Aug 92' + ENDM + + +CTRLC EQU 03H ; Control-C character +BEL EQU 07H ; Bell character +LF EQU 0AH ; Line Feed character +CR EQU 0DH ; Carriage Return character + +CPMBIOS EQU 0 ; CP/M BIOS warm boot (JP) +CPMBDOS EQU 5 ; CP/M BDOS entry point (JP) +CPMFCB EQU 5CH ; CP/M standard FCB #1 (+1 filename, +9 filetype) +CPMFCB2 EQU 6CH ; CP/M standard FCB #2 + +; From Z3LIB Get.. + EXTRN GETNAME, PRTNAME, Z3INIT, WHRENV + +; From SYSLIB Get.. + EXTRN PUTUD, GETUD, SUA, EPRINT, CRLF, CAPINE, CIN, COUT + + +;::::: PROGRAM START + + ORG 100H + CSEG + + +BPSYSGEN: JP START ; bypass header + DEFB 'Z3ENV' ; this is a ZCPR3 utility + DEFB 1 ; show external environment + +ENVADR: DEFW 0 ; addr of Z3 environment + +START: LD HL,(CPMBDOS+1) ; BDOS entry as starting point for Z3ENV search + CALL WHRENV ; get Z3 Environment + LD (ENVADR),HL ; ..store it + CALL Z3INIT ; init ENV ptr for Z3LIB modules + CALL GETNAME ; get actual program name + CALL GETQFLG ; check ENV quiet flag + AND A ; zero means 'verbose' i.e. not quiet + JR NZ,START1 ; ..if quiet mode, skip msg +START0: CALL EPRINT + DEFB 'B/P SYSGEN Utility V',VER/10+'0','.',VER MOD 10 + '0',REV + DATE + DEFB CR,LF,LF + DEFB 0 + +START1: CALL PUTUD ; currently logged in drive/user + LD HL,RESDISK ; prepare exit with resetting disk system + PUSH HL ; by putting addr of 'RESDISK' on stack + LD HL,(CPMBIOS+1) ; get BIOS entry addr + LD A,8*3 ; move forward to fn #9 SELDSK + CALL ADDHLA + LD DE,BIOSELD ; ptr to target addr + LD BC,8*3 ; bytes to copy (8 JP instructions, 3 bytes each) + LDIR ; ..copy + + + ; Evaluate command line (if invalid parameters, switch to interactive mode) +EVALCMD: LD HL,CPMFCB ; set ptr to standard FCB #1 + LD A,(HL) ; get drive + LD (SRCDRV),A ; ..and store it (SRC) + INC HL ; move ptr forard + LD A,(HL) ; get byte/char + CP '/' ; is this a help request ? + JP Z,HELP ; ..if so, jump display help + ; ..and quit (addr of exit routine on stack) + + ; syntax: BPSYSGEN [d:]fn[.ft] [d:] + ; drive #1 = source, drive #2 = destination + LD A,(CPMFCB2) ; get first byte of standard FCB #2 + LD (DSTDRV),A ; store drive # (DEST) + LD (DSTDR2),A ; ..and a copy (as indicator for cmdline input) + LD B,A ; remember value + LD A,(HL) ; get first char of filename in FCB #1 + CP ' ' ; is it ? + JP NZ,SRCRD0 ; ..if not, jump read sys file + LD A,B ; else, restore char (from FCB #2) + AND A ; is it ? + JP NZ,SRCREAD ; ..if not, jump read sys tracks + ; else, no source specified in command line + ; (switch to interactive mode) + LD A,(SRCDRV) ; get source drive number + LD (DSTDRV),A ; ..and overwrite destination drive number + + +;::::: SOURCE DRIVE + + ; interactive mode +SRCINP: CALL EPRINT + DEFB 'Source Drive (CR to skip)? ' + DEFB 0 + CALL CAPINE ; get user input + CALL CRLF + CP CR ; is it ? + JP Z,SRCRD1 ; ..if so, skip + SUB 40H ; else, convert ascii to number + LD (SRCDRV),A ; ..and store it + CALL EPRINT + DEFB 'Place source disk in drive ' + DEFB 0 + LD A,(SRCDRV) ; get source drive number + ADD A,40H ; convert to ascii + CALL COUT ; ..and display it + CALL EPRINT + DEFB ': and press return to continue...' + DEFB 0 +SRCINP0: CALL CIN ; get input + CP CTRLC ; is it ? + RET Z ; ..if so, return + CP CR ; ? + JR NZ,SRCINP0 ; ..if not, loop ask for new input + CALL CRLF + + + ; start reading +SRCREAD: CALL RDTRACK ; read system tracks of source disk + JR SRCRD1 ; ..and skip over +SRCRD0: CALL RDFILE ; read system file +SRCRD1: CALL CHKSYS ; check if a valid system was loaded/read + ; (fn _not_ implemented, simply returns) + JP NZ,E$NOSYS ; ..if not, jump error and exit + LD A,(DSTDRV) ; get # of destination disk + AND A + JP NZ,DSTINP0 ; ..if not empty (= zero), jump to continue + ; else, fall through and ask user + + +;::::: DESTINATION DRIVE + + ; interactive mode +DSTINP: CALL EPRINT + DEFB CR,LF,'Destination Drive (^C quits)? ' + DEFB 0 + CALL CAPINE ; get user input + CP CTRLC ; is it ? + RET Z ; ..if so, return + SUB 40H ; else, convert ascii to number + LD (DSTDRV),A ; ..and store it + CALL CRLF +DSTINP0: LD A,(DSTDR2) ; get copy of # destination disk + AND A ; check if valid + JR NZ,DSTWRIT ; ..if so, running in command line mode + ; ..continue writing to destination immediately + ; else, fall through and ask user for input + CALL EPRINT + DEFB 'Place destination disk in drive ' + DEFB 0 + LD A,(DSTDRV) ; get destination drive number + ADD A,40H ; convert to ascii + CALL COUT ; ..and display it + CALL EPRINT + DEFB ': and press return to continue...' + DEFB 0 +DSTINP1: CALL CIN ; get input + CP CTRLC ; is it ? + RET Z ; ..if so, return + CP CR ; ? + JR NZ,DSTINP1 ; ..if not, loop ask for new input + CALL CRLF + + + ; start writing + ; exit through "RET", addr of RESDISK routine is on stack +DSTWRIT: CALL WRTRACK + CALL GETQFLG + AND A ; check if quiet flag is set + RET NZ ; ..if not (= verbose), exit program + LD A,(DSTDR2) ; else, get copy of # dest. disk (indicator cmdline mode) + AND A ; check if valid + RET NZ ; ..if not, exit program + JP DSTINP ; else, loop ask for input + + + ; initiate a reset of disk system when returning to system +RESDISK: LD C,13 ; BDOS fn #13 (reset disk system) + CALL CPMBDOS + JP GETUD ; set Drive/User and let return from there + + +;::::: HELP SCREEN + +HELP: CALL PRGNAME + CALL EPRINT + DEFB ' Places a copy of the operating ' + DEFB 'system onto the system',CR,LF + DEFB ' tracks of a drive on the system.',CR,LF,LF + DEFB ' Syntax: ' + DEFB 0 + CALL PRGNAME + CALL EPRINT + DEFB ' [DIR:[Ufn.Ft]] [D:]',CR,LF,LF + DEFB ' Examples:',CR,LF,LF + DEFB ' ' + DEFB 0 + CALL PRGNAME + CALL EPRINT + DEFB ' - Execute in Interactive Mode',CR,LF + DEFB ' ' + DEFB 0 + CALL PRGNAME + CALL EPRINT + DEFB ' A: - Prompt for Source, ' + DEFB 'Place System onto A',CR,LF + DEFB ' ' + DEFB 0 + CALL PRGNAME + CALL EPRINT + DEFB ' B:ZSDOS64.COM - Get System from File, ' + DEFB 'Prompt for Drive',CR,LF + DEFB ' ' + DEFB 0 + CALL PRGNAME + CALL EPRINT + DEFB ' A: B: - Copy System from Drive A ' + DEFB 'to Drive B',CR,LF + DEFB ' ' + DEFB 0 + CALL PRGNAME + CALL EPRINT + DEFB ' // - display this help',CR,LF + DEFB 0 + RET + + +;::::: SUPPORT FUNCTIONS + + ; get Quiet Flag from Z3 Environment + ; in: - + ; out: A= Quiet Flag, defaults to A= 0 (not quiet) +GETQFLG: LD HL,(ENVADR) ; get local ENVPTR + LD A,H ; check if invalid (= zero) + OR L + RET Z ; ..if so, return + LD A,40 ; else, move ptr forward + CALL ADDHLA ; to Quiet Flag + LD A,(HL) ; get value + RET ; ..and return + + + ; print program name on CON: device + ; (either the actual name, or fallback to default) + ; only used by HELP +PRGNAME: LD A,(ENVADR+1) ; get high byte of ENVPTR + OR A ; check if valid (<> zero) + JP NZ,PRTNAME ; ..if so, display actual name + ; and let return from there + CALL EPRINT ; else, display default + DEFB 'BPSYSGEN' + DEFB 0 + RET + + + ; Read system tracks - source +RDTRACK: LD A,(SRCDRV) ; get source drive + CALL SELDRV ; and select it + JP Z,E$SRC ; ..if error, jump + LD (SRCDPH),HL ; store addr of DPH + LD A,10 ; move forward to DPB addr + CALL ADDHLA ; at DPH+10 + LD E,(HL) ; get DPB addr in DE + INC HL + LD D,(HL) + EX DE,HL ; swap regs + LD (SRCDPB),HL ; ..and store DPB addr + LD E,(HL) ; get sectors per track in DE + INC HL ; at DPB+0 + LD D,(HL) + LD (SECTTRK),DE ; store value + LD A,12 ; move forward to track offset + CALL ADDHLA ; (beginning of directory) at DPB+13 + LD E,(HL) ; get track offset in DE + INC HL + LD D,(HL) + LD A,D ; check upper nybble + AND A ; is it zero ? + JP NZ,RDTRK0 ; ..if not, jump to adjust + OR E ; check lower nybble + JP Z,E$NOSYS ; ..if also zero, jump to error and exit + CP 4 ; check upper limit for # of system tracks + JR C,RDTRK1 ; ..if within boundaries, skip over +RDTRK0: LD DE,2 ; set (default) # of system tracks + +RDTRK1: LD B,E ; trk offset in B (counter) + LD DE,(SECTTRK) ; get sect/trk + LD HL,0 ; set initial value +RDTRK2: ADD HL,DE ; multiply by addition + DJNZ RDTRK2 ; loop till done + XOR A ; nullify A + OR H ; check if H is zero + JP NZ,E$NOSYS ; ..if not, jump error and exit + PUSH HL ; save regs + LD BC,0 + CALL BIOSTTR ; set track # 0 + POP HL ; restore regs + LD C,H ; move # of sectors containing system + LD B,L ; to BC (as counter) + LD DE,0 ; set intial value + LD HL,FILEBUF ; set target addr to file buffer + ; (at 0x0900, page-aligned after end of program) + +RDTRK3: PUSH DE ; save regs + PUSH BC + PUSH HL + LD HL,(SRCDPH) ; get addr of DPH + LD E,(HL) ; get skew table ptr in DE + INC HL + LD D,(HL) + CALL BIOSTRN ; translate logical sector # in BC + LD B,H ; move physical sector # to BC + LD C,L + CALL BIOSTSE ; ..and set (physical) sector + POP BC ; restore target addr + PUSH BC + CALL BIOSTDM ; set as DMA buffer addr + CALL BIOREAD ; read one sector + OR A ; check for error (A <> 0) + JP NZ,E$READ ; ..if error, jump + POP HL ; restore target addr + LD DE,128 ; increase by 128 bytes (1 sector) + ADD HL,DE + POP BC ; restore regs / clear stack + POP DE + DEC B ; decrease counter + RET Z ; ..if finished, return + INC C + LD A,C + AND 00000011b ; mask lower 2 bits + LD A,'.' + CALL Z,COUT ; display progress every 4 sectors (0.5 kB) + LD A,(SECTTRK) + CP C ; max. # sect/trk reached ? + JR NZ,RDTRK3 ; ..if not, loop + INC DE ; increase trk counter + LD C,0 ; reset sect counter + PUSH DE ; save regs + PUSH BC + PUSH HL + LD B,D ; copy trk # in BC + LD C,E + CALL BIOSTTR ; ..and set track # + POP HL ; restore regs + POP BC + POP DE + JR RDTRK3 ; loop + + + ; Read system file (img) - source +RDFILE: LD A,(ENVADR+1) ; get base addr of ENV + AND A ; check if invalid (= zero) + JR Z,RDFIL0 ; ..if no ENV, skip over + LD A,(CPMFCB+0DH) ; else, get user no from standard FCB #1 + CALL SUA ; ..and log in +RDFIL0: LD DE,CPMFCB ; set ptr to standard FCB #1 + LD C,15 ; BDOS fn #15 Open File + CALL BDOSSV + JP Z,E$SOPEN + LD HL,32 ; ptr to current record + ADD HL,DE + LD (HL),16 ; set # of current record + ; (skip 16 records = 2kB, MOVSYS boot loader code) + LD HL,FILEBUF-128 ; set addr of file buffer (-128 ahead of loop) + +RDFIL1: LD A,128 ; move forward by 128 bytes (1 sector) + CALL ADDHLA + EX DE,HL ; swap regs + LD C,26 ; BDOS fn #26 Set DMA Address + CALL BDOSSV + EX DE,HL ; swap regs back + LD C,20 ; BDOS fn #20 Read Sequentially + CALL BDOSSV + DEC A ; A= 1 returned means EOF, so decrease A + JR Z,RDFIL1 ; ..if zero, continue with next sector + LD C,16 ; BDOS fn #16 Close File + JP BDOSSV + + + ; Write system tracks - destination +WRTRACK: LD A,(DSTDRV) ; get destination drive + CALL SELDRV ; and select it + JP Z,E$DEST ; ..if error, jump and exit + LD (DSTDPH),HL ; store addr of DPH + LD A,10 ; move forward to DPB addr + CALL ADDHLA ; at DPH+10 + LD E,(HL) ; get DPB addr in DE + INC HL + LD D,(HL) + EX DE,HL ; swap regs + LD (DSTDPB),HL ; ..and store DPB addr + LD E,(HL) ; get sectors per track in DE + INC HL ; at DPB+0 + LD D,(HL) + LD (SECTTRK),DE ; store value + LD A,12 ; move forward to track offset + CALL ADDHLA ; (beginning of directory) at DPB+13 + LD E,(HL) ; get track offset in DE + INC HL + LD D,(HL) + LD A,D ; check upper nybble + AND A ; is it zero ? + JP NZ,WRTRK0 ; ..if not, jump to adjust + OR E ; check lower nybble + JP Z,E$NOSYS ; ..if also zero, jump to error and exit + CP 4 ; check upper limit for # of system tracks + JR C,WRTRK1 ; ..if within boundaries, skip over + +WRTRK0: LD DE,2 ; set (default) # of system tracks + +WRTRK1: LD B,E ; trk offset in B (counter) + LD DE,(SECTTRK) ; get sect/trk + LD HL,0 ; set initial value +WRTRK2: ADD HL,DE ; multiply by addition + DJNZ WRTRK2 ; loop till done + XOR A ; nullify A + OR H ; check if H is zero + JP NZ,E$NOSYS ; ..if not, jump error and exit + PUSH HL ; save regs + LD BC,0 + CALL BIOSTTR ; set track # 0 + POP HL ; save regs + LD C,H ; move # of sectors containing system + LD B,L ; to BC (as counter) + LD DE,0 ; set initial value + LD HL,FILEBUF ; set origin addr (file buffer) + +WRTRK3: PUSH DE ; save regs + PUSH BC + PUSH HL + LD HL,(DSTDPH) ; get addr of DPH + LD E,(HL) ; get skew table ptr in DE + INC HL + LD D,(HL) + CALL BIOSTRN ; translate logical sector # in BC + LD B,H ; move physical sector # to BC + LD C,L + CALL BIOSTSE ; ..and set (physical) sector + POP BC ; restore origin addr + PUSH BC + CALL BIOSTDM ; set as DMA buffer addr + LD C,0 + CALL BIOWRIT ; write one sector + OR A ; check for error (A <> 0) + JP NZ,E$WRITE ; ..if error, jump + POP HL ; restore origin addr + LD DE,128 ; ..and increase by 128 bytes (1 sector) + ADD HL,DE + POP BC ; restore regs / clear stack + POP DE + DEC B ; decrease counter + JR NZ,WRTRK4 ; ..if not finished, continue + LD C,1 ; else, force write (flush to disk) + JP BIOWRIT ; ..and let return from there + +WRTRK4: INC C + LD A,C + AND 00000011b ; mask lower 2 bits + LD A,'.' + CALL Z,COUT ; display progress every 4 sectors (0.5 kB) + LD A,(SECTTRK) + CP C ; max. # sect/trk reached ? + JR NZ,WRTRK3 ; ..if not, loop + INC DE ; increase trk counter + LD C,0 ; reset sect counter + PUSH DE ; save regs + PUSH BC + PUSH HL + LD B,D ; copy trk # in BC + LD C,E + CALL BIOSTTR ; ..and set track + POP HL ; restore regs + POP BC + POP DE + JR WRTRK3 ; loop + + + ; check if a valid B/P Bios was loaded + ; *** function not implemented *** + ; in: - + ; out: Z-Flag set if ok, NZ= error +CHKSYS: XOR A ; always return Z-Flag set + RET + + + ; select disk drive + ; in: A= drive number (one-based) + ; out: Z-Flag set if error +SELDRV: DEC A ; -1 to comply with CP/M BIOS standards + LD C,A + LD E,0 + CALL BIOSELD ; call BIOS fn #9 directly + LD A,H + OR L + RET + + + ; call BDOS saving regs BC, DE, HL + ; out: A= 0 and Z-Flag set if not found +BDOSSV: PUSH BC + PUSH DE + PUSH HL + CALL CPMBDOS + INC A ; 0xFF --> 0x00 if not found + POP HL + POP DE + POP BC + RET + + + ; add A to HL (result in HL) +ADDHLA: ADD A,L ; add L + LD L,A ; store result in L + RET NC ; ..if no overflow, return + INC H ; else, increment H + RET + + +;::::: ERROR MESSAGES + + ; display msg on CON: then exit with warm boot +E$READ: CALL EPRINT + DEFB BEL,'*** Read error' + DEFB 0 + JP EXIT + +E$SRC: CALL EPRINT + DEFB BEL,'*** Bad source!' + DEFB 0 + JP EXIT + +E$WRITE: CALL EPRINT + DEFB BEL,'*** Write error' + DEFB 0 + JP EXIT + +E$DEST: CALL EPRINT + DEFB BEL,'*** Bad destination!' + DEFB 0 + JP EXIT + +E$NOSYS: CALL EPRINT + DEFB BEL,'*** No system!' + DEFB 0 + JP EXIT + +E$SOPEN: CALL EPRINT + DEFB BEL,"*** Can't open source file!" + DEFB 0 + + +;::::: EXIT PROGRAM + +EXIT: CALL CRLF + LD HL,0 ; set addr + JP (HL) ; and jump to CP/M WBOOT + + +;::::: BIOS JUMPS (for direct calls) + + ; area is filled with actual jumps at runtime + ; to call BIOS fn's directly +BIOSELD: JP 0 ; fn #9 SELDSK select disk +BIOSTTR: JP 0 ; fn #10 SETTRK set track +BIOSTSE: JP 0 ; fn #11 SETSEC set sector +BIOSTDM: JP 0 ; fn #12 SETDMA set buffer addr +BIOREAD: JP 0 ; fn #13 READ read one sector +BIOWRIT: JP 0 ; fn #14 WRITE write one sector +BIOLIST: JP 0 ; fn #15 LISTST list status (not used) +BIOSTRN: JP 0 ; fn #16 SECTRN sector translation + + + +;::::: RAM STORAGE (not in DSEG !) + +SECTTRK: DEFW 0 ; sectors per track (sect/trk), used for src+dst +SRCDPH: DEFW 0 ; source: addr of Disk Parameter Header (DPH) +SRCDPB: DEFW 0 ; source: addr of Disk Parameter Block (DPB) +DSTDPH: DEFW 0 ; destination: addr of DPH +DSTDPB: DEFW 0 ; destination: addr of DPB +SRCDRV: DEFB 0 ; source: drive # (from standard FCB #1) +DSTDRV: DEFB 0 ; destination drive # +DSTDR2: DEFB 0 ; destination drive # (copy) + ; extracted from cmdline, used as indicator for run mode + + + +;::::::::::::::::::::::::::::::::::::::::::::::::::::: +; Z3LIB - 0x0735 +; SYSLIB - 0x07e3 +; end addr 0x08cc (DSEG Z3+SYS = 4 bytes) +;::::::::::::::::::::::::::::::::::::::::::::::::::::: + + ; buffer start addr = 0x0900 +FILEBUF: EQU $+512-($-BPSYSGEN AND 255) + + DSEG + + END + + +;************************************************************************ +; Remarks jxl: +; BPSYSGEN.COM, included in available B/P Bios package(s), was dis- +; assembled and extensively commented. Labels are up to seven chars long +; to comply with M-REL standards. However, it is recommended to use SLR +; tools that support labels up to sixteen chars. +; In its current state, the compiled/linked file matches exactly the +; original BPSYSGEN.COM, i.e. no changes to the source were made. +; The program is pretty straightforward. It supports a command line +; mode and an interactive mode. (Code portions for the latter are pretty +; short.) Functionality to check if the running system is valid, was +; not implemented. Since other B/P Bios tools perform such checks, this +; is rather surprising. +; An interesting approach was used to end the program and literally +; return to the system. The address of RESDISK routine is pushed on the +; stack at the very beginning. +;************************************************************************ diff --git a/Source/BPBIOS/UTIL/confz4.z80 b/Source/BPBIOS/UTIL/confz4.z80 new file mode 100644 index 00000000..65bc670e --- /dev/null +++ b/Source/BPBIOS/UTIL/confz4.z80 @@ -0,0 +1,489 @@ + TITLE "ZCPR 4 Configuration Utility" +;************************************************************************ +;* C O N F Z 4 * +;* Configure ZCPR 4 options * +;* by Harold F. Bower and Cameron W. Cotrill * +;*----------------------------------------------------------------------* +;* Disassembly: jxl Jan 2025 * +;* public release 1.0 Apr 2025 * +;* see remarks at the end * +;*----------------------------------------------------------------------* +;* LINK with Version 4 libraries: Z3LIB, SYSLIB * +;* * +;* A>Z80ASM CONFZ4/RS * +;* A>SLRNK CONFZ4/N,/A:100,/D:080A,CONFZ4,Z3LIBS/S,SYSLIBS/S,/E * +;************************************************************************ + +VER EQU 10 +REV EQU ' ' + +DATE MACRO + DEFB '18 Nov 95' + ENDM + + +BEL EQU 07H ; Bell character +BS EQU 08H ; Backspace character +TAB EQU 09H ; Tab character +LF EQU 0AH ; Line Feed character +CR EQU 0DH ; Carriage Return character + +CPMBIOS EQU 0 ; CP/M BIOS warm boot (JP) +CPMBDOS EQU 5 ; CP/M BDOS entry point (JP) +CPMFCB EQU 5CH ; CP/M standard FCB #1 (+1 filename, +9 filetype) +CPMDMA EQU 80H ; CP/M standard DMA buffer + + +; From Z3LIB Get.. + EXTRN GETNAME, PRTNAME, Z3INIT, WHRENV + +; From SYSLIB Get.. + EXTRN EPRINT, CRLF, CAPIN, PA2HC, COUT + + +;::::: PROGRAM START + + ORG 100H + CSEG + + +CONFZ4: JP START ; bypass header + DEFB 'Z3ENV' ; this is a ZCPR3 utility + DEFB 1 ; show external environment + +ENVADR: DEFW 0 ; addr of Z3 environment + DEFW CONFZ4 ; type 4 filler + + DEFB 'CONFZ41 ',0 ; configuration name + +START: LD (STACK),SP + LD SP,STACK + CALL EPRINT + DEFB 'B/P System Command Processor Configuration V' + DEFB VER/10+'0','.',VER MOD 10 + '0',REV,' ' + DATE + DEFB CR,LF + DEFB 0 + + CALL INITZ3 ; find Z3ENV and check Wheel Byte + CALL GETNAME ; get actual program name + CALL CHKHLP ; check if help was requested + SUB ' ' ; ##### convert to ... ?? + LD (UNUSED1),A ; ##### and store (not used at all) + CALL CHKSYS ; check if running B/P Bios + LD HL,(BPCNFG) ; addr CONFIG area + INC HL ; move ptr fwd + INC HL + LD A,(HL) ; get option flags (OPTF1) + AND 00000001B ; mask bit 0 (0= unbanked, 1= banked) + LD (BPBNKD),A ; store indicator + JR NZ,CHKXENV ; ..if banked, jump to continue + CALL EPRINT ; else, display msg and exit + DEFB CR,LF,'+++ Not Banked System..aborting...!',BEL + DEFB 0 + JP EXIT + + ; check for extended environment +CHKXENV: INC HL ; move ptr fwd + INC HL + INC HL + LD A,(HL) ; get first system bank (SYSBNK) + LD (SYSBNK),A ; store it + LD HL,(ENVADR) ; addr ENV + LD DE,8 ; offset to type + ADD HL,DE ; move ptr + BIT 7,(HL) ; check high bit (= 0x80+ for extended Z3ENV) + JR NZ,CHKVERS ; ..if set, jump to continue + CALL EPRINT + DEFB CR,LF,'+++ Not Extended Environment..aborting..!',BEL + DEFB 0 + JP EXIT + + ; check ZCPR version +CHKVERS + LD DE,55 ; offset addr CPR (8+55 = 63) + ADD HL,DE ; move ptr + LD E,(HL) ; get addr in DE + INC HL + LD D,(HL) + LD HL,5 ; offset to version byte in ZCPR 4.x + ; (code starts with JP.., JR.., VERSION) + ADD HL,DE ; move ptr + LD A,(HL) ; get byte + CP 41H ; is it 4.1 (or higher) ? + JR NC,PVRSION ; ..if so, jump to continue + PUSH AF ; else, display error msg and exit + CALL EPRINT + DEFB CR,LF,BEL,"+++ Can't Configure Vers : " + DEFB 0 + POP AF + CALL PA2HC + CALL EPRINT + DEFB ' of Command Processor!' + DEFB 0 + JP EXIT + + ; display version +PVRSION: PUSH AF + CALL EPRINT + DEFB CR,LF,' Configuring Options for CPR Version : ' + DEFB 0 + POP AF ; restore version # + PUSH AF + RRCA ; rotate upper nybble to lower + RRCA ; (major version #) + RRCA + RRCA + AND 00001111B ; mask lower nybble + ADD A,'0' ; ..and convert to ascii + CALL COUT ; display major version # + LD A,'.' + CALL COUT + POP AF ; restore version # + AND 00001111B ; mask lower nybble + ADD A,'0' ; ..and convert to ascii + CALL COUT ; display minor version # + CALL CRLF + LD DE,10 ; move forward by another 10 bytes + ADD HL,DE ; (in Z40-1.Z80 three bytes are defined as 'Space + ; reserved for expansion' - this is the last byte) + LD (PFLGADR),HL ; store addr + + ; branch interactive/cmdline mode + LD A,(CPMFCB+1) ; get first char from cmdline + CP ' ' ; is it ? + JP NZ,EVALCMD ; ..if not, jump cmdline mode + CALL EPRINT ; else, interactive mode + DEFB CR,LF,'Turn Time ON in Prompt Line ([Y]/N)? : ' + DEFB 0 + CALL CAPIN ; get user input + LD BC,0FE01H ; default to ON, European format + ; ( 11111110 00000001 B ) + CP 'N' ; is it 'N' ? + JR NZ,RUNIMOD ; ..if not, skip over + LD C,0 ; else, clear C (indicating OFF) + + ; run interactive mode +RUNIMOD: CALL SETOPTB ; set byte + CALL EPRINT + DEFB CR,LF,'US (mm/dd/yy) or European (dd.mm.yy) Dates ([U]/E) : ' + DEFB 0 + CALL CAPIN ; get user input + LD BC,0FD00H ; default to US format + ; ( 11111101 00000000 B ) + CP 'E' ; is it 'E' ? + JR NZ,RUNIM0 ; ..if not, skip over + LD C,00000010B ; else, set European format +RUNIM0: CALL SETOPTB ; set byte + JP EXIT + + ; evaluate command line +EVALCMD: LD HL,CPMDMA + LD A,(HL) ; get # of chars + INC HL ; set ptr to start of cmdline + PUSH HL ; save regs + CALL ADDHLA ; move ptr to end of cmdline + LD (HL),0 ; set terminator + POP HL ; restore start of cmdline + CALL SKPWHSP ; skip any whitespace at the beginning + LD A,(HL) ; get char + CP '/' ; is it option char ? + JR NZ,ECMD0 ; ..if not, skip over + INC HL ; else, move ptr forward +ECMD0: LD A,(HL) ; get byte + OR A + JR Z,ECMD1 ; ..if zero, jump and exit + CALL CMPRMPT ; else, attempt processing option + JR ECMD0 ; ..and loop + +ECMD1: JP EXIT + + + ; cmdline: /T[+|-] Toggle Time in Prompt + ; option byte, bit 0 = 0 off / 1 on + ; + ; cmdline: /U /E US/Europe format + ; option byte, bit 1 = 0 US / 1 European + + ; process prompt on/off +CMPRMPT: CP 'T' ; is char 'T' (Toggle) ? + JR NZ,CMFORMT ; ..if not, try processing format option + INC HL + LD C,00000001B ; prepare for ON + LD A,(HL) ; get next char + CP '+' ; is it '+' ? + JR Z,CMPRMP0 ; ..if so, skip over + LD C,00000000B ; else, prepare for OFF + CP '-' ; is it '-' ? + JR NZ,CMFORMT ; ..if not, rather check format +CMPRMP0: LD B,11111110B ; default to European format + +CMSETOP: CALL SETOPTB ; set +CMSETX: INC HL ; move ptr fwd + RET ; ..and exit + + ; process format +CMFORMT: LD B,11111101B ; default to ON (else, format wouldn't make sense) + LD C,00000010B ; prepare for European + CP 'E' ; is it 'E' ? + JR Z,CMSETOP ; ..if so, set byte + LD C,00000000B ; else, prepare for US + CP 'U' ; is it 'U' ? + JR Z,CMSETOP ; ..if so, set byte + JR CMSETX ; jump exit + + + ; set option byte + ; in: B= format (US/European) + ; C= on/off +SETOPTB: EX DE,HL ; swap regs (save HL) + LD HL,(PFLGADR) ; addr of Prompt flag in ZCPR4 config area + LD A,(HL) ; get byte + AND B ; apply format setting + OR C ; merge on/off setting + LD (HL),A ; ..and save byte + LD HL,010FH ; offset to option byte in SYSBNK + CALL GETFRB ; get current setting + AND B ; apply format setting + OR C ; merge on/off setting + CALL SETINB ; ..and write back + EX DE,HL + RET + + + ; check if help was requested + ; get first token from command line (in FCB #1) +CHKHLP: LD HL,CPMFCB+1 + LD A,(HL) ; get char + CP '/' ; is this a help request ? + RET NZ ; ..if not, return + INC HL ; move ptr fwd + LD A,(HL) ; check following char + CP '/' ; if it is also '/' + RET NZ ; ..if not, return + ; else, fall through and show help screen + + +;::::: HELP SCREEN + +HELP: CALL EPRINT + DEFB CR,LF,' ' + DEFB 0 + CALL PPRGNAM + CALL EPRINT + DEFB ' Configure Running B/P Command Processor Options.',CR,LF,LF + DEFB ' Syntax:',CR,LF,' ' + DEFB 0 + CALL PPRGNAM + CALL EPRINT + DEFB ' - Configure in Interactive Mode',CR,LF,' ' + DEFB 0 + CALL PPRGNAM + CALL EPRINT + DEFB ' /T[+|-] - Toggle Time in Prompt [Set On/Off]',CR,LF,' ' + DEFB 0 + CALL PPRGNAM + CALL EPRINT + DEFB ' /E - Display Date in European (dd.mm.yy) form',CR,LF,' ' + DEFB 0 + CALL PPRGNAM + CALL EPRINT + DEFB ' /U - Display Date in US (mm/dd/yy) form',CR,LF,' ' + DEFB 0 + CALL PPRGNAM + CALL EPRINT + DEFB ' // - display this screen',CR,LF,LF + DEFB ' Arguments may be combined as:',CR,LF,' ' + DEFB 0 + CALL PPRGNAM + CALL EPRINT + DEFB ' /T+U - Turn Time On, US-style Date Display',CR,LF,LF + DEFB 'This program will only run in Banked B/P Systems.',CR,LF + DEFB 0 + + +;::::: EXIT PROGRAM + +EXIT: CALL CRLF + LD SP,(STACK) ; restore stack + RET ; ..and return to system + + +;::::: SUPPORT FUNCTIONS + + ; init Z3ENV and check Wheel byte + ; if not successful, exit program +INITZ3: LD HL,(CPMBDOS+1) + CALL WHRENV ; find Z3 Environment Descriptor + LD (ENVADR),HL ; store ENV addr + LD A,H ; check if invalid (= zero) + OR L + JP Z,E$BPBIO ; ..if so, jump exit + CALL Z3INIT ; init for Z3LIB routines + LD A,41 ; offset to addr wheel byte (Z3WHL) + CALL ADDHLA ; move ptr fwd + LD E,(HL) ; get addr in DE + INC HL + LD D,(HL) + EX DE,HL ; swap regs + LD A,(HL) ; get value of wheel byte + AND A ; check if zero + RET NZ ; ..if not ON, return + CALL EPRINT ; else, display message and exit + DEFB BEL,CR,LF,'Must be wheel to Execute !',CR,LF + DEFB 0 + JR EXIT + + + ; check if running under B/P Bios + ; if not, program is terminated +CHKSYS: LD HL,(CPMBIOS+1) ; get warm boot addr (BIOS fn #1) + LD L,30*3 ; adjust ptr to fn #30 + LD A,(HL) ; check byte at ptr location + CP 0C3H ; is it opcode 0xC3 (JP) ? + JR NZ,E$BPBIO ; ..if not, jump error and exit + CALL JUMPHL ; else, "call" B/P Bios fn #30 (RETBIO) + LD (BPADDR),BC ; store base addr of B/P Bios + LD (BPCNFG),DE ; " config area addr + LD HL,-6 ; move ptr 6 bytes backward + ADD HL,DE ; (signature string) + LD A,(HL) ; get byte + CP 'B' ; is it 'B' ? + JR NZ,E$BPBIO ; ..if not, jump error and exit + INC HL + LD A,(HL) ; get next byte + CP '/' ; is it '/' ? + JR NZ,E$BPBIO ; ..if not, jump error and exit + INC HL + LD A,(HL) ; and get next byte + CP 'P' ; is it 'P' ? + RET Z ; ..if so, return + ; else, fall through (error and exit) + + + ; error msg +E$BPBIO: CALL EPRINT + DEFB CR,LF,BEL,'Not B/P Bios, aborting...!',CR,LF + DEFB 0 + RST 0 + + + ; print program name on CON: device + ; (either the actual name, or fallback to default) + ; only used by HELP +PPRGNAM: LD A,(ENVADR+1) ; get high byte of local ENVPTR + OR A ; check if valid (<> zero) + JP NZ,PRTNAME ; ..if so, display actual name + ; and let return from there + CALL EPRINT ; else, display default + DEFB 'SIZERAM' ; apparently wrong :-) + DEFB 0 + RET + + + ; skip whitespace ( or ) + ; in: HL= ptr to string + ; out: HL= ptr to first char <> whitespace +SKPWHSP: DEC HL ; prior to loop, set ptr back +SKPWH0: INC HL ; move ptr fwd + LD A,(HL) ; get byte + CP ' ' ; is it ? + JR Z,SKPWH0 ; ..if so, loop + CP TAB ; is it ? + JR Z,SKPWH0 ; ..if so, loop + RET ; else, return + + + ; add A to HL (result in HL) +ADDHLA: ADD A,L ; add L + LD L,A ; store result in L + RET NC ; ..if no overflow, return + INC H ; else, increment H + RET + + + ; the following routines rearrange Top of Stack by injecting an + ; intermediate return addr, and putting the Bios fn call on top + ; so that HL regs are preserved + ; order of steps: + ; [1] HL (= addr) is pushed onto stack + ; [2] intermediate return addr is swapped to Top of Stack + ; [3] HL (= addr) is pushed onto stack again + ; [4] Bios fn JP addr is swapped to Top of Stack + ; [5] Bios is "called" through RET, and returns to intermediate addr + + ; get byte from ram bank (in C) - in the form LD A,(HL) + ; in: HL= addr + ; out: A= byte +GETFRB: PUSH BC + PUSH HL ; save addr + LD BC,(SYSBNK) ; C= System Bank, B= not used + LD HL,GETFRB0 ; load return addr + EX (SP),HL ; put it on stack + PUSH HL ; save HL again (previous top of stack) + LD HL,(BPADDR) ; get B/P Bios base addr + LD L,35*3 ; adjust ptr to fn #35 (FRGETB) + EX (SP),HL ; put addr on stack + RET ; ..and "call" Bios fn through stack + +GETFRB0: POP BC ; restore regs + RET ; ..and finally return + + ; set byte in ram bank (in C) - in the form LD (HL),A + ; in: HL= addr, A= byte to set +SETINB: PUSH BC + PUSH HL ; save addr + LD BC,(SYSBNK) + LD HL,GETFRB0 ; load return addr + EX (SP),HL ; put it on stack + PUSH HL ; save HL again (previous top of stack) + LD HL,(BPADDR) ; get B/P Bios base addr + LD L,37*3 ; adjust ptr to fn #37 (FRPUTB) + EX (SP),HL + RET ; ..and "call" Bios fn through stack + + + ; "called" as a pseudo-routine that returns to caller + ; in: HL= target addr +JUMPHL: JP (HL) ; jump to addr in HL regs + + +;::::: RAM STORAGE (_no_ DSEG !) + +PFLGADR: DEFW 0 ; addr of Prompt flag (last reserved option byte) +SYSBNK: DEFB 0 ; beginning of System Bank(s) +UNUSED1: DEFB 0 ; ##### +BPADDR: DEFW 0 ; base addr B/P Bios +BPCNFG: DEFW 0 ; addr of B/P Bios CONFIG area +BPBNKD: DEFB 0 ; indicator banked system + ; (bit 0 of OPTF1, 0= unbanked, 1= banked) + + DEFS 30H ; room for stack +STACK: DEFW 0 ; stack storage location + + + END + + +;::::::::::::::::::::::::::::::::::::::::::::::::::::: +; Z3LIB - 0x06b4 +; SYSLIB - 0x0762 +; end addr 0x080a (begin DSEG of LIB's) +;::::::::::::::::::::::::::::::::::::::::::::::::::::: + + +;************************************************************************ +; Remarks jxl: +; CONFZ4.COM, included in available B/P Bios package(s), was dis- +; assembled and extensively commented. Labels are up to seven chars long +; to comply with M-REL standards. However, it is recommended to use SLR +; tools that support labels up to sixteen chars. +; In its current state, the compiled/linked file matches exactly the +; original CONFZ4.COM, i.e. no changes to the source were made. Possible +; optimisations detected during disassembly are marked with "#####" in the +; comment. +; The program seems to be in an early stage as it does not comply with +; general coding standards seen by HFB/CWC. For instance, no DSEG is used. +; Only 2 options can be configured with this program. It is not known +; whether provisions were made in ZCPR v4.1 for further options. +;************************************************************************ diff --git a/Source/BPBIOS/UTIL/hashini.z80 b/Source/BPBIOS/UTIL/hashini.z80 new file mode 100644 index 00000000..a74f8e02 --- /dev/null +++ b/Source/BPBIOS/UTIL/hashini.z80 @@ -0,0 +1,752 @@ + TITLE "HASHINI Drive Utility" +;************************************************************************ +;* H A S H I N I * +;* Set Drive Volume Name and Init for File Stamps * +;* by Harold F. Bower and Cameron W. Cotrill * +;*----------------------------------------------------------------------* +;* Disassembly: jxl Mar 2025 * +;* public release 1.0 Apr 2025 * +;* see remarks at the end * +;*----------------------------------------------------------------------* +;* LINK with Version 4 libraries: Z3LIB, SYSLIB * +;* * +;* A>Z80ASM HASHINI/RS * +;* A>SLRNK HASHINI/N,/A:100,/D:09E5,HASHINI,Z3LIBS/S,SYSLIBS/S,/E * +;************************************************************************ + +VER EQU 02 +REV EQU ' ' + +DATE MACRO + DEFB '12 Sep 93' + ENDM + + +CTRLC EQU 03H ; Control-C character +BEL EQU 07H ; Bell character +BS EQU 08H ; Backspace character +TAB EQU 09H ; Tab character +LF EQU 0AH ; Line Feed character +CR EQU 0DH ; Carriage Return character +ESC EQU 1BH ; Escape character + +CPMBIOS EQU 0 ; CP/M BIOS warm boot (JP) +CPMBDOS EQU 5 ; CP/M BDOS entry point (JP) +CPMFCB EQU 5CH ; CP/M standard FCB #1 (+1 filename, +9 filetype) +CPMFCB2 EQU 6CH ; CP/M standard FCB #2 +CPMDMA EQU 80H ; CP/M standard DMA buffer + + +; From Z3LIB Get.. + EXTRN GETNAME, PRTNAME, GETQUIET, Z3INIT + +; From SYSLIB Get.. + EXTRN BLINE, EPRINT, CRLF, CAPIN, COUT, CODEND + + +;::::: PROGRAM START + + ORG 100H + CSEG + + +HASHINI: JP START ; bypass header + DEFB 'Z3ENV' ; this is a ZCPR3 utility + DEFB 1 ; show external environment + DEFB 1 + +ENVADR: DEFW 0 ; addr of Z3 environment + + DEFB 1 + DEFB 'HASHINI ' + DEFB 0 + + ; config area (for ZNCFG.COM) +CFGAREA: DEFB 0 ; default value for program quiet flag + DEFB 0FFH + +START: LD (STACK),SP ; save stack + LD SP,STACK + CALL Z3INIT ; init ENVPTR for Z3LIB routines + CALL GETNAME ; get ptr to program name + CALL GETQUIET ; check ENV quiet flag + LD HL,CFGAREA ; ptr to config area + OR (HL) ; merge flags (ENV + program) + LD (PRGQFLG),A ; store program quiet flag + CALL EPRINT + DEFB CR,LF,'Initialize Volume Label and File Stamps Ver ' + DEFB VER/10+'0','.',VER MOD 10 + '0',REV,' ' + DATE + DEFB CR,LF + DEFB 0 + LD C,25 ; get current disk (BDOS fn #25) + CALL CPMBDOS + LD (OLDDRV),A ; remember drive # + CALL EVALCMD ; evaluate command line + JR INITWSPC + + +;::::: MAIN LOOP + +START0: LD SP,STACK ; reset stack pointer + CALL EPRINT + DEFB CR,LF,LF,'Initialize another Disk? (Y/[N]) : ' + DEFB 0 + CALL CINPUT ; get user input + CP 'Y' ; is it 'Y' ? + JP NZ,EXIT ; ..if not, jump to exit + CALL SELODRV ; restore previously logged drive + CALL CRLF + OR 0FFH ; from now on run interactively + + ; init workspace (ram storage) +INITWSPC: LD (RUNMODE),A ; store mode + LD HL,WSPC ; clear workspace data area + LD B,(STACK-WSPC)-3 + CALL FILLZ + + +;::::: DISK DRIVE + +GETDISK: LD A,(RUNMODE) ; get mode + OR A ; running in cmdline mode ? + JR Z,GETVOLN ; ..if so, drive is known, jump to continue + + ; interactive mode - ask for disk to initialize +IMDISK: CALL EPRINT + DEFB CR,LF,LF,'Initialize which Disk for ' + DEFB 0 + LD A,(STMPTYP) ; stamp format indicator + OR A ; is it P2Dos ? + JR NZ,IMDISK1 ; ..if not, jump to continue + CALL EPRINT ; display chosen format + DEFB 'P2DOS' + DEFB 0 + JR IMDISK2 ; skip over +IMDISK1: CALL EPRINT + DEFB 'NZTIME' + DEFB 0 + +IMDISK2: CALL EPRINT + DEFB ' Date/Time Stamps? : ' + DEFB 0 + CALL CINPUT ; get user input + CP 'A' ; disk drive letter must be + JR C,IMDISK3 ; between 'A' and 'P' + CP 'P'+1 + JR C,IMDISK4 +IMDISK3: CALL EPRINT ; else, notify user and loop + DEFB BEL,BS,' ',BS + DEFB 0 + JR IMDISK + +IMDISK4: LD (CURRDSK),A ; store disk drive letter + + +;::::: VOLUME NAME + +GETVOLN: LD A,(VOLNAME) + OR A + JR NZ,IMVOLN3 + + ; interactive mode - ask for volume name +IMVOLN: CALL EPRINT + DEFB CR,LF,'Enter Volume Name [1-11 chars] : ' + DEFB 0 + LD HL,CPMDMA ; set ptr to standard buffer + LD (HL),11 ; prepare char count (max. 11 chars) + XOR A ; clear A + LD (CPMDMA+1),A ; prepare end-of-string + DEC A ; let capitalize (A= non-zero) + CALL BLINE ; get user input + LD A,(HL) ; check char count + OR A ; is it empty string (nothing entered) ? + JR Z,IMVOLN ; ..if so, loop + LD DE,VOLNAME ; point to volname buffer +IMVOLN1: LD A,(HL) ; get char + LDI ; ..and copy over + OR A ; end of string ? + JR NZ,IMVOLN1 ; ..if not, loop + +IMVOLN3: LD A,(PRGQFLG) ; get program quiet flag + OR A ; running in quiet mode ? + JR Z,DSKPROC ; ..if so, skip over + CALL EPRINT + DEFB CR,LF,' Confirm Initialize Drive ' + DEFB 0 + LD A,(CURRDSK) + CALL COUT + CALL EPRINT + DEFB ': (Y/[N]) ' + DEFB 0 + CALL CINPUT ; get user input + CP 'Y' + JP NZ,FINISH + + +;::::: PROCESS DISK + +DSKPROC: LD A,(CURRDSK) ; get current disk drive letter + SUB 'A' ; make numeric + PUSH AF ; save regs + LD E,A ; drive # in E + CALL BDSELD ; select disk drive (BDOS call) + CALL EPRINT ; display warning + DEFB BEL,CR,LF,'+++ Existing Files will be ERASED! +++' + DEFB CR,LF,' --- Proceed anyway (Y/[N]) : ' + DEFB 0 + + CALL CINPUT ; get user input + CP 'Y' ; is it 'Y' ? + JP NZ,FINISH ; ..if not, jump to finish processing + POP AF ; restore regs + LD C,A ; drive # in C + CALL BIOSELD ; select disk drive (BIOS call) + LD A,H ; check if DPH addr is valid + OR L + JP Z,E$DRVILL ; ..if not, jump display error msg and exit + + ; get parameters of current disk drive + LD E,(HL) ; get addr of skew table in DE + INC HL + LD D,(HL) + LD (SKEWTBL),DE ; and store value + LD DE,9 + ADD HL,DE ; move ptr fwd (to DPH+10) + LD E,(HL) ; addr of DPB in DE + INC HL + LD D,(HL) + PUSH DE ; move addr to IX + POP IX + + ; ??? ##### CODEND not used + CALL CODEND ; get first free memory page addr in HL + + LD D,(IX+8) ; get DirMax in DE + LD E,(IX+7) ; (max. dir entries -1) + INC DE ; +1 + LD (DIRMAX),DE ; store value + SRL D ; /2 + RR E + SRL D ; /4 + RR E + LD (STMPMAX),DE ; store value + ; (1 stamp dir entry for 4 file dir entries) + LD BC,0 + LD HL,CPMDMA ; set to standard buffer + PUSH DE ; save regs + PUSH BC + LD DE,VOLNAME ; ptr to volume name + LD A,(DE) ; get char + OR A ; is it zero ? ( means empty string) + LD B,3*32 ; prepare counter for 3 stamp entries + JR Z,MKSTMP ; ..if no volume name, jump to continue + + ; make a volume name entry + ; HL= ptr to standard buffer, DE= ptr to VOLNAME + ; B= char count, C= char + LD (HL),020H ; set first byte of dir entry (user area) + ; to 0x20 - indicates time stamp + INC HL ; move ptr fwd + LD B,11 ; number of chars +MKVOLN: LD A,(DE) ; get VOLNAME char in A + LD C,' ' ; prepare for byte + OR A ; end of string ? + JR Z,MKVOLN1 ; ..if so, skip over + LD C,A ; else, get char in C + INC DE ; move VOLNAME ptr forward +MKVOLN1: LD (HL),C ; copy char to buffer + INC HL ; move ptr fwd + DJNZ MKVOLN ; loop till done + LD B,32-12 ; clear remaining bytes of stamp entry + CALL FILLZ + LD B,2*32 ; fill next 2 stamp entries + + ; make a stamp entry and write to dir +MKSTMP: LD A,0E5H ; CP/M default byte for free dir entries + CALL FILLA ; fill stamp entries + LD A,(STMPTYP) ; get chosen stamp format (0x00 = P2Dos, 0xFF = NZTime) + OR A ; ..and check + LD A,021H ; prepare for P2Dos + JR Z,MKSTMP1 ; ..if so, skip over + LD A,0A1H ; else, prepare for NZTime +MKSTMP1: LD (HL),A ; store byte + INC HL ; move ptr fwd + LD B,32-1 ; ..and clear remaining bytes of stamp entry + CALL FILLZ + POP BC ; restore regs + POP DE + CALL PVBOSE ; if verbose mode, display msg + DEFB CR,LF,'...Writing Initialized Directory...' + DEFB 0 + + LD DE,0 ; initial start # + LD (STMPCUR),DE ; set # of current stamp entry + CALL WRSTMP ; ..and write stamp to directory + LD HL,CPMDMA ; reset ptr to begin of standard buffer + LD A,0E5H ; clear first part of stamp entry + LD B,32 + CALL FILLA +MKSTMP2: CALL WRSTMP ; ..and write next stamp entry + LD HL,(STMPCUR) ; get current # + LD DE,(STMPMAX) ; get max. # + OR A ; clear flags + SBC HL,DE ; check if all entries were written + ADD HL,DE + JR NZ,MKSTMP2 ; ..if not, loop + LD BC,1 ; set C= 1 to indicate Directory Write (forced) + CALL BIOWRIT ; ..and perform through BIOS + JP DSKDONE + + + ; display help and exit +HLPEXIT: XOR A ; clear A + LD (RUNMODE),A ; ..and store mode (cmdline) + JR HELP + +E$DRVILL: CALL EPRINT ; display error msg and fall through + DEFB CR,LF,LF,BEL,'Illegal drive name' + DEFB 0 + + +;::::: HELP + +HELP: CALL EPRINT + DEFB CR,LF,'Usage: Set Drive Volume Name & ' + DEFB 'Initialize for P2Dos/NzTime file stamps',CR,LF,LF + DEFB 'Syntax:',CR,LF,TAB + DEFB 0 + CALL PPRGNAM + CALL EPRINT + DEFB ' [d:][volname] [/][P | Z | Q]',CR,LF + DEFB 'Examples:',CR,LF,TAB + DEFB 0 + CALL PPRGNAM + CALL EPRINT + DEFB TAB,'- Enter Interactive Mode',CR,LF,TAB + DEFB 0 + CALL PPRGNAM + CALL EPRINT + DEFB ' /P',TAB,'- Init Drive interactively w/P2D stamps',CR,LF,TAB + DEFB 0 + CALL PPRGNAM + CALL EPRINT + DEFB ' d:',TAB,'- Initialize drive "d" w/default Stamp',CR,LF,TAB + DEFB 0 + CALL PPRGNAM + CALL EPRINT + DEFB ' d:name',TAB,'- Init drive "d" adding Vol ID "name"',CR,LF,TAB + DEFB TAB,TAB,' file with default Stamps',CR,LF,TAB + DEFB 0 + CALL PPRGNAM + CALL EPRINT + DEFB ' d: ZQ',TAB,'- Init drive "d" for NZTime Stamps',CR,LF,TAB + DEFB TAB,TAB,' suppressing unneeded messages',CR,LF,TAB + DEFB 0 + CALL PPRGNAM + CALL EPRINT + DEFB ' //',TAB,'- Display this message',CR,LF,LF + DEFB 'Note: ZCNFG may be used to configure a flag to suppress',CR,LF + DEFB ' drive confirmation prompt and status messages',CR,LF + DEFB 0 + + JP FINISH + + + ; print program name on CON: device + ; (either the actual name, or fallback to default) + ; only used by HELP +PPRGNAM: LD A,(ENVADR) ; get high byte of ENV ptr + OR A ; check if valid (<> zero) + JP NZ,PRTNAME ; ..if so, display actual name + ; and let return from there + CALL EPRINT ; else, display default name + DEFB 'HASHINI' + DEFB 0 + RET + + + ; write a stamp entry to directory + ; in: IX= ptr DPB + ; STMPCUR= # of current stamp entry +WRSTMP: PUSH BC ; save regs + PUSH DE + PUSH HL + LD HL,0 + LD BC,(STMPCUR) ; get # of current stamp entry + LD D,(IX+1) ; get sectors per track (DPB+0) + LD E,(IX+0) + LD A,17 ; set counter + + ; determine track # (in BC) and sector # (in HL) +WRSTMP1: OR A ; clear flags + SBC HL,DE ; divide by subtraction + CCF ; inverse C-flag + JR C,WRSTMP2 + ADD HL,DE ; compensate overflow + OR A ; clear flags +WRSTMP2: RL C ; divide BC by 2 (track #) + RL B + DEC A ; decrease counter + JR Z,WRSTMP3 ; ..if zero, exit loop + RL L ; else, also divide HL by 2 (sector #) + RL H + JR WRSTMP1 ; and continue + +WRSTMP3: PUSH HL ; save (log.) sector # + LD H,(IX+14) ; get track offset (# sys tracks) + LD L,(IX+13) + ADD HL,BC ; add to calculated track # + LD B,H + LD C,L + CALL BIOSTTR ; set track + POP BC ; restore (log.) sector # + LD DE,(SKEWTBL) ; get addr of skew table + CALL BIOSTRN ; translate logical to physical sector + LD B,H + LD C,L + CALL BIOSTSE ; set (phys.) sector + LD BC,CPMDMA ; set buffer addr + CALL BIOSTDM + LD BC,0 ; set C= 0 to indicate Unallocated Write + CALL BIOWRIT ; ..and perform through BIOS + OR A ; check for error + JR Z,WRSTMPX ; ..if not, jump to exit subroutine + CALL EPRINT ; else, display msg + DEFB CR,LF,BEL,'Directory write error' + DEFB 0 + JR FINISH + +WRSTMPX: LD BC,(STMPCUR) ; get current stamp # + INC BC ; increase + LD (STMPCUR),BC ; ..and save again + POP HL ; restore regs + POP DE + POP BC + RET + + + ; select disk drive that was logged at start of program + ; using BIOS fn first, then BDOS fn +SELODRV: LD A,(OLDDRV) ; get # of old logged disk drive + LD C,A ; in C + LD B,0 + PUSH BC ; save it + LD DE,1 ; ??? ##### not necessary + CALL BIOSELD ; select disk drive (through BIOS) + POP DE ; restore drive # in E + ; ..and fall through + + + ; call BDOS fn #14 SELDSK + ; in: E= drive # +BDSELD: LD C,14 + JP CPMBDOS ; jump BDOS and let return from there + + +;::::: FINISH PROCESSING DISK + +FINISH: CALL SELODRV ; restore previously logged drive + ; ..and fall through + +DSKDONE: LD A,(CURRDSK) + SUB 40H ; make numeric + LD B,A ; use value as counter + SCF ; set C-flag + LD HL,0 ; start with all bits cleared +DSKDN0: ADC HL,HL ; shift Carry bit into position + DJNZ DSKDN0 ; loop till done + EX DE,HL ; bit mask in DE (selected disk drive) + LD C,37 ; BDOS fn #37 RESDSK reset disk system + CALL CPMBDOS + LD A,(RUNMODE) ; get mode + OR A ; running in cmdline mode ? + JP NZ,START0 ; ..if not, loop for next drive + ; else, fall through and exit + + +;::::: EXIT PROGRAM + +EXIT: LD SP,(STACK) ; restore stack + RET ; ..and return to system + + +;::::: SUPPORT FUNCTIONS + + ; EVALCMD Evaluate command line + ; based on tokens provided by CP/M parser in FCB #1/#2 + ; in: A= # of current drive + ; out: A= 0x00 cmdline mode, 0xFF interactive mode + ; Syntax: [d:][volname] [/][P | Z | Q] +EVALCMD: XOR A ; clear A + LD (CURRDSK),A ; ..and variables + LD (RUNMODE),A + LD HL,CPMFCB ; set ptr to standard FCB #1 + LD A,(HL) ; get drive # + OR A ; check if zero + JR Z,ECMD1 ; ..if so, skip over + ADD A,40H ; else, make ascii + CP 'P'+1 ; check if valid + JR NC,ECMD1 ; ..if not, skip over + LD (CURRDSK),A ; else, save disk drive letter +ECMD1 + INC HL ; move ptr fwd + LD A,(HL) ; get char + LD DE,VOLNAME ; ptr to buffer for volume name + LD B,11 ; max. 11 chars + CP ' ' ; is it ? + JR Z,ECMD2 ; ..if so, jump to continue + CP '/' ; is it option or help request ? + JR NZ,ECMD1V ; ..if not, jump to copy volume name + INC HL ; else, move ptr fwd + CP (HL) ; and check next char + JP Z,HLPEXIT ; ..if also '/', jump to display help + JR ECMD3OPT ; else, this char indicates an option + + ; volume name found, copy it +ECMD1V0: LD A,(HL) ; get char +ECMD1V: CP ' ' ; is it ? + JR Z,ECMD2 ; ..if so, jump to continue + LD (DE),A ; save char in VOLNAME buffer + INC DE ; move both ptr's forward + INC HL + DJNZ ECMD1V0 ; loop till done + + ; eval 2nd cmdline token (FCB #2) +ECMD2: XOR A ; clear A + LD (DE),A ; store in VOLNAME to indicate no name + LD HL,CPMFCB2+1 ; set ptr to standard FCB #2, after drive letter + LD A,(HL) ; get char + CP '/' ; is it option or help request ? + JR NZ,ECMD3OPT ; ..if not, letter must be an option, so skip over + INC HL ; else, move ptr fwd + CP (HL) ; and check next char + JP Z,HLPEXIT ; ..if also '/', jump to display help + + ; eval option and done +ECMD3OPT: CALL EVLOPT ; eval option + RET NZ ; if error, switch to interactive mode and return + ; else, continue final check + LD HL,CPMFCB ; set ptr to standard FCB #1 + LD A,(HL) ; get byte + OR A ; is it zero ? + JR Z,ECMDIM ; ..if so, jump done (interactive mode) + INC HL ; move ptr fwd + LD A,(HL) ; get char + CP ' ' ; is it ? + JR NZ,ECMDCM ; ..if not, jump done (cmdline mode) + LD A,(CPMFCB2+1) ; get char of 2nd token + CP ' ' ; is it ? + JR NZ,ECMDCM ; ..if not, jump done (cmdline mode) + ; else, fall through (interactive mode) + +ECMDIM: OR 0FFH ; set status (interactive mode) + RET +ECMDCM: XOR A ; set status (cmdline mode) + RET + + + ; evaluate _one_ option on cmdline + ; in: HL= ptr to char (already behind a leading '/') + ; out: A= 0x00 cmdline mode, 0xFF interactive mode + ; Z-flag reset (NZ) in case of error, i.e. interactive mode + ; possible flags are /Q (quiet), /P (P2Dos stamps), /Z (NZTime stamps) +EVLOPT: LD B,7 ; max. 7 chars + +EVLOPTQ: LD A,(HL) ; get char + CP 'Q' ; option /Q - quiet ? + JR NZ,EVLOPTP ; ..if not, jump to check next option + LD A,(PRGQFLG) ; get program quiet flag + XOR 0FFH ; toggle + LD (PRGQFLG),A ; ..and save back + JR EVLONXT ; jump to continue + +EVLOPTP: CP 'P' ; option /P - P2Dos stamps ? + JR NZ,EVLOPTZ ; ..if not, jump to check next option + XOR A ; clear A + LD (STMPTYP),A ; ..and store stamp type + JR EVLONXT ; jump to continue + +EVLOPTZ: CP 'Z' ; option /Z - NZTime stamps ? + JR NZ,EVLONX1 ; ..if not, jump to check for whitespace + OR 0FFH ; set A= 0xFF + LD (STMPTYP),A ; store stamp type + ; ..and fall through to read next char + +EVLONXT: INC HL ; move ptr fwd + LD A,(HL) ; get char + ; options are separated by whitespace +EVLONX1: CP ' ' ; is it ? + JR Z,EVLOXIT ; ..if so, jump to exit loop + CP TAB ; is it ? + JR Z,EVLOXIT ; ..if so, jump to exit loop + JR NZ,EVLOERR ; else, invalid option char found + DJNZ EVLOPTQ ; loop till done + +EVLOXIT: XOR A ; set return code 0x00 (clear A and flags) + RET + +EVLOERR: LD A,(PRGQFLG) ; get program quiet flag + OR A ; running in verbose mode ? + LD A,BEL + CALL Z,COUT ; ..if so, notify user + CALL EPRINT + DEFB CR,LF,'+++ Unrecognized Option "' + DEFB 0 + LD A,(HL) + CALL COUT + CALL EPRINT + DEFB '" ... Setting Interactive' + DEFB 0 + OR 0FFH ; set return code 0xFF + RET + + + ; get console input + ; and check for abort request +CINPUT: CALL CAPIN ; get char and capitalize + CP CTRLC ; is it ? + JP Z,EXIT + CP ESC ; is it ? + JP Z,EXIT + CP 'a' ; below 'a' ? (not possible, CAPIN capitalizes) + RET C + CP 'z'+1 ; between lowercase 'a' and lowercase 'z' ? + RET NC + AND 01011111b ; remove bit 5 to capitalize + RET + + + ; ##### unreferenced code (not used) + ; copy 32 (0x20) bytes from (HL) to (DE) + LD B,32 +UNUSED1: LD A,(HL) + LD (DE),A + INC HL + INC DE + DJNZ UNUSED1 + RET + ; ##### + + + ; fill memory with zero, or byte + ; in: A= byte + ; B= # of bytes + ; HL= target addr +FILLZ: XOR A ; clear A +FILLA: LD (HL),A ; store byte + INC HL ; move ptr fwd + DJNZ FILLA ; loop + RET + + + ; verbose print - print string to CON: if quiet flag is off + ; in: (Stack) contains start addr of nul-terminated string +PVBOSE: LD A,(PRGQFLG) ; get program quiet flag + OR A ; running in verbose mode ? + JP Z,EPRINT ; ..if so, jump to print and let return from there + EX (SP),HL ; else, swap HL and top-of-stack +PVBOSE0: LD A,(HL) ; get char + INC HL ; move ptr fwd + OR A ; is byte = zero ? + JR NZ,PVBOSE0 ; ..if not, loop + EX (SP),HL ; else, swap back + RET + + + ; entry points for indirect BIOS calls + ; BC is loaded with absolute offset from WBOOT (fn #1) + ; to respective jump instruction, i.e. 3 bytes per fn +BIOSELD: PUSH BC + LD BC,3*8 ; fn #9 SELDSK select disk + JR BIOSFN + +BIOSTTR: PUSH BC + LD BC,3*9 ; fn #10 SETTRK set track + JR BIOSFN + +BIOSTSE: PUSH BC + LD BC,3*10 ; fn #11 SETSEC set sector + JR BIOSFN + +BIOSTDM: PUSH BC + LD BC,3*11 ; fn #12 SETDMA set buffer addr + JR BIOSFN + +BIOREAD: PUSH BC + LD BC,3*12 ; fn #13 READ read one sector (not used) + JR BIOSFN + +BIOWRIT: PUSH BC + LD BC,3*13 ; fn #14 WRITE write one sector + JR BIOSFN + +BIOSTRN: PUSH BC + LD BC,3*15 ; fn #16 SECTRN sector translation + JR BIOSFN + + + ; call BIOS fn indirectly + ; in: BC= offset to fn in Bios jump table +BIOSFN: EX (SP),HL ; swap HL and top-of-stack (= prev. BC) + PUSH HL ; save HL (prev. BC) + LD HL,(CPMBIOS+1) ; Bios base addr + ADD HL,BC ; add offset to fn # + POP BC ; restore BC + EX (SP),HL ; swap HL and top-of-stack again + RET ; "call" by returning to Bios fn + + +UNUSED2: + DEFB 0,0,0,0,0,0 ; ##### unreferenced chunk of data + DEFB '!!!TIME&DAT' ; obviously not used + DEFB 0,0,0,0,0,0,0,0 + DEFB 0,0,0,0,0,0,0,0 + DEFB 0,0,0,0,0,0,0,0 + + +;::::::::::::::::::::::::::::::::::::::::::::::::::::: +; Z3LIB - 0x08a7 +; SYSLIB - 0x091a +; end addr 0x09e5 (begin DSEG) +;::::::::::::::::::::::::::::::::::::::::::::::::::::: + + + DSEG + +STMPTYP: DEFB 0 ; stamp type flag, 0x00 = P2Dos, 0xFF = NZTime +PRGQFLG: DEFB 0 ; program quiet flag, 0x00 = verbose +VOLNAME: DEFS 12 ; buffer for volume name, 11 bytes + terminator + +RUNMODE: DEFB 0 ; indicator, 0x00 = cmdline mode / 0xFF = interactive mode +OLDDRV: DEFB 0 ; logged drive at program start +CURRDSK: DEFB 0 ; current disk drive letter + +WSPC: ; workspace starts here +DIRMAX: DEFW 0 ; max. # of dir entries (from DPH +1) +STMPMAX: DEFW 0 ; max. # of stamp entries (= DIRMAX / 4) +STMPCUR: DEFW 0 ; current # of stamp entry (used as counter) +SKEWTBL: DEFW 0 ; addr of skew table (from DPH) + + DEFS 070H ; room for stack +STACK: DEFW 0 ; stack storage location + + END + + +;************************************************************************ +; Remarks jxl: +; HASHINI.COM, included in available B/P Bios package(s), was dis- +; assembled and extensively commented. Labels are up to seven chars long +; to comply with M-REL standards. However, it is recommended to use SLR +; tools that support labels up to sixteen chars. +; In its current state, the compiled/linked file matches exactly the +; original SHOWHD.COM, i.e. no changes to the source were made. Possible +; optimisations detected during disassembly are marked with "#####" in the +; comment. It is fair to say that the program seems to be in an early +; stage; as the version number indicates. Apparently, provisions were made +; to test exitence, or even generate a DateStamper !!!TIME&.DAT file +; (which is not the case right now.) +; The program supports an interactive and a command line mode. Labels +; start with "IM" to indicate code specifically for interactive mode. +;************************************************************************ diff --git a/Source/BPBIOS/UTIL/ldsys.z80 b/Source/BPBIOS/UTIL/ldsys.z80 new file mode 100644 index 00000000..25214797 --- /dev/null +++ b/Source/BPBIOS/UTIL/ldsys.z80 @@ -0,0 +1,640 @@ + TITLE "B/P Bios System Loader" +;************************************************************************ +;* L D S Y S * +;* Load a B/P Bios based system into RAM memory for direct execution * +;* by Harold F. Bower and Cameron W. Cotrill * +;*----------------------------------------------------------------------* +;* Disassembly: jxl Dec 2024 * +;* public release 1.0 Apr 2025 * +;* see remarks at the end * +;*----------------------------------------------------------------------* +;* LINK with Version 4 libraries: VLIB, Z3LIB, SYSLIB * +;* * +;* A>Z80ASM LDSYS/RS * +;* A>SLRNK LDSYS/N,/A:100,/D:0CF8,LDSYS,VLIBS/S,Z3LIBS/S,SYSLIBS/S,/E * +;************************************************************************ + +VER EQU 12 +REV EQU ' ' + +DATE MACRO + DEFB '17 Jul 96' + ENDM + + +BEL EQU 07H ; Bell character +LF EQU 0AH ; Line Feed character +CR EQU 0DH ; Carriage Return character + +CPMBDOS EQU 5 ; CP/M BDOS entry point (JP) +CPMFCB EQU 5CH ; CP/M standard FCB #1 (+1 filename, +9 filetype) +CPMDMA EQU 80H ; CP/M standard DMA buffer + + +; From VLIB Get.. + EXTRN VPRINT, Z3VINIT + +; From Z3LIB Get.. + EXTRN GETNAME, PRTNAME, ZFNAME, Z3LOG, WHRENV + EXTRN GZMTOP ; ##### not used, but linked + +; From SYSLIB Get.. + EXTRN PUTUD, GETUD, F$OPEN, F$READ, SETDMA, PFN3, PHL4HC, COUT, CODEND + EXTRN F$CLOSE, CRLF ; ##### not used, but linked + + +;::::: PROGRAM START + + ORG 100H + CSEG + + +LDSYS: JP START ; bypass header + DEFB 'Z3ENV' ; this is a ZCPR3 utility + DEFB 1 ; show external environment + +ENVADR: DEFW 0 ; addr of Z3 environment + DEFW LDSYS ; type 4 filler + + DEFB 'LDSYS ',0 ; configuration name + +FTYPE: DEFB 'IMG' ; standard file type + +START: LD (STACK),SP + LD SP,STACK + CALL PUTUD ; currently logged drive/user + LD HL,(CPMBDOS+1) + CALL WHRENV ; find Z3 Environment Descriptor + PUSH AF + LD (ENVADR),HL ; store ENV addr + CALL Z3VINIT ; ..and init for Z3LIB routines + CALL GETNAME ; get actual program name + CALL VPRINT + DEFB CR,LF,1,'B/P Bios System Loader',2,' Vers ',VER/10+'0','.' + DEFB VER MOD 10 + '0',REV,' ' + DATE + DEFB CR,LF,' Copyright (C) 1991,3 by H.F.Bower & C.W.Cotrill',CR,LF + DEFB 0 + + ; get first token from command line (in FCB #1) + LD A,(CPMFCB+1) + CP '/' ; is this a help request ? + JP Z,HELP ; ..if so, jump display help screen + POP AF + JR Z,E$NOFIL ; else, jump error no file specified + + LD HL,(ENVADR) ; get addr Z3ENV + LD DE,70 ; offset to high byte BIOS addr + ADD HL,DE ; move ptr + LD H,(HL) ; get high byte of B/P Bios page addr + LD L,30*3 ; ..and set low byte to fn #30 + LD A,(HL) ; check byte at ptr location + CP 0C3H ; is it opcode 0xC3 (JP) ? + JR NZ,E$NOFIL ; ..if not, jump error and exit + CALL JUMPHL ; else, "call" B/P Bios fn #30 (RETBIO) + LD HL,-6 ; move ptr 6 bytes backward + ADD HL,DE ; (signature string) + LD A,(HL) ; get byte + CP 'B' ; is it 'B' ? + JR NZ,E$NOFIL ; ..if not, jump error and exit + INC HL ; ptr fwd + LD A,(HL) ; get byte + CP '/' ; is it '/' ? + JR NZ,E$NOFIL ; ..if not, jump error and exit + INC HL ; ptr fwd + LD A,(HL) ; get byte + CP 'P' ; is it 'P' ? + JR NZ,E$NOFIL ; ..if not, jump error and exit + LD DE,6 ; else, set ptr to OPTF1 (Bios Option Flags) + ADD HL,DE ; at CONFIG+2 + BIT 7,(HL) ; check bit 7 (0= not locked, 1= locked, can't reload) + JR Z,E$NOFIL ; ..if not set, skip over + + +E$RUNBP: CALL VPRINT + DEFB CR,LF,BEL,'*** Running Bios Cannot be Replaced ! ***',CR,LF + DEFB 0 + JP EXIT + +E$NOFIL: LD A,(CPMFCB+1) + CP ' ' + JR NZ,EVALCMD + CALL VPRINT + DEFB ' *** No file specified ! ***',CR,LF,BEL + DEFB 0 + + +;::::: EXIT PROGRAM + +EXIT: CALL GETUD ; set previous drive/user + LD SP,(STACK) ; set stack to initial location + RET ; ..and return to system + + +;::::: EVALUATE COMMAND LINE + +EVALCMD: LD DE,CPMFCB + LD HL,CPMDMA+1 ; set ptr to start of string +ECMD1: LD A,(HL) ; get char + INC HL ; move ptr fwd + CP ' ' ; is it ? + JR Z,ECMD1 ; ..if so, loop get next char + DEC HL ; non-blank char found, move ptr back + XOR A ; and nullify A + CALL ZFNAME ; parse token into FCB + JP NZ,E$AMBIG ; filename must be unambiguous, jump if error + LD HL,9 ; move ptr to file type + ADD HL,DE + LD A,(HL) ; get char + CP ' ' ; is it ? + JR NZ,RDIMG ; ..if not, skip over + PUSH DE ; else, save regs + EX DE,HL ; swap regs + LD HL,FTYPE ; ptr to standard file type + LD BC,3 ; 3 chars + LDIR ; ... and copy + POP DE ; restore ptr to ZCPR3 FCB + + +;::::: READ IMAGE FILE + +RDIMG: CALL Z3LOG ; log in drive/user + CALL F$OPEN ; attempt to open file + OR A + JP NZ,E$OPEN ; ..if error, jump error and exit + CALL CODEND ; get first available page after code end + LD (WSPCBEG),HL ; ..and store it +RDIMG0: PUSH HL + CALL SETDMA ; set DMA buffer addr (HL) + LD DE,CPMFCB ; set standard FCB #1 + CALL F$READ ; read one sector (128 bytes) + POP HL ; restore start addr + JR NZ,RDIMG1 ; ..if end of file, jump exit loop + LD DE,128 ; else, move buffer addr forward + ADD HL,DE + JR RDIMG0 ; ..and loop +RDIMG1: CALL GETUD ; set previously logged drive/user + CALL VPRINT + DEFB CR,LF,' CCP starts at : ' + DEFB 0 + + +;::::: READ IMAGE HEADER + +; header contains information at following offsets: +; ZCPR CCP 0x10 (16) filename +; 0x1B (27) Unbanked base addr, 0x1D (29) Unbanked size +; 0x1F (31) Banked base addr, 0x22 (33) Banked size +; ZSDOS 0x30 (48) filename +; 0x3B (59) Unbanked base addr, 0x3D (61) Unbanked size +; 0x3F (63) Banked base addr, 0x41 (65) Banked size +; B/P Bios 0x50 (80) filename +; 0x5B (91) Unbanked base addr, 0x5D (93) Unbanked size +; 0x5F (95) Banked base addr, 0x62 (98) Banked size +; 0x70 (112) IMG filename + +RDHDR: LD DE,27 ; offset CCP Unbanked base addr + CALL PSEGAS ; display addr and size of segment + LD DE,33 ; offset CCP Banked size + CALL GBYTEWS ; check if empty (0x0000) + JR Z,RDHDR0 ; ..if so, skip over + CALL VPRINT + DEFB ' Banked Ccp at : ' + DEFB 0 + LD DE,31 ; offset to CCP Banked base addr + CALL PSEGAS ; display addr and size +RDHDR0: CALL VPRINT + DEFB ' DOS starts at : ' + DEFB 0 + LD DE,59 ; offset to DOS Unbanked base addr + CALL PSEGAS ; display addr and size of segment + LD DE,65 ; offset to DOS Banked size + CALL GBYTEWS ; check if empty (0x0000) + JR Z,RDHDR1 ; ..if so, skip over + CALL VPRINT + DEFB ' Banked Dos at : ' + DEFB 0 + LD DE,63 ; offset to DOS Banked base addr + CALL PSEGAS ; display addr and size +RDHDR1: CALL VPRINT + DEFB ' BIOS starts at : ' + DEFB 0 + LD DE,91 ; offset to B/P Bios Unbanked base addr + CALL PSEGAS ; display addr and size of segment + LD DE,97 ; offset to B/P Bios Banked size + CALL GBYTEWS ; check if empty (0x0000) + JR Z,LDSEG ; ..if so, skip over + CALL VPRINT + DEFB ' Banked Bios at : ' + DEFB 0 + LD DE,95 ; offset to B/P Bios Banked base addr + CALL PSEGAS ; display addr and size + + +;::::: LOAD SYSTEM SEGMENTS + +LDSEG: CALL VPRINT + DEFB CR,LF,' ...installing ' + DEFB 0 + CALL CHKBNKD ; check options flag if banked system + JR Z,LDSEG0 ; ..if not, skip over + CALL VPRINT + DEFB 'Banked ' + DEFB 0 +LDSEG0: CALL VPRINT + DEFB 'System',CR,LF,LF + DEFB 0 + +LDSEG1: DI ; disable interrupts + LD HL,(WSPCBEG) ; get addr WSPC area + LD DE,100H ; + 100H to account for file base + ADD HL,DE + + ; ZCPR Unbanked portion + LD (CCPUSTRT),HL ; store start in WSPC area + LD DE,27 ; file offset to ZCPR Unbanked base addr + CALL G2WRDWS + LD (CCPUSIZ),BC ; store size + LD (CCPUADR),DE ; store base addr + LD HL,(CCPUSTRT) ; get start in WSPC + PUSH HL + ADD HL,BC ; calc end / start of ZSDOS Unbanked portion + LD (DOSUSTRT),HL ; ..and store it + POP HL ; restore start + LDIR ; copy ZCPR Unbanked + ; from img file to target addr + + ; ZCPR Banked portion + LD DE,31 ; offset to ZCPR Banked base addr + CALL G2WRDWS + LD (CCPBSIZ),BC ; store size + LD (CCPBADR),DE ; store base addr + LD HL,(DOSUSTRT) ; get previously calc'd end + LD (CCPBSTRT),HL ; ..and store it as Banked start in WSPC + LD A,B ; check if size is zero + OR C + JR Z,LDSEG2 ; ..if so, skip over + ADD HL,BC ; else, calc new start of ZSDOS Unbanked + LD (DOSUSTRT),HL ; ..and update it + + ; ZSDOS Unbanked portion +LDSEG2: LD DE,59 ; offset to ZSDOS Unbanked base addr + CALL G2WRDWS ; DE= base addr, BC= size + LD (DOSUSIZ),BC ; store size + LD HL,(DOSUSTRT) ; get ZSDOS Unbanked start in WSPC area + PUSH HL + ADD HL,BC ; calc end / start of B/P Bios Unbanked portion + LD (BIOUSTRT),HL ; ..and store it + POP HL ; restore start + LDIR ; copy ZSDOS Unbanked + ; from img file to target addr + + ; ZSDOS Banked portion + LD DE,63 ; offset to ZSDOS Banked base addr + CALL G2WRDWS + LD (DOSBSIZ),BC ; store size + LD (DOSBADR),DE ; store base addr + LD HL,(BIOUSTRT) ; get previously calc'd end + LD (DOSBSTRT),HL ; ..and store it as Banked start in WSPC + LD A,B ; check if size is zero + OR C + JR Z,LDSEG3 ; ..if so, skip over + ADD HL,BC ; else, calc new start of B/P Bios Unbanked + LD (BIOUSTRT),HL ; ..and update it + + ; B/P Bios Unbanked portion +LDSEG3: LD DE,91 ; offset to B/P Bios Unbanked base addr + CALL G2WRDWS + LD (BIOUSIZ),BC ; store size + LD (BIOUADR),DE ; store base addr + LD HL,(BIOUSTRT) ; get start in WSPC area + PUSH HL + ADD HL,BC ; calc end / beginning of Banked portion + LD (BIOBSTRT),HL ; ..and store it + POP HL ; restore start + LDIR ; copy B/P Bios Unbanked + ; from img file to target addr + + ; B/P Bios Banked portion + LD DE,95 ; offset to B/P Bios Banked base addr + CALL G2WRDWS + LD (BIOBSIZ),BC ; store size + LD (BIOBADR),DE ; store base addr + + ; use B/P Bios functions at new location (Unbanked portion was just loaded) + LD HL,(BIOUADR) ; get (new) B/P Bios base addr + LD L,82h ; offset to TPABNK in config area + LD A,(HL) ; get value + LD L,27*3 ; offset to B/P Bios fn #27 (SELMEM) + CALL JUMPHL ; "call" fn + LD HL,CCPBSIZ ; ptr to stored ZCPR Banked size + CALL LDBNKD + LD HL,DOSBSIZ ; ptr to stored ZSDOS Banked size + CALL LDBNKD + LD HL,BIOBSIZ ; ptr to stored B/P Bios Banked size + CALL LDBNKD + + ; Z3ENV Descriptor + LD BC,(WSPCBEG) ; get (new) B/P Bios base addr + LD HL,155 ; offset to addr of Z3 Environment Descriptor + ADD HL,BC ; in B/P Bios config area (CONFIG+26) + LD E,(HL) ; get addr in DE + INC HL + LD D,(HL) + LD HL,128 ; offset from start of WSPC area (img file) + ADD HL,BC + LD BC,128 ; bytes to copy + LDIR + + ; boot new system + LD SP,80H ; set stack pointer to default + XOR A ; nullify A + ; ..and fall through, initiating a cold boot + + +;::::: SUPPORT FUNCTIONS + + ; call B/P Bios function (at new base addr in RAM) + ; in: A= offset to JP (fn # *3) +BIOSFN: LD HL,(BIOUADR) ; get (new) B/P Bios base addr + LD L,A ; adjust to JP of fn # + ; ..and fall through + + + ; "called" as a pseudo-routine that returns to caller + ; in: HL= target addr +JUMPHL: JP (HL) ; jump to addr in HL regs + + + ; load banked portions of (new) system from WSPC area to SYSBNK + ; segment information is stored as consecutive 16-bit words + ; in the order + ; in: HL= ptr to + ; uses B/P Bios functions at new location (Unbanked portion) +LDBNKD: LD C,(HL) ; get low byte + LD A,C + INC HL ; move ptr fwd + LD B,(HL) ; get high byte + INC HL ; ptr fwd + OR B ; check if is zero + RET Z ; ..if so, return + + PUSH BC ; save regs + PUSH HL + LD HL,(BIOUADR) ; get (new) B/P Bios base addr + LD L,82H ; offset to TPABNK in config area + LD C,(HL) ; get value + INC HL ; move ptr to SYSBNK + LD B,(HL) ; get value + LD A,29*3 ; offset to B/P Bios fn #29 (XMOVE) + CALL BIOSFN + POP DE ; restore regs, DE now ptr to + POP BC + LD HL,(BIOUADR) ; get (new) B/P Bios base addr + LD L,25*3 ; offset to B/P Bios fn #25 (MOVE) + PUSH HL ; put on stack, so it is called at return + ; and let Bios routine return to initial caller + EX DE,HL ; swap regs + LD E,(HL) ; get in DE + INC HL + LD D,(HL) + INC HL + LD A,(HL) + INC HL + LD H,(HL) ; get in HL + LD L,A + RET ; ..and call B/P Bios fn #25 (MOVE) + ; to copy banked segment to SYSBNK + + + ; get _two_ consecutive 16-bit words from offset addr in WSPC area + ; in: DE= offset + ; out: DE= first value (at addr) + ; BC= second value (at addr+2) + ; HL= ptr to high byte of second value in WSPC area + ; uses BC, DE, HL +G2WRDWS: CALL G1WRDWS ; get first word in HL + EX DE,HL ; swap regs + INC HL ; move ptr fwd + LD C,(HL) ; get second word in BC + INC HL + LD B,(HL) + RET + + + ; print base addr and size of system segment ton CON: + ; in: DE= offset in WSPC area +PSEGAS: CALL G1WRDWS ; get 16-bit word (in HL) at offset (in DE) + CALL PHL4HC ; ..and print to CON: as hex digits + EX DE,HL ; swap regs + INC HL ; move ptr fwd + LD E,(HL) ; get next 16-bit word in DE + INC HL + LD D,(HL) + CALL VPRINT + DEFB ' (' + DEFB 0 + EX DE,HL ; swap regs + CALL PHL4HC ; print value (now in HL) to CON: as hex digits + CALL VPRINT + DEFB 'H Bytes)',CR,LF + DEFB 0 + RET + + + ; get _one_ 16-bit word from offset addr in WSPC area + ; in: DE= offset + ; out: HL= value + ; DE= ptr to high byte in WSPC area +G1WRDWS: LD HL,(WSPCBEG) ; addr WSPC area + ADD HL,DE ; add offset + LD E,(HL) ; get low byte at ptr addr in E + INC HL + LD D,(HL) ; get high byte at ptr addr in D + EX DE,HL ; swap regs + RET + + + ; get byte from offset addr in WSPC area + ; in: DE= offset + ; out: A= value, Z-Flag set if following byte is eqal + ; HL= ptr to next byte in WSPC area +GBYTEWS: LD HL,(WSPCBEG) ; addr WSPC area + ADD HL,DE ; add offset + LD A,(HL) ; get byte + INC HL ; move ptr fwd + OR (HL) ; check if next byte has same value + RET + + + ; check if img file contains a banked system + ; in: - + ; out: Z-Flag set for Unbanked Bios, NZ= Banked +CHKBNKD: LD HL,(WSPCBEG) ; addr WSPC area + INC H ; + 100H to account for file base + EX DE,HL ; swap regs, DE holds result over next calc's + LD BC,29 ; offset to ZCPR Unbanked size + CALL SEGTSIZ ; ..add ZCPR size(s) to DE + LD BC,61 ; offset to ZSDOS Unbanked size + CALL SEGTSIZ ; ..add ZSDOS size(s) to DE + LD HL,128 ; DE= offset to beginning of B/P Bios in + ADD HL,DE ; img file, move fwd by 128 more bytes + LD A,(HL) ; get B/P Bios options flag OPTF1 (at CONFIG+2) + AND 00000001b ; check bit 0, and set Z-Flag accordingly + RET + + + ; get total size of a system segment (add Unbanked and Banked sizes) + ; in: BC= offset in WSPC area to Unbanked size + ; out: DE= sum of segment sizes +SEGTSIZ: LD HL,(WSPCBEG) ; addr WSPC area + ADD HL,BC ; add offset + LD C,(HL) ; get 16-bit word in BC + INC HL ; (Unbanked size) + LD B,(HL) + EX DE,HL ; swap regs + ADD HL,BC ; add retrieved value + EX DE,HL ; ..and swap regs back + INC HL ; move ptr 3 bytes fwd + INC HL + INC HL + LD C,(HL) ; get 16-bit value in BC + INC HL ; (Banked size) + LD B,(HL) + EX DE,HL ; swap regs + ADD HL,BC ; add retrieved value + EX DE,HL ; ..and swap regs back + RET + + +;::::: ERROR MESSAGES + +E$AMBIG: CALL VPRINT + DEFB CR,LF,BEL,' --- Ambiguous File: ' + DEFB 0 + JR E$FNAME + +E$OPEN: CALL VPRINT + DEFB CR,LF,BEL,' --- Error Opening: ' + DEFB 0 + +E$FNAME: LD DE,CPMFCB+1 ; ptr to file name in standard FCB #1 + CALL PFN3 ; print it + JP EXIT + + +;::::: HELP SCREEN + +HELP: CALL VPRINT + DEFB CR,LF,1 + DEFB 0 + CALL PPRGNAM + CALL VPRINT + DEFB 2,' Loads and executes a System image prepared by',CR,LF + DEFB ' BPBUILD containing a B/P Bios.',CR,LF,LF + DEFB ' Syntax:',CR,LF + DEFB ' ' + DEFB 0 + CALL PPRGNAM + CALL VPRINT + DEFB ' // - print this message',CR,LF + DEFB ' ' + DEFB 0 + CALL PPRGNAM + CALL VPRINT + DEFB ' [du|dir:]name[.typ] - load system image',CR,LF,LF + DEFB ' File Type Defaults to "' + DEFB 0 + LD HL,FTYPE ; ptr to default file type + LD B,3 ; # of chars +HELP0: LD A,(HL) ; get char + INC HL ; move ptr fwd + CALL COUT ; display char on CON: + DJNZ HELP0 ; ..and loop + CALL VPRINT + DEFB '" if not explicitly entered',CR,LF,LF + DEFB 'NOTE: This utility will NOT load a system ' + DEFB 'if the "Lock" bit in',CR,LF + DEFB 'the Option Byte (Bit 7 of CONFIG+2) is Set to "1"',CR,LF + DEFB 0 + JP EXIT + + + ; print program name on CON: device + ; (either the actual name, or fallback to default) + ; only used by HELP +PPRGNAM: LD A,(ENVADR+1) ; get high byte of ENVPTR + OR A ; check if valid (<> zero) + JP NZ,PRTNAME ; ..if so, display actual name + ; and let return from there + CALL VPRINT ; else, display default + DEFB 'LDSYS' + DEFB 0 + RET + + +;::::::::::::::::::::::::::::::::::::::::::::::::::::: +; VLIB - 0x06db +; Z3LIB - 0x08fc +; SYSLIB - 0x0bcf +; end addr 0x0bf8 (begin DSEG) +;::::::::::::::::::::::::::::::::::::::::::::::::::::: + + +;::::: RAM STORAGE + + DSEG + +WSPCBEG: DEFW 0 ; begin of workspace + ; (first available page, returned by CODEND) + + ; addresses of new system as extracted from img file + ; first _Unbanked_, then _Banked_ +BIOUADR: DEFW 0 ; B/P Bios Unbanked base addr +CCPUADR: DEFW 0 ; ZCPR Unbanked base addr +CCPUSTRT: DEFW 0 ; start in WSPC area +CCPUSIZ: DEFW 0 ; size +DOSUSTRT: DEFW 0 ; ZSDOS Unbanked start +DOSUSIZ: DEFW 0 ; size +BIOUSTRT: DEFW 0 ; B/P Bios Unbanked start +BIOUSIZ: DEFW 0 ; size + +CCPBSIZ: DEFW 0 ; ZCPR Banked size +CCPBADR: DEFW 0 ; base addr +CCPBSTRT: DEFW 0 ; start +DOSBSIZ: DEFW 0 ; ZSDOS Banked size +DOSBADR: DEFW 0 ; base addr +DOSBSTRT: DEFW 0 ; start +BIOBSIZ: DEFW 0 ; B/P Bios Banked size +BIOBADR: DEFW 0 ; base addr +BIOBSTRT: DEFW 0 ; start + + + DEFW GZMTOP ; reference Z3LIB/SYSLIB routines, so they are linked + DEFW F$CLOSE + DEFW CRLF + + DEFS 30H-6 ; room for stack + ; -6 to account for above ref's +STACK: DEFW 0 ; stack storage location + + END + + +;************************************************************************ +; Remarks jxl: +; LDSYS.COM, included in available B/P Bios package(s), was dis- +; assembled and extensively commented. Labels are unique up to the seventh +; character to comply with M-REL standards. However, it is recommended to +; use SLR tools that support labels up to sixteen chars. +; In its current state, the compiled/linked file _almost_ matches the +; original LDSYS.COM with the exception of Z3LIB routine GZMTOP, and +; SYSLIB routines F$CLOSE and CRLF. Even though they are part of the +; original program, they are neither needed nor referenced. This seems +; to indicate that other versions of the LIB's were used. To reproduce +; the original program, the above mentioned routines are referenced (in +; stack area) to have them included when linking. +; +; As a byproduct of the disassembly, the structure of a B/P Bios image +; file was documented. This file contains an excerpt. +;************************************************************************ diff --git a/Source/BPBIOS/UTIL/showhd.z80 b/Source/BPBIOS/UTIL/showhd.z80 new file mode 100644 index 00000000..d494acc6 --- /dev/null +++ b/Source/BPBIOS/UTIL/showhd.z80 @@ -0,0 +1,409 @@ + TITLE "B/P Bios HD drive partition display" +;************************************************************************ +;* S H O W H D * +;* Display DPH and DPB data for making B/P HD Partition data the same * +;* by Harold F. Bower and Cameron W. Cotrill * +;*----------------------------------------------------------------------* +;* Disassembly: jxl Jan 2025 * +;* public release 1.0 Apr 2025 * +;* see remarks at the end * +;*----------------------------------------------------------------------* +;* LINK with Version 4 libraries: SYSLIB * +;* * +;* A>Z80ASM SHOWHD/RS * +;* A>SLRNK SHOWHD/N,/A:100,/D:064D,SHOWHD,SYSLIBS/S,/E * +;************************************************************************ + +VER EQU 10 +REV EQU ' ' + +DATE MACRO + DEFB '2 Nov 91' + ENDM + + +CTRLC EQU 03H ; Control-C character +BEL EQU 07H ; Bell character +TAB EQU 09H ; Tab character +LF EQU 0AH ; Line Feed character +CR EQU 0DH ; Carriage Return character +ESC EQU 1BH ; Escape character + +CPMBIOS EQU 0 ; CP/M BIOS warm boot (JP) +CPMFCB EQU 5CH ; CP/M standard FCB #1 (+1 filename, +9 filetype) + + +; For SYSLIB make visible... + PUBLIC COUT + +; From SYSLIB Get.. + EXTRN EPRINT, BOUT, CAPINE, PAFDC, PHLFDC, PA2HC + + +;::::: PROGRAM START + + ORG 100H + CSEG + + +SHOWHD: JP START ; bypass header + DEFB 'Z3ENV' ; this is (not really) a Z3CPR utility + DEFB 1 ; show external environment + +ENVADR: DEFW 0 ; addr of Z3 environment + +START: LD (STACK),SP + LD SP,STACK + CALL EPRINT + DEFB CR,LF,'Show Hard Drive Partition Data - ' + DATE + DEFB CR,LF + DEFB 0 + + LD A,(CPMFCB+1) ; check first char of cmdline + CP '/' ; is this a help request ? + JP Z,HELP ; ..if so, jump + +START0: CALL EPRINT + DEFB CR,LF,'Enter Drive Letter [A..P] : ' + DEFB 0 + CALL CAPINE ; get user input + CP CTRLC ; is it ? + JP Z,0 ; ..abort + CP ESC ; is it ? + JP Z,0 ; ..abort + CP 'A' ; below ascii 'A' ? + JR C,START0 ; ..if so, loop ask for new input + CP 'P'+1 ; greater than ascii 'P' ? + JR NC,START0 ; ..if so, loop ask for new input + LD (DRLTR),A ; store drive letter + + CALL EPRINT + DEFB CR,LF,LF,'Drive: ' + DEFB 0 + CALL COUT ; display drive + CALL EPRINT + DEFB CR,LF,TAB,'DPH Info',TAB,TAB,'BPCNFG Info',CR,LF + DEFB 0 + + CALL GDPHADR ; get DPH addr for selected Disk drive + LD (DPHADR),HL ; ..and store it + LD A,H ; check if invalid (= zero) + OR L + JR NZ,PDSKDAT ; ..if not, skip over + CALL EPRINT + DEFB CR,LF,BEL,'+++ Invalid Drive : ' + DEFB 0 + LD A,(DRLTR) ; get drive letter + CALL COUT ; ..and display it + JP START0 ; then loop to ask for new input + + +;::::: DISPLAY DISK DRIVE DATA + +PDSKDAT: LD DE,10 ; offset in DPH to DPB addr + ADD HL,DE + LD E,(HL) ; DPB addr in DE + INC HL + LD D,(HL) + EX DE,HL ; swap regs + LD (DPBADR),HL ; ..and store DPB addr + CALL EPRINT + DEFB CR,LF,LF,' Sectors/Track = ' + DEFB 0 + LD E,(HL) ; get Sect/Trk from DPB in DE + INC HL + LD D,(HL) + INC HL + EX DE,HL ; swap regs + CALL PHLFDC ; ..and display (as decimal) + SRL H ; divide by 2 + RR L + SRL H ; .. /4 + RR L + SRL H ; .. /8 + RR L + LD (KBTRK),HL ; store kByte/Trk + EX DE,HL ; swap regs + CALL P2TAB + CALL EPRINT + DEFB '(same)',CR,LF,' Blk Shift Fctr = ' + DEFB 0 + LD A,(HL) ; get next byte from DPB (= BSH, Block Shift Factor) + INC HL ; move ptr fwd + CALL PAFDC ; display BSH + CALL P2TAB + SUB 3 ; BSH -3 + LD B,A ; use as counter for multiplication + LD (BSH3),A ; ..and also store it + LD A,1 ; set initial value + JR Z,PBLKSIZ ; if BSH -3 = 0, skip over + +BLKSZLP: ADD A,A ; *2 + DJNZ BLKSZLP ; loop + +PBLKSIZ: CALL PAFDC ; display block size + ; (BSH= 3 -> 1k, 4 -> 2k, ... 8 -> 32k) + CALL EPRINT + DEFB 'k/Block',CR,LF,' Block Mask = ' + DEFB 0 + LD A,(HL) ; next byte from DPB (= BSM, Block Mask) + INC HL + CALL PAFDC ; ..display it + CALL EPRINT + DEFB CR,LF,' Extent Mask = ' + DEFB 0 + LD A,(HL) ; next byte from DPB (= EXM, Extent Mask) + INC HL + CALL PAFDC ; ..display it + CALL EPRINT + DEFB CR,LF,' Disk Blocks-1 = ' + DEFB 0 + LD E,(HL) ; next 16-bit value from DPB in DE + INC HL ; (= Disk Size in BLS units -1) + LD D,(HL) + INC HL + EX DE,HL ; swap regs + CALL PHLFDC ; display value + CALL P2TAB + INC HL ; +1 (= Disk Size) + LD A,(BSH3) ; get BSH-3 + LD B,A ; set as initial loop counter + OR A ; check if zero (means single density 1k/block) + LD A,0 ; nullify A + JR Z,PDSKCAP ; ..if already zero, no more calc needed + +DSKCLP: ADD HL,HL ; double HL (2, 4, 8 etc. k/block) + ADC A,0 ; a power-of-two multiple + DJNZ DSKCLP ; ..and loop + LD (DCAPH),A ; store disk capacity in kByte + LD (DCAPML),HL ; as 24-bit value + +PDSKCAP: CALL PDSKSZ ; ..and display it + CALL EPRINT + DEFB 'k Total (' + DEFB 0 + PUSH DE + LD DE,(KBTRK) ; kByte/Trk + LD HL,(DCAPML) ; disk capacity in kByte + LD A,(DCAPH) + LD BC,-1 ; set initial counter value + OR A + +DSKTRLP: INC BC ; increase counter (quotient) + SBC HL,DE ; divide by subtraction + SBC A,0 ; check for underflow + JR NC,DSKTRLP ; ..and loop while more to go + + LD H,B ; result in HL + LD L,C + CALL PHLFDC ; ..display it + CALL EPRINT + DEFB ' Tracks)' + DEFB 0 + POP DE ; restore DPB ptr + EX DE,HL ; swap to HL + CALL EPRINT + DEFB CR,LF,' Max Dirs - 1 = ' + DEFB 0 + LD E,(HL) ; get next 16-bit value from DPB in DE + INC HL ; (= Dir Max -1) + LD D,(HL) + INC HL + EX DE,HL ; swap regs + CALL PHLFDC ; ..and display value + CALL P2TAB + INC HL ; +1 (= Dir Max) + CALL PHLFDC ; ..and display, too + EX DE,HL + CALL EPRINT + DEFB ' Dir Entries',CR,LF,' Alloc bytes = ' + DEFB 0 + LD A,(HL) ; next byte from DPB (= AL0, Allocation byte 0) + INC HL + LD D,(HL) ; (= AL1, Allocation byte 1) + INC HL + CALL PA2HC ; display AL0 as hex + CALL EPRINT + DEFB 'H, ' + DEFB 0 + LD A,D ; AL1 in A + CALL PA2HC ; ..and display as hex + CALL EPRINT + DEFB 'H',CR,LF,' Check Size = ' + DEFB 0 + LD E,(HL) ; next 16-bit value from DPB in DE + INC HL ; (= CKS, Check Size) + LD D,(HL) + INC HL + EX DE,HL ; swap regs + CALL PHLFDC ; display value + EX DE,HL ; swap regs back + CALL EPRINT + DEFB CR,LF,' Track Offset = ' + DEFB 0 + LD E,(HL) ; next 16-bit value from DPB in DE + INC HL ; (= Track Offset) + LD D,(HL) + INC HL + EX DE,HL ; swap regs + CALL PHLFDC ; display value + EX DE,HL ; swap regs back + CALL P2TAB + CALL EPRINT + DEFB '(same)',CR,LF + DEFB 0 + JP 0 ; and exit with Warm Boot + + + ; print 2 tabs on CON: +P2TAB: PUSH AF + LD A,TAB ; in A + CALL COUT ; display on CON: + CALL COUT ; 2x + POP AF ; restore + RET + + +;::::: HELP + +HELP + CALL EPRINT + DEFB CR,LF,'SHOWHD - Display DPH and DPB data for ' + DEFB 'specified drive for making B/P',CR,LF + DEFB ' Hard Drive Partition data the same as ' + DEFB 'an operating system.',CR,LF,LF + DEFB ' Syntax:',CR,LF,LF + DEFB TAB,'SHOWHD <-- Execute program interactively',CR,LF + DEFB TAB,'SHOWHD // <-- Display this message',CR,LF + DEFB 0 + LD SP,(STACK) + RET + + +;::::: SUPPORT FUNCTIONS + + ; get addr of Disk Parameter Header (DPH) + ; in: Disk drive letter in mem variable + ; out: HL= addr DPH +GDPHADR: LD HL,(CPMBIOS+1) ; addr Bios fn #1 (WBOOT) + LD L,9*3 ; adjust ptr to fn #9 (SELDSK) + LD A,(DRLTR) ; get drive letter + SUB 'A' ; ..and convert to number + LD C,A ; copy to reg. C (for Bios call) + LD E,0 + JP (HL) ; "call" Bios fn #9 and let return from there + ; (SELDSK returns DPH addr in HL) + + + ; print disk size to CON: (capacity of a drive in kB) + ; output as decimal with provision for 3-byte values - see ZXD21.Z80 PRBIG + ; in: 24-bit value to print in A,H,L +PDSKSZ: PUSH DE ; save regs + PUSH BC + EX AF,AF' ; swap AF + PUSH AF ; save it + EX AF,AF' ; ..and swap back + LD B,0 + LD C,-1 ; set initial result + LD DE,86A0H ; 100,000 = 0x0186A0, set lower 2 bytes + OR A ; clear C-Flag +PDSKSZ0: INC C ; accumulate count + SBC HL,DE ; subtract lower 2 bytes + SBC A,1 ; ..and upper byte + JR NC,PDSKSZ0 ; loop till done + ADD HL,DE ; adjust underflow + ADC A,1 + CALL PHLD1 + LD DE,10000 ; print 10000's + CALL PHLD + LD DE,1000 ; print 1000's + CALL PHLD + LD DE,100 ; print 100's + CALL PHLD + LD DE,10 ; print 10's + CALL PHLD + LD A,L ; print 1's + CALL PHLD2 + POP AF ; restore regs + EX AF,AF' ; swap + POP BC ; ..and also restore other regs + POP DE + RET + + + ; print content of HL to CON: as decimal + ; divide HL by DE, convert remainder to ascii digit and print it + ; (similar to SYSLIB's PHLFDC/PHDC1 - see ZXD21.Z80 DECDSP) + ; in: HL= value, DE= divisor +PHLD: LD C,-1 ; set initial count + OR A ; clear C-Flag +PHLD0: INC C ; accumulate count + SBC HL,DE ; divide by subtraction + SBC A,0 + JR NC,PHLD0 ; ..and loop while more to go + ADD HL,DE ; compensate underflow + ADC A,0 +PHLD1: EX AF,AF' ; swap to retain flags + LD A,C ; get result (quotient) + OR A ; is it zero ? + JR NZ,PHLD2 ; ..if not, skip over + OR B ; get prior digit print flag + JR Z,PHLD3 ; ..if anything printed yet, jump + XOR A ; else, print a zero +PHLD2: ADD A,'0' ; convert to ascii + LD B,A ; remember for next loop + CALL COUT ; ..and display it +PHLD3: EX AF,AF' ; swap regs back + RET + + + ; intercept COUT to re-route SYSLIB calls to to BOUT + ; --> declare COUT as PUBLIC, and do _not_ import from SYSLIB +COUT: JP BOUT + + +;::::::::::::::::::::::::::::::::::::::::::::::::::::: +; SYSLIB - 0x0530 +; end addr 0x064d (begin DSEG) +;::::::::::::::::::::::::::::::::::::::::::::::::::::: + + +;::::: RAM STORAGE + + DSEG + +KBTRK: DEFW 0 ; kByte/Trk (Sect/Trk divided by 8) +BSH3: DEFB 0 ; BSH -3 (Block Shift Factor -3) + + ; disk capacity as 24-bit value +DCAPH: DEFB 0 ; high byte +DCAPML: DEFW 0 ; middle and low byte + +DRLTR: DEFB 0 ; drive letter (entered by user) +DPHADR: DEFW 0 ; addr DPH (not used) +DPBADR: DEFW 0 ; addr DPB (not used) + + DEFS 30H ; room for stack +STACK: DEFW 0 ; stack storage location + + END + + +;************************************************************************ +; Remarks jxl: +; SHOWHD.COM, included in available B/P Bios package(s), was dis- +; assembled and extensively commented. Labels are up to seven chars long +; to comply with M-REL standards. However, it is recommended to use SLR +; tools that support labels up to sixteen chars. +; In its current state, the compiled/linked file matches exactly the +; original SHOWHD.COM, i.e. no changes to the source were made. +; +; The program is not very complex. However, one thing might be worth +; to be pointed out: SYSLIB's routine COUT is replaced with an own +; implementation. While it is just a re-routing to another SYSLIB routine, +; it shows how simply this can be achieved. Bear in mind that _all_ +; SYSLIB routines calling COUT would now call the local implementation +; instead. With this technique existing routines can be modified without +; rewriting them entirely. +;************************************************************************ diff --git a/Source/BPBIOS/UTIL/sizeram.z80 b/Source/BPBIOS/UTIL/sizeram.z80 new file mode 100644 index 00000000..71626856 --- /dev/null +++ b/Source/BPBIOS/UTIL/sizeram.z80 @@ -0,0 +1,546 @@ + TITLE "B/P Bios RAM size display" +;************************************************************************ +;* S I Z E R A M * +;* Determine size and location of (banked) Memory * +;* by Harold F. Bower and Cameron W. Cotrill * +;*----------------------------------------------------------------------* +;* Disassembly: jxl Dec 2024 * +;* public release 1.0 Apr 2025 * +;* see remarks at the end * +;*----------------------------------------------------------------------* +;* LINK with Version 4 libraries: VLIB, Z3LIB, SYSLIB * +;* * +;* A>Z80ASM SIZERAM/RS * +;* A>SLRNK SIZERAM/N,/A:100,/D:0750,SIZERAM,VLIBS/S,Z3LIBS/S,SYSLIBS/S,/E * +;************************************************************************ + +VER EQU 12 +REV EQU ' ' + +DATE MACRO + DEFB '30 Aug 01' + ENDM + + +BEL EQU 07H ; Bell character +LF EQU 0AH ; Line Feed character +CR EQU 0DH ; Carriage Return character + +CPMBIOS EQU 0 ; CP/M BIOS warm boot (JP) +CPMBDOS EQU 5 ; CP/M BDOS entry point (JP) +CPMFCB EQU 5CH ; CP/M standard FCB #1 (+1 filename, +9 filetype) + + +; From Z3LIB Get.. + EXTRN GETNAME, PRTNAME, Z3INIT, WHRENV + +; From SYSLIB Get.. + EXTRN EPRINT, CRLF, PAFDC, PHLFDC, COUT, CODEND + + +;::::: PROGRAM START + + ORG 100H + CSEG + + +SIZERAM: JP START ; bypass header + DEFB 'Z3ENV' ; this is a ZCPR3 utility + DEFB 1 ; show external environment + +ENVADR: DEFW 0 ; addr of Z3 environment + DEFW SIZERAM ; type 4 filler + + DEFB 'SIZERAM ',0 ; configuration name + +START: LD (STACK),SP + LD SP,STACK + CALL EPRINT + DEFB 'B/P Banked RAM Sizing Utility V',VER/10+'0','.' + DEFB VER MOD 10 + '0',REV,' ' + DATE + DEFB CR,LF + DEFB 0 + CALL CHKZ3E ; check if Z3 Environment is valid + CALL GETNAME ; get actual program name + CALL CHKHELP ; check cmdline for help request + CALL CHKSYS ; check if running under B/P Bios + CALL M$BVER ; display version # msg + LD HL,(BPCNFG) ; get addr of config area + INC HL ; move ptr fwd + INC HL + LD A,(HL) ; get OPTF1 (option flag at CONFIG+2) + AND 00000001b ; mask bit 0 + LD (BPBNKD),A ; ..and store it + JP NZ,BNKDSYS ; if banked, jump to continue + + +;::::: NON-BANKED SYSTEM + +NBNKSYS: INC HL ; move ptr to TPABNK in config area + INC HL + CALL EPRINT + DEFB CR,LF,LF,'Non-Banked System using TPA Banks = ' + DEFB 0 + LD A,(HL) ; get value + PUSH AF + CALL PAFDC ; ..and display + LD A,'/' + CALL COUT + POP AF ; restore value + INC A ; increase it + CALL PAFDC ; ..and display + CALL CRLF + JP EXIT + + +;::::: BANKED SYSTEM + +BNKDSYS: INC HL ; move ptr to UABNK in config area + LD DE,UABNK ; ..and make local copies + LD BC,5 ; (5 bytes, UABNK..MAXBNK) + LDIR + CALL CODEND ; get first available page after code end + LD (WSPCBEG),HL ; and store it + EX DE,HL ; swap regs + + ; memory read/write tests for all ram banks at addr 0x0000 + ; building a map in WSPC area: b1= zero if no bank found, b2= initially read byte + + ; test #1: 0x00/0xFF byte - iterate over banks in forward order + LD HL,0 ; set addr 0x0000 + LD C,0 ; start with bank #0 (TPA) +MEMRW: CALL GETFRB ; get byte + LD B,A ; store in B + CPL ; invert (complement) byte + CALL SETINB ; write it back + CALL GETFRB ; read again + CPL ; ..and invert + XOR B ; xor'd with initially read byte + JR NZ,MEMRW0 ; ..if no match, skip over + LD A,B ; get initially read byte + CALL SETINB ; write it + CALL GETFRB ; and read again + SUB B ; subtract initially read byte + JR NZ,MEMRW0 ; ..if not zero, skip over + + ; injected opcode 0xF6 (OR n) to skip following XOR A + DEFB 0F6h ; = OR 0AFH (write non-zero) +MEMRW0: XOR A ; nullify A + LD (DE),A ; store in WSPC area + INC DE ; move ptr fwd + LD A,B ; get initially read byte + LD (DE),A ; store it, too + INC DE ; move ptr fwd + INC C ; bank # +1 + JR NZ,MEMRW ; ..loop till all possible (256 / 0x100) banks tested + + ; test #2: write no. in each bank (iterate backward), then read and compare (forward) + DEC C ; correct bank # (loop was 1 ahead) +MEMWRB: DEC DE ; move ptr back + DEC DE + LD A,(DE) ; get byte + OR A ; check if bank exists + JR Z,MEMWRB0 ; ..if not, skip over + LD A,C ; else, get bank # + CALL SETINB ; and write in bank +MEMWRB0: LD A,C ; get bank # + SUB 1 ; -1 + LD C,A ; set bank # + JR NC,MEMWRB ; ..if not below zero, loop + INC C ; correct bank # + +MEMRDB: LD A,(DE) ; get byte from WSPC area + OR A ; check if bank exists + JR Z,MEMRDB0 ; ..if not, skip over + CALL GETFRB ; read byte from bank + CP C ; compare to bank # + JR Z,MEMRDB0 ; ..if match, skip over + XOR A ; else, set as indicator + LD (DE),A ; that bank doesn't exist +MEMRDB0: INC DE ; move ptr fwd + INC DE + INC C ; bank # +1 + JR NZ,MEMRDB ; ..loop till all possible (256 / 0x100) banks tested + + ; restore bytes initially read in all banks + LD DE,(WSPCBEG) ; set ptr to start of WSPC addr +MEMRST: LD A,(DE) ; get byte + OR A ; check bank exists + JR Z,MEMRST0 ; ..if not, skip over + INC DE ; move ptr fwd + LD A,(DE) ; get initially read byte + CALL SETINB ; ..and restore it + INC DE ; ptr fwd + JR MEMRST1 ; skip over +MEMRST0: INC DE ; ptr fwd + INC DE +MEMRST1: INC C ; bank # +1 + JR NZ,MEMRST ; loop till done + ; ..then fall through to display collected data + + + ; display information for Banked System + ; detect ranges of continuous ram banks + ; + ; HL= ptr in WSPC area + ; C= counter (up) bank #, B= counter (down) for outer loop + ; D= bank # begin of range, E= bank # end of range + LD BC,0 + LD HL,(WSPCBEG) ; set ptr to start of WSPC addr +BRANGLP: LD A,(HL) ; get byte + OR A ; check bank exists + JR NZ,BRANGE ; ..if so, skip over + INC HL ; else, use a shorter loop + INC HL ; ..move ptr fwd + INC C ; ..and bank # + JR NZ,BRANGLP ; loop until max. reached (256 / 0x100) + JR PCNFIG ; else, display Bios config report + +BRANGE: LD D,C ; store start of range (bank # in D) +BRANG0: INC HL ; ptr fwd + INC HL + INC C ; bank # +1 + JR NZ,BRANG1 ; ..if not max., skip over + DEC B + JR PBRANG ; else, display bank ranges + +BRANG1: LD A,(HL) ; get byte + OR A ; check bank exists + JR NZ,BRANG0 ; ..if so, loop + ; else, fall through + + ; display collected information +PBRANG: LD E,C ; get current bank # in E + DEC E ; loop is ahead, so -1 + CALL EPRINT + DEFB CR,LF,'RAM Banks ' + DEFB 0 + LD A,D ; get begin of range + CALL PAFDC ; ..and display it + CALL EPRINT + DEFB ' - ' + DEFB 0 + LD A,E ; get end of range + CALL PAFDC ; ..and display it + CALL EPRINT + DEFB ' (' + DEFB 0 + LD A,E ; get end of range + INC A ; adjust for correct calc + SUB D ; calc difference of begin/end + PUSH HL + LD L,A ; get value in L + LD H,0 ; ..and multiply for display + ADD HL,HL ; *2 + ADD HL,HL ; *4 + ADD HL,HL ; *8 + ADD HL,HL ; *16 + ADD HL,HL ; *32 (fixed bank size of 32k assumed) + CALL PHLFDC ; ..and display + POP HL + CALL EPRINT + DEFB 'k Bytes)' + DEFB 0 + LD A,B ; check if more to go + OR A + JR Z,BRANGLP ; loop till done + + ; display information as stored in B/P Bios config area +PCNFIG: CALL EPRINT + DEFB CR,LF,LF,'Bios Reports:',CR,LF + DEFB ' TPA Banks = ' + DEFB 0 + LD A,(TPABNK) ; get TPA bank # + PUSH AF ; save regs + CALL PAFDC ; and display it + LD A,'/' + CALL COUT + POP AF ; restore value + INC A ; +1 (TPA bank is build by 2 consecutive banks) + ; fixed size of 32k per bank is assumed + CALL PAFDC ; and display it + CALL EPRINT + DEFB CR,LF,' System Bank = ' + DEFB 0 + LD A,(SYSBNK) ; get SYSTEM bank # + CALL PAFDC ; and display it + CALL EPRINT + DEFB CR,LF,' User Bank = ' + DEFB 0 + LD A,(UABNK) ; get # of USER banks + OR A + JR NZ,PCNFIG0 ; ..if not zero, skip over + CALL EPRINT + DEFB '(None)' + DEFB 0 + JR PCNFIG1 +PCNFIG0: CALL PAFDC ; display # of USER banks +PCNFIG1: CALL EPRINT + DEFB CR,LF,' RAM Disk Start = ' + DEFB 0 + LD A,(RAMBNK) ; get # of begin RAM Disk + CALL PAFDC + CALL EPRINT + DEFB CR,LF,' Last Used Bank = ' + DEFB 0 + LD A,(MAXBNK) ; get max. available bank # + CALL PAFDC + CALL EPRINT + DEFB CR,LF,LF,' -- Scan Complete.',CR,LF + DEFB 0 + JP EXIT + + +;::::: SUPPORT FUNCTIONS + + ; get first token from command line (in FCB #1) + ; and check if help was requested +CHKHELP: LD HL,CPMFCB+1 + LD A,(HL) ; get byte + CP '/' ; is this a help request ? + RET NZ ; ..if not, return + INC HL ; else, move ptr fwd + LD A,(HL) ; and get next byte + CP '/' ; is it also '/' ? + RET NZ ; ..if not, return + ; else, fall through and display help + + +;::::: HELP SCREEN + +HELP: CALL EPRINT + DEFB CR,LF,' ' + DEFB 0 + CALL PPRGNAM + CALL EPRINT + DEFB ' Determines location and Size of Banked Memory.',CR,LF + DEFB ' (Only TPA Banks printed if Non-Banked)',CR,LF,LF + DEFB ' Syntax:',CR,LF + DEFB ' ' + DEFB 0 + CALL PPRGNAM + CALL EPRINT + DEFB ' - Print 32k RAM banks present and B/P Allocations',CR,LF + DEFB ' ' + DEFB 0 + CALL PPRGNAM + CALL EPRINT + DEFB ' // - display this screen',CR,LF + DEFB 0 ; fall through and exit + + +;::::: EXIT PROGRAM + +EXIT: CALL CRLF + LD SP,(STACK) ; restore stack pointer + RET ; ..and return to system + + +;::::: SUPPORT FUNCTIONS + + ; check if running under ZCPR3 and status of wheel byte + ; terminate program if not succesful +CHKZ3E: LD HL,(CPMBDOS+1) + CALL WHRENV ; find Z3 Environment Descriptor + LD (ENVADR),HL ; store ENV ptr + LD A,H ; check if invalid (= zero) + OR L + JP Z,E$BPBIO ; ..if so, jump error and terminate + CALL Z3INIT ; else, init for Z3LIB routines + LD A,41 ; offset to addr of wheel byte (Z3WHL) + CALL ADDHLA ; adjust ptr + LD E,(HL) ; get addr in DE + INC HL + LD D,(HL) + EX DE,HL ; swap regs + LD A,(HL) ; get value of wheel byte + AND A ; check if zero + RET NZ ; ..if not (wheel on), return + CALL EPRINT ; else, display message and exit + DEFB BEL,CR,LF,'Must be wheel to Execute !',CR,LF + DEFB 0 + JR EXIT + + + ; check if running under B/P Bios + ; if not, program is terminated +CHKSYS: LD HL,(CPMBIOS+1) ; get warm boot addr (BIOS fn #1) + LD L,30*3 ; adjust ptr to fn #30 + LD A,(HL) ; check byte at ptr location + CP 0C3H ; is it opcode 0xC3 (JP) ? + JR NZ,E$BPBIO ; ..if not, jump error and terminate + CALL JUMPHL ; else, "call" B/P Bios fn #30 (RETBIO) + LD (BPVERS),A ; store version of B/P Bios + LD (BPADDR),BC ; " base addr + LD (BPCNFG),DE ; " config area addr + LD HL,-6 ; move ptr 6 bytes backward + ADD HL,DE ; (signature string) + LD A,(HL) ; get byte + CP 'B' ; is it 'B' ? + JR NZ,E$BPBIO ; ..if not, jump error and exit + INC HL ; ptr fwd + LD A,(HL) ; get byte + CP '/' ; is it '/' ? + JR NZ,E$BPBIO ; ..if not, jump error and exit + INC HL ; ptr fwd + LD A,(HL) ; get byte + CP 'P' ; is it 'P' ? + RET Z ; ..if so, return + ; else, fall through (error and exit) + + + ; msg aborting +E$BPBIO: CALL EPRINT + DEFB CR,LF,BEL,'Not B/P Bios, aborting...!',CR,LF + DEFB 0 + RST 0 + + + ; print program name on CON: device + ; (either the actual name, or fallback to default) + ; only used by HELP +PPRGNAM: LD A,(ENVADR+1) ; get high byte of ENVPTR + OR A ; check if valid (<> zero) + JP NZ,PRTNAME ; ..if so, display actual name + ; ..and let return from there + CALL EPRINT ; else, display default + DEFB 'SIZERAM' + DEFB 0 + RET + + + ; msg B/P Bios Vers x.x +M$BVER: CALL EPRINT + DEFB ' (B/P Bios Vers ' + DEFB 0 + LD A,(BPVERS) ; get version # + RRCA ; reverse nybbles in A + RRCA + RRCA + RRCA + AND 00001111b ; mask lower nybble + ADD A,'0' ; make it ascii + CALL COUT ; ..and display + LD A,'.' + CALL COUT + LD A,(BPVERS) ; get version # + AND 00001111b ; mask lower nybble + ADD A,'0' ; make it ascii + CALL COUT ; ..and display + CALL EPRINT + DEFB ')',CR,LF + DEFB 0 + RET + + + ; add A to HL (result in HL) +ADDHLA: ADD A,L ; add L + LD L,A ; store result in L + RET NC ; ..if no overflow, return + INC H ; else, increment H + RET + + + ; the following routines rearrange Top of Stack by injecting an + ; intermediate return addr, and putting the Bios fn call on top + ; so that HL regs are preserved + ; order of steps: + ; [1] HL (= addr) is pushed onto stack + ; [2] intermediate return addr is swapped to Top of Stack + ; [3] HL (= addr) is pushed onto stack again + ; [4] Bios fn JP addr is swapped to Top of Stack + ; [5] Bios is "called" through RET, and returns to intermediate addr + + ; get byte from ram bank - in the form LD A,(HL) + ; in: C= bank #, HL= addr + ; out: A= byte +GETFRB: PUSH BC + PUSH HL ; save addr + LD HL,GETFRB0 ; load return addr + EX (SP),HL ; put it on stack + PUSH HL ; save HL again (previous top of stack) + LD HL,(BPADDR) ; get B/P Bios base addr + LD L,35*3 ; adjust ptr to fn #35 (FRGETB) + EX (SP),HL ; put addr on stack + RET ; ..and "call" Bios fn through stack + +GETFRB0: POP BC ; restore regs + RET ; ..and finally return + + ; set byte in ram bank - in the form LD (HL),A + ; in: C= bank #, HL= addr, A= byte to set +SETINB: PUSH BC + PUSH HL ; save addr + LD HL,GETFRB0 ; load return addr + EX (SP),HL ; put it on stack + PUSH HL ; save HL again (previous top of stack) + LD HL,(BPADDR) ; get B/P Bios base addr + LD L,37*3 ; adjust ptr to fn #37 (FRPUTB) + EX (SP),HL ; put addr on stack + RET ; ..and "call" Bios fn through stack + + + ; "called" as a pseudo-routine that returns to caller + ; in: HL= target addr +JUMPHL: JP (HL) ; jump to addr in HL regs + + +;::::: LOCAL DATA (not in DSEG) + +WSPCBEG: DEFW 0 ; addr begin of workspace area + ; (first available page, returned by CODEND) + + ; data retrieved from running system +BPVERS: DEFB 0 ; B/P Bios version +BPADDR: DEFW 0 ; B/P Bios base addr +BPCNFG: DEFW 0 ; addr of Config Area +BPBNKD: DEFB 0 ; indicator banked system (bit 0 of OPTF1) --> not used + + ; local copies of RAM bank configuration +UABNK: DEFB 0 ; beginning of User Bank(s) +TPABNK: DEFB 0 ; TPA Bank +SYSBNK: DEFB 0 ; beginning of System Bank(s) +RAMBNK: DEFB 0 ; base bank # for Ram Disk +MAXBNK: DEFB 0 ; highest permissible Bank # + + + DEFS 30H ; room for stack +STACK: DEFW 0 ; stack storage location + + +;::::::::::::::::::::::::::::::::::::::::::::::::::::: +; Z3LIB - 0x05ae +; SYSLIB - 0x065c +; end addr 0x0750 (begin DSEG) +;::::::::::::::::::::::::::::::::::::::::::::::::::::: + + +;::::: RAM STORAGE + + DSEG + + END + + +;************************************************************************ +; Remarks jxl: +; SIZERAM.COM, included in available B/P Bios package(s), was dis- +; assembled and extensively commented. Labels are up to seven chars long +; to comply with M-REL standards. However, it is recommended to use SLR +; tools that support labels up to sixteen chars. +; In its current state, the compiled/linked file matches exactly the +; original INITRAM.COM, i.e. no changes to the source were made. +; +; The program uses an interesting technique to read and write data in +; alternative ram banks utilizing B/P Bios functions no. 35 FRGETB and +; no. 37 FRPUTB. Top of Stack is manipulated to keep registers intact +; and "call" functions through a RET statement (instead of CALL.) +; Another specialty which is worth mentioning: Routine MEMRW (memory +; read/write) contains an "injected" opcode to alter the behaviour at +; runtime. Otherwise a more complex logic and/or additional routine +; would have been necessary. +; Storage of local data is in CSEG (code segment), not DSEG. There +; seems to be no particular reason for this. So, it can be assumed that +; this just happened by mistake. +;************************************************************************ diff --git a/Source/BPBIOS/UTIL/zscfg2.z80 b/Source/BPBIOS/UTIL/zscfg2.z80 new file mode 100644 index 00000000..d91d1846 --- /dev/null +++ b/Source/BPBIOS/UTIL/zscfg2.z80 @@ -0,0 +1,1323 @@ + TITLE "Change ZSDOS v2 Configuration Settings" +;************************************************************************ +;* Z S C F G 2 * +;* Set the user-configurable parameters in a running ZSDOS v2 system * +;* by Harold F. Bower and Cameron W. Cotrill * +;*----------------------------------------------------------------------* +;* Disassembly: jxl Jan 2025 * +;* public release 1.0 Apr 2025 * +;* see remarks at the end * +;*----------------------------------------------------------------------* +;* LINK with Version 4 libraries: VLIB, Z3LIB, SYSLIB * +;* * +;* A>Z80ASM ZSCFG2/RS * +;* A>SLRNK ZSCFG2/N,/A:100,/D:145E,ZSCFG2,VLIBS/S,Z3LIBS/S,SYSLIBS/S,/E * +;************************************************************************ + +VER EQU 20 +REV EQU 'b' + +DATE MACRO + DEFB '' + ENDM + + +CTRLC EQU 03H ; Control-C character +BEL EQU 07H ; Bell character +TAB EQU 09H ; Tab character +LF EQU 0AH ; Line Feed character +CR EQU 0DH ; Carriage Return character + +CPMBIOS EQU 0 ; CP/M BIOS warm boot (JP) +CPMBDOS EQU 5 ; CP/M BDOS entry point (JP) +CPMDMA EQU 80H ; CP/M standard DMA buffer + + +; From VLIB Get.. + EXTRN GXYMSG, VPRINT, AT, EREOL, STNDOUT, STNDEND, CLS, GOTOXY, Z3VINIT + +; From Z3LIB Get.. + EXTRN GETQUIET, WHRENV + +; From SYSLIB Get.. + EXTRN BDOS, CRLF, CIN, PHL4HC, COUT, CAPS, @B2HH, @B2HL + + +;::::: PROGRAM START + + ORG 100H + CSEG + + +ZSCFG2: JP START ; bypass header + DEFB 'Z3ENV' ; this is a ZCPR3 utility + DEFB 1 ; show external environment + +ENVADR: DEFW 8000H ; addr of Z3 environment + +START: LD (STACK),SP + LD SP,STACK + + ; clear variables in ram + LD HL,DOSBASE + LD B,DOSTYVE-DOSBASE +CLRVAR: LD (HL),0 + INC HL + DJNZ CLRVAR + + LD A,0FFH ; set effective Bit Mask + LD (OFLGMSK),A ; to default state (all bits = 1) + LD HL,(CPMBDOS+1) ; starting from BDOS warm boot addr + CALL WHRENV ; find Z3 Environment Descriptor + LD (ENVADR),HL ; store ptr + CALL Z3VINIT ; ..and init for VLIB/Z3LIB routines + LD C,12 + CALL BDOS ; get BDOS version # + CP 22H ; must be CP/M 2.2 + JP NZ,E$ZSDOS ; ..if not, jump error and exit + LD C,48 + CALL BDOS ; check if ZSDOS + LD (DOSTYVE),HL ; save DOS type and version # + LD HL,CPMDMA ; set to cmdline buffer + LD B,(HL) ; get char count + INC HL ; move ptr fwd + CALL CMDPDL ; get past delimiters (skip , , and Comma) + JP Z,START0 ; ..if cmdline empty, jump to continue (interactive mode) + CP '/' ; is this a help request ? + LD (RUNMODE),A ; store run mode + JP NZ,START0 ; ..if not, jump to continue + INC HL + LD A,(HL) ; else, get next char + CP '/' ; help requested ? + JP NZ,START0 ; ..if not, jump to continue + + +;::::: HELP SCREEN + + CALL VPRINT + DEFB CR,LF,LF,1,'ZSCFG2',2,' Ver ',VER/10+'0','.' + DEFB VER MOD 10 + '0',REV,' - Examine/Set ZSDOS Vers 2 parameters' + DEFB CR,LF,LF,' Syntax:',CR,LF,LF + DEFB ' ZSCFG - Interactive',CR,LF + DEFB ' ZSCFG o[p],[o[p]],.. - Expert Mode',CR,LF,LF + DEFB ' Options [parameters]:',CR,LF,LF + DEFB ' P [-] Public Files R [-] Read/Only sustain',CR,LF + DEFB ' ! [-] Disk Change Alert F [-] Fast Relog',CR,LF + DEFB ' W [-] Public/Path Write S [-] Path w/o SYStem',CR,LF + DEFB ' C [ -, B or Hex value ] Clock address',CR,LF + DEFB ' * [ -, Z, or Hex value ] Wheel write protect',CR,LF + DEFB ' > [ -, Z, I, or Hex value ] DOS Search Path',CR,LF,LF + DEFB ' + [ A, C, M ][ - ] Access, Create, Modify Time Stamps',CR,LF,LF + DEFB '[more]..' + DEFB 0 + CALL CIN + CP CTRLC ; is it ? + JP Z,EXIT0 ; ..then exit program + LD A,CR ; print extra + CALL COUT + CALL EREOL + CALL VPRINT + DEFB ' Examples:',CR,LF,LF + DEFB ' ZSCFG2 *Z,P,!-',CR,LF + DEFB ' (ZCPR3 Wheel, Public ON, Warning OFF)',CR,LF,LF + DEFB ' ZSCFG2 CE800 F R',CR,LF + DEFB ' (Clock Routine=E800H, Fast Relog ON, R/O Sustain ON)',CR,LF,LF + DEFB ' ZSCFG2 CB,>I',CR,LF + DEFB ' (Clock=Bios+4EH, Int Path)',CR,LF,LF + DEFB ' Note:',CR,LF + DEFB ' Delimiters are : TAB, SPACE and Comma',CR,LF,LF + DEFB 0 + JP EXIT0 ; ..and exit program + + +START0: CALL VPRINT + DEFB CR,LF,1,'ZSCFG2'2,' V',VER/10+'0','.' + DEFB VER MOD 10 + '0',REV,' Copyright (C) 1991/2' + DEFB ' Harold F. Bower/Cameron W. Cotrill',CR,LF,LF + DEFB 0 + + LD A,(RUNMODE) ; check mode + OR A ; running interactively ? + CALL Z,CLS ; ..if so, clear screen first + LD A,(DOSTYVE+1) ; get DOS type + CP 'S' + JP NZ,E$ZSDOS ; ..if not ZSDOS, jump error and exit + LD A,(DOSTYVE) ; get DOS version # (BCD) + CP 20H ; minimum 2.0 required + JR NC,PDOSVER ; ..if so, jump to continue + CALL VPRINT ; else, display error and exit + DEFB CR,LF,BEL,'+++ Must have ZSDOS 2.0 or later +++',CR,LF + DEFB 0 + JP EXIT0 ; ..and exit program + + ; print DOS version +PDOSVER: PUSH AF + CALL VPRINT + DEFB ' ...Configuring ZSDOS Ver ' + DEFB 0 + POP AF ; restore version # + PUSH AF + CALL @B2HH ; convert upper nybble (major vers.) + CALL COUT ; and display it + LD A,'.' + CALL COUT + POP AF + CALL @B2HL ; convert lower nybble (minor vers.) + CALL COUT ; and display it + CALL CRLF + LD A,(RUNMODE) ; check run mode + OR A ; is interactive ? + JR NZ,PENVBA0 ; ..if not, jump + LD HL,(ENVADR) ; get ENV addr + LD A,H ; check if valid (<> zero) + OR L + JR NZ,PENVBAS + CALL VPRINT + DEFB CR,LF,'No Z3 Environment Found',CR,LF + DEFB 0 + JP FNDDOS + + ; Z3ENV found, print basic information +PENVBAS: CALL GXYMSG + DEFB 1,40,'Z3 Environment at : ' + DEFB 0 + LD HL,(ENVADR) ; get ENV addr + CALL PHLXH ; display addr (as hex) + CALL CRLFGXY + DEFB 2,40,'ZCPR Path Address : ' + DEFB 0 +PENVBA0: LD DE,9 + LD HL,(ENVADR) ; get ENV addr + ADD HL,DE ; adjust ptr to EXPATH + LD E,(HL) ; addr ZCPR Path in DE + INC HL + LD D,(HL) + EX DE,HL ; swap regs + LD (ZPTHADR),HL ; store addr + LD A,(RUNMODE) ; check run mode + OR A ; is interactive ? + JR NZ,PENVBA1 ; ..if not, skip over + CALL PHLXH ; display addr (as hex) + CALL CRLFGXY + DEFB 3,45,'Wheel Byte at : ' + DEFB 0 +PENVBA1: LD DE,41 + LD HL,(ENVADR) ; get ENV addr + ADD HL,DE ; adjust ptr to Z3WHL + LD E,(HL) ; addr ZCPR Wheel byte in DE + INC HL + LD D,(HL) + EX DE,HL ; swap regs + LD (ZWHLADR),HL ; store addr + LD A,(RUNMODE) ; check run mode + OR A ; is interactive ? + JR NZ,FNDDOS ; ..if not, skip over + CALL PHLXH ; display addr (as hex) + CALL CRLF + + ; find DOS base +FNDDOS: LD HL,(ENVADR) ; get ENV addr + LD A,H ; check if reasonable + OR L + JR C,FNDDSIZ ; ..if not, continue with standard DOS size + LD DE,8 ; offset to Environment ID byte + EX DE,HL + ADD HL,DE ; adjust ptr + BIT 7,(HL) ; test bit 7 (set means Extended Environment Descr.) + JR Z,FNDDSIZ ; ..if not set (= zero), continue with standard size + LD HL,66 ; offset to DOS start addr + ADD HL,DE ; adjust ptr + LD E,(HL) ; and get addr in DE + INC HL + LD D,(HL) + EX DE,HL ; swap regs + JR FNDDO0 ; jump to continue + + ; use DOS standard size (0xE00H, 3.5kB) +FNDDSIZ: LD A,(CPMBIOS+2) ; high byte of Bios WBOOT addr + SUB 0Eh ; DOS assumed 3.5kB below Bios + LD H,A ; make it 16-bit + LD L,0 + +FNDDO0: LD (DOSBASE),HL ; store DOS base addr + PUSH HL ; move to IX + POP IX + LD DE,21 ; offset to FLAGS byte in ZSDOS header + ADD IX,DE ; (hdr is similar to v1.x) + LD (OFLGADR),IX ; store addr + LD A,(RUNMODE) ; check run mode + OR A ; is interactive ? + JP NZ,EXPMODE ; ..if not, jump + + +;::::: INTERACTIVE MODE + + ; print current settings (based on Flag bytes) on CON: +PSETTG: CALL CRLF + CALL AT ; pos cursor + DEFB 22,1 + CALL EREOL ; clear line + LD HL,0501H ; row 5, col 1 + CALL GOTOXY + + CALL VPRINT + DEFB ' 1 - Public Files : ' + DEFB 0 + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + BIT 0,(IX+0) ; check bit 0 (Public Files, 1= enabled) + CALL PYESNO ; display Yes/No + + CALL VPRINT + DEFB CR,LF,' 2 - Pub/Path Write Enable : ' + DEFB 0 + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + BIT 1,(IX+0) ; check bit 1 (Public/Path Write, 1= enabled) + CALL PYESNO + + CALL VPRINT + DEFB CR,LF,' 3 - Read-Only Vector : ' + DEFB 0 + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + BIT 2,(IX+0) ; check bit 2 (Read-Only, 1= enabled) + CALL PYESNO + + CALL VPRINT + DEFB CR,LF,' 4 - Fast Fixed Disk Log : ' + DEFB 0 + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + BIT 3,(IX+0) ; check bit 3 (Fast Relog, 1= enabled) + CALL PYESNO + + CALL VPRINT + DEFB CR,LF,' 5 - Disk Change Warning : ' + DEFB 0 + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + BIT 4,(IX+0) ; check bit 4 (Disk Chg Warning, 1= enabled) + CALL PYESNO + + CALL VPRINT + DEFB CR,LF,' 6 - Path w/o System Attr : ' + DEFB 0 + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + BIT 6,(IX+0) ; check bit 6 (Path w/o System, 1= enabled) + CALL PYESNO + + CALL VPRINT + DEFB CR,LF,' 7 - DOS Search Path : ' + DEFB 0 + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + BIT 5,(IX+0) ; check bit 5 (ZCPR Path, 1= eanbled) + JR Z,PSETTG1 + CALL VPRINT + DEFB 1,'Enabled',2 + DEFB 0 + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + LD E,(IX-4) ; get addr DOS internal path + LD D,(IX-3) + LD L,(IX+8) ; get reference addr (new in v2) + LD H,(IX+9) + OR A + SBC HL,DE ; compare the 2 addr's + JR NZ,PSETTG0 ; ..if not internal, skip over + CALL VPRINT + DEFB ' - Internal' + DEFB 0 + JR PSETTG2 + +PSETTG0: CALL VPRINT + DEFB ' Addr = ' + DEFB 0 + EX DE,HL + CALL PHLXHHI ; display addr (as hex w/ highlighting) + JR PSETTG2 + +PSETTG1: CALL VPRINT + DEFB 1,'Disabled',2 + DEFB 0 + +PSETTG2: CALL EREOL + CALL VPRINT + DEFB CR,LF,' 8 - Wheel Byte Protect : ' + DEFB 0 + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + LD L,(IX-2) ; get addr of WHEEL byte + LD H,(IX-1) + LD A,H ; check if valid (<> zero) + OR L + JR Z,PSETTG3 ; ..if not, skip over + PUSH HL + CALL VPRINT + DEFB 1,'Enabled',2,' Addr = ' + DEFB 0 + POP HL + CALL PHLXHHI ; display addr (as hex w/ highlighting) + CALL EREOL + JR PSETTG4 +PSETTG3: CALL VPRINT + DEFB 1,'Disabled',2,'..Assumed ON' + DEFB 0 + CALL EREOL + +PSETTG4: CALL VPRINT + DEFB CR,LF,' T - Time Routine (Clock) : ' + DEFB 0 + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + LD L,(IX+2) ; get addr of time/date routine + LD H,(IX+3) + CALL PTIMERS ; display Time Routine status (addr or 'disabled') + + CALL VPRINT + DEFB CR,LF,' A - Stamp Last Access Time : ' + DEFB 0 + LD A,00000001b ; check bit 0 + CALL PSTAMPS ; and display status + + CALL VPRINT + DEFB CR,LF,' C - Stamp Create Time : ' + DEFB 0 + LD A,00000010b ; check bit 1 + CALL PSTAMPS ; and display status + + CALL VPRINT + DEFB CR,LF,' M - Stamp Modify Time : ' + DEFB 0 + LD A,00000100b ; check bit 2 + CALL PSTAMPS ; and display status + + CALL CRLF + LD HL,01501H ; row 21, col 1 + CALL GOTOXY ; pos cursor + CALL EREOL ; clear line + CALL GXYMSG + DEFB 20,1,'Entry to Change ("X" to EXIT) : ' + DEFB 0 + CALL EREOL + ; --- << end of print settings >> --- + + + ; interactive mode - get console input and branch accordingly + ; B indicates the bit to be changed +IMCINPT: CALL CIN + CALL CAPS ; capitalize input + CP ' ' ; is it a control char (below ) ? + JR C,IMCINPT ; ..if so, loop to get new input + CALL COUT ; else, echo char + CP 'X' ; is it 'X' ? + JP Z,EXIT ; exit program + LD B,00000001b + CP '1' ; Public Files ? + JP Z,IMTGOP ; toggle bit in Option Flag (interactive) + LD B,00000010b + CP '2' ; Public/Path Write ? + JP Z,IMTGOP + LD B,00000100b + CP '3' ; Read-Only ? + JP Z,IMTGOP + LD B,00001000b + CP '4' ; Fast Relog ? + JP Z,IMTGOP + LD B,00010000b + CP '5' ; Disk Change Warning ? + JP Z,IMTGOP + LD B,01000000b + CP '6' ; Search Path w/o System Attr ? + JP Z,IMTGOP + CP '7' ; DOS Search Path ? + JP NZ,IMWHL ; ..if not, jump to continue checking input + + + ; interactive mode - change Path + CALL CRLFGXY ; else, fall through to change DOS Path + DEFB 21,16,'DOS Path [(' + DEFB 1,'D',2,')isable, (' + DEFB 1,'S',2,')et, (' + DEFB 1,'I',2,')nternal' + DEFB 0 + LD HL,(ENVADR) ; get ENV addr + LD A,H ; check if valid (<> zero) + OR L + JR Z,IMPATH + CALL VPRINT + DEFB ', (',1,'Z',2,')CPR3' + DEFB 0 +IMPATH: CALL VPRINT + DEFB '] : ' + DEFB 0 + + ; input +IMPTHIN: CALL CINCAPS ; get user input and capitalize + CP 'D' ; is it 'D'isable ? + JR Z,IMPTHDS + CP 'Z' ; is it 'Z'CPR ? + JR Z,IMPTHZ + CP 'I' ; is it 'I'nternal ? + JR NZ,IMPTHST ; ..if not, jump to check other options + ; else, fall through + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + LD L,(IX+8) ; get reference addr (new in v2) + LD H,(IX+9) + JR IMPTHEN + + ; set +IMPTHST: CP 'S' ; is it 'S'et addr ? + JR NZ,IMPTHIN ; ..loop if input not valid + CALL CRLFGXY + DEFB 22,25,'Enter PATH Address : ' + DEFB 0 + LD HL,0 ; set initial value + CALL CINADR ; get user input, converted addr in HL + JR IMPTHEN ; jump to set addr and enable + + ; disable +IMPTHDS: LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + RES 5,(IX+0) ; bit 5 = 0 to disable Path + JP PSETTG ; jump display (new) settings + + ; zcpr +IMPTHZ: LD HL,(ENVADR) ; get ENV addr + LD A,H ; check if valid (<> zero) + OR L + JP Z,PSETTG ; ..if not, jump display settings + LD HL,(ZPTHADR) ; else, get addr of Path in ENV + + ; enable +IMPTHEN: LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + SET 5,(IX+0) ; bit 5 = 1 to enable path + LD (IX-3),H ; ..and set addr + LD (IX-4),L + JP PSETTG ; jump display (new) settings + + + ; input >8 i.e. not Option Flag byte, change other options + + ; interactive mode - change Wheel +IMWHL: CP '8' ; change Wheel ? + JP NZ,IMTIME ; ..if not, jump to next + CALL CRLFGXY + DEFB 21,20,'WHEEL Addr [(' + DEFB 1,'D',2,')isable, (' + DEFB 1,'S',2,')et' + DEFB 0 + LD HL,(ENVADR) ; get ENV addr + LD A,H ; check if valid (<> zero) + OR L + JR Z,IMWHL0 ; ..if no ENV, skip over + CALL VPRINT + DEFB ', (',1,'Z',2,')CPR3' + DEFB 0 +IMWHL0: CALL VPRINT + DEFB '] : ' + DEFB 0 + + ; input +IMWHLIN: CALL CINCAPS ; get user input and capitalize + LD HL,0 ; prepare for disable + CP 'D' ; is it 'D'isable ? + JR Z,IMWHLST + CP 'Z' ; is it 'Z'CPR Wheel ? + JR Z,IMWHLZ + CP 'S' ; is it 'S'et addr ? + JR NZ,IMWHLIN ; ..loop if no valid input + CALL CRLFGXY + DEFB 22,25,'Enter WHEEL Address : ' + DEFB 0 + LD HL,0 ; set initial value + CALL CINADR ; get user input, converted addr in HL + JR IMWHLST ; jump set value + + ; zcpr +IMWHLZ: LD HL,(ENVADR) ; get ENV addr + LD A,H ; check if valid (<> zero) + OR L + JP Z,PSETTG ; ..if not, jump display settings + LD HL,(ZWHLADR) ; get Wheel byte addr from ENV + + ; set +IMWHLST: LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + LD (IX-1),H ; and set addr + LD (IX-2),L + JP PSETTG ; jump display (new) settings + + ; interactive mode - change Time +IMTIME: CP 'T' ; change Time ? + JR NZ,IMASTMP ; ..if not, jump to next + CALL CRLFGXY + DEFB 21,15,'Time (Clock)' + DEFB 0 + CALL ASKSET ; ask disable/set + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + LD (IX+2),L ; get addr of time/date routine (GSTIME) + LD (IX+3),H + LD A,0FFH ; prepare for unload value + ADC A,0 ; C-Flag is dummy vector flag + LD (IX+6),A ; ...to set UNLOAD to 0 + LD (IX+7),A ; (rather than 0xFFFF) + JP PSETTG ; jump display (new) settings + + + ; changes are reflected in Time flag byte (new in v2) +IMASTMP: CP 'A' ; change Stamp Access Time ? + JR NZ,IMCSTMP ; ..if not, jump to next + CALL CRLFGXY + DEFB 21,15,'Stamp Last Access Time' + DEFB 0 + CALL ASKENBL ; ask disable/enable (C-Flag is indicator) + LD B,00000001b ; mask bit 0 + JP IMTFLG ; and toggle in Time Flag byte (interactive) + ; +IMCSTMP: CP 'C' ; change Stamp Create Time ? + JR NZ,IMMSTMP ; ..if not, jump to next + CALL CRLFGXY + DEFB 21,15,'Stamp Create Time' + DEFB 0 + CALL ASKENBL ; ask disable/enable (C-Flag is indicator) + LD B,00000010b ; mask bit 1 + JP IMTFLG ; and toggle + ; +IMMSTMP: CP 'M' ; change Stamp Modify Time ? + JR NZ,INPINVL ; ..if not, jump invalid user input + CALL CRLFGXY + DEFB 21,15,'Stamp Modify Time' + DEFB 0 + CALL ASKENBL ; ask disable/enable (C-Flag is indicator) + LD B,00000100b ; mask bit 2 + JP IMTFLG ; and toggle + + + ; interactive mode - invalid (not a menu option) +INPINVL: CALL VPRINT ; alert and ask for new input + DEFB 8,' ',8,BEL + DEFB 0 + JP IMCINPT + + +;::::: EXIT PROGRAM + +EXIT: CALL VPRINT + DEFB CR,LF,LF,'Returning to system ...',CR,LF + DEFB 0 +EXIT0: LD SP,(STACK) ; restore stack + RET + + +;::::: SUPPORT FUNCTIONS (interactive mode) + + ; toggle bit in Flag byte + ; in: B= bit mask (respective bit is set) +IMOFLG +IMTGOP: LD A,B + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + XOR (IX+0) ; toggle bit + LD (IX+0),A ; and save value again + JP PSETTG ; jump, display (new) settings + + + ; set/reset bit in Time flag byte (new in v2) + ; in: B= bit maks (respective bit is set) + ; C-Flag set = disable, NC= enable +IMTFLG: LD A,B ; get bit + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + JR C,IMTFLGR ; ..if C-Flag set, jump + OR (IX+1) ; merge with current value (= set bit) + + ; set +IMTFLGS: LD (IX+1),A ; and save value again + JP PSETTG ; jump display (new) settings + + ; reset +IMTFLGR: CPL ; invert bit mask + AND (IX+1) ; merge with current value (= reset bit) + JR IMTFLGS + + +;::::: EXPERT MODE + +EXPMODE: LD HL,CPMDMA ; set ptr to command line buffer + LD B,(HL) ; get char count + INC HL ; move ptr forward to first char + + ; evaluate command line +EMEVCMD: CALL CMDPDL ; get past delimiters (skip , , and Comma) + JP Z,EMSETOF ; ..if end of cmdline, jump set Option Flags + CP '*' ; change Wheel ? + JP Z,EMWHL + CP '+' ; change Time ? + JP Z,EMSTAMP + CP 'C' ; change Clock (stamp) ? + JP Z,EMTIME + CP 'R' ; change R/O ? + JR NZ,EMRELOG ; ..if not, jump to next + + ; first, handle options which can be switched on/off + ; more complex handling routines further down below + + ; change R/O Vector + CALL PVBOSE + DEFB 'R/O Sustain = ' + DEFB 0 + LD C,00000100b ; mask bit 2 + JP EMOFLG ; toggle Option Flags (Read Only) + +EMRELOG: CP 'F' ; change Fast Relog ? + JR NZ,EMDWARN ; ..if not, jump to next + CALL PVBOSE + DEFB 'Fast Relog = ' + DEFB 0 + LD C,00001000b ; mask bit 3 + JP EMOFLG ; toggle Option Flags + +EMDWARN: CP '!' ; change Disk Warning ? + JR NZ,EMPUBFL ; ..if not, jump to next + CALL PVBOSE + DEFB 'Change Warning = ' + DEFB 0 + LD C,00010000b ; mask bit 4 + JP EMOFLG ; toggle Option Flags + +EMPUBFL: CP 'P' ; change Public Files Flag ? + JR NZ,EMPUBWR ; ..if not, jump to next + CALL PVBOSE + DEFB 'Public Files = ' + DEFB 0 + LD C,00000001b ; mask bit 0 + JP EMOFLG ; toggle Option Flags + +EMPUBWR: CP 'W' ; change Public/Path Write ? + JR NZ,EMSYSAT ; ..if not, jump to next + CALL PVBOSE + DEFB 'Pub/Path Write = ' + DEFB 0 + LD C,00000010b ; mask bit 1 + JP EMOFLG ; toggle Option Flags + +EMSYSAT: CP 'S' ; change Path w/o Sys Attr ? + JR NZ,EMSETPA ; ..if not, jump next + CALL PVBOSE + DEFB 'Path w/o SYS = ' + DEFB 0 + LD C,01000000b ; mask bit 6 + JP EMOFLG ; toggle Option Flags + +EMSETPA: CP '>' ; set Path ? + JP Z,EMPATH ; ..if so, jump to continue + ; else, fall through (not a valid option) + + ; move forward in command line to next possible option +EMCMDFW: CALL CMDATDL ; move forward to next , , or Comma + JP NZ,EMEVCMD ; and continue evaluating cmdline + + ; set Option flag when end of cmdline was reached +EMSETOF: LD A,(OFLGMSK) ; get effective Bit Mask + LD HL,OFLGWIP ; ptr to Option Flag byte (wip) + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + AND (IX+0) ; Bit Mask AND current Flag Byte + OR (HL) ; set new flags (wip) + LD (IX+0),A ; write back new Option Flag byte + JP EXIT0 ; ..and exit program + + ; change Wheel +EMWHL: CALL PVBOSE + DEFB 'Wheel Protect = ' + DEFB 0 + CALL CMDNCHR ; get next char from cmdline + CALL Z,PV$INVL ; ..if end-of-string (), display msg + JR Z,EMSETOF ; ...and jump, set Option Flags + CP '-' ; disable ? + JR NZ,EMWHL0 ; ..if not, jump + CALL PV$DABL ; else, display msg + LD DE,0 ; zero addr to disable + JR EMWHL2 ; ..and jump to continue + +EMWHL0: CP 'Z' ; use Z3WHL ? + LD DE,(ZWHLADR) ; get Wheel byte addr from ENV + JR Z,EMWHL4 ; ..if so, jump to continue + CALL CMDADR ; else,read addr from cmdline in DE + CALL Z,PV$INVL ; ..if not valid, display msg + JR Z,EMCMDFW ; ..and jump + +EMWHL1: CALL PV$DEX ; display addr +EMWHL2: LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + LD (IX-1),D ; set new Wheel byte addr + LD (IX-2),E +EMWHL3: CALL CMDATDL ; move forward to next , , or Comma + JP EMEVCMD ; then continue evaluating cmdline +EMWHL4: PUSH HL ; save regs (ptr in cmdline) + LD HL,(ENVADR) ; get ENV addr + LD A,H ; check if valid (<> zero) + OR L + POP HL ; restore regs + JR NZ,EMWHL5 ; ..if valid, skip over + CALL PV$INVL ; else, display msg + JP EMEVCMD ; ..and continue evaluating cmdline + +EMWHL5: CALL PVBOSE + DEFB 'Z-System @ ' + DEFB 0 + JR EMWHL1 ; jump to set addr (in DE) + + ; change Path +EMPATH: CALL PVBOSE + DEFB 'Search Path = ' + DEFB 0 + CALL CMDNCHR ; get next char from cmdline + CALL Z,PV$INVL ; ..if end of string (), display msg + JP Z,EMSETOF ; ...and loop, set Option Flags + CP '-' ; disable ? + JR NZ,EMPTH0 ; ..if not, jump + CALL PV$DABL ; else, display msg + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + RES 5,(IX+0) ; bit 5 = 0 to disable Path + JP EMEVCMD ; and continue evaluating cmdline + +EMPTH0: CP 'I' ; 'I'nternal Path ? + JR NZ,EMPTH1 ; ..if not, jump + LD E,(IX+8) ; get reference addr (new in v2) + LD D,(IX+9) + CALL PVBOSE + DEFB 'Internal',CR,LF + DEFB 0 + JR EMPTH3 ; jump to set addr (in DE) +EMPTH1: CP 'Z' ; 'Z'CPR Path ? + LD DE,(ZPTHADR) ; get addr of Path in ENV + JR Z,EMPTH4 ; ..if option, jump + CALL CMDADR ; else,read addr from cmdline in DE + CALL Z,PV$INVL ; ..if not valid, display msg + JP Z,EMCMDFW ; ..and jump +EMPTH2: CALL PV$DEX ; display addr +EMPTH3: LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + LD (IX-3),D ; set new Path addr + LD (IX-4),E + SET 5,(IX+0) ; and set bit 5 = 1 to enable Path + JP EMWHL3 +EMPTH4: PUSH HL ; save regs (ptr in cmdline) + LD HL,(ENVADR) ; get ENV addr + LD A,H ; check if valid (<> zero) + OR L + POP HL ; restore regs + JR NZ,EMPTH5 ; ..if valid, skip over + CALL PV$INVL ; else, display msg + JP EMEVCMD ; ..and continue evaluating cmdline + +EMPTH5: CALL PVBOSE + DEFB 'Z-System @ ' + DEFB 0 + JR EMPTH2 ; jump to set addr (in DE) + + + ; change Clock Routine + ; ##### CHECK: changed order, requires additional PUSH/POP AF +EMTIME: CALL CMDNCHR ; get next char from cmdline + PUSH AF + CALL PVBOSE + DEFB 'Clock Routine = ' + DEFB 0 + POP AF + CALL Z,PV$INVL ; ..if end of string (), display msg + JP Z,EMSETOF ; ..and loop, set Option Flags + CALL EMTROUT ; check Time routine options (addr in DE) + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + LD (IX+2),E ; set addr of time/date routine (GSTIME) + LD (IX+3),D + LD A,0FFH ; prepare for unload value + ADC A,0 ; C-Flag is dummy vector flag + LD (IX+6),A ; ...to set UNLOAD to 0 + LD (IX+7),A ; (rather than 0xFFFFH) + JP EMSTMX0 ; jump to continue evaluating cmdline + + + ; change Time Stamp(s) +EMSTAMP: CALL CMDNCHR ; get next char from cmdline + JP Z,EMSETOF ; ..if end of string (), loop set Option Flags + LD (CHARCMD),A ; store char + CALL CMDNCHR ; and get next one from cmdline + JR NZ,EMASTMP ; ..if not end of string, jump to continue + INC B ; set counter back (= 1 char remaining) + DEC HL ; set ptr back + LD A,' ' ; set as if it were read from cmdline + +EMASTMP: PUSH AF ; save this char + LD A,(CHARCMD) ; restore previous char + CP 'A' ; is it 'A'ccess ? + JR NZ,EMCSTMP ; ..if not, jump next + CALL PVBOSE + DEFB 'Stamp Access = ' + DEFB 0 + LD D,00000001b ; bit mask (bit 0= Access Stamp) + JR EMSTMST ; and jump to set/reset + +EMCSTMP: CP 'C' ; is it 'C'reate ? + JR NZ,EMMSTMP ; ..if not, jump next + CALL PVBOSE + DEFB 'Stamp Create = ' + DEFB 0 + LD D,00000010b ; bit mask (bit 1= Create Stamp) + JR EMSTMST ; and jump to set/reset + +EMMSTMP: CP 'M' ; is it 'M'odify ? + JR NZ,EMSTMX ; ..if not, skip over and loop + CALL PVBOSE + DEFB 'Stamp Modify = ' + DEFB 0 + LD D,00000100b ; bit mask (bit 2= Modify Stamp) + + ; set/reset +EMSTMST: POP AF ; restore following char + CALL EMTFLG ; get new Time flag in E + LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + LD (IX+1),E ; and write back Time flag byte + JR EMSTMX0 ; skip over, and loop + +EMSTMX: POP AF +EMSTMX0: JP EMEVCMD ; continue evaluating cmdline + + +;::::: SUPPORT FUNCTIONS (expert mode) + + ; expert mode - toggle bit in wip Option Flag byte based on following char + ; in: HL= ptr cmdline + ; B= char count (remaining chars) + ; C= bit mask (respective bit is set) +EMOFLG: CALL CMDNCHR ; get next char and capitalize it + CP '-' ; disable ? + LD A,C ; bit mask in A + JR NZ,EMOFLG0 ; ..if not '-', jump (default to enable) + PUSH AF + CALL PV$DABL ; display 'Disabled' if verbose + POP AF + LD C,0 + JR EMOFLG1 + +EMOFLG0: PUSH AF + CALL PVBOSE + DEFB 'Active',CR,LF + DEFB 0 + POP AF +EMOFLG1: CPL ; invert mask + PUSH HL + LD HL,OFLGMSK ; ptr to effective Bit Mask + AND (HL) ; merge (= reset) current bit + LD (HL),A ; ..and store new Bit Mask + LD HL,OFLGWIP ; ptr to Flag byte (wip) + LD A,C ; get current bit + OR (HL) ; merge (set/reset) with Option Flag (wip) + LD (HL),A ; ..and save back + POP HL + JP EMCMDFW ; ..and loop + + + ; expert mode - return bit pattern to toggle Time Stamp (Access/Create/Modify) + ; set/reset bit in Time flag byte (new in v2) + ; in: D= bit mask (respective bit is set) + ; A= char from cmdline + ; ( disable = '-' / enable = , , Comma + ; everything else is invalid ) + ; out: E= new Time flag byte +EMTFLG: LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + PUSH AF ; save char + LD A,(IX+1) ; get current Time flag byte + OR D ; set respective bit (= 1) + XOR D ; and invert it (= 0) + LD E,A ; new Time flag in E (prepared to disable) + POP AF ; restore char + CP '-' ; disable ? + JR Z,PV$DABL ; ..if so, jump display msg + ; ...and return from there with C-Flag set + CALL CHKDLM ; else, must be , , or Comma + JR NZ,PV$INVL ; ..if not, jump display 'invalid' and return from there + LD A,E ; get new Time flag byte + OR D ; set respetive bit (= 1) + LD E,A ; and copy as new Time flag byte + CALL PVBOSE + DEFB 'Enabled',CR,LF + DEFB 0 + XOR A + RET + + ; expert mode - change Time Routine + ; either disable or get addr of routine +EMTROUT: CP '-' ; disable ? + LD DE,(TIMEDIS) ; get disable vector + JR NZ,EMTROU0 ; ..if not '-', jump to continue + ; else, fall through + +PV$DABL: CALL PVBOSE + DEFB 'Disabled',CR,LF + DEFB 0 + SCF + RET + +EMTROU0: LD DE,(CPMBIOS+1) ; get Bios WBOOT addr (fn #1) + LD E,26*3 ; adjust to fn #26 (TIME) + CP 'B' ; 'B'ios routine ? + JP Z,PV$DEX ; ..if not, diplay msg and let return from there + CALL CMDADR ; else, read addr from cmdline (in DE) + JP NZ,PV$DEX ; ..if valid, display addr and let return from there + CALL PV$INVL ; else, display msg + POP DE ; restore regs + JP EMCMDFW ; ..and jump + +PV$INVL: PUSH AF + CALL PVBOSE + DEFB '-- Invalid --',CR,LF + DEFB 0 + POP AF + RET + + + ; get hex addr from command line + ; in: HL= ptr in cmdline string + ; B= char counter (remaining chars) + ; out: A= 0 and Z-Flag set if end of string, else NZ= valid + ; DE= addr + ; HL= moved fwd, B= decremented by digit count +CMDADR: LD DE,0 ; set initial value +CMDADR0: CALL CHKXDIG ; check if char is valid hex digit + JR NC,CMDADR1 ; ..if not, jump to additional check + EX DE,HL ; swap regs + CALL ADDDIGA ; new result in HL + EX DE,HL ; swap back + CALL CMDNCHR ; get next char from cmdline + JR NZ,CMDADR0 ; ..if not (end of string), loop + DEC HL ; else, move ptr back + INC B ; ..and correct counter + JR CMDADRX ; ..then exit + +CMDADR1: LD A,(HL) ; get char again + CALL CHKDLM ; check if , , or Comma + JR Z,CMDADRX ; ..if so, jump to exit + LD DE,0 ; else, set zero addr (char not valid) +CMDADRX: LD A,D ; set status (Z-Flag), non-zero = ok + OR E + RET + + ; get _past_ delimiter(s) parsing command line + ; read string, skip whitespace (, ) and Comma + ; stop if other char or terminating byte is found + ; in: HL= ptr to string + ; B= max. char count + ; out: HL= ptr to first non-matching char, Z-Flag set if end reached +CMDPDL: LD A,(HL) ; get byte + OR A ; check for (end of string) + RET Z ; ..if so, return (Z-Flag set) + CALL CAPS ; make char uppercase + CALL CHKDLM ; check for , , or Comma + RET NZ ; ..if other char, return + INC HL ; else, ptr fwd + DJNZ CMDPDL ; ..and loop + XOR A ; reached max. char count, set flag + RET ; and return + + + ; stop _at_ next delimiter parsing command line + ; read string, skip any char until , , or Comma is found + ; (opposite to previous fn), stop if , , Comma or terminating + ; in: HL= ptr in cmdline string + ; B= char count (remaining chars) + ; out: HL= ptr to found , , or Comma / at end of string + ; B= decremented accordingly + ; A= char, Z-Flag not set (NZ) if found + ; A= 0, Z-Flag set if not found +CMDATDL: LD A,(HL) ; get byte + OR A ; check for (end of string) + RET Z ; ..if so, return (Z-Flag set) + CALL CHKDLM ; check for , , or Comma + JR Z,CMDATD0 ; ..if found, jump exit + INC HL ; else, ptr fwd + DJNZ CMDATDL ; ..and loop + XOR A ; reached max. char count, set flag + RET ; and return + +CMDATD0: OR A ; char is , , or Comma - set status (NZ) + RET + + + ; checks if char is a delimiter (, , or Comma) + ; in: A= char + ; out: Z-Flag set if match, NZ= none of them +CHKDLM: CP ' ' + RET Z + CP ',' + RET Z + CP TAB + RET + + + ; get next char from command line + ; in: HL= ptr in cmdline string + ; B= char counter (remaining chars) + ; out: A= next char (capitalized) + ; Z-Flag set if end of string, NZ= valid + ; HL= incremented, B= decremented +CMDNCHR: INC HL ; move ptr fwd + LD A,(HL) ; get char + CALL CAPS ; capitalize it + DEC B ; counter -1 + RET + + ; get console input (1 char) and capitalize +CINCAPS: CALL CIN + JP CAPS + + + ; get console input, hex addr in HL + ; in: A= (possible) first char + ; out: HL= addr +CINADR: CALL CAPS ; capitalize A + LD (CHARTMP),A ; store for echo + CP CR ; is it (marks end) ? + RET Z ; ..if so, return + CALL CHKXDIG ; else, check if hex digit + JR NC,CINADR0 ; ..if not, get next char + PUSH AF + LD A,(CHARTMP) ; get char back + CALL COUT ; ..and echo + POP AF + CALL ADDDIGA ; add to HL +CINADR0: CALL CIN ; get console input + JR CINADR ; ..and loop + + + ; check if char is a valid hex digit + ; in: A= char + ; out: A= converted char, C-Flag set if ok, NC= not ok +CHKXDIG: SUB '0' ; convert ascii to number + JP M,CHKXDI0 + CP 9+1 ; is it below 10 ? + RET C ; ..if so, return (= ok) + SUB 7 ; else, check A..H + CP 10 + JR C,CHKXDI0 + CP 16 + RET ; return with C-Flag (status) set accordingly + +CHKXDI0: XOR A ; nullify A + DEC A ; exit with C-Flag reset (digit not valid) + RET + + + ; add hex digit in A to HL +ADDDIGA: ADD HL,HL ; make room for new digit in HL by shifting + ADD HL,HL ; 4 bits left (*8, power-of-two-multiple) + ADD HL,HL + ADD HL,HL + ADD A,L ; add A + LD L,A ; and store new total + RET + + + ; print YES / NO with highlighting + ; in: Z-Flag not set (NZ) = YES, set = NO +PYESNO: JR Z,PYSNO0 + CALL VPRINT + DEFB 1,'YES',2 + DEFB 0 + RET +PYSNO0: CALL VPRINT + DEFB 1,'NO',2,' ' + DEFB 0 + RET + + + ; verbose print - print string to CON: if quiet option is off + ; in: (Stack) contains start addr of nul-terminated string +PVBOSE: CALL GETQUIET ; get quiet flag + JP Z,VPRINT ; if verbose (= not quiet), jump to display + ; and let return from there + EX (SP),HL ; swap HL and string addr +PVBOSE0: LD A,(HL) ; get char + INC HL ; move ptr fwd + OR A ; is it (= end of string) ? + JR NZ,PVBOSE0 ; ..if not, loop get next char + EX (SP),HL ; else, swap back (on Stack = addr behind string) + RET + + + ; print value as hex if in verbose mode (quiet flag = off) + ; in: DE= value +PV$DEX: CALL GETQUIET ; get quiet flag + JR NZ,PV$DEX0 ; if quiet, skip over + EX DE,HL ; swap regs + CALL PHLXH ; display addr in HL (as hex) + EX DE,HL ; swap back + CALL CRLF ; display extra +PV$DEX0: AND A ; clear C-Flag + RET + + + ; print status of Access/Create/Modify routines + ; based on Time flag byte (new in v2) + ; in: A= bit to test (0= Acc, 1= Cre, 2= Mod) +PSTAMPS: LD IX,(OFLGADR) ; ptr to ZSDOS Flag byte + AND (IX+1) ; compare with flag byte + ; (did not exist in v1, apparently added in v2) + JR PSTMPS0 ; jump to continue + + ; ##### orphaned code, seems as if combined print function was planned + LD DE,(TIMEDIS) ; get disable vector + OR A + SBC HL,DE + ADD HL,DE + ; ##### + +PSTMPS0: JR Z,PDISABL ; ..if bit not set, jump display 'disabled' + CALL VPRINT ; else, display 'enabled' + DEFB 1,'Enabled',2 + DEFB 0 + JP EREOL + + + ; print status of Time routines - addr or 'disabled' +PTIMERS: LD DE,(TIMEDIS) ; get disable vector + OR A ; clear Flags + SBC HL,DE ; compare HL and DE + ADD HL,DE ; preserving registers + JR Z,PDISABL ; ..if disable vector, display msg + CALL PHLXHHI ; else, display addr (as hex w/ highlighting) + JP EREOL + +PDISABL: CALL VPRINT + DEFB 1,'Disabled',2 + DEFB 0 + JP EREOL + + ; print addr in HL with highlighting + ; in: HL= addr +PHLXHHI: CALL STNDOUT ; turn on 'standout' display + CALL PHLXH ; display as hex plus 'H' + JP STNDEND ; turn off 'standout' + + + ; print addr in HL as four-digit hex and append 'H' + ; in: HL= addr +PHLXH: CALL PHL4HC ; display as 4-digit hex + LD A,'H' ; and display 'H' + JP COUT ; print , then jump to GXYMSG (return addr on stack) + + +CRLFGXY: CALL CRLF + JP GXYMSG ; ask user whether to disable routine, or set addr for it + + + ; print 'Routine...' and ask for disable/set +ASKSET: CALL VPRINT + DEFB ' Routine [(' + DEFB 1,'D',2,')isable), (' + DEFB 1,'S',2,')et] : ' + DEFB 0 +ASKSET0: CALL CINCAPS ; get user input (capitalized) + CP 'D' ; disable ? + LD HL,(TIMEDIS) ; get disable vector + SCF ; set C-Flag for later calc + RET Z ; ..if disable, return + CP 'S' ; set addr ? + JR NZ,ASKSET0 ; ..if not, loop ask for new input + CALL CRLFGXY ; else, prompt user to enter addr + DEFB 22,25,'Enter Address of Routine : ' + DEFB 0 + LD HL,0 + JP CINADR ; jump to get input, and let return from there + + + ; print 'Routine...' and ask for disable/enable it + ; out: C-Flag set = disable, NC= enable +ASKENBL: CALL VPRINT + DEFB ' Routine [(' + DEFB 1,'D',2,')isable), (' + DEFB 1,'E',2,')nable] : ' + DEFB 0 +ASKENB0: CALL CINCAPS ; get user input (char) and capitalize it + CP 'D' ; is it 'D'isable ? + SCF ; set C-Flag (indicator) + RET Z + CP 'E' ; is it 'E'nable ? + JR NZ,ASKENB0 ; ..if not, loop ask for new input + RET ; else, return with C-Flag reset (NC) + + + ; error msg +E$ZSDOS: CALL VPRINT + DEFB CR,LF,BEL,'*** ERROR: DOS is not ZSDOS!',CR,LF + DEFB 0 + JP EXIT + + +;::::::::::::::::::::::::::::::::::::::::::::::::::::: +; VLIB - 0x114f +; Z3LIB - 0x1370 +; SYSLIB - 0x13e9 +; end addr 0x145e (begin DSEG) +;::::::::::::::::::::::::::::::::::::::::::::::::::::: + + +;::::: RAM STORAGE + + DSEG + +DOSBASE: DEFW 0 ; DOS base addr +OFLGADR: DEFW 0 ; addr FLAGS byte in ZSDOS hdr +ZPTHADR: DEFW 0 ; addr of Path in ENV +ZWHLADR: DEFW 0 ; addr of Wheel byte in ENV +TIMEDIS: DEFW 0 ; addr of Time routines disable vector +CHARCMD: DEFB 0 ; ExMod Time Stamp - remember char from cmdline +OFLGWIP: DEFB 0 ; Option Flag ('work in progress') +OFLGMSK: DEFB 0 ; effective Bit Mask for Option Flag +RUNMODE: DEFB 0 ; indicator run mode (0= interactive) + DEFB 0 ; not used +CHARTMP: DEFB 0 ; temporary storage of char +DOSTYVE: DEFW 0 ; (ZS)DOS type and version # + + DEFS 40H ; room for stack +STACK: DEFW 0 ; stack storage location + + END + + +;************************************************************************ +; Remarks jxl: +; From available options in ZSCFG2 it can be assumed that configuration +; area in ZSDOS v2 is almost identical to v1. Most options can be altered +; by changing the respective bit in the OPTION FLAG byte. +; +; Bit 7 6 5 4 3 2 1 0 +; \ \ \ \ \ \ \ \__ Public Files enable (1) - disable (0) +; \ \ \ \ \ \ \____ Public/Path Write enable (1) - disable (0) +; \ \ \ \ \ \______ Read-Only enable (1) - disable (0) +; \ \ \ \ \________ Fast Fixed Disk Relog enable (1) - disable (0) +; \ \ \ \__________ Disk Change Warning enable (1) - disable (0) +; \ \ \____________ ZCPR Path enable (1) - disable (0) +; \ \______________ Path w/o System Attr enable (1) - disable (0) +; \________________ Reserved +; +; Offsets to other features remained unchanged, compared to v1, and so +; Path and Wheel addresses can be found at the same locations. Apparently, +; a new "reference" Path address was added at offset Option Flag byte +8/9. +; It is used to reset the configurable Path address, but cannot be changed +; itself. +; Some changes were obviously be made to Time Stamp related options. An +; additional flag byte was implemented at offset Option Flag byte +1. The +; address of the Time Stamp routine (v1: GSTIME) was moved by one byte +; position and is located at offset +2/3. The pointer to remove Time Stamp +; routine (v1: UNLOAD) is now located at offset +6/7. +; Bytes at offset +4/5 are not in use anymore. +; +; TIME FLAG byte +; Bit 7 6 5 4 3 2 1 0 +; \ \ \__ Access stamp enable enable (1) - disable (0) +; \ \____ Create stamp enable (1) - disable (0) +; \______ Modify stamp enable (1) - disable (0) +; +; +; Source code +; ZSCFG2.COM, included in available B/P Bios package(s), was disassembled +; and extensively commented. Labels are up to seven chars long to comply +; with M-REL standards. However, it is recommended to use SLR tools that +; support labels up to sixteen chars. +; The program supports an interactive and a so-called expert mode. +; To indicate the respective mode, labels start either with "IM" or "EM" +; where appropriate. +; +; In its current state, the compiled/linked file matches exactly the +; original ZSCFG2.COM, i.e. no changes to the source were made. Possible +; optimisations detected during disassembly are marked with "#####" in the +; comment. +;************************************************************************ diff --git a/Source/BPBIOS/bpart.txt b/Source/BPBIOS/bpart.txt new file mode 100644 index 00000000..3c127ba2 --- /dev/null +++ b/Source/BPBIOS/bpart.txt @@ -0,0 +1,1247 @@ + Banked/Portable Basic IO System (B/P Bios) Pt I + by + Harold F. Bower and Cameron W. Cotrill + +=============================================================== +NOTE: The first two parts of this article were published in The +Computer Journal (TCJ), but the third part was pending when TCJ +ceased publishing. Harold F. Bower +=============================================================== +For the past several years we have attempted to address some of +what we consider to be fundamental problems in the 8-bit +Z80/Z180/HD64180 system software arena. Our first effort, ZSDOS, +was directed toward what we believed to be architectural weak- +nesses in CP/M and its clones in the late 1980s. Such weaknesses +included; inefficient code, inconsistent implementations of some +DOS functions, numerous different and incompatible file Date/Time +Stamping methods, and just plain errors (remember Function 37?). +Now in the 1990s, even more effort is needed to correct the +proliferation of systems designed on faulty (or at least weak) +architectures, and to provide a logical and consistent path to +increase the functionality of our systems. + +To understand our concerns in this area, let us review the way in +which CP/M 2.2, as modified by the Z-System, uses available +memory. For standard CP/M and compatible systems, the only +absolute memory addresses are contained in the Base Page which is +the range of 0 to 100H. All addresses above this point are +variable (within certain limits). User programs are normally run +from the Transient Program Area (TPA) which is the space from the +top of the Base Page (100H) to the base of the Basic Disk Operat- +ing System (BDOS). Figure 1 depicts assigned areas pictorially +along with some common elements assigned to each memory area. + + FFFFH +------------------+ + | Z-System Buffers | ENV, TCAP, IOP, FCP, RCP + +------------------+ (~5k) + | Bios | Code + ALV, CSV, Sector Buffers + +------------------+ (~5.5k) + | Operating System | CP/M 2.2, ZRDOS, ZSDOS1 + +------------------+ (3.5k) + | Command Processor| CCP, ZCPR3.x + +------------------+ (2k) + | Transient | + | | + | Program | + | | + | Area | + 0100H +------------------+ + | Base Page | IOBYTE, Jmp WB, Jmp Dos, FCB, Bufr + 0000H +------------------+ + Figure 1. Typical Z-System Memory Map + +The sizes depicted for the Z-System buffers is typical of many, +and allows a certain functionality. It is sometimes necessary to +delete some capabilities to add others, since every addition in +this area pushes the other components lower, decreasing available +TPA space. Likewise, any new features or more elaborate routines +in the Bios decreases available TPA. + +There have been some attempts at ameliorating these difficulties, +but none have directly addressed the entire problem. One system +in relatively widespread use is NZCOM. It allows a fairly easy +method of changing systems "on the fly". The main drawback, +however, is that to obtain large TPA, system features must be +sacrificed by deleting or downsizing the resident Z-System seg- +ments (FCP,IOP,RCP,NDR,TCAP). To us, this method is only viable +in systems which do not have extended memory capabilities. With +the ever-increasing use of systems based on the Hitachi 64180 and +Zilog Z180, other solutions are more attractive and offer a +larger TPA without sacrificing system capabilities. + +The final major factor contributing to shrinkage of TPA is the +increasing commonality of large hard disk drives. Disk space is +managed by a bit-mapped buffer (ALV) where each bit represents an +allocation block of storage space. Typical allocation units are +2k for floppy diskettes and 4k for Hard Disk Partitions. Assum- +ing 4k allocation blocks, a 20 MB drive needs approximately +20000/4 = 5000 bits or 625 bytes. With 80 to 100 MB drives being +common these days (one B/P user reported that the smallest drive +he could obtain was 850 MB!) you should see that several kilo- +bytes are now required, further reducing available TPA space. + +The first requirement to place us on the road to more powerful +systems is to overcome the 64k memory limit imposed on direct +access by the Z80 family of processors in a consistent and logi- +cal manner. Such a technique, generically called memory banking, +means that we can access more than 64k of memory for something +more than simply a RAM disk. + +One of the first attempts to tackle the 64k memory barrier was +Digital Research with CP/M Plus (aka CP/M3). While it banked +both portions of the BIOS as well as the Basic Disk Operating +System (BDOS) and included some useful additions to the BIOS, it +was relatively incompatible with CP/M 2.2 in many key features. +In addition, CP/M Plus made no provision for banking application +code. The adoption of a CP/M 2.2 standard for the Z-System has +served to widen the compatibility gap even further on the majori- +ty of our systems. + +There are some internal inconsistencies in the CP/M 3 architec- +ture as well which were never fully resolved. A prime case in +point is the function to return Disk Free Space (Function 46). +The specification states that three bytes are returned reflecting +the number of available 128-byte records on a disk. This equates +to 2^24 * 128 or 16,777,216 * 128 = 2,097,152 kB. While we know +of no one who has actually installed a single disk partition of +more than 2 Gigabytes on a Z-System, it would create problems +since CP/M Plus can handle disks up to eight times this size, but +not correctly report free space. Simply returning free space in +terms of 128-byte records is inconsistent as well since disk +space is allocated in blocks which have a minimum size of 1k, +with 2k and 4k commonly used. This is only one example of +several, and we do not consider it a viable system for future Z- +System growth; although it is still being actively installed. + +Several manufacturers have attempted to bank portions of operat- +ing system software over the years, yet either locked the soft- +ware into their hardware as Epson did with the QX-10, or made +such changes as to limit portability of common tools as in the +XLM-180. This latter system, while it used the Hitachi 64180 +processor with its memory mapping capabilities, required system +tailoring of much of the common Z-System software base. + +The release of MicroMint's SB-180 in the early 1980s marked a +decision point in Z-System development. First, it retained all +standard ZCPR3 definitions, it used a CP/M 2.2 compatible BDOS, +and it forced programmers to think more of portability and compa- +tibility in system software. This was a major thrust in the +development of XBIOS which placed the greatest possible amount of +BIOS code in alternate memory locations outside of the primary +64k address space. Furthermore, capabilities to bank additional +features (Resident System eXtensions, or RSXs) were widely sup- +ported with DateStamper, DosDisk and others requiring no sacri- +fice in TPA to execute. Since its last upgrade, however, several +severe problems have come to light, among them are the inability +to properly handle hard disk sizes greater than 32MB and sluggish +performance due to banking of Console routines. + +We considered this history and wanted to develop a system which +included as much machine independence as possible. Not only +should newer systems with the 64180/Z180 processor be included, +but S100 systems with banked memory, addon boards such as Terry +Hazen's MDISK for the Ampro Little Board, and homebrew systems as +well. The goal here was as much selfish desire as anything else. +By developing a single common architecture, only one tool for a +given purpose would be needed across a variety of machines. As +an example, Hal has several YASBECs, two SB-180s (one modified +with static memory), an SB180FX, an Ampro Little Board, a couple +of mongrel S-100 systems, and recently acquired a P112. Each +system had its own Formatter, Configuration utility, Clock type, +native disk formats, etc. To us, this seems out of place now, +particularly with the scarcity of systems programmers in the Z- +Community. It made more sense to develop a common software +architecture so that more programming resources could be devoted +to applications type efforts. + +Another goal of the effort was to retain the maximum compatibili- +ty with existing Z-System software for the same reasons cited +above. Customizing a huge number of common utilities as was done +in the XLM-180, seemed to be the wrong approach. We therefore +decided to retain the greatest possible commonality with CP/M 2.2 +(actually our ZSDOS), and use existing Z-System segments to their +greatest potential without sacrificing performance. As those of +you who tracked our efforts as we developed ZSDOS know, we do not +like slow systems or large code sizes (TCJ issues 37 and 38). We +also decided that our architecture had to be capable of outra- +geous expansion and extension capabilities without invalidating +previous software efforts. Further, we wanted to create a gener- +al purpose banked memory interface that allows applications +programs as well as the operating system to access alternate +banks of memory. The final results are the Banked & Portable +(B/P) Bios. + +B/P Bios attacks the memory problem in a manner which is easily +adaptable to different hardware. All HD64180/Z180-based systems +bank memory in 4k slices, and many S100 and addon systems bank in +16 or 32k increments. We therefore decided on an architecture +which retains common memory in the upper 32k of address space +(8000-FFFFH), and switches the lower 32k (0-7FFFH) among any +available banks of RAM. Figure 2 displays this architecture +pictorially. + + FFFFH +----------+ + | | + | BNK1 | + | | + 8000H +----------+ +----------+ +----------+ +----------+ + | | | |+ | |+ | |+ + | BNK0 | | System || | User || | RAM Disk ||+ + | | | || | || | ||| + 0000H +----------+ +----------+| +----------+| +----------+|| + +- - - - - + +- - - - - + +- - - - - +| + | Max Bank | + +----------+ + Figure 2. B/P Bios Memory Scheme + +BNK1 is ALWAYS present in the address space and is referred to as +the Common Bank. It contains all Z-System buffers, Common por- +tions of the Bios, BDOS and the Command Processor as well as the +upper portion of TPA. Part of the Bios which makes B/P unique is +the structure which allows controlled access to other banks in +the lower 32k. + +At least one 32k bank is required in a minimal banked B/P system. +The system bank, as a minimum, holds portions Bios and a copy of +the Command Processor which speeds Warm Boots by simply copying +the banked code to the Common bank and executing the warm entry. +Figure 3 depicts memory use in a maximally-configured banked +system. In such configurations the System bank holds banked +portions of; the ZSDos2 operating System, banked Command Proces- +sor, BIOS, and Hard Disk allocation bit maps. + + FFFFH +------------------+ + | Z-System Buffers | + +------------------+ + | User Space | + +------------------+ + | Bios | + +------------------+ + | Operating System | +------------------+ 8000H + +------------------+ / | Bios Buffers | + | Command Processor| / | Banked Bios Part | + +------------------+/ +------------------+ + 8000H | Transient | | Banked Dos Part | + | | +------------------+ + | Program | | Banked CCP Part | + | | +------------------+ + | Area | | CCP Restoral | + 0100H +------------------+ +------------------+ 0100H + | Base Page | | Base Page Copy | + 0000H +------------------+ +------------------+ 0000H + TPA (BNK0/BNK1) System Bank + Figure 3. Fully-banked Memory Map + +The B/P Bios began with one of Cam's superb architectures. He +started with the standard CP/M 2.2 Jump Table, added in those +from CP/M Plus with changes to correct some of the inconsisten- +cies, then added in a new series to permit logical and easy +access to new routines. The code, in assembly source form, was +divided into logically functioning elements, with the greatest +possible amount placed into machine independent modules. As an +example, the Disk deblocker and IOBYTE decoder functions are +machine independent and need no change between systems, while the +actual disk and character device drivers require custom tailoring +for each type of computer. Standard interfaces, in terms of +register usage and value limits, result in common software re- +quirements across vastly different hardware systems. + +Each software module of the Bios includes relocation directives +to the assembler telling it whether the code is to go into the +main memory, or into another bank of memory. If a non-banked +system is assembled, all code is placed into the main 64k area, +while banked systems use the main 64k area for common code and +data as well as banked code and data areas. All tools (format- +ter, configuration utility, etc) automatically accommodate both +types of Bios without any intervention. The choice of whether to +bank each section of code or not was painstakingly examined for +performance and size penalties. Many of our design choices may +be debated, but B/P is here and it works! + +By itself, fixing the Bios is not a complete answer to our cur- +rent Z-System dilemma, but it is a prerequisite. We also consid- +ered it essential to bank the Disk Operating System. Starting +with ZSDOS, Hal used the new BIOS banking functions to bank +significant portions of the BDOS. At every juncture, size and +speed were traded off to keep the system small and fast. We +corrected the flaw in the CP/M Plus Disk Size function cited +above by returning four bytes containing the number of kilobytes +free (a more meaningful measure). File Time/Date stamping func- +tions for DateStamper(tm), P2DOS (CP/M Plus compatible), and Joe +Wright's NZTIM are all embedded within the Operating System and +are concurrently active. While ZSDos2 is still a work in pro- +gress, copies are included in the B/P Bios package to allow users +to benefit from the newer system. Latest versions were posted in +the BPBIOS: directory on the Ladera Z-Node until its demise, and +no replacement is yet available. The most recent version of +ZSDos2 in 1993 added directory hashing for true speed demons. + +Also incorporated in ZSDos2 is a ZCPR34-compliant Command Line +Parser. With the permission of Jay Sage, we also modified ZCPR34 +to operate in the banked environment, added many common features +of Resident Command Processor packages, and simplified it to use +the new ZSDos2 Command Line Parser. By folding all features into +the CPR, the need for a Resident Command Processor (RCP) exten- +sion in high memory all but disappears, typically adding 2k to +the TPA. + +As a closing note to this first installment, systems using B/P +Bios, ZSDos2 and the expanded CPR are currently in operation on +the new D-X Designs Pty Ltd P112, Micromint's SB180, a modified +SB180 with static memory, two versions of the SB180FX, three +YASBEC configurations including a laptop with VGA LCD display, +Ampro Little Board (with Terry Hazen's MDISK expansion), and in +non-banked mode on a Compu/Time S100 and Teletek. All tools are +common across the hardware systems with a complete Z3 Environment +and additional segments typically resulting in the equivalent of +a "standard" 60k CP/M system. This size is without the RCP +typically used to enhance the Command Processor. + +The next part of this article will describe the B/P Bios inter- +faces and standards, while part 3 will cover proposed standards +for the evolving ZSDos2, its associated Command Processor and +some of the support utilities. + +=================================================================== + Banked/Portable Basic IO System (B/P Bios) Pt II + by + Harold F. Bower and Cameron W. Cotrill + +As we discussed in the first part of this article, our efforts in +the design and construction of our Banked/Portable Bios were +directed towards building an architecture that would viably +support applications on Z80/180 computers for a number of years. +One of the initial ground rules was a prohibition on the use of +Self-Modifying code. As in our development of ZSDOS, we want to +retain the ability to place operating system components into ROM +if desired. This goal was met, but at the price of slightly +increased code size, particularly in non-banked systems such as +those placed on system boot disks. Exceptions to this rule do +exist, but primarily in system components which are intended +specifically for execution from RAM such as portions dynamically +relocated at load time. + +Another key consideration addressed in B/P Bios was the need to +provide a mechanism to identify the Bios and to locate Bios- +specific data areas and options. The solution to this was Bios +Function 30 which returns, among other things, a pointer to the +start of a standardized data structure containing configuration +information. This vector allows examination or alteration of +various parameters such as Data Rates, Drive parameters and +configuration flags. Using this vector instead of assuming +absolute locations within the BIOS is crucial to obtaining and +maintaining portability and standardization. + +The Configuration Area pointer serves a secondary purpose as +well. The six bytes preceding the returned address point to a +string which must begin with the Ascii letters "B/P". The fol- +lowing three characters contain a suffixing identifier for the +hardware base. Between us, we have either implemented or planned +B/P Bios installations to varying degrees on the following sys- +tems: + + "-18" - MicroMint SB-180 (HD64180 CPU, 9266 FDC, 5380 SCSI) + "-FX" - MicroMint SB180FX (Z180 CPU, 9266 FDC, 53C80 CSI) + "-YS" - YASBEC (Z180 CPU, 1772 FDC, DP8490 SCSI) + "-DX" - D-X Designs P112 (Z182 CPU, 37C665 FDC, Flash ROM) + (Add-on 5380 SCSI supported) + "-CT" - Compu/Time S-100 set (Z80 CPU, 1795 FDC, 1MB Memory) + "-TT" - Teletek (Z80 CPU, 765 FDC) + "-AM" - Ampro Little Board (Z80 CPU, 1770 FDC, T. Hazen's MDISK) + "-XL" - XL M-180 SBC (HD64180 CPU, 9266 FDC, PIO SCSI) + +This method of identification can serve to prevent customized +programs from operating on the incorrect hardware. For example, +the HDBOOT hardware-specific program distributed for YASBEC and +Ampro Little Board computers will not modify a Hard Disk boot +record unless the system on the Boot Tracks contains either the +"-YS" or "-AM" identifiers. + +With the additions made to the ZCPR3 Environment Descriptor in +Version 3.4, it readily became apparent to us that the Environ- +ment belongs to low-level hardware-dependent portions of the +Operating System, with allowances being made for high-level use. +While this decision may be debated, we adopted the ENV structure +and require it within the Bios with only one necessary change. +The four bytes associated with the second printer have been +usurped to provide data on a resident User Space. To provide +compatibility with other vectors added to Operating System com- +ponents, the four bytes are reallocated as: + + 1 byte - Number of free 128-byte blocks + 2 bytes - Pointer to start of User Space + 1 byte - Total size in 128-byte blocks + +The User Space is always assigned below all other ZCPR3 System +Segments and the Starting Address Pointer serves double-duty as +the lowest address in reserved memory. This is needed in hard +disk systems since the ALV buffers are dynamically calculated at +system load (boot) time. For Non-banked systems, if the amount +of space needed by the ALV buffers extends beyond the base of the +User Space pointer, a warning is printed to alert users that a +smaller system is required to allow full use of the hard drive +without overwriting System Segments. In banked systems, the +check is performed against the end of the primary 32k System +Bank. The use of a byte to indicate amount of free space remain- +ing will allow multiple RSX-like additions to be chained into the +User Space in a (hopefully) controlled manner. A similar con- +struct is being developed for banked applications, but has not +yet been fully developed. + +As most of us are painfully aware, Floppy Disk formats in the +CP/M compatible world are woefully non-standardized. To maximize +the efficiency of B/P Bios, we have NO required format. Our +system may be assembled with hard-coded invariant formats (the +smallest code requirements), with calculated skew values or +indexed tables, or with a user-configurable suite of non-con- +flicting formats, including 3.5", 5.25" and 8" drives as well as +"High-Density" formats where the hardware is supported. For +standard distribution, the Ampro/SB-180 5.25" formats are includ- +ed in an auto-select mode. 8" drive capability is in the SB-180, +SB180FX, P112, Compu/Time and Teletek versions, but not in YASBEC +or Ampro Little Board since those controllers will not handle the +higher data rates. Using this scheme, tailoring options may be +used to gain every byte and clock cycle possible, for example, by +deleting 8" formats if you only have 3.5 or 5.25" drives connect- +ed to the system. + +The B/P BIOS is divided into a number of files, some of which are +machine dependent, and some are generic and need not be edited to +assemble a working system. Much use is made of conditional +assembly to include option-dependent modules and relocation +bases. The Basic file, BPBIO-xx.Z80, specifies which source code +elements are used to assemble the Bios image under the direction +of an included file, DEF-xx.LIB, which selects features and +contains Hardware-dependent equates. Modules requiring customi- +zation for different hardware systems are given names which end +with a generic "-xx" designator to identify specific versions. +These names correspond to the suffix embedded in the identifier +string covered above. By maintaining the maximum possible code +in common modules which require no alteration, B/P Bios is rela- +tively easy to convert to different machines. + +While some of these versions cannot take full advantage of B/P +Bios, such as the Ampro Little Board which, without Terry Hazen's +MDISK, contains only 64k of memory, the benefits of having only +one set of support utilities and common operating procedures +across different computers often outweigh the disadvantages of a +slightly larger Bios. Those of you with several different types +of computers will readily understand. + +With B/P Bios, systems may be changed "on the fly" in a manner +similar to that employed with NZBLITZ/NZCOM. The system placed +on the boot disk's system tracks must be relatively small to fit +in the limited space, often sacrificing features. Once started, +however, the rules change. A special loader is used to move pre- +configured system images in place and start execution. These +images are built from an assembled B/P Bios REL file, ZSDOS +version 1 or 2 ZRL file, and a Command Processor REL or ZRL file. +The utilities to build the image file and load it into position +account for both banked and unbanked component locations. The +build utility also allows you to alter many of the Environment +parameters as the image is built. For example, the extra large +Command Processor demonstrated several years ago at the Trenton +Computer Fest includes most of the common features from RCPs. +Consequently, RCP space is often not needed and may be removed +typically freeing 2k for the TPA. + +Different system images may be generated with BPBUILD and then +loaded as specific functions or configurations are desired, +without regard to the system on the Boot Tracks. Tailoring of +these image files is performed with the B/P Bios configuration +utility, BPCNFG, to include Startup Alias file names unique to +that system. In this manner, different images may chain from one +to another as system sizes and needs change. A given image file +might be duplicated with only minor configuration changes. Hal +uses this technique in system backups where two hard disk parti- +tions are activated for backups to external hard drives, but +different parameters are configured for various backup media and +drive types. + +To provide some comparative numbers, a YASBEC with a 20MB hard +drive is typically limited to a 53K non-banked system for place- +ment on the Boot Tracks. A 56K system is achieved simply by +banking portions of the Bios. With the banked ZSDos2 and the +associated large Command Processor, Z41, a 58.0K system is stan- +dard with the default 2K RCP and 1.5K IOP space reservations. +This expands to 60K with no RCP and 61.5K if no IOP is needed. +The large expansion in size with the banked ZSDos2 is due to +banking of the ALV and CSV bit storage areas needed for hard and +floppy drives. Placing these elements into the system bank means +that large system sizes are no longer dependent on the hard disk +sizes (yes, even a 200 MB hard drive on a YASBEC sports a 60K +system configuration), but with the penalty that normal programs +which count ALV bits to determine disk free space and file size +no longer function correctly. This difficulty has, in part, been +addressed by providing modules in the DSLIB utility library (a +companion to SYSLIB and Z3LIB) which "know" about ZSDos2 and +properly return disk free space values. Source code for DSLIB +was released to Z-Nodes several years ago, and many of the in- +cluded routines are used in our utilities, such as the ZXD direc- +tory lister provided as part of the B/P Bios package. + +If even more Transient Program Area is needed, one additional +means exists to expand available memory, but at a possible ex- +pense. Part of the BPBUILD process is to size the Code and Data +requirements of the relocatable modules, and locate them at +static addresses for loading. Since the resident portions of +both the Z41 Command Processor and ZSDos2 are smaller than their +non-banked counterparts, the lower limit for applications pro- +grams, which are allowed to overwrite the Command Processor, and +Resident System Extensions (RSXes) which nestle immediately below +the Command Processor see a higher memory address. The caveat to +this approach, however, is that only programs which use the +enhanced environment parameters compliant with ZCPR 3.4 and later +will function properly. To avoid such potential problems and +provide maximum commonality with existing CP/M programs, BPBUILD +also allows the user to direct that the Command Processor and +resident DOS elements be linked to begin at "standard" locations +reflecting sizes of 2K and 3.5K respectively. + +THE INTERFACE. + +B/P Bios entry points are contained in a Table of 3-byte Absolute +jumps at the beginning of the Bios Image. Parameters needed for +each function are passed to the Bios in specified registers. To +avoid future compatibility problems, some of the ground rules for +Bios construction include; No alteration of Alternate or Index +registers as a result of Bios calls, and all registers listed in +the documentation as being Preserved/Unaffected MUST be returned +to the calling program in their entry state. The first seventeen +jumps (indices 0-16) constitute the standard CP/M 2.2 jump table. + +Following those are additional sequences patterned roughly after +CP/M 3 and the B/P-unique extensions. The Bios entry points +listed in order of their appearance in the jump table are: + + 0 - CBOOT Execute Cold Start initialization on the first + execution. The code is later overwritten, and the + argument of this jump then points to the IOP Device + jump table. (all registers used) + 1 - WBOOT Execute Warm Restart initialization, reload the + Resident part of the Command Processor and log onto + the default drive. (all registers used) + 2 - CONST Return Console Input Status as; A=0FFH if Character + is ready, A=0 if No character is ready. (Uses AF) + 3 - CONIN Read a character from the Console, waiting until one + if ready, then return it in A masked as specified in + the Bios, Normally with Bit 7 set to 0. (Uses AF) + 4 - CONOUT Send the character in C register to the console masked + as specified in the Bios (Uses AF) + 5 - LIST Send the character in C register to the List Device + (normally a printer) masked as specified in the Bios. + (Uses AF) + 6 - AUXOUT Send the character in C register to the Auxiliary + Output masked as specified in the Bios. (Uses AF) + 7 - AUXIN Read a character from the Auxiliary Input port masked + as specified in the Bios. (Uses AF) + 8 - HOME Position the head(s) on the selected drive to Track 0. + (Uses All primary registers) + 9 - SELDSK Select the drive specified by the value in Drive C + where Drive A=0...P=15. (Uses All primary registers) +10 - SETTRK Select the Logical track contained in Register BC for + a future disk operation (All registers preserved) +11 - SETSEC Select the Logical sector contained in Register BC + for a future This difficulty has, in part, been + addressed by providing modules in the DSLIB utility + library (a companion to SYSLIB and Z3 disk operation + (All registers preserved) +12 - SETDMA Set the address in Register BC for a future disk + operation (All registers preserved) +13 - READ Read a Logical 128-byte sector from the Disk, Track + and Sector set by Functions 9-11 to the address set + with Function 12. On return, Register A=0 if the + operation was successful, Non-Zero if Errors occurred. + (Uses All primary registers) +14 - WRITE Write a logical 128-byte sector to the Disk, Track and + Sector set by Functions 9-11 from the address set with + Function 12. If Register C=1, an immediate write and + flush of the Bios buffer is performed. If C=0, the + write may be delayed due to the deblocking. (Uses all + Primary registers) +15 - LISTST Return A=FF if the Printer is ready to accept a charac- + ter for printing, otherwise return A=0. (Uses AF) +16 - SECTRN Translate the Logical Sector Number in register BC + (Only C used at present) to a Physical Sector number + using the Translation Table addressed in the Selected + Drive's DPH. (Uses All Primary regs) + +This ends the strict CP/M 2.2-compliant portion of the Bios Jump +Table. The next series of entry Jumps roughly follows those used +in CP/M Plus (aka CP/M 3), but with corrections to what we per- +ceived to be deficiencies in the calling parameters and struc- +tures. + +17 - CONOST Return A=FF if the Console is ready to accept another + output character, otherwise return A=0. (Uses AF) +18 - AUXIST Return A=FF if the Auxiliary Input has a character + waiting, otherwise return A=0. (Uses AF) +19 - AUXOST Return A=FF if the Aux. Output is ready to accept + another character for output, otherwise return A=0. + (Uses AF) +20 - DEVTBL This corresponds roughly to an analogous CP/M Plus + function although precise bit definitions vary some- + what. The Character IO table consists of four + devices; defaulting to COM1, COM2, PIO, and NUL. + Each has an input and output mask, data rate settings + and protocol flags. Not all defined settings (e.g. + ACK/NAK and XON/XOFF handshaking, etc) are imple- + mented in all versions, but are available for use. + (Uses HL) +21 - DEVINI Initialize Character IO settings and other specified + functions. This is very close to the CP/M Plus + function and can be used torestore IO configurations + after alteration by programs which directly access + hardware such as modem programs. (Uses all primary + registers) +22 - DRVTBL Return a Pointer to the DPH table for Drives A-P where + a 16-bit 00 entry means that no drive is defined. + (Uses HL) +23 - MULTIO +24 - FLUSH Write any pending Data to disk as mentioned in Func- + tion 14 above. (Uses all primary registers) +25 - MOVE Move number of bytes specified in BC from the location + starting at (HL) to an area addressed by (DE). For + banked moves, the Source and Destination banks must + have been previously specified with an XMOVE function. + Note that this function reverses the functions of the + DE and HL register pairs from the CP/M Plus function. + (Uses all Primary registers except A) +26 - TIME If Register C=0, Read the Date and Time to a 6-byte + field addressed by (DE). If C=1, Set the Date and + Time from 6-byte field addressed by (DE). On exit, + register A=1 if the operation was successful, A=0 if + an error occurred or No clock exists. The Date/Time + string is in ZSDOS format as opposed to Digital + Research's format used in CP/M Plus for this function. + Also, This function must conform to additional re- + quirements of DateStamper(c) in that on exit, register + E must contain the entry contents of (DE+5) and HL + must point to the entry (DE)+5. If the clock supports + 1/10 second increments, the current .1 second count + may be returned in register D. A recent addition + (suggested by Terry Hazen in TCJ #79) uses BC to + return the address of a free-running 8-bit counter + decremented every 100 milliseconds. Such a feature is + invaluable in user programs such as modem drivers. + (Uses all primary registers) +27 - SELMEM Select the Memory Bank specified in the A register and + make it active in the address range 0-7FFFH. (All + registers preserved) +28 - SETBNK Set the Bank Number in A for the next Disk IO. (All + registers preserved) +29 - XMOVE Set Source and Destination Bank numbers in registers C + and B respectively for a future Move (Function 25). + (All registers preserved) + +This marks the end of the CP/M Plus "Type" jumps and begins the +unique additions to the B/P Bios table to support Banking, Direct +IO and interfacing. + +30 - RETBIO Return the Bios version number and a pointer to + internal BIOS data areas as: + A = Bios Version Number + BC --> Page Address of B/P Bios + DE --> Start of Configuration area + HL --> Start of Device Vector table +31 - DIRDIO Execute low-level functions directly on Floppy or SCSI + devices. (described below) +32 - STFARC Set the bank number for a subsequent Function 33 + execution. (All resisters preserved) +33 - FRJP Switch to bank number specified with Function 32, then + execute routine at address in HL, returning to + address on stack top. (Uses all primary registers) +34 - FRCLR This entry is used for error exits from banked routines + to return to the entry bank. (Uses all primary + registers) +35 - FRGETB Load the byte addressed by HL from the bank number + specified by the C register into the register A. + (Uses A) +36 - FRGETW Load the Word addressed by HL from the bank number + specified by the C register into the DE register pair. + (Uses DE) +37 - FRPUTB Store the byte in register A to the memory addressed by + HL in the bank specified in register C. (All registers + preserved) +38 - FRPUTW Save the Word in DE to the memory addressed by HL in + the bank specified in register C. (All registers + preserved) +39 - RETMEM Return a Byte identifying the Memory Bank number + currently in context in the A Register. (Uses A) + + +DIRECT DISK IO. BIOS Function 31 permits low-level access to +Floppy and Hard Disks (currently via SCSI interface) by specify- +ing a Driver Number and desired Function. While some hardware +types do not support all of the parameters specified, particular- +ly for Floppy Drives, this architecture supports all types, +although specific systems may ignore certain functions. In this +manner, for example, a single Format program supports NEC765, +SMC9266, SMC37C665, DP8743 and WD1770/1772/179x controller types +with widely differing interfaces. Floppy Disk functions are +accessed by entering a 1 value into Register B (Floppy Driver +Number) and the desired function number in Register C, then +jumping to or calling BIOS Entry jump number 31. + +FLOPPY DISK SUBFUNCTIONS: + + 0 - (STMODE) Set the Floppy Disk Controller for Read/Write opns. + On entry, Register A contains a Density Flag (0 = Double, + 0FFH = Single Density). No data is returned from this + function. NOTE: This routine assumes that Functions 1 + (STSIZE) and 3 (STSECT) have been called first. (Uses AF) + 1 - (STSIZE) Set Drive Size (3.5/5.25" or 8"), Drive Speed (300 or + 360 rpm) and Motor Needed flag. On entry, A=0 for normal + floppy speed (synonymous with "Normal" 250 kbps MFM Double- + Density), A=0FFH for High speed motors (synonymous with "Hi- + Density" 500 kbps MFM). Register D=0 if the motor is always + on or no motor control is needed, while D=0FFH if motor + control is necessary. Finally, register E must contain the + drive size as; 0=Hard Disk, 001B=8" Drive, 010B=5.25" Drive, + and 011B=3.5" Drive. Nothing is returned from this command. + While all of these functions may not be supported on any + specific computer type, the interface from using programs + should always pass the necessary parameters for compatibility. + NOTE: This routine assumes that Function 2 (STHDRV) has been + called first. Call this routine before calling Function 0 + (STMODE). (Uses AF) + 2 - (STHDRV) Set Head and Drive Number for Disk Operations. This + routine is entered with register A containing the Floppy unit + number coded in bits 0 and 1 (Unit 0=00, 1=01 ..3=11), and the + Head in Bit 2 (0=Head 0, 1=Head 1). Nothing is returned from + this function. (Uses AF) + 3 - (STSECT) Set Physical Sector Number, Size and Last Sector + Number on the Track. On entry, Register A contains the + desired physical sector number desired, D contains the sector + size where 0=128 byte sectors, 1=256..3=1024, and E contains + the last sector number on a side. Normally register E is + unused in Western Digital controllers, but is needed with 765- + compatible units. Nothing is returned from this function. + (Uses AF) + 4 - (SPEC) Set Step Rate and Head Load/Unload Time. On entry, the + A register contains the drive step rate in milliseconds. + Within the Bios, this rate is rounded up to the nearest slower + controller rate if the specified rate is not an even match. + Implementation of this function in the Bios also accommodates + the need to adjust values reflecting the step rate when the + data rates are changed from 250 to 500 kbps and vice versa. + Register D should contain the desired Head Unload time in mil- + liseconds, and E to the desired Head Load time in mS. With + some controllers such as the Western Digital 177x and 179x + family, only the Step Rate is universally variable. In these + systems, rates signaled by the Bios settings are rounded up to + the closest fixed step rate such as the 2, 3, 5, or 6 milli- + second rates in the 1772 (YASBEC) or 6, 10, 20, or 30 milli- + second rates used in the 1770 (Ampro Little Board) and 1795 + (Compu/Time). Nothing is returned from this function. + (Uses AF) + 5 - (RECAL) - Recalibrate Drive (moves the head to track 0). There + are no entry parameters for this function. On exit, the zero + flag is Set and A=0 if no errors occurred, otherwise the Zero + flag is Reset and A is Non-Zero. NOTE: This routine assumes + that STHDRV, STSIZE and SPEC have been called first. (Uses AF) + 6 - (SEEK) - Set the Track for disk operations and seek to it. On + entry, Register A is set to the desired Track Number, D sig- + nifies whether Verification of the seek is required (D=0 for + No Verify, D=0FFH if verifying), and E indicates whether or + not to double-step (E <> 0 for Double-Step, E=0 for No Double- + Step). On exit, A=0 and the Zero Flag is Set (Z) if the + operation was successfully completed while A <> 0 and the Zero + Flag is cleared (NZ) if an error occurred. NOTE: This routine + assumes that STHDRV, STMODE and SPEC have been called first. + (Uses AF) + 7 - (SREAD) - Read from the floppy disk. On entry, HL must point + to a Buffer to receive the data read. It assumes that Mode, + Track, Head/Drive, and Sector have been previously set. On + exit, A=0 and the Zero flag is set (Z) if the sector was + satisfactorily read, A <> 0 and the Zero flag is cleared (NZ) + if an error occurred. (Uses AF and HL) + 8 - (SWRITE) - Write to the floppy disk. On entry, HL must point + to a Buffer from which to send the data. It assumes that + Mode, Head/Drive, Track, and Sector have been previously set. + On exit, A=0 and the Zero flag is set (Z) if the sector was + successfully written, A <> 0 and the Zero flag is cleared (NZ) + if an error occurred. (Uses AF and HL) + 9 - (READID) - Read the first correct ID information on a track. + There are no entry parameters for this function. The Zero + flag is set (Z) and A=0 if no errors occurred, otherwise the + Zero flag is Reset (NZ) and A is non-zero. NOTE: This routine + assumes that STHDRV and STMODE have been called first. + (Uses AF) +10 - (RETDST) - Return the status of a drive. There are no entry + parameters for this function. On exit, A contains the raw + unmasked status byte of the drive or the last operation + depending on the controller type, BC contains the binary + number representing the FDC controller type (e.g. 765, 9266, + 1772, etc), and HL contains the address of the status byte + returned in register A. NOTE: This routine assumes that + STHDRV has already been called. (Uses AF, BC and HL) +11 - (FMTTRK) - Format a complete track on one side of a Floppy + Disk. It assumes that the Mode, Head/Drive, Track, and + Sector have already been set. On entry, HL points to data + required by the controller to format a track. This varies + between controllers, so RETDST should be called to determine + controller type before setting up data structures. On entry, + D must also contain the number of Sectors per Track, and E + must contain the number of bytes to use for Gap 3 in the + floppy format. On exit, A=0 and the Zero flag is Set (Z) if + the operation was satisfactorily completed, A <> 0 and the + Zero flag cleared (NZ) if errors occurred. (Uses all primary + registers) + +HARD DISK SUBFUNCTIONS: + +These functions are available to directly access Hard Drives. To +date, only drives connected by a SCSI type interface have been +used, but the interface is generic enough to allow mapping to +other interfaces such as IDE. The functions are accessed by +loading the desired function number in the C register, loading a +2 (SCSI driver) into the B register and calling or jumping to +Jump number 31 in the Bios entry jump table. Since this inter- +face is not as standardized as Floppy functions in order to +handle SASI as well as SCSI devices, the interface has only basic +functions with the precise operations specified by the User in +the Command Descriptor Block passed with Function 2. This places +a greater burden on User programs, but it allows more flexibility +to take advantage of changing features in the newer SCSI drives. + +An additional constraint placed on the Hard Disk interface is the +restriction to 512 byte physical sectors at the interface. Since +most hard drives now default to this sector size, no difficulties +have been reported in the few years since B/P Bios has been +released, so this constraint should pose no serious limitation. + + 0 - Set User Data Area Address for Direct SCSI IO, Return number + of bytes available for the SCSI Command Descriptor Block. + On entry, DE must point to a 512 byte User Data Area to Send/ + Receive. This is mandatory since 512 bytes are always + returned from a direct access due to the wide variety of + controller types handled. On exit, A contains the number of + bytes available in the Command Descriptor Block which will + usually be 10, but may be scaled back to 6 in limited + applications. (Uses AF and HL) + + 1 - Set Physical Device bit and store Logical Unit Number (LUN) in + SCSI Command Block (Byte 1, bits 7-5) from byte in A. On + entry, register A contains a bit-mapped byte indicating the + SCSI Physical Unit number (bits 0-2) and Logical Unit Number + (bits 5-7). On exit, A returns a "1" bit in the proper + position for the SCSI physical drive unit with Bit 7 being the + host computer, Bit 0 indicating Unit 0, etc. (Uses AF) + + 2 - Direct SCSI driver. This routine performs the function + described by the command in the SCSI Command Descriptor Block + addressed by DE. On entry, register A must also contain a + flag signifying whether or not user data is to be written by + this command (A=0 if No data to be written, FF if the address + set with Function 0 contains user data to write). At the end + of the function, 512 bytes are always transferred from the + Bios IO Buffer to the User's Space set by Fcn 0. This may be + inefficient, but was the only way we could accommodate the + wide variety of different SASI/SCSI controllers within reason- + able code constraints. Additionally, Register A contains 0 if + the function performed with no errors, and 02H if a check + condition was encountered. Also, Register L returns the + unmasked Status byte (0FFH indicating a timeout error), and H + returns the first Message byte received. (Uses all primary + registers) + NOTE: This routine assumes the Command Block is properly + configured for the type of Hard Disk Controller set in B/P + Bios, and that the selected disk is properly described in the + Bios Unit definitions (if necessary). Errors in phasing + result in program exit and Warm Boot. It assumes the user + has executed Functions 0 and 1 to set the data transfer source/ + destination address and logical/physical drive addresses. + +In the final part of this series, we will describe some of the +utilities developed and modified to support banked systems and +address our ongoing efforts with the banked ZSDos2, Command +Processor and future directions. + +=================================================================== + Banked/Portable Basic IO System (B/P Bios) Pt III + by + Harold F. Bower and Cameron W. Cotrill + +Having covered the Bios in detail in Part 2 of this series, we +now turn our attention to the rest of the operating system. For +those who have seen or operate a B/P Bios-based system, you +probably wondered if the Command Processor (Z4x) or the Banked +Operating System (ZSDos2) will ever be finished. In a nutshell, +probably not. They are furnished with the B/P Bios package to +allow system owners to glimpse the possibilities and to take full +advantage of the Bios primitives as well as experiment with some +different concepts. With that said, ZSDos2 is still a "work-in- +progress". + +Banking the operating system creates some inefficiencies and +incompatibilities. An example of the former is that for file +functions, File Control Block (FCB) information must be copied to +high memory, the banked portion of the operating system swapped +in context, and the operation concluded. This is not the end, +however, for the modified FCB must then be copied back to the +User Transient Program Area (TPA) in case the application needs +to access the updated data such as record number which is au- +tomatically incremented after each sequential read or write. +This adds overhead and was optimized as much as possible. Also, +certain functions such as character IO were not banked at all to +keep responsive to acceptable levels. + +Incompatibilities were handled by documenting them, and providing +utilities adapted to handle the new features. An example of this +is the free space calculations handled by counting bits in the +Allocation Bit Map (ALV) buffer which contains one bit for each +allocation unit on the drive. ALV data is placed in the system +bank to allow large (several hundred megabyte) drives to be used +without sacrificing any TPA space. We provide the ZXD.COM direc- +tory lister (a heavily modified version of Richard Conn's XD) +linked with DSLIB routines which "know" about the banked systems +and correctly compute and return free space. DSLIB is freely +available from many systems. + +The last "standard" version of the banked ZSDos2 was produced in +1993 as ZS227G.ZRL, with a significant change released shortly +thereafter as ZS203.ZRL (the .ZRL type stands for Z-System Relo- +catable, a Microsoft .REL file with named Commons for selected Z- +System structures). This latter version supports "hashed" direc- +tories for very rapid access to files since it drastically reduc- +es the number of comparisons needed to locate files in the direc- +tory. Both are included in the distribution package for use. +The reasons why will become clear after a small tutorial. + +Conventional CP/M 2.2 (and clones) set a pointer to the first +file in a directory upon a Search First (function 17) then use a +sequential search method with Search Next (function 18) until the +request is satisfied or the list of files is exhausted. With +ZS203 running with a hashed directory (identified by a 20H in the +user byte of the first file on a disk when logged in), a Search +First request performs a mathematical calculation over a portion +of the FCB to obtain the number of a "bucket" which is a fixed +number of directory entries. Subsequent Search Next requests +then begin a sequential search until either the file is found, or +an uninitialized entry (E5H in the User byte) is located. For +sparsely-populated directories, the search seems nearly instanta- +neous, and a comparable time is taken to find the first file +placed in a disk as the last. Only in a very heavily-loaded disk +does the time approach that of a conventional CP/M 2.2 system. + +One nuance of this type of a directory structure is that removing +a file from the directory cannot be done in the common way by +placing an E5H in the User byte, since that signifies an unini- +tialized entry and would terminate a search if following entries +hashed to the same value. 0C6H was defined to mark an unused +(erased), but not terminal entry. Adding or renaming a file +computes the hash value, then examines the computed "bucket" +sequentially until either a C6H or E5H byte is found, then uses +that position. + +With this brief description, you might be wondering why anyone +would want to continue with non-hashed directories, so to 'fess +up...there are some incompatibilities. First, this is a "classi- +cal" hashing structure taught in Computer Science classes and not +the table-driven method used in CP/M+, so anyone using tools for +that system will probably encounter problems. Next, directory +listing programs that do not recognize the C6H byte in the User +position as a deleted entry will probably report the file with a +weird user number. In addition, DateStamper(tm) File Stamps are +not supported since the !!!TIME&.DAT needed by that system cannot +use the first directory entry due to the hash flag, so you must +use P2DOS or ZSTIME stamps. + +If you carefully tickled the gray matter while reading the de- +scription, you probably wondered what the impact of a REName +function would be on performance. In a word..horrible! To +rename a file, the new name must be hashed and an available +directory entry (or more) must be located. Next, the contents of +each directory entry after the File Type field for the old file +name must be copied to the corresponding new location, and the +old entries must be marked as unused with the C6H User byte. For +this reason, programs such as WordStar4 which frequently rename +files pause noticeably with much head activity during these +operations. + +Finally, the biggest caution of all with hashed directories is to +insure that you NEVER write to a hashed directory with a non- +hashed Operating System. For this reason, your A: drive upon +bootup should always contain a Non-hashed directory. When creat- +ing a large image file (see Part 2), you can exchange drive and +partitions to place a hashed unit as A: but only with ZS203 as +the Operating system. Should you make an error, you will prob- +ably see files in a directory list that you cannot access and +can't remove without using raw sector reads and writes with DU3 +or suffering further corruption of the directory system! + +With all of these cautions, you might wonder why anyone in their +right mind would want to choose this scheme! The short answer is +SPEED!!! Once set up properly, overlays, such as those used with +WordStar4 load almost instantly. This is due to finding the file +in the directory very quickly, on the first disk read for sparse- +ly-occupied directories. This is where you really begin to +appreciate how much time is wasted in the operating system simply +searching for files. Consequently, we offer it as an alternative +for learning. + +Both variants of ZSDos2 contain some new Operating System func- +tion calls which can be used to advantage by your programs if +they first verify that you are running under ZSDos2. They are +also used by many of the support utilities as well as the banked +Command Processor. They are: + +46 - Return Disk Free Space in kilobytes to DMA location (4 + bytes) + Enter: C = 46 + E = drive (A=0) + Exit : Drive free space in K is at DMA+0 (LSB)..DMA+3 (MSB) + A reflects 0 on success, <>0 on Error logging drive + +49 - Return Address of Environment Descriptor + Enter: C = 49 + Exit : HL - Points to Z34+ Environment Descriptor + +152 - Parse Filename to Z34 specs + Enter: C = 152 + DE - points to FCB to receive parse + DMA points to start of string to parse + Exit : A = L = Number of Question Marks in fn.ft + DE - points to character after last one parsed (delim) + FCB+15 will be 0 for Ok parse, 0FFH if errors occurred + + +Z41.ZRL is the latest version of the banked Command Processor +based on ZCPR34. One of the first things you will probably +notice is that warm boots of the system after completing an +operation that overwrites the Command Processor is that the +system does not reload the Command Processor from Disk. A copy +of the portion that resides in TPA space is retained in the +System Bank and simply restored via an Inter-Bank block move; +much faster than a disk seek and read! + +Z41 integrates many of the RCP features commonly in use and may +mean that you can completely eliminate the use of a Resident +Command Processor (RCP) at a typical saving of 2k bytes. Dis- +playing the built-in Help with Wheel privileges (the Z-System +"Superuser" equivalent) results in the following: + + CPR + CLS cp DATE DIR ECHO + era feed get go H + jump list NOTE p poke + port prot reg ren res + save sp spop TIME type + VER WHL + +Of the 27 resident commands available, only the ones listed in +capital letters are available when the Wheel Byte is turned off, +such as when operating in a dial in BBS system. Even some func- +tions available to all users, have certain features disabled, +such as the DATE/TIME Setting functions which are reserved for +those with Wheel privileges. For those not familiar with the Z- +System, these built-in functions are: + + CLS - Clear the screen using the current TermCap definition + cp - Copy a file from one location to another + DATE - Display the date + DIR - Display files in the current or a specified directory + ECHO - Print the remainder of the line to the Console + era - Erase a file or files + feed - Send a Form Feed byte to the Paper (eject) + get - Load a file from the current directory to a specified + memory address + go - Execute code at 100H. Typically used to re-execute + command files + H - Help. Display list of available commands in CP, RCP and + FCP + jump - Execute code at specified address + list - Send specified file to the List Device (usually printer) + NOTE - Simply ignore the rest of the line + p - Display (Peek) memory contents + poke - Enter Hex bytes into memory at specified address + port - Read from or write a byte to a specified IO Port + prot - Set/Clear System and Read-Only Attribute bits in + specified file + reg - Set, increment, decrement, clear the 10 ZCPR3 Registers + ren - Rename a file + res - Reset Disk Subsystem and relog all drives + save - Write memory from 100h to file for specified length + sp - Return free space on specified drive + spop - "Pop" the value from the Top of the ZCPR3 Shell Stack + TIME - Display the time (Set if Wheel) + type - Display a file on the Console + VER - Display the Z41, ZSDos2 and B/P Bios Version Numbers + WHL - Turn Wheel Byte On (w/password), Off or Display status + +This Command Processor relies on ZSDos2 and a banked B/P Bios and +will NOT work without them. To keep duplicated code to a mini- +mum, the Command Line parser in ZSDos2 as well as the other new +functions are used instead of discrete code used in other Command +Processor Replacements. As additional enhancements, the prompt +line can optionally display the time from ZSDos2, and the date +display can be configured to display in either "Mmm DD,YY" (US +style) or "DD Mmm YY" (European) forms. These two features were +"hard-wired" in the original Z40 distributed several years ago +but have since been made configurable via the CONFZ4.COM Utility +with Z41. + +The actual TPA memory requirements of Z41 and ZSDos2 are less +than the "standard" CP/M sizes of 2 and 3.5 kilobytes respective- +ly. For the largest possible TPA space, they can be autosized +(an option in the BPBUILD utility). Unfortunately, there are +still some legacy programs out there that incorrectly subtract +the BDOS "standard" size from the base of the BIOS jump table +resulting in an incorrect memory reference. To handle this +occasional hiccup, there is an option to locate the start of Z41 +and ZSDos2 TPA portions at "standard" locations below the BIOS +with dead space on the high end padding to the next higher system +element. This has proven to be an adequate method of handling +the occasional problem if the need arises. + +We have developed a suite of utilities to support B/P Bios in the +same manner as we did with the original ZSDOS1. Several of these +are modifications to older routines and contain changes necessary +to function in the banked environment. In addition, a few of +them have been released in source code to illustrate methods of +accessing the enhanced features of B/P Bios. The core programs +distributed with the package are: + +BPBUILD - Create a loadable banked image file. Input files + needed include the output of assembling a BPBIO-xx file + (in MicroSoft REL format), a REL or ZRL image of an + Operating System (ZSDOS1 or the current version of the + banked ZSDos2 are recommended), and a REL or ZRL image of + a Command Processor (ZCPR33.REL or later, or the current + banked ZCPR4 are recommended). + +BPCNFG - Configure the B/P Bios options in a system Image File, + Diskette Boot Tracks, or executing in memory. Due to the + memory mapping, some features such as re-defining hard + drive partitions are disabled if configuring the currently + executing system. + +BPDBUG - A DDT-like debugger with support for B/P Bios Banked + memory. While primitive, it allows poking around in a + banked or non-banked environment. + +BPFORMAT - Format a floppy drive under B/P Bios from either built-in + formats (from available DPB definitions) or from a library + of alien formats. + +BPSWAP - Swap B/P Bios logical drive definitions. + +BPSYSGEN - Our generic version of the classic SYSGEN program used to + add a system image onto the boot sectors of a hard or floppy + disk. + +EMULATE - Lock any or all Floppy Disk Drive(s) to specified formats, + native or alien, from a Database of formats. Also displays + current formats and restores drives to auto-selection if the + Bios was assembled with AUTOSEL option. + +HDBOOT - Add Hard Drive Boot record to an image applied to the first + tracks of a Hard Drive with BPSYSGEN (currently only avail- + able for YASBEC and AMPRO). + +HDIAG - Run Diagnostics, Format, Verify and examine Hard Drive + parameters. While SASI/SCSI controllers have been supported + since the first release, GIDE support was added in 1997. + Due to the wide variation in disks, controllers, vendors and + versions, not all functions are supported on all variations. + The program currently recognizes the following Hard Disk/ + Controller subsystems: + + Adaptec ACB-4000A + Shugart 1610-3 / Xebec 1410A + Seagate SCSI + Shugart 1610-4 (Minimal SCSI) + Conner SCSI + Maxtor SCSI + Quantum SCSI + Syquest SCSI + GIDE (Generic IDE) + +INIRAMD - Initialize a RAM Drive and prepare it for P2DOS and/or + DateStamper style file stamps. + +INITDIR - ZSDOS utility to initialize disks with P2DOS (CP/M+) + stamps. + +INSTAL12 - Install CCP, DOS, B/P Bios in a MOVCPM "type" image from + standard size (2k CCP, 3.5k DOS, ~4.375k Bios) files. + +IOPINIT - Initialize an IOP Buffer defined in a Z3 Environment to + the standard Dummy format and patch it into the Jump Table. + This utility was necessary to overcome size constraints in + a Boot Track image where some of the initialization code + normally in a Bios had to be removed to fit existing popular + disk formats. + +LDSYS - Load an IMG file created by BPBUILD into memory and begin + execution. + +MOVxxSYS - System generation facility for Boot Track installation + where the "xx" identifies the version. System images of 50 + to 53k are typically configured in non-banked bootable + systems. An image size of 53k will typically accommodate a + 20 MB Hard drive with three partitions. If you configure + for more storage or use 2k allocation blocks, you may have + to configure a smaller system. You will be warned of this + necessity by a beep and "Mem Ovfl" warning on bootup. These + programs can create a system image in memory, or write the + image to a disk file for later transfer to boot tracks with + BPSYSGEN. + +PARK - Move Hard Drive heads to designated Landing Zone if available + (provided in source code form as an example of using direct + drivers). + +SETCLOK - Extract a clock from ZSDOS1 CLOCKS.DAT file and set the + B/P Bios clock from a library of different clocks. This is + a legacy program from ZSDOS1 and is usually not needed. + +SIZERAM - Test the memory complement of the system and display the + RAM allocation by 32k bank number as well as the parameters + reported in the Environment. + +SHOWHD - Display current Drive Disk Parameter Block data on any + system to assist in maintaining Hard Drive Partitions during + conversion to B/P Bios. + +TDD - Customized version of ZSDOS utility TD to display, set or + update the Bios Interrupt clock as well as a growing number + of additional clocks such as the Dallas DS-1216E (aka No- + Slot-Clock) and Dallas DS-1202 used in the D-X Designs' P112. + +TURB - A routine available for Z8S180 and Z80182 systems which allow + bypassing of the divide-by-two circuit from the crystal + oscillator via chip-level register settings. It also allows + addition and removal of Memory Wait States to accommodate + speed changes. This program was originally named TURBO, but + shortened when we realized the name conflict with Borland's + Pascal Compiler. + +ZSCFG2 - Configure ZSDos2 options in running system. + +ZXD - Directory Lister from ZSDOS1, updated to function properly + with the banked ZSDos2. Other directory listers may not + correctly display disk free space in banked systems. + +As with all of the programs we produce, each of the above utili- +ties contains built-in Help accessed with the // argument, and is +aware of necessary environment limitations. We have attempted to +make them as bulletproof as possible, but they have been known to +err. User feedback is always welcome in this regard. + +WHAT'S NEXT? + +This package is probably the end of the line for us. Will we +ever release the source? Yes, when we decide to stop supporting +it. Until then, it remains our "labor of love" product and an +exciting as well as challenging learning experience. We are all +a little older, hopefully wiser, and looking for new challenges, +so stay tuned for UZI180, an adaptation of Doug Braun's original +Unix Z80 Implementation, enhanced by Stefan Nitschke for the +Z280, now ported to the Zilog Z180 family. + +-------------------------------------------------------------- +Closing note: The B/P Bios System is released under the GNU GPL +in 2001. It is now Free Software subject to the provisions of +the GPL. H.F.Bower, 2 December 2001. diff --git a/Source/BuildShared.cmd b/Source/BuildShared.cmd index 38aa8fc6..698050f0 100644 --- a/Source/BuildShared.cmd +++ b/Source/BuildShared.cmd @@ -8,6 +8,7 @@ pushd QPM && call Build || exit /b & popd pushd ZCPR && call Build || exit /b & popd pushd ZCPR-DJ && call Build || exit /b & popd pushd ZSDOS && call Build || exit /b & popd +pushd ZSDOS2 && call Build || exit /b & popd pushd CPM3 && call Build || exit /b & popd pushd ZPM3 && call Build || exit /b & popd pushd CPNET && call Build || exit /b & popd diff --git a/Source/Clean.cmd b/Source/Clean.cmd index 0b879078..c878314b 100644 --- a/Source/Clean.cmd +++ b/Source/Clean.cmd @@ -8,6 +8,7 @@ pushd QPM && call Clean.cmd & popd pushd ZCPR && call Clean.cmd & popd pushd ZCPR-DJ && call Clean.cmd & popd pushd ZSDOS && call Clean.cmd & popd +pushd ZSDOS2 && call Clean.cmd & popd pushd CBIOS && call Clean.cmd & popd pushd CPM3 && call Clean.cmd & popd pushd ZPM3 && call Clean.cmd & popd diff --git a/Source/Doc/Introduction.md b/Source/Doc/Introduction.md index b6ef4b48..43f4f86b 100644 --- a/Source/Doc/Introduction.md +++ b/Source/Doc/Introduction.md @@ -328,6 +328,9 @@ please let me know if I missed you! contributed a driver for the Xosera FPGA-based video controller. +* Jörg Linder has contributed disassembled and nicely commented + source for ZSDOS2 and the BPBIOS utilities. + `\clearpage`{=latex} ## Related Projects diff --git a/Source/Fonts/Build.cmd b/Source/Fonts/Build.cmd index 9032d1bb..ee112570 100644 --- a/Source/Fonts/Build.cmd +++ b/Source/Fonts/Build.cmd @@ -8,19 +8,14 @@ set PATH=%TOOLS%\lzsa;%TOOLS%\fonttool;%PATH% echo. echo Preparing compressed font files... -lzsa -f2 -r font8x8u.bin font8x8c.bin || exit /b -lzsa -f2 -r font8x11u.bin font8x11c.bin || exit /b -lzsa -f2 -r font8x16u.bin font8x16c.bin || exit /b -lzsa -f2 -r fontcgau.bin fontcgac.bin || exit /b -lzsa -f2 -r fontvgarcu.bin fontvgarcc.bin || exit /b +for %%f in (font6x8 font8x8 font8x11 font8x16 fontcga fontvgarc) do call :genfont %%f -fonttool font8x8u.bin > font8x8u.asm || exit /b -fonttool font8x11u.bin > font8x11u.asm || exit /b -fonttool font8x16u.bin > font8x16u.asm || exit /b -fonttool font8x8c.bin > font8x8c.asm || exit /b -fonttool font8x11c.bin > font8x11c.asm || exit /b -fonttool font8x16c.bin > font8x16c.asm || exit /b -fonttool fontcgau.bin > fontcgau.asm || exit /b -fonttool fontcgac.bin > fontcgac.asm || exit /b -fonttool fontvgarcu.bin > fontvgarcu.asm || exit /b -fonttool fontvgarcc.bin > fontvgarcc.asm || exit /b +goto :eof + +:genfont +echo Processing font %1... +lzsa -f2 -r %1u.bin %1c.bin || exit /b +fonttool %1u.bin >%1u.asm || exit /b +fonttool %1c.bin >%1c.asm || exit /b + +goto :eof diff --git a/Source/Fonts/Makefile b/Source/Fonts/Makefile index 75b4e705..8ea48a82 100644 --- a/Source/Fonts/Makefile +++ b/Source/Fonts/Makefile @@ -1,8 +1,8 @@ OBJECTS = \ - font8x8u.asm font8x11u.asm font8x16u.asm fontcgau.asm fontvgarcu.asm \ - font8x8c.asm font8x11c.asm font8x16c.asm fontcgac.asm fontvgarcc.asm + font6x8u.asm font8x8u.asm font8x11u.asm font8x16u.asm fontcgau.asm fontvgarcu.asm \ + font6x8c.asm font8x8c.asm font8x11c.asm font8x16c.asm fontcgac.asm fontvgarcc.asm -OTHERS = font8x8c.bin font8x11c.bin font8x16c.bin fontcgac.bin fontvgarcc.bin +OTHERS = font6x8c.bin font8x8c.bin font8x11c.bin font8x16c.bin fontcgac.bin fontvgarcc.bin TOOLS = ../../Tools @@ -14,6 +14,9 @@ include $(TOOLS)/Makefile.inc %.rel: %.asm %.bin: %.asm +font6x8c.bin: font6x8u.bin + $(BINDIR)/lzsa -f2 -r $< $@ + font8x8c.bin: font8x8u.bin $(BINDIR)/lzsa -f2 -r $< $@ diff --git a/Source/Fonts/font6x8.png b/Source/Fonts/font6x8.png new file mode 100644 index 00000000..77bf355f Binary files /dev/null and b/Source/Fonts/font6x8.png differ diff --git a/Source/Fonts/font6x8u.bin b/Source/Fonts/font6x8u.bin new file mode 100644 index 00000000..ea0579d0 Binary files /dev/null and b/Source/Fonts/font6x8u.bin differ diff --git a/Source/Fonts/fonts.txt b/Source/Fonts/fonts.txt index 4c7add63..2b24f378 100644 --- a/Source/Fonts/fonts.txt +++ b/Source/Fonts/fonts.txt @@ -17,16 +17,18 @@ There are multiple fonts associated with ROMWBW supported hardware: MBC-VDP tms.asm 9938/9958 RCBUS-VRC vrc.asm PLD RCBUS-TMS tms.asm 99x8 + XOSERA xosera.asm ? Name Glyph Cell Size Comp Board & Display Mode ------------------------------------------------------------------------------------------------ -font8x8 6x8 8x8 2048 1034 ECB-SCG, ECB-VGA3 (80x60), MBC-VDP +font6x8 6x8 8x8 2048 1094 ECB-SCG, MBC-VDP +font8x8 6x8 8x8 2048 1034 ECB-VGA3 (80x60) font8x11 8x11 8x11 2816 1252 ECB-VGA3 (80x43) font8x16 8x14 8x16 4096 1466 ECB-CVDU (EGA), ECB-VGA3 (80x24, 80x25, 80x30), MBC-VDC (EGA) fontcga 8x8 8x16 4096 1280 ECB-CVDU (CGA), MBC-VDC (CGA) fontvrc 8x8 8x8 1024 650 VGARC ----- ----- - 14080 5682 + 16128 6776 Notes: @@ -36,7 +38,7 @@ Notes: but the font definition must still be 8x16. The CGA font is used for this. For inclusion in HBIOS the .bin format files must be converted to assembler .asm format. -This is acheived using the fonttool utility and is completed automatically as part of the build process. +This is achieved using the fonttool utility and is completed automatically as part of the build process. i.e. fonts files are converted to .asm format and then copied to the HBIOS directory. To replace a font, simply copy it to the Fonts directory using the same naming convention above, diff --git a/Source/HBIOS/Build.cmd b/Source/HBIOS/Build.cmd index 5f86f255..4fba30af 100644 --- a/Source/HBIOS/Build.cmd +++ b/Source/HBIOS/Build.cmd @@ -98,6 +98,8 @@ call :asm game || exit /b call :asm usrrom || exit /b call :asm updater || exit /b +:: call :asm fonts || exit /b + :: Sysconf builds as both BIN and COM files tasm -t%CPUType% -g3 -fFF -dROMWBW sysconf.asm sysconf.bin sysconf_bin.lst || exit /b tasm -t%CPUType% -g3 -fFF -dCPM sysconf.asm sysconf.com sysconf_com.lst || exit /b diff --git a/Source/HBIOS/Makefile b/Source/HBIOS/Makefile index 771732d4..04bf955d 100644 --- a/Source/HBIOS/Makefile +++ b/Source/HBIOS/Makefile @@ -1,6 +1,6 @@ MOREDIFF = game.bin hbios_rom.bin nascom.bin usrrom.bin \ - dbgmon.bin hbios_app.bin imgpad2.bin rom2.bin rom3.bin romldr.bin \ + dbgmon.bin hbios_app.bin rom2.bin rom3.bin romldr.bin \ eastaegg.bin hbios_img.bin rom1.bin game.bin updater.bin usrrom.bin DEST = ../../Binary @@ -24,7 +24,7 @@ endif include $(TOOLS)/Makefile.inc FONTS := font8x11c.asm font8x11u.asm font8x16c.asm font8x16u.asm font8x8c.asm font8x8u.asm \ - fontcgac.asm fontcgau.asm fontvgarcc.asm fontvgarcu.asm + font6x8c.asm font6x8u.asm fontcgac.asm fontcgau.asm fontvgarcc.asm fontvgarcu.asm ifeq ($(CPUFAM),2) TASM=$(BINDIR)/uz80as -t hd64180 @@ -32,7 +32,7 @@ else ifeq ($(CPUFAM),3) TASM=$(BINDIR)/uz80as -t z280 endif -DEPS=prereq dbgmon.bin romldr.bin nascom.bin tastybasic.bin game.bin eastaegg.bin updater.bin sysconf.bin sysconf.com usrrom.bin imgpad2.bin +DEPS=prereq dbgmon.bin romldr.bin nascom.bin tastybasic.bin game.bin eastaegg.bin updater.bin sysconf.bin sysconf.com usrrom.bin ifeq ($(ROM_PLATFORM),UNA) ROMDEPS=romldr.bin dbgmon.bin diff --git a/Source/HBIOS/hbios.asm b/Source/HBIOS/hbios.asm index adf700b2..d5781f95 100644 --- a/Source/HBIOS/hbios.asm +++ b/Source/HBIOS/hbios.asm @@ -1927,7 +1927,7 @@ ROMRESUME: ; ; LAUNCH S100 MONITOR FROM ROM BANK 3 LD A,BID_IMG2 ; S100 MONITOR BANK - LD IX,0 ; EXECUTION RESUMES HERE + LD IX,HWMON_IMGLOC ; EXECUTION RESUMES HERE CALL HBX_BNKCALL ; CONTINUE IN RAM BANK, DO NOT RETURN HALT ; WE SHOULD NOT COME BACK HERE! ; @@ -9506,12 +9506,23 @@ ORG_FONTS .EQU $ ; MEMECHO "FONTS" ; -#IFDEF USEFONT8X8 -FONT8X8: +#IFDEF USEFONT6X8 +FONT6X8: ; -; FOR NOW, WE NEVER COMPRESS THE 8X8 FONT. SEE TMS DRIVER. +; FOR NOW, WE NEVER COMPRESS THE 6X8 FONT. SEE TMS DRIVER. ; #IF USELZSA2 & FALSE + #INCLUDE "font6x8c.asm" + #ELSE + #INCLUDE "font6x8u.asm" + #ENDIF + MEMECHO " 6X8" +#ENDIF +; +#IFDEF USEFONT8X8 +FONT8X8: +; + #IF USELZSA2 #INCLUDE "font8x8c.asm" #ELSE #INCLUDE "font8x8u.asm" diff --git a/Source/HBIOS/imgpad2.asm b/Source/HBIOS/imgpad2.asm deleted file mode 100644 index 43099f3d..00000000 --- a/Source/HBIOS/imgpad2.asm +++ /dev/null @@ -1,10 +0,0 @@ -#INCLUDE "std.asm" -; -SLACK .EQU $8000 - .FILL SLACK,00H -; - .ECHO "Padspace space created: " - .ECHO SLACK - .ECHO " bytes.\n" - - .END \ No newline at end of file diff --git a/Source/HBIOS/layout.inc b/Source/HBIOS/layout.inc index 79fdb6d1..2f7b5250 100644 --- a/Source/HBIOS/layout.inc +++ b/Source/HBIOS/layout.inc @@ -185,9 +185,9 @@ HWMON_IMGLOC .EQU BNK_NXTLOC ; LOCATION OF BINARY LOAD IMAGE IN BANK BNK_NXTLOC .SET HWMON_IMGLOC + HWMON_SIZ ; IMG LOC OF NEXT COMPONENT ; FONTS_BNK .EQU BNK_CUR -;;;FONTS_LOC .EQU $E000 -FONTS_SIZ .EQU $2000 -;;;FONTS_END .EQU FONTS_LOC + FONTS_SIZ +FONTS_LOC .EQU $0000 +FONTS_SIZ .EQU $4000 +FONTS_END .EQU FONTS_LOC + FONTS_SIZ FONTS_IMGLOC .EQU BNK_NXTLOC ; LOCATION OF BINARY LOAD IMAGE IN BANK BNK_NXTLOC .SET FONTS_IMGLOC + FONTS_SIZ ; IMG LOC OF NEXT COMPONENT ; @@ -206,19 +206,19 @@ BNK3_SLACK .EQU BNKTOP - BNK_NXTLOC ; REMAINING BANK SPACE .ECHO "BANK3 BID_IMG2 \t" \ .ECHO BNK3_LEN \ .ECHO "\t" \ .ECHO BNK3_SLACK \ .ECHO "\n" .ECHO "-------------------------------\n" ; - #IF (BNK1_LEN > BNKTOP) +#ENDIF +; +#IF (BNK1_SLACK < 0) .ECHO "*** ROM BANK 1 IS TOO BIG!!!\n" !!! ; FORCE AN ASSEMBLY ERROR IF BANK SIZE EXCEEDS SPACE - #ENDIF +#ENDIF ; - #IF (BNK2_LEN > BNKTOP) +#IF (BNK2_SLACK < 0) .ECHO "*** ROM BANK 2 IS TOO BIG!!!\n" !!! ; FORCE AN ASSEMBLY ERROR IF BANK SIZE EXCEEDS SPACE - #ENDIF +#ENDIF ; - #IF (BNK3_LEN > BNKTOP) +#IF (BNK3_SLACK < 0) .ECHO "*** ROM BANK 3 IS TOO BIG!!!\n" !!! ; FORCE AN ASSEMBLY ERROR IF BANK SIZE EXCEEDS SPACE - #ENDIF -; #ENDIF diff --git a/Source/HBIOS/romldr.asm b/Source/HBIOS/romldr.asm index 12470dbf..b0217222 100644 --- a/Source/HBIOS/romldr.asm +++ b/Source/HBIOS/romldr.asm @@ -1554,7 +1554,7 @@ s100mon1: call ldelay ; wait for UART buf to empty di ; suspend interrupts ld a,HWMON_BNK ; S100 monitor bank - ld ix,0 ; execution resumes here + ld ix,HWMON_IMGLOC ; execution resumes here jp HB_BNKCALL ; do it ; str_smon .db "S100 Z180 Monitor",0 diff --git a/Source/HBIOS/s100mon.z80 b/Source/HBIOS/s100mon.z80 index 49000945..fbcfb5a2 100644 --- a/Source/HBIOS/s100mon.z80 +++ b/Source/HBIOS/s100mon.z80 @@ -432,16 +432,16 @@ CNTLB0_VALUE equ 00H ; For setting final baud rate from ; jp mon_start - DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;To clean up PROM for easy reading - DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - Db 0,0,0,0 +;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;To clean up PROM for easy reading +;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +;;; Db 0,0,0,0 ; Jump to monitor!!! ; diff --git a/Source/HBIOS/std.asm b/Source/HBIOS/std.asm index 274f0199..fe9b96df 100644 --- a/Source/HBIOS/std.asm +++ b/Source/HBIOS/std.asm @@ -549,6 +549,14 @@ V80X43 .EQU 5 ; ECB-VGA3 V80X60 .EQU 6 ; ECB-VGA3 V40X24 .EQU 7 ; EF9345 ; +; FONT IDS +; +FONTID_8X8 .EQU 1 +FONTID_8X11 .EQU 2 +FONTID_8X16 .EQU 3 +FONTID_CGA .EQU 4 +FONTID_VGARC .EQU 5 +; ; KEYBOARD LAYOUTS ; KBD_US .EQU 0 ; US ENGLISH diff --git a/Source/HBIOS/tms.asm b/Source/HBIOS/tms.asm index f2c3bbc7..679bddf1 100644 --- a/Source/HBIOS/tms.asm +++ b/Source/HBIOS/tms.asm @@ -150,8 +150,10 @@ TMS_COLS .EQU 40 DEVECHO "X" DEVECHO TMS_ROWS ; -#DEFINE USEFONT8X8 -#DEFINE TMS_FONT FONT8X8 +;;;#DEFINE USEFONT8X8 +;;;#DEFINE TMS_FONT FONT8X8 +#DEFINE USEFONT6X8 +#DEFINE TMS_FONT FONT6X8 ; TERMENABLE .SET TRUE ; INCLUDE TERMINAL PSEUDODEVICE DRIVER ; diff --git a/Source/Makefile b/Source/Makefile index c6b219b2..4e8c667b 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -23,6 +23,7 @@ shared: $(MAKE) --directory ZCPR $(ACTION) $(MAKE) --directory ZCPR-DJ $(ACTION) $(MAKE) --directory ZSDOS $(ACTION) + $(MAKE) --directory ZSDOS2 $(ACTION) $(MAKE) --directory CPM3 $(ACTION) $(MAKE) --directory ZPM3 $(ACTION) $(MAKE) --directory CPNET $(ACTION) diff --git a/Source/ZSDOS2/Build.cmd b/Source/ZSDOS2/Build.cmd new file mode 100644 index 00000000..6be69ba9 --- /dev/null +++ b/Source/ZSDOS2/Build.cmd @@ -0,0 +1,12 @@ +@echo off +setlocal + +set TOOLS=../../Tools + +set PATH=%TOOLS%\tasm32;%TOOLS%\zxcc;%PATH% + +set TASMTABS=%TOOLS%\tasm32 + +set CPMDIR80=%TOOLS%/cpm/ + +zxcc Z80ASM -ZSDOS2/6FS || exit /b diff --git a/Source/ZSDOS2/Clean.cmd b/Source/ZSDOS2/Clean.cmd new file mode 100644 index 00000000..12d1c7de --- /dev/null +++ b/Source/ZSDOS2/Clean.cmd @@ -0,0 +1,6 @@ +@echo off +setlocal + +if exist *.lst del *.lst +if exist *.rel del *.rel +if exist *.sym del *.sym diff --git a/Source/ZSDOS2/Makefile b/Source/ZSDOS2/Makefile new file mode 100644 index 00000000..4fecd9e8 --- /dev/null +++ b/Source/ZSDOS2/Makefile @@ -0,0 +1,5 @@ +TOOLS = ../../Tools + +OBJECTS = zsdos2.rel + +include $(TOOLS)/Makefile.inc diff --git a/Source/ZSDOS2/zsdos2.z80 b/Source/ZSDOS2/zsdos2.z80 new file mode 100644 index 00000000..c40fbd4a --- /dev/null +++ b/Source/ZSDOS2/zsdos2.z80 @@ -0,0 +1,4116 @@ + TITLE "ZSDOS 2" +;************************************************************************ +;* Z S D O S v2 * +;* A banked CP/M 2.2 compatible replacement BDOS * +;* by Harold F. Bower and Cameron W. Cotrill * +;*----------------------------------------------------------------------* +;* Disassembly: jxl May 2025 * +;* public release 1.0 May 2025 * +;* see remarks at the end * +;*----------------------------------------------------------------------* +;* Assemble with SLR Z80ASM * +;* * +;* A>Z80ASM ZSDOS2/6 * +;************************************************************************ + + + NAME ('DOS') + + +VER EQU 20H +REV MACRO + DEFB '27g' + ENDM + +DATE MACRO + DEFB '1993' + ENDM + + +;::::: DEFINITIONS + + +RAMLOW EQU 0000H ; Start address memory + + ; Bios entry points + + COMMON /_BIOS_/ +BIOS EQU $ + + CSEG + +; BOOT EQU BIOS+0000H ; Cold Boot +; WBOOT EQU BIOS+0003H ; Warm Boot +CONST EQU BIOS+0006H ; Console Status +CONIN EQU BIOS+0009H ; Console Input +CONOUT EQU BIOS+000CH ; Console Output +LIST EQU BIOS+000FH ; List Output +PUNCH EQU BIOS+0012H ; Punch Output +READER EQU BIOS+0015H ; Reader Input +HOME EQU BIOS+0018H ; Home Disk +SELDSK EQU BIOS+001BH ; Select Disk +SETTRK EQU BIOS+001EH ; Select Track +SETSEC EQU BIOS+0021H ; Select Sector +SETDMA EQU BIOS+0024H ; Set DMA Address +READ EQU BIOS+0027H ; Read 128 Bytes +WRITE EQU BIOS+002AH ; Write 128 Bytes +; LISTST EQU BIOS+002DH ; List Status +SECTRN EQU BIOS+0030H ; Sector Translation +MOVE EQU BIOS+004BH ; (Interbank) move +SELMEM EQU BIOS+0051H ; Select memory bank +XMOVE EQU BIOS+0057H ; Set memory banks for MOVE +RETMEM EQU BIOS+0075H ; Return current memory bank + +OTPABK EQU BIOS+082H ; offset TPA bank (from B/P Bios base) +OSYSBK EQU BIOS+083H ; offset SYS bank +OZ3ENV EQU BIOS+098H ; offset Z3ENV + + + ; Control chars + +CONTC EQU 03H ; Key to generate warm boot +CONTH EQU 08H ; Backspace +TAB EQU 09H ; Tab +LF EQU 0AH ; Line feed +CR EQU 0DH ; Carriage return +CONTP EQU 10H ; Set/reset print flag +CONTR EQU 12H ; Retype line +CONTS EQU 13H ; Stop console output +CONTX EQU 18H ; Delete line (backspaces) +CONTU EQU 15H ; Same as Control-X +RUBOUT EQU 7FH ; Delete last char + + + ; Disk related + +MAXEXT EQU 1FH ; Maximum extent number +MAXMOD EQU 3FH ; Maximum data module number +TDCKSM EQU 91H ; Checksum of !!!TIME&.DAT + + + ; Attribute bits + +PUBATT EQU 2 ; Public attribute offset +PSFATT EQU 7 ; Public/system file (internal only) +WHLATT EQU 8 ; Wheel protect attribute offset +ROATT EQU 9 ; Read only attribute offset +SYSATT EQU 10 ; System attribute offset +ARCATT EQU 11 ; Archive attribute offset + + + ; FCB positions + +FCBEXT EQU 12 ; Extent number +FCBUSR EQU 13 ; User valid at offset 13 if set (internal) +FCBMOD EQU 14 ; Data module number - D7 used as unmod flag +FCBREC EQU 15 ; Record number +NXTREC EQU 32 ; Next record number + + + ; Internal + +; ZSDOS 1 = 6D / ZSDOS 2 = ED +FLGBITS EQU 11101101B ; PUBlic On, P/P Write Off, R/O On, + ; Fast Relog On, Disk Chg Warning Off, + ; Path On, No System Path On + ; (Reserved) On + + + + ;_______________________// Non-Banked // + + DEFB 'ZSDOS',VER/16+'0' + + ; ZSDOS entry point + JP ENTRY ; jump to start of program code + + +;::::: DATA / CONFIGURATION AREA + + ; CP/M 2.2 compatible error vector table +STBDSC: DEFW ERROR ; Bad sector message +STSEL: DEFW ERROR ; Select error +STRO: DEFW ERROR ; Drive read only +SFILRO: DEFW ERROR ; File read only + + ; External Path +PATH: DEFW PATHAD ; Path address for file open, 0 if no Path + + ; Wheel Byte pointer +WHEEL: DEFW 0 ; Address of Wheel byte, 0 if none + + ; User configuration byte(s) +FLAGS: DEFB FLGBITS ; Flag byte (see above) +STFLAG: DEFB 0110B ; Stamp enable/disable + ; bit2= Modify, bit1= Create, bit0= Access + + ; Dispatch table for time/date stamp routines +GSTIME: DEFW DOTDER ; Address of get/set time/date routine + DEFW DOTDER +UNLOAD: DEFW 0 ; Pointer to remove time stamp routine +IPATH: DEFW PATHAD ; copy to restore Internal Path (see ZSCFG2) + + ;----- + +TABCNT: DEFB 0 ; tab counter +TABCX1: DEFB 0 ; temporary tab counter (used by RDBUF) +FCONTP: DEFB 0 ; list enable flag (Control-P) - used by BGii +LASTCH: DEFB 0 ; last character - used by BGii +USER: DEFB 0 ; user number - used by BGii +DEFDRV: DEFB 0 ; default drive number - used by BGii and DS +DRIVE: DEFB 0 ; drive number + + ;----- + +FCB0: DEFB 0 ; FCB byte 0 +DMA: DEFW 0080H ; DMA address +TRANS: DEFW 0 ; translation vector +TEMP0: DEFW 0 ; number of files on drive +DIRBUF: DEFW 0 ; directory buffer pointer - used by BGii +IXP: DEFW 0 ; disk parameter block +CSV: DEFW 0 ; check sum pointer +ALV: DEFW 0 ; allocation vector pointer + + ;----- + +MAXSEC: DEFW 0 ; number of sectors/track +NBLOCK: DEFB 0 ; block shift +NMASK: DEFB 0 ; mask number of blocks +NEXTND: DEFB 0 ; extent mask + +MAXLEN: DEFW 0 ; maximum block number-1 +NFILES: DEFW 0 ; maximum number of files-1 +NDIR0: DEFB 0 ; first two entries ALV buffer + DEFB 0 ; ..(NDIR1) +NCHECK: DEFW 0 ; number of checksum entries +NFTRK: DEFW 0 ; first track number + + ;----- + +FUNCT: DEFB 0 ; function code +PEXIT: DEFW 0 ; exit code + + ;----- + +FLDRV: DEFB 0 ; drive select used flag +RDWR: DEFB 0 ; read/write flag +SEARQU: DEFB 0 ; search question mark used +SEARPU: DEFB 0 ; search public file + + ;----- + +RECDIR: DEFW 0 ; record directory (checksum) +FILCNT: DEFW 0 ; file counter +SECPNT: DEFB 0 ; sector pointer +SUBFLG: DEFB 0 ; submit flag (reset disk command) +DCOPY: DEFW 0 ; copy address FCB +SEAREX: DEFB 0 ; exit code search +SEARNB: DEFB 0 ; search number of bytes +ERMODE: DEFB 0 ; BDOS error mode +ARWORD: DEFW 0 ; DE argument on entry - used for BGii +DEVAL: DEFW 0 ; return value for DE reg +SPSAVE: DEFW 0 ; Stack pointer location + + ;----- + +FINITD: DEFB 0 ; INITDR flag preventing code re-execution +TPABNK: DEFB 0 ; TPA bank number + + + DEFB 'ZSDOS ',VER/16+'0','.',VER MOD 16 + '0' + DEFB ' Copyright (c) ' + DATE + DEFB ' by C.W.Cotrill & H.F.Bow' +IXSAVE: DEFB 'er' ; User's IX register + +ZSDOSS: DEFW 0 ; ZSDOS Stack + DEFB 0,0,0,0 ; ..also used as buffer to read/set clock + + ;----- + + ; Time/Date +RWCODE: DEFB 0 ; 0= read stamp, 1= write stamp +STOFF: DEFB 0 ; offset in stamp +STATUS: DEFB 0FFH ; status of first routine for exit checs + + ; Other +FCBADR: DEFW 0 ; address of (target) FCB +FCBBUP: DEFB 0 ; number of FCB bytes to copy/update +ZSFCB: DEFS 36 ; buffer for internal FCB (36 bytes) +ZSSTMP: DEFS 15 ; buffer for Time Stamp (15 bytes) + + + + ;:::::::::::::::::::::::::::::::::::::::: + ;::::: ZSDOS Entry Point + +ENTRY: CALL RETMEM ; B/P Bios fn #39 (A= current memory bank) + LD (TPABNK),A ; save TPA bank number + XOR A ; clear A + LD B,A ; for later 16-bit addr's + LD L,A + LD H,A ; set HL to zero + LD (PEXIT),HL ; clear exit code + LD (FLDRV),HL ; reset drive select and R/W flags + LD (SPSAVE),SP ; save stack pointer + LD SP,ZSDOSS ; get internal stack pointer + PUSH IX ; save index register on our stack + PUSH DE ; save parameter register + POP IX ; get it back in IX + LD (ARWORD),DE ; save in memory for BGii + LD HL,DOSEXIT ; get exit address ZSDOS + PUSH HL ; save it on stack to return from ZSDOS + LD A,C ; get function code (reg B= 0) + LD (FUNCT),A ; save it for later use + CP 12 ; is it a non-disk function ? + JR C,ENTRY0 ; ..if so, jump + CP MAXCMD ; fcn < maximum command number (49) ? + JR C,ENTRY1 ; ..if so, jump + + ; extended function scanner for added functions + CP 98 ; is it less than cmnd 98 ? + RET C ; ..if so, return (fcn not known/valid) + CP 152 ; is it cmnd 152 ? + JP Z,CMD152 ; ..if so, execute it + CP 103+1 ; is it greater than cmnd 103 ? + RET NC ; ..if so, return (fcn not known/valid) + SUB 98-MAXCMD ; rework 98..103 --> 50..55 + LD C,A ; save reworked function number + ; ..and fall through to ENTRY0 + + ; for Non-disk functions (ie. fcn # less than 12), push address of + ; SAVEA routine on Stack (save A reg as return code). Saves code in + ; Console Routines, as a simple RET can be used in most cases. +ENTRY0: LD HL,SAVEA + PUSH HL ; vector return through A reg save +ENTRY1: LD HL,CTABLE ; load table + ADD HL,BC ; add + ADD HL,BC ; add twice to get word value + LD A,(HL) ; get LSB + INC HL ; pointer to MSB + LD H,(HL) ; get MSB + LD L,A ; save LSB in L + + ; copy byte argument into A and C to simplify Function calls + ; allows direct Bios jumps for several fcn's with code savings + LD C,E ; place arg in C for BIOS + LD A,E ; and in A for others + JP (HL) ; jump to routine + + + ;:::::::::::::::::::::::::::::::::::::::: + ;::::: Command Table + +CTABLE: DEFW ERROR5 ; Warm boot (Bios) with ERMODE clear + DEFW CMND01 ; Console input + DEFW WRCON ; Console output + DEFW READER ; Reader input (BIOS) + DEFW PUNCH ; Punch output (BIOS) + DEFW LIST ; List output (BIOS) + DEFW CMND06 ; Direct console I/O + DEFW CMND07 ; Get I/O byte + DEFW CMND08 ; Set I/O byte + DEFW CMND09 ; Print string + DEFW CMND10 ; Read console buffer + DEFW CMND11 ; Get console status + DEFW CMND12 ; Return version number + DEFW CMND13 ; Reset disk system + DEFW CMND14 ; Select disk + DEFW CMND15 ; Open file + DEFW CMND16 ; Close file + DEFW CMND17 ; Search for first + DEFW CMND18 ; Search for next + DEFW CMND19 ; Delete file + DEFW CMND20 ; Read sequential + DEFW CMND21 ; Write sequential + DEFW CMND22 ; Make file + DEFW CMND23 ; Rename file + DEFW CMND24 ; Return login vector + DEFW CMND25 ; Return current disk + DEFW CMND26 ; Set DMA address + DEFW CMND27 ; Get address allocation vector + DEFW CMND28 ; Write protect disk + DEFW CMND29 ; Get R/O vector + DEFW CMND30 ; Set file attributes + DEFW CMND31 ; Get address disk parameter header (DPH) + DEFW CMND32 ; Get/set user code + DEFW CMND33 ; Read random + DEFW CMND34 ; Write random + DEFW CMND35 ; Compute file size + DEFW CMND36 ; Set random record + DEFW CMND37 ; Reset multiple drive + DEFW DUMMY ; Function 38 (unused) + DEFW CMND39 ; Return fixed disk login vector + DEFW CMND40 ; Write random with zero fill + DEFW DUMMY ; Function 41 (unused) + DEFW DUMMY ; Function 42 (unused) + DEFW DUMMY ; Function 43 (unused) + DEFW DUMMY ; Function 44 (unused) + DEFW CMND45 ; Set Error Mode + DEFW CMND46 ; Return Disk Free Space + DEFW CMND47 ; Return DMA + DEFW CMND48 ; Return DOS version + DEFW CMND49 ; Return Environment Descriptor Address +MAXCMD EQU ($-CTABLE)/2 + DEFW CMD98 ; Get Time + DEFW CMD99 ; Set Time + DEFW CMD100 ; Get Flags + DEFW CMD101 ; Set Flags + DEFW CMD102 ; Get Stamp + DEFW CMD103 ; Put Stamp + + + ;:::::::::::::::::::::::::::::::::::::::: + ;::::: I/O Routines + + ;-------------------------------------------------- + ; fn #1 CONIN + ; enter: none, exit: A= char + ;-------------------------------------------------- + ; read char fron Console + ; and echo if char = CR, LF, TAB, CONTH or >=Space +CMND01: CALL GETCH ; get character (and test it) + RET C ; ..if less than Space, exit +PUTCH: PUSH HL ; save regs for other calls + CALL WRCON ; echo character + POP HL + RET + + + ;-------------------------------------------------- + ; fn # 6 Direct Console I/O + ; enter: E= 0FFH (In), exit: A= Input Character + ; 0FEH (In) Console Status + ; 0FDH (In) Input Character + ; 00H..0FCH (Out) 00H + ;-------------------------------------------------- + ; enhanced to CP/M 3 spec + ; checks ZSDOS typeahead for reliable Console I/O under all + ; conditions as per a suggestion by Bridger Mitchell +CMND06: INC E ; test if get char is available + JR Z,DCIO1 ; ..if yes, do input + INC E ; test for 0xFE + JR Z,DCIO2 ; ..if so, get status + INC E ; test for 0xFD + JR Z,GETCH ; ..if so, wait for input char + JP CONOUT ; else, print char (Bios Console Output) +DCIO2: LD A,(LASTCH) ; check for buffered char + OR A + LD A,00000001B ; preset ready + CALL Z,CONST ; call Bios Console Status + AND A ; test it + RET ; and return to caller +DCIO1: CALL DCIO2 ; get console status + RET Z ; ..if no character present, exit + ; else, fall through + + ; get char from Console +GETCH: LD HL,LASTCH ; check ZSDOS type ahead for char + LD A,(HL) + LD (HL),0 ; reset last character + OR A ; set flags + CALL Z,CONIN ; call Bios Console Input + ; get char and fall through to test it + + ; test char + ; out: Carry= 0 for CR, LF, TAB, CONTH, or >=Space + ; Carry= 1 for all other characters + CP CR ; is it a Carriage Return ? + RET Z ; ..if so, return + CP LF ; Line Feed ? + RET Z ; ..return + CP TAB ; Tab ? + RET Z ; ..return + CP CONTH ; Backspace ? + RET Z ; ..return + CP ' ' ; test >= Space + RET ; ..and return to caller + + + ;-------------------------------------------------- + ; fn # 8 Set I/O Byte + ; enter: E= I/O Byte, exit: A= 00H + ;-------------------------------------------------- +CMND08: LD (RAMLOW+0003H),A ; save it in RAM and fall through + + + ;-------------------------------------------------- + ; fn # 7 Get I/O Byte + ; enter: None, exit: A= I/O Byte (0003H) + ;-------------------------------------------------- +CMND07: LD A,(RAMLOW+0003H) ; get I/O byte from RAM + RET + + + ;-------------------------------------------------- + ; fn # 10 Read Console Buffer + ; enter: DE= address Buffer, exit: A= 00H + ;-------------------------------------------------- +CMND10: LD A,(TABCNT) + LD (TABCX1),A ; save start Tab position + INC DE + XOR A + LD (DE),A ; set char count to zero + INC DE ; point to actual buffer start +RDBUF1: PUSH DE ; save buffer pointer + CALL GETCH ; get next byte from user + POP DE + LD HL,RDBUF1 + PUSH HL ; return address to stack + LD HL,(ARWORD) + LD C,(HL) ; put buffer length in C + INC HL ; and point to current length + CP CR + JR Z,JZRBX ; ..if CR, then exit + CP LF +JZRBX: JP Z,RDBUFX ; ..or if LF, then exit + + ; delete char from buffer + ; (Rubout, Backspace, CR, LF are _never_ in the buffer) +RDBUF2: CP RUBOUT ; delete char ? + JR Z,DOBACK ; ..if so, jump + CP CONTH ; Control-H also deletes + JR NZ,RDBUF3 ; ..if no delete, skip to next test +DOBACK: LD A,(HL) + AND A ; test if attempting to del from empty line + RET Z ; ..if so, then exit +DOBAK0: DEC DE ; back up to last character + DEC (HL) ; erase from buffer + PUSH DE ; save buffer pointer + LD B,(HL) ; get new char count + INC HL ; point to first char + EX DE,HL + LD HL,TABCNT + LD C,(HL) ; save current Tab count + INC HL + LD A,(HL) ; get starting Tab position + DEC HL + LD (HL),A ; init the counter + INC B ; insure non-zero + JR DOBAK2 ; jump to done test +DOBAK1: LD A,(DE) ; get char from buffer + CALL WRCON2 ; counts chars + INC DE +DOBAK2: DJNZ DOBAK1 ; continue count until done + LD A,C ; get prior Tab count + SUB (HL) ; get diff between new and old + LD B,A ; set up as count + LD (HL),C ; restore prior count + POP DE ; restore pointer + + ; delete B chars from Console + PUSH DE ; save pointer +DOBAK5: LD C,CONTH + PUSH BC ; save counter from destruction + CALL CONOUT ; call Bios Console Output + LD C,' ' + CALL CONOUT ; output Backspace, Space to CON: only + LD A,CONTH + CALL WRCON ; now Backspace CON:, counter, and printer + POP BC ; restore counter + DJNZ DOBAK5 ; loop until all done + POP DE ; restore pointer + RET + + ; erase buffer +RDBUF3: CP CONTU ; test erase line + JR Z,ERALIN ; ..if so, do it + CP CONTX + JR NZ,RDBUF4 ; skip to next test if no erase line +ERALIN: XOR A + OR (HL) ; line empty ? + RET Z ; ..if so, exit + PUSH HL + CALL DOBAK0 ; else, delete another (skip empty check) + POP HL + JR ERALIN ; if Ctrl-R=True, do following code + ; else bypass + +RDBUF4: CP CONTR ; if Ctrl-R type clean buffer version on CON: + JR NZ,RDBUF5 + PUSH HL ; save pointer to buffer length + CALL CROUT ; do CR/LF + LD HL,TABCNT + LD (HL),0 ; init Tab count + INC HL + LD B,(HL) ; and get Tab offset count + LD A,' ' + INC B ; insure nz value + JR RETY1A ; so case of lh side of screen ok +RETYP1: CALL WRCON ; space off start of line +RETY1A: DJNZ RETYP1 + POP HL ; point to buffer length + LD B,(HL) ; get how many chars to print + INC HL ; restore buffer pointer + EX DE,HL ; put buffer pointer in DE + INC B ; comp for first djnz + JR RETYP3 ; skip to done test +RETYP2: LD A,(DE) ; get char from buffer + CALL WRCTL ; output it + INC DE ; bump pointer +RETYP3: DJNZ RETYP2 ; loop until done + RET + + ; toggle line printer echo +RDBUF5: CP CONTP ; toggle printer ? + JR NZ,RDBUF6 ; ..if not, next test + LD HL,FCONTP + LD A,(HL) ; get printer echo flag + CPL ; toggle it + LD (HL),A ; put back + RET + + ; check if Ctrl-C is first char in BUFF, exit if so +RDBUF6: LD (DE),A ; put character in buffer + PUSH HL + CALL WRCTL ; echo the character + POP HL + INC (HL) ; increment the character count + LD A,(HL) ; get current length + CP C ; test against buffer size + JR Z,RDBUFX + DEC A ; set Z flag for first character + LD A,(DE) ; get the character back + INC DE ; and bump the pointer + RET NZ ; ..if not the first character, return + CP CONTC ; possible user abort ? + RET NZ ; ..if not, return + JP ERROR5 ; else, jump to error reset exit + + ; done with Read Console Buffer function +RDBUFX: POP HL ; clear RDBUF1 return address + LD A,CR + JR WRCON ; ..and echo a CR + + ; print Control char as '^X' +WRCTL: CP ' ' ; test if Control char + JR NC,WRCON ; ..if not, send it out + CP TAB ; test if Tab + JR Z,WRCON0 ; ..if it is, then expand with spaces + PUSH AF ; save char + LD A,'^' ; output a caret + CALL WRCON1 ; no need for Tab test here + POP AF + ADD A,40H ; convert to printable + ; ..and fall through to WRCON + + + ;-------------------------------------------------- + ; fn #2 CONOUT + ; enter: E= char, exit: none (A= Bios reg A) + ;-------------------------------------------------- + ; output char with list echo, Tab expansion +WRCON: CP TAB ; is it a Tab ? + JR NZ,WRCON1 ; ..if not, jump +WRCON0: LD A,' ' ; expand Tab with spaces + CALL WRCON1 ; write space + LD A,(TABCNT) ; get Tab count + AND 7 ; test if done + JR NZ,WRCON0 ; ..if not, then repeat + LD A,TAB ; return Tab + RET ; return to caller +WRCON1: PUSH BC ; save pointers + PUSH DE + LD C,A ; save character + PUSH BC + +BGPTCH0 EQU $+1 ; <--- BGii patches this addr + + CALL CMND11 ; test status and CONTS/CONTC + POP BC ; get character back + PUSH BC ; save it again + CALL CONOUT ; call Bios Console Output + POP BC ; get character back + PUSH BC ; save it again + LD A,(FCONTP) ; get printer echo flag + OR A ; test it + CALL NZ,LIST ; ..if non-zero, output char to printer + POP BC ; restore character + LD A,C ; fall through to count routine + POP DE ; restore pointers + POP BC + + ; count characters in line as shown by f10 + LD HL,TABCNT ; get pointer to Tab counter +WRCON2: INC (HL) ; increment Tab counter + CP RUBOUT ; test if character = Rubout + JR Z,WRCON3 ; ..if so, treat like Backspace + CP ' ' + RET NC ; ok if not Control char + CP TAB ; only DOBACK ever gets Tabs through here + JR Z,WRCON4 ; ..if Tab, handle differently + CP CONTH + JR Z,WRCON3 ; ..or Backspace + INC (HL) ; must have been echoed as two chars + CP LF + JR Z,WRCON3 ; unless it's LF + CP CR ; ..or CR + RET NZ + LD (HL),2 ; reset Tab counter +WRCON3: DEC (HL) ; decrement Tab counter + DEC (HL) + RET ; and exit + +WRCON4: LD A,7 ; bumped by one already + ADD A,(HL) ; Tabs are every 8 spaces + AND 0F8H ; ..MOD 8 + LD (HL),A ; save updated Tab count + RET ; ..and continue + + + ;-------------------------------------------------- + ; fn # 11 Get Console Status + ; enter: None, exit: A= 00H No character + ; 01H Char. present + ;-------------------------------------------------- + ; BGii uses this routine +BGCONST: +CMND11: CALL DCIO2 ; get character present status + RET Z ; ..if none, then exit + CALL GETCH ; get next console char + CP CONTS ; is it stop char ? + JR NZ,GCONS2 ; ..if not, jump + CALL CONIN ; call Bios Console Input to get next char + CP CONTC ; does the user want to exit (Ctrl-C) ? + JR NZ,CMND11 ; ..if not, check for another character + JP ERROR5 ; else, jump to warm boot and clear ERMODE +GCONS2: LD (LASTCH),A ; save character + LD A,1 ; character present code + RET ; return to caller + + ; echo CR,LF +CROUT: LD DE,MCRLF ; fall through to output routine + + + ;-------------------------------------------------- + ; fn # 9 Print String + ; enter: DE= address String, exit: None (A= '$') + ;-------------------------------------------------- +CMND09: LD A,(DE) ; get byte from buffer + CP '$' ; test, last byte ? + RET Z ; ..if yes, then return to caller + INC DE ; else, point to next byte + CALL WRCON ; ..and output character + JR CMND09 ; loop, test again + + + ;:::::::::::::::::::::::::::::::::::::::: + ;::::: Error Routines + +PRDEC: LD BC,100 + CALL NUM + LD C,10 + CALL NUM + LD BC,0101H + + ; display number +NUM: LD D,-1 ; load number -1 +NUM1: INC D ; increment number + SUB C ; divide by C + JR NC,NUM1 ; ..if not finished, then loop + ADD A,C ; restore last value + PUSH AF ; save it + LD A,D ; test if '0' + OR B ; and if leading zero + JR Z,NUM2 ; ..if yes, then exit + LD B,A ; set no leading zero + LD A,D ; get number + ADD A,'0' ; make ascii + CALL PUTCH ; echo number preserving BC +NUM2: POP AF ; restore number + RET ; and exit + + +;::::: ERROR MESSAGES + +MDSKCH: DEFB 'Changed$' +MBADSC: DEFB 'Bad Sector$' +MSEL: DEFB 'No Drive$' +MFILRO: DEFB 'File ' +MRO: DEFB 'W/P$' +MBERR: DEFB 'ZSDOS Error on $' +MBFUNC: DEFB CR,LF,'Call' +MDRIVE: DEFB ': $' +MFILE: DEFB ' File: $' +MCRLF: DEFB CR,LF,'$' + + + ; new ZDSOS error handler + ; in: B= error code + ; DE= message pointer +ERROR: LD A,(ERMODE) + LD C,A ; save error mode + RRCA ; test suppress print + JR C,ERROR3 ; ..if suppressed, then skip to display + + ; print ZSDOS Error on X: explanation + PUSH BC + PUSH DE ; save params + CALL CROUT ; output CR,LF + LD DE,MBERR + CALL CMND09 ; output 'ZSDOS Error on' + LD A,(DEFDRV) ; get current default drive + ADD A,'A' ; convert to ascii + CALL WRCON ; output to Console + LD DE,MDRIVE ; point to Drive tag + CALL CMND09 ; ouput also + POP DE ; restore error message pointer + CALL CMND09 ; send message + + ; now print CALL: XXX [FILE: XXXXXXXX.XXX] + LD DE,MBFUNC + CALL CMND09 ; display 'Call: ' + LD A,(FUNCT) ; get function number + CALL PRDEC ; output it + LD A,(FLDRV) + AND A ; was FCB used ? + JR Z,ERROR2 ; ..if not, skip file name display + POP BC ; get error type + PUSH BC + PUSH IX ; save FCB pointer + LD A,(FUNCT) ; are we erasing a file ? + CP 19 ; ..if so, get name from DIRBUF + JR NZ,ERROR0 ; ..ambiguous name may have been used + CALL CALDIR ; get Dir buffer pointer + EX (SP),HL ; to show that we are really gagged on +ERROR0: LD DE,MFILE + CALL CMND09 ; output 'File: ' + POP HL ; point to FCB + LD B,11 ; output this many chars +ERROR1: INC HL + LD A,3 + CP B ; time to send '.' ? + LD A,46 ; get ready for it + CALL Z,PUTCH ; ..and send it if time + LD A,(HL) ; get char + AND 7FH ; mask attributes + CALL PUTCH ; output it + DJNZ ERROR1 + +ERROR2: CALL CROUT ; send CR,LF + POP BC ; get error mode back +ERROR3: LD A,4 + SUB B ; test if select error + JR NZ,ERROR4 ; ..if not, skip + LD HL,DRIVE ; point to old default + LD A,(HL) ; get it + DEC HL ; point to bad drive + CP (HL) ; same ? + JR Z,ERROR4 ; ..if so, skip relog + PUSH BC + CALL SELSYB ; switch System bank + CALL SELDK ; get Bios back in step + POP BC +ERROR4: BIT 1,C ; test if return error mode + JR NZ,ERROR7 ; ..if return error, go + LD A,1 + SUB B ; test if fatal error + JR NC,ERROR6 ; ..if not a fatal error, jump + ; else, fall through + + + ;-------------------------------------------------- + ; fn # 0 Boot + ; enter: None, exit: None + ;-------------------------------------------------- +ERROR5: XOR A ; clear A + LD (ERMODE),A ; set DOS error mode to default CP/M + LD A,(OTPABK) ; store TPABNK = 0 (at B/P Bios base +0x82) + CALL SELMEM ; ..and also set it, BIOS fn #27 SELMEM (A= bank #) + RST 0 ; ..and leave + +ERROR6: CALL DCIO1 ; get console char if present + AND A ; test if any + JR NZ,ERROR6 ; keep getting them until typeahead eaten + CALL GETCH ; now get operator's response + CP CONTC ; test if abort + RET NZ ; ..if operator said ignore error + JR ERROR5 ; else, boot + +ERROR7: LD A,B ; get error + LD H,A ; save code in H reg for return + AND A ; test if disk changed warning + RET Z ; ..if so, continue relog + LD L,0FFH ; set extended error code + LD (PEXIT),HL ; save as return code + ; ..and fall through to DOS exit + + + ;:::::::::::::::::::::::::::::::::::::::: + ;::::: DOS Exit Routine + +DOSEXIT: LD A,(FLDRV) ; test Drive select used flag + OR A + JR Z,DOSEXT0 ; ..if no, then exit + LD A,(FCB0) ; get FCB byte 0 + LD (IX+0),A ; save it + CALL SELTPB ; select TPA bank + LD HL,ZSFCB ; buffer internal FCB + LD DE,(FCBADR) + LD A,(FCBBUP) ; get number of bytes to copy + OR A ; test if empty + JR Z,DOSEXT1 ; ..if zero, skip + LD C,A ; else, set byte counter (16-bit) + LD B,0 + LDIR ; and copy +DOSEXT1: LD A,(DRIVE) ; get old Drive number + CALL SELSYB ; switch System bank + CALL SELDK ; select disk + + + ; Stack is in an undefined condition at this point, if error handler + ; was invoked. Independent of Stack position, the user's IX register + ; has to be restored. (Thanks to Joe Wright for catching this one!) +DOSEXT0: CALL SELTPB ; select TPA bank + LD SP,(SPSAVE) ; restore user stack + LD IX,(IXSAVE) ; restore IX + LD HL,(PEXIT) ; get exit code + LD DE,(DEVAL) ; and DE reg for DateStamper + LD A,L ; copy function code + LD B,H + RET ; and return to caller + + + ;:::::::::::::::::::::::::::::::::::::::: + ;::::: Disk Routines + + ;-------------------------------------------------- + ; fn # 13 Reset Disk System + ; enter: None, exit: A= 00H No $*.* on A + ; FFH $*.* on A + ;-------------------------------------------------- +CMND13: CALL SELSYB ; switch System bank + JP CMD13B ; and continue in Banked code + + + + ;_______________________// Banked // + COMMON /BANK2/ + + ;-------------------------------------------------- + ; Reset Disk System + ; (continue CMND13) + ;-------------------------------------------------- +CMD13B: LD HL,RAMLOW+80H ; set up default DMA address + LD (DMA),HL ; and save it + CALL STDMA ; do Bios call + XOR A ; set default drive = 'A' + LD (DEFDRV),A ; save it + LD DE,0FFFFH ; reset all drives + ; ..and fall through to CMD37B + + + + ;_______________________// Non-Banked // + CSEG + + ;-------------------------------------------------- + ; fn # 37 Reset Mult Drive + ; enter: DE= Bit Mask, exit: A= 00H + ;-------------------------------------------------- + ; fixed disk login vector is also altered by this call +CMND37: CALL SELSYB ; switch System bank + JP CMD37B ; and continue in Banked code + + + + ;_______________________// Banked // + COMMON /BANK2/ + + ;-------------------------------------------------- + ; Reset Multiple Login Drive + ; (continue CMND37) + ;-------------------------------------------------- + ; fixed disk login vector is also altered by this call +CMD37B: CALL UNLOG ; clear selected Drives in DE from login + LD A,(FLAGS) + BIT 2,A ; test hard R/O enabled + JR NZ,UNWPT1 ; ..if enabled, jump + LD HL,DSKWP ; get Drive W/P vector + CALL ANDDEM ; reset W/P stat only of requested Drives +UNWPT1: LD A,(FUNCT) + CP 13 ; skip hard disk login change ? + LD HL,HDLOG + CALL NZ,ANDDEM ; clear HD login vector if fcn 37 +RELOG1: LD HL,(HDLOG) + CALL HLORDE ; don't clear fixed disks from T/D + EX DE,HL ; place modified logout in DE + LD HL,TDFVCT + CALL ANDDEM ; clear T/D vector as needed + LD A,(DEFDRV) ; get default drive + CALL SELDK + + + ; check for possible existance of submit file + + ; ZSDOS watches for any $*.* file in any User on any Drive during + ; re-log, make, and delete. In this manner, SUBFLG will always be + ; valid - even under Fast Relog and NZCOM. (Thanks to Joe Wright + ; for suggesting the need for this, and suggesting ways to do it.) +SUBEXT: LD A,(SUBFLG) ; get submit flag + JP SAVEA ; exit + + + ; check first byte of Dir entry or FCB for '$' + ; in: HL= pointer to Dir or FCB +CKSUB: INC HL ; point to file name + LD A,(HL) ; get first char file name + DEC HL + SUB '$' ; test if '$' + RET NZ ; ..if not, then exit + DEC A ; load with 0xFF + LD (SUBFLG),A ; save it in subflg + RET + + ; unlog Drive mask in DE +UNLOG: LD A,E ; get LSB + CPL ; complement it + LD E,A + LD A,D ; get MSB + CPL ; complement it + LD D,A ; DE = not reset + LD HL,LOGIN ; get address of login vector +ANDDEM: LD A,E ; clear login bits of reset drives + AND (HL) ; ..a byte at a time + LD (HL),A ; put to memory + INC HL + LD A,D + AND (HL) + LD (HL),A + RET + + + + ;_______________________// Non-Banked // + CSEG + + ;-------------------------------------------------- + ; fn # 17 Search for First Entry of File + ; enter: DE= Address of FCB, exit: A= Directory Code + ;-------------------------------------------------- +CMND17: CALL SELDRV ; select drive from FCB + LD A,(IX+0) + SUB '?' ; test if '?' + JR Z,CMD17B ; ..if so, all entries match + LD A,(IX+FCBMOD) ; get system byte + CP '?' ; test if '?' + JR Z,CMD17A ; ..if yes, jump + LD (IX+FCBMOD),0 ; load system byte with zero +CMD17A: LD A,15 ; test first 15 items in FCB +CMD17B: CALL SEARCH ; do search +CMD17C: CALL SELTPB ; select TPA bank + LD HL,(DIRBUF) ; copy Directory buffer + LD BC,128 ; Directory = 128 bytes + LD DE,(DMA) ; to DMA address + LDIR + RET ; exit + + + ;-------------------------------------------------- + ; fn # 18 Search for Next Occurrence of File + ; enter: DE= Address of FCB, exit: A= Directory Code + ;-------------------------------------------------- +CMND18: LD IX,(DCOPY) ; get last FCB used by search + LD (ARWORD),IX ; save FCB pointer for BGii + CALL SELDRV ; select drive from FCB + CALL SEARCN ; search next file match + XOR A ; clear A (zero) + LD (FCBBUP),A ; ..save as num of bytes to update in FCB + JR CMD17C ; and copy Directory to DMA address + + + ;-------------------------------------------------- + ; fn # 19 Delete File + ; enter: DE= Address of FCB, exit: A= Error Code + ;-------------------------------------------------- +CMND19: CALL SELDRV ; select drive from FCB + ; (also switches System bank) + CALL DELETE ; ..and continue in Banked code + +CMND19A: LD A,(SEAREX) ; get exit byte 00= file found, 0FFH= not + JR SAVEA ; and exit + + + ;-------------------------------------------------- + ; fn # 23 Rename File + ; enter: DE= Address of FCB, exit: A= Error Code + ;-------------------------------------------------- +CMND23: CALL SELDRV ; select drive from FCB + CALL RENAM ; rename file + JR CMND19A ; and exit + + + ;-------------------------------------------------- + ; fn # 25 Get Current Disk + ; enter: None, exit: A= Current Disk + ;-------------------------------------------------- +CMND25: LD A,(DEFDRV) ; get current drive +SAVEA: LD (PEXIT),A ; return character +DUMMY: RET ; ..and exit ZSDOS + + + ;-------------------------------------------------- + ; fn # 101 Set Flags + ; enter: DE=Flags, exit: None + ;-------------------------------------------------- +CMD101: LD (FLAGS),A ; set ZSDOS flags + ; ..and fall through + + + ;-------------------------------------------------- + ; fn # 100 Get flags + ; enter: None, exit: HL= Flags + ;-------------------------------------------------- +CMD100: LD A,(FLAGS) ; get ZSDOS flags + JR SAVEA ; ..and exit + + + ;-------------------------------------------------- + ; fn # 30 Set File Attributes + ; enter: DE= Address of FCB, exit: A= Error Code + ;-------------------------------------------------- +CMND30: CALL SELDRV ; select drive from FCB + CALL CSTAT ; change status bits of file + JR CMND19A ; and exit + + + ;-------------------------------------------------- + ; fn # 12 Get Version Number + ; enter: None, exit: A= Version Number (22H, CP/M compatible) + ;-------------------------------------------------- +ZDPCH1: +CMND12: LD HL,22H ; set CP/M compatible version number + LD A,E + CP 'D' ; is caller testing for DateStamper ? + JR NZ,CMD12A ; ..if not, jump exit + LD H,E ; otherwise return DS Active flag + LD DE,CMD98A ; have a clock, so get clock address +CMD12A: LD (DEVAL),DE ; in case DS gave us a clock address + JR SAVHL ; for speed + + + ; The following code section may seem a bit obscure. When the Z80 jumps + ; in at a label, it executes the LD HL instruction. The DEFB 0DDH turns + ; the LD HL instructions that follow into LD IX. In effect, this turns + ; the DEFB 0DDH into a one byte relative jump to SAVHL. As IX is never + ; used by these calls, its loss is of no consequence. + ; A similar trick is used in SEAR15. + + + ;-------------------------------------------------- + ; fn # 48 Get DOS and Version + ; enter: None, exit: H= DOS type: 'S'=ZSDOS, 'D'=ZDDOS + ; L= BCD Version Number + ;-------------------------------------------------- +CMND48: LD HL,'S' SHL 8 + VER ; 'S' indicates ZSDOS, ZRDOS returns 0 + DEFB 0DDH ; trash IX and fall through + + + ;-------------------------------------------------- + ; fn # 29 Get R/O Vector + ; enter: None, exit: HL= R/O Vector + ;-------------------------------------------------- +CMND29: LD HL,(DSKWP) ; get disk W/P vector + DEFB 0DDH ; trash IX and fall through + + + ;-------------------------------------------------- + ; fn # 39 Get Fixed Disk Vector + ; enter: None, exit: HL= Fixed Disk Vector + ;-------------------------------------------------- +CMND39: LD HL,(HDLOG) ; return fixed disk login vector + DEFB 0DDH ; trash IX and fall through + + + ;-------------------------------------------------- + ; fn # 27 Get Alloc. Address (ALV) + ; enter: None, exit: HL= Address of Allocation Vector + ;-------------------------------------------------- +CMND27: LD HL,(ALV) ; get allocation vector + DEFB 0DDH ; trash IX and fall through + + + ;-------------------------------------------------- + ; fn # 49 Return ENV Address + ; enter: None, exit: HL= Address Env. Descriptor + ;-------------------------------------------------- +CMND49: LD HL,(OZ3ENV) ; get Z3ENV address (Bios base +0x98) + DEFB 0DDH ; trash IX and fall through + + + ;-------------------------------------------------- + ; fn # 24 Get Login Vector + ; enter: None, exit: HL= Login Vector + ;-------------------------------------------------- +CMND24: LD HL,(LOGIN) ; get login vector + DEFB 0DDH ; trash IX and fall through + + + ;-------------------------------------------------- + ; fn # 31 Get DPB Address + ; enter: None, exit: HL= Address of DPB + ;-------------------------------------------------- +CMND31: LD HL,(IXP) ; get drive table + DEFB 0DDH ; trash IX and fall through + + + ;-------------------------------------------------- + ; fn # 47 Get DMA address + ; enter: None, exit : HL= Current DMA Address + ;-------------------------------------------------- +CMND47: LD HL,(DMA) ; get current DMA address + LD A,H ; test if valid (<> zero) + OR L +SAVHL: LD (PEXIT),HL ; save it + RET ; and exit + + + ;-------------------------------------------------- + ; fn # 45 Set error mode + ; enter: E= FFH (Get), exit: A=0 0H + ; FEH (Get Err/Disp) + ; 01H (Set ZSDOS) + ; 00H (Set CP/M) + ;-------------------------------------------------- + ; ##### implementation does not comply with documentation +CMND45: LD (ERMODE),A + RET + + + ;-------------------------------------------------- + ; fn # 32 Set/Get User Code + ; enter: E= FFH (Get), exit: A= User Number + ; User Number (Set) 00H + ;-------------------------------------------------- +CMND32: LD HL,USER ; point to User byte location + INC A ; test if 0xFF + LD A,(HL) ; get old user code + JR Z,SAVEA ; ..if 0xFF, then exit + LD A,E ; get new User code + AND 1FH ; mask it + LD (HL),A ; save it + RET ; and exit + + + ;-------------------------------------------------- + ; fn # 35 Compute File Size + ; enter: DE= Address of FCB, exit: A= Error Code + ;-------------------------------------------------- +CMND35: CALL SELDR1 ; select drive from FCB + LD A,36 ; 36 bytes + LD (FCBBUP),A ; ..to update in FCB + CALL FILSZ ; compute file size + JR CMND19A ; and exit + + + ;-------------------------------------------------- + ; fn # 36 Set Random Record + ; enter: DE= Address of FCB, exit: A= 00H + ;-------------------------------------------------- +CMND36: LD HL,32 ; set pointer to next record + CALL CALRRC ; calculate random record count +LDRRC: LD (IX+33),D ; and save it + LD (IX+34),C + LD (IX+35),B + RET ; ..exit + + + ; ##### CHECK: unreferenced code + PUSH IX + CALL SELDRV + JP NOTUSE2 + ; ##### + + + ;----- + ; Select Disk From FCB +BGSELDRV: +SELDRV: LD A,(ERMODE) ; are we in modified User mode ? + AND A + JR NZ,SELDR1 ; ..if so, jump + LD HL,(ARWORD) + LD BC,FCBUSR ; else, point to User number + ADD HL,BC + LD (HL),A ; clear User flag +SELDR1: LD A,0FFH ; set disk select done flag + LD (FLDRV),A + LD HL,(ARWORD) ; get argument of fcn call (DE= FCB address) + LD (FCBADR),HL ; ..and save it + LD DE,ZSFCB ; set to internal FCB + PUSH DE + POP IX ; ..copy to IX + LD (ARWORD),DE ; ..and save + LD BC,36 ; byte count + LDIR ; ..and copy + LD A,16 ; 16 bytes + LD (FCBBUP),A ; save # bytes to update in FCB + LD A,(DEFDRV) ; get current drive + LD E,A ; save it in register E + LD HL,(ARWORD) + LD A,(HL) ; get drive from FCB + LD (FCB0),A ; save it + CP '?' ; test if '?' + JR Z,CMND14 ; ..if yes, then select drive from reg E + PUSH IX ; save BGii's IX register + + ; IX won't be altered on cmnd14 + LD IX,(ARWORD) ; get FCB pointer + AND 1FH ; mask drive + PUSH HL + JR Z,SELDR0 ; select drive from register E + LD E,(HL) ; get drive from FCB + DEC E ; decrement drive number, so A= 0 +SELDR0: CALL CMND14 ; do select of drive + POP HL ; restore FCB pointer + + ; resolve User for FCB + ; in: IX= FCB ptr + ; out: A= User + LD A,(IX+FCBUSR) ; ..get potential User in case + BIT 7,A ; is this a valid User ? + JR NZ,RESUS1 ; ..if there is, then skip + LD A,(USER) ; get User number + JR RESUS1 ; ..and bypass push IX + + ; set User in FCB to value passed in A +RESUSR: PUSH IX +RESUS1: LD IX,(ARWORD) + AND 1FH ; user number in A + LD (IX+0),A ; save in FCB 0 byte + OR 80H ; set valid DOS user flag + LD (IX+FCBUSR),A ; ..and in FCB 13 byte + POP IX ; restore caller's IX + RET + + + + ;_______________________// Banked // + COMMON /BANK2/ + + ; select disk error exit + ; Stack is off by one level here, but there is a one way trip around +SELDK3: LD HL,(STSEL) ; load error message address + LD B,4 ; select error + LD DE,MSEL ; load select error message + JP JUMPHL ; Select Disk from E register + + + + ;_______________________// Non-Banked // + CSEG + + ;-------------------------------------------------- + ; fn # 14 Select Disk + ; enter: E= Disk Number, exit: A= 00H No $*.* File + ; FFH $*.* File + ;-------------------------------------------------- +CMND14: LD A,(DEFDRV) ; get current drive + LD (DRIVE),A ; save it in memory + CALL SELSYB ; switch System bank + JP CMD14B ; ..and continue in Banked code + + + + ;_______________________// Banked // + COMMON /BANK2/ + + ;-------------------------------------------------- + ; Select Disk + ; (continue CMND14) + ;-------------------------------------------------- +CMD14B: LD A,E ; copy Drive number + + ; call w/ A= drive no. (0..15 = A..P) +SELDK: LD HL,(LOGIN) ; get login vector + AND 0FH ; mask Drive number + LD B,A ; save counter + CALL NZ,SHRHLB +SELDK0: EX DE,HL ; put Drive bit mask in DE + LD HL,DEFDRV ; get pointer last drive + BIT 0,E ; test if Drive logged in + JR Z,SELDK2 ; ..if not, log it in + CP (HL) ; test same Drive ? + RET Z ; ..if yes, then exit + + ; NOTE: + ; A long standing DOS bug concerns the SELECT function. If fcn 14 is + ; called and the drive doesn't exist, the default will still point + ; to the bad drive unless we fix it in the error routine. + ; It is for this reason that drive is saved above. We must allow + ; default to assume the illegal drive value long enough for the + ; error handler to print ot, then re-select the old default. +SELDK2: LD (HL),A ; save new current Drive + PUSH DE ; save Drive logged in flag + LD C,A ; copy Drive number + LD B,A + CALL DRVOK ; test if Drive is valid (Z3ENV Drive vector) + JR NC,SELDK3 ; ..if not, exit + CALL SELDSK ; do Bios call Select Disk + LD A,H ; test if error + OR L + JR Z,SELDK3 ; ..if yes, illegal Drive number + LD DE,TRANS ; point to local translation storage + LD BC,2 ; ..and move 2-byte ptr in + LDIR + LD (TEMP0),HL ; save address in temp0 + LD C,6 ; advance to Dirbuf part of DPH + ADD HL,BC ; as TEMP1 and TEMP2 unused in P?DOS + LD DE,DIRBUF ; load Dirbuf pointer + LD C,8 ; copy 8 bytes + LDIR + LD HL,(IXP) ; get Drive parameter address + LD C,15 ; copy 15 bytes + LDIR + POP DE ; get Drive logged in flag + BIT 0,E ; test it + RET NZ ; Drive logged in, so return + CALL GETCDM + EX DE,HL ; Drive mask in DE + LD HL,(LOGIN) ; get login vector + CALL HLORDE ; set Drive bit in login vector + LD (LOGIN),HL ; save login vector + LD A,(FLAGS) ; get flags + BIT 3,A ; fast relog enabled ? + JR Z,INITDR ; if disabled, skip + + + ; The following code checks the WACD size to determine if the drive + ; being selected is a fixed disk. If WACD is 0, the disk is non- + ; removable. However, BIOS may support remapping of logical drives. + ; Therefore BDOS must catch the swap and clear the Hard Disk ALV and + ; allow the allocation bitmaps to be rebuilt. Hence, every disk + ; that is being selected for the first time traverses this code. + ; If a disk was logged as a fixed disk and all of the sudden has a + ; WACD buffer, the Fixed Disk Login Vector is cleared. + ; For bug-free operation of Fast Fixed Disk Logging, if drives are + ; swapped, NEVER SWAP TWO FIXED DRIVES! + + LD HL,(NCHECK) ; is this a fixed Drive ? + LD A,H + OR L + LD C,A ; save fixed disk flag (Z= true) + LD HL,(HDLOG) + LD A,E ; see if logged as fixed disk + AND L + LD L,A + LD A,D + AND H ; MSB + OR L ; Z flag set if HL and DE = 0 + LD A,0FFH ; don't alter flags + JR Z,SELDK4 ; ..if not logged as fixed disk, skip over + INC A ; else, flag as logged +SELDK4: LD B,A ; save logged as fixed disk flag (Z= true) + OR C ; test if still fixed disk + RET Z ; skip re-map if logged and not swapped + XOR A + LD H,A + LD L,A ; null vector + OR B ; was it logged as fixed disk ? + JR Z,SELDK5 ; invalidate HDLOG vector + ; (drive no longer considered fixed disk) + LD A,C + OR A ; wasn't fixed disk before - is it now ? + JR NZ,INITDR ; ..if it isn't, skip vector update + LD HL,(HDLOG) + CALL HLORDE ; else, add this drive to fixed disk vector +SELDK5: LD (HDLOG),HL ; update fixed disk vector + ; ..and fall through to INITDR + + + ; init drive + ; clear ALV bit buffer after Drive reset +INITDR: LD HL,(MAXLEN) ; get length ALV buffer-1 (bits) + CALL SHRHL3 ; divide by 8 to get bytes + LD B,H + LD C,L ; counter to BC (will be count+1 cleared) + LD HL,(ALV) ; get pointer ALV buffer + PUSH HL + LD D,H + LD E,L + INC DE ; ALV buffer +1 in DE + XOR A + LD (HL),A ; clear first 8 bits + LDIR ; and remainder of buffer + POP HL ; get ALV pointer + LD DE,(NDIR0) ; get first two bytes ALV buffer + LD (HL),E ; save LSB + INC HL ; increment pointer + LD (HL),D ; save MSB + LD HL,(TEMP0) ; clear number of files on this Drive + LD (HL),A ; clear LSB (A still has 0) + INC HL ; increment pointer + LD (HL),A ; clear MSB + LD A,0FFH ; set initial value for flag + LD (FINITD),A + +ZDPCH2 EQU $ ; <--- Intercept first scan (ZDS Patch) + + CALL SETFCT ; set file count +INITD2: LD A,0FFH ; update Directory checksum + CALL RDDIR ; read FCB's from Directory + CALL TSTFCT ; test last FCB + JP Z,SUBEXT ; return subflg for strict CP/M compat + CALL CALDIR ; calculate entry point FCB + LD A,(HL) ; get first byte FCB + CP 0E5H ; test empty Directory entry + JR Z,INITD2 ; ..if yes, then get next FCB + AND 7FH ; mask + CP 21H ; test time stamp + JR Z,INITD2 ; ..if yes, then get next FCB + + + ; check if FCB belongs to !!!TIME&.DAT file + LD A,(FINITD) ; get first loop flag + OR A ; test if zero + JR Z,INITD5 ; ..if yes, then jump + ; to prevent re-execution of following code + INC A ; ..else, increment + LD (FINITD),A ; and save flag again + LD BC,00C00H ; set counter B=12, and clear C + PUSH HL +INITD3: LD A,(HL) ; get byte from FCB + AND 7FH ; mask high bit + ADD A,C ; add in previous result + LD C,A ; ..and save it in C + INC HL ; move ptr forward + DJNZ INITD3 ; loop till done + CP TDCKSM ; test if matches checksum of !!!TIME&.DAT + JR NZ,INITD4 ; ..if not, skip over + LD HL,(TDFVCT) ; else, get T/D vector + CALL SDRVB ; set drive bit in HL + LD (TDFVCT),HL ; and save T/D vector again +INITD4: POP HL + +ZDPCH3 EQU $ ; <--- Test for T&D if first time (ZDS Patch) + +INITD5: CALL CKSUB ; test for submit file + LD C,1 ; set bit in ALV buffer + CALL FILLBB ; set bits from FCB in ALV buffer + CALL TSTLF ; test for last file + CALL NC,SETLF0 ; ..and update the last file count if so + JR INITD2 ; get next FCB + + + + ;_______________________// Non-Banked // + CSEG + + ;----- + ; return mask for current Drive in HL +GETCDM: LD HL,0 ; no drives to Or + + ; set Drive bit in HL +SDRVB: EX DE,HL ; copy HL=>DE + LD HL,1 ; get mask drive 'A' + LD A,(DEFDRV) ; get current drive + OR A ; test if drive 'A' + JR Z,HLORDE ; ..if yes, then done +SDRVB0: ADD HL,HL ; get next mask + DEC A ; decrement drive number + JR NZ,SDRVB0 ; ..and test if done +HLORDE: LD A,D ; HL= HL or DE + OR H + LD H,A + LD A,E + OR L + LD L,A + RET ; exit + + +SHRHL3: LD B,3 ; ZSDOS v1 comment: "used in a few places" + ; ##### used exactly once - make INITDR inline + + ;----- + ; shift HL right logical B bits +SHRHLB: SRL H + RR L ; Shift HL right one bit (divide by 2) + DJNZ SHRHLB + RET + + + + ;_______________________// Banked // + COMMON /BANK2/ + + ;----- + ; calculate Sector/Track directory +STDIR: LD HL,(FILCNT) ; get FCB counter Directory + SRL H ; divide by 4 + RR L + SRL H + RR L + LD (RECDIR),HL ; save value (used by checksum) +STDIR2: EX DE,HL ; move to DE +STDIR1: LD HL,0 ; clear HL + + + ; calculate Sector/Track + ; Track= HL,DE / MAXSEC, Sector= HL,DE MOD MAXSEC + ; in: HL, DE= sector number (128 byte sector) +CALST: LD BC,(MAXSEC) ; get sectors/track + LD A,17 ; set up loop counter +CALST0: OR A + SBC HL,BC ; HL > BC ? + CCF + JR C,CALST1 ; ..if yes, then jump + ADD HL,BC ; else, restore HL + OR A ; clear Carry +CALST1: RL E ; shift result in DE + RL D + DEC A ; test last bit done + JR Z,CALST2 ; ..if yes, then exit + ADC HL,HL ; else, shift next bit in HL + JR CALST0 ; continue + +CALST2: PUSH HL ; save sector number + LD HL,(NFTRK) ; get first track + ADD HL,DE ; add track number + LD B,H ; copy it to BC + LD C,L + CALL SETTRK ; Bios call Set Track + POP BC ; restore sector number + LD DE,(TRANS) ; get translation table address + CALL SECTRN ; Bios call Sector Translation + LD B,H ; copy result in BC + LD C,L + JP SETSEC ; Bios call Set Sector + + + ; get Disk map block number from FCB + ; out: HL= FCB address + ; DE= DM + ; BC= offset in DM + ; Zero Flag set (Z) if DM= 0, else reset (NZ) + ; (squeezed by Joe Wright) +GETDM: LD L,(IX+NXTREC) ; get record number in L + RL L ; shift it left once + LD A,(NEXTND) ; get EXM + AND (IX+FCBEXT) ; And the extent number + LD H,A ; to H + LD A,(NBLOCK) ; get BSH + LD B,A ; to B + INC B ; +1 + CALL SHRHLB ; shift HL right B times + LD D,B ; zero to D + LD A,L ; result in A + +GETDM4: LD HL,(ARWORD) + LD C,16 ; add offset 16 to point to DM + ADD HL,BC + LD C,A ; add entry FCB + ADD HL,BC + LD A,(MAXLEN+1) ; test 8 bits/16 bits FCB entry + OR A + LD E,(HL) ; get 8 bit value + JR Z,GETDMX ; ..if 8-bit entries, exit + + ADD HL,BC ; add twice (16-bit values) + LD E,(HL) ; get LSB + INC HL ; increment pointer + LD D,(HL) ; get MSB + DEC HL ; decrement pointer +GETDMX: LD A,D ; check for zero DM value + OR E + RET ; and exit + + + ; calculate Sector number + ; in: DE= block number from FCB +CALSEC: LD HL,0 ; clear MSB sector number + LD A,(NBLOCK) ; get loop counter + LD B,A ; save it in B + EX DE,HL +CALSC0: ADD HL,HL ; shift L,D,E + RL E + DJNZ CALSC0 ; B times + EX DE,HL + LD A,(NMASK) ; get sector mask + AND (IX+NXTREC) ; And with next record + OR E ; set up LSB sector number + LD E,A + RET ; and exit + + + + ;_______________________// Non-Banked // + CSEG + + ;----- + ; check file Read-Only status, then fall through to CALDIR +CKRODI: CALL CHKFRO ; abort if the file is R/O + ; ..fall through + + + ;----- + ; calculate DIRBUF entry point +CALDIR: LD A,(SECPNT) ; get sector pointer +CALDIR1: LD HL,(DIRBUF) ; get start address dirbuf +CALDI0: ADD A,L ; add L=L+A + LD L,A + RET NC ; ..if no Carry, then exit + INC H ; increment H + RET ; and exit + + + ;----- + ; init file count +SETFCT: LD HL,-1 ; set up file count + LD (FILCNT),HL ; save it + RET ; and exit + + + ;-------------------------------------------------- + ; fn # 28 Write Protect Disk + ; enter: None, exit: A= 00H + ;-------------------------------------------------- +CMND28: LD HL,(DSKWP) ; get disk W/P vector + CALL SDRVB ; include drive bit + LD (DSKWP),HL ; save disk W/P vector + LD DE,(NFILES) ; get max number of files-1 (bumped below) + LD HL,(TEMP0) ; get pointer to disk parameter block + INC HL ; correct pointer + + ; setlf0 relocated inline here +SETLF0: INC DE ; increment last file + LD (HL),D ; save it in TEMP0 + DEC HL + LD (HL),E + RET ; and exit + + + + ;_______________________// Banked // + COMMON /BANK2/ + + ;----- + ; search using first 15 bytes of FCB, test if found +SRCT15: CALL SEAR15 ; search on 15-bytes.. + ; ..fall through to test presence + + + ;----- + ; test file count +TSTFCT: LD HL,(FILCNT) ; test file count= 0xFFFF + LD A,H ; get MSB + AND L ; And LSB + INC A ; test if result= 0xFF + RET ; and exit + + + ;----- + ; test last file +TSTLF: LD HL,(TEMP0) ; get pointer to last file + LD DE,(FILCNT) ; get file counter + LD A,E ; subtract DE-(HL) + SUB (HL) + INC HL + LD A,D + SBC A,(HL) + RET ; and exit + + + ;----- + ; get next FCB from Drive + ; in: A= 0 check checksum, A= 0FFH update checksum +RDDIR: LD C,A ; save checksum flag + LD HL,(FILCNT) ; get file counter + INC HL ; increment it + LD (FILCNT),HL ; and save it + LD DE,(NFILES) ; get maximum number of files + LD A,E ; is this the last file ? + SUB L + LD A,D + SBC A,H + JP C,SETFCT ; ..if so, set file count to 0xFFFF + LD A,L ; get file count LSB + RRCA ; *32 + RRCA + RRCA + AND 60H ; mask it + LD (SECPNT),A ; save it for later use + RET NZ ; ..if not first FCB sector, return + PUSH BC ; save checksum flag + CALL STDIR ; calculate sector/track Directory +RDDIR2: CALL DMADIR ; set up DMA Directory + CALL READR ; read a record + CALL STDMA ; ..and set up user's DMA + POP BC ; check/update checksum Directory + + ; C= 0 check checksum, C= 0FFH update checksum +CHKDIR: LD HL,(NCHECK) ; get number of checked records + LD DE,(RECDIR) ; get current record + XOR A ; clear Carry + SBC HL,DE ; test current record + RET Z ; ..if zero, exit + RET C ; ..if greater than NCHECK, exit + CALL CKS127 ; checksum first 127 bytes + ADD A,(HL) ; ..then 128th byte + LD HL,(CSV) ; get pointer checksum directory + ADD HL,DE ; add current record + INC C ; test checksum flag + JR NZ,CHKDR1 ; 0xFF -> update checksum + LD (HL),A ; update checksum + RET ; and exit + +CHKDR1: CP (HL) ; test checksum + RET Z ; ..if ok, exit + + ; checksum differs, so Disk has changed - relog and continue + LD A,(FLAGS) + BIT 4,A ; inform user ? + LD B,0 ; disk change error code + LD DE,MDSKCH ; disk changed message + CALL NZ,ERROR ; inform user + + ; relog current Drive after media change detected + CALL GETCDM ; get current Drive mask in HL + EX DE,HL ; transfer mask to DE + CALL UNLOG ; reset login vector for logged Drive + CALL RELOG1 ; do the meat of relogging + + ; Caveat emptor: this call is recursive.. + CALL SETFCT ; re-initialize search file count + XOR A ; we only get here by checking + JR RDDIR ; ..and all checking is done in RDDIR + + + ;----- + ; read sector from Drive +READR: CALL READ ; Bios call Read Sector + JR WRITE0 + + + ;----- + ; write sector on Drive +WRITER: CALL WRITE ; Bios call Write Sector +WRITE0: OR A ; test exit code + RET Z ; ..if ok, exit + LD B,1 ; disk I/O error code + LD DE,MBADSC ; load bad sector message + LD HL,(STBDSC) ; load bad sector vector + JP JUMPHL ; output error + + + + ;_______________________// Non-Banked // + CSEG + + ; ##### CHECK: unreferenced code + PUSH IX + CALL CMND16 + ; ##### + + + ; JP target of unreferenced code between CMND36 and SELDRV +NOTUSE2: LD HL,(FCBADR) + LD (ARWORD),HL + ; JP target of unreferenced code between CMND34 and CMND21 +NOTUSE3: POP IX + JP SELTPB ; select TPA bank + + + ;-------------------------------------------------- + ; fn # 16 Close File + ; enter: DE= Address of FCB, exit: A= Directory Code + ;-------------------------------------------------- + +BGPTCH2 EQU $+1 ; <--- BGii patch point + +CMND16: CALL SELDR1 ; select Drive from FCB + ; (also switches System bank) + JP CLOSE ; ..and continue in Banked code + + + + ;_______________________// Banked // + COMMON /BANK2/ + + ;-------------------------------------------------- + ; Close File + ; (continue CMND16) + ;-------------------------------------------------- +CLOSE: BIT 7,(IX+FCBMOD) ; test FCB/file modified + RET NZ ; ..if not, no close required + CALL CHKRO ; test disk W/P + CALL SRCT15 ; search file and test present + RET Z ; ..if not, then exit with error + CALL CKRODI ; check file W/P, get Directory entry + LD BC,16 ; offset to DM block + ADD HL,BC ; add offset + EX DE,HL ; save DIR ptr in DE + LD HL,(ARWORD) ; get FCB ptr + ADD HL,BC ; add offset + EX DE,HL + LD B,C ; transfer counter + + ; copy FCB (DE) to DIR (HL), if and only if DIR= 0 or DIR= FCB +CLOSE0: INC (HL) + DEC (HL) ; test DIR for 0 + LD A,(DE) ; get byte from FCB + JR Z,CLOSE1 ; ..if 0, ok to copy + CP (HL) ; test if same as DIR + JP NZ,RETCFF ; ..if not, abort close and return error +CLOSE1: LD (HL),A ; else save in DIR + INC DE + INC HL + DJNZ CLOSE0 ; bump pointers and loop until done + + LD DE,-20 ; add -20 to get extent number from DIR + ADD HL,DE ; HL= pointer to extent number + LD A,(IX+FCBEXT) ; get extent number FCB + CP (HL) ; compare with extent number Directory + JR C,CLOSE3 ; ..if FCB < Directory, then jump + LD (HL),A ; save extent number in Directory + INC HL ; get pointer to next record + INC HL + INC HL + LD A,(IX+FCBREC) ; get next record FCB + LD (HL),A ; save next record in Directory +CLOSE3: CALL CLOSE6 ; clear Archive bit and write FCB + CALL GETDME ; get data module and extent + JR Z,CLOSE4 + PUSH BC ; save prior module and extent + LD BC,0 + CALL SETDME ; set FCB data module and extent to 0 + CALL SRCT15 ; find proper DIR entry + POP BC + JR Z,JSETDME ; ..if extent 0 not found, exit +CLOSE4: PUSH BC + CALL CLOSE6 ; clear Archive bit and write FCB + LD B,4 ; mask for STFLAG (bit2 = Modify stamp) + LD HL,STUP ; address of stamp update routine + CALL STPMSK ; mask stamp type and update if enabled + POP BC ; get original module and extent bak +JSETDME: JP SETDME ; restore to FCB and exit + +CLOSE6: CALL CALDIR ; get directory entry + LD BC,11 ; point to Archive byte + ADD HL,BC + RES 7,(HL) ; reset Archive bit + RES 7,(IX+ARCATT) ; reset bit in FCB + + ; write FCB to disk +WRFCB: CALL CALDIR ; point to Dir entry to write + LD A,FCBUSR ; offset to User byte in FCB + CALL CALDI0 ; ..do the add here + LD (HL),0 ; prevent writing it to disk + CALL STDIR ; calculate setor/track Directory + LD C,0FFH ; update checksum Directory + CALL CHKDIR +WRITD1: CALL DMADIR ; set up DMA Directory (label for DS) + LD C,1 ; write Directory flag + CALL WRITER ; write record + JP STDMA ; set up DMA user + + + + ;_______________________// Non-Banked // + CSEG + + ;-------------------------------------------------- + ; fn # 26 Set DMA Address + ; enter: DE= DMA Address, exit: A= 00H + ;-------------------------------------------------- +CMND26: LD (DMA),DE ; save DMA address + + ; set DMA address +STDMA: LD BC,(DMA) ; get DMA address + JR DMADR0 ; ..and do Bios call + + ; set DMA address Directory +DMADIR: LD BC,(DIRBUF) ; get DMA address Directory +DMADR0: JP SETDMA ; Bios call Set DMA + + + + ;_______________________// Banked // + COMMON /BANK2/ + + ;----- + ; get bit from ALV buffer + ; in: DE= block number + ; out: A= bit in LSB + ; B= bit number in A + ; HL= pointer in ALV buffer +GETBIT: LD A,E ; get bit number + AND 7 ; mask it + INC A ; +1 + LD C,A ; save it + SRL D ; get byte number + RR E ; divide DE by 8 + SRL D + RR E + SRL D + RR E + LD HL,(ALV) ; get start address ALV buffer + LD B,A ; save bit number for next shift + ADD HL,DE ; add byte number + LD A,(HL) ; get 8 bits +GETBT0: RLCA ; get correct bit + DJNZ GETBT0 + LD B,C ; restore bit number + RET ; and return to caller + + + ;-------------------------------------------------- + ; Delete File + ; (continue CMND19) + ;-------------------------------------------------- +DELETE: CALL COMCOD ; call common code w/ VDEL on stack + + ; delete core routine +VDEL: CALL CKRODI ; check file W/P, get Directory entry + LD (HL),0E5H ; remove file + INC HL + LD A,(HL) ; get first char + SUB '$' ; see if submit file + JR NZ,VDEL1 ; ..if not, skip over + LD (SUBFLG),A ; clear subflag if $*.* erased +VDEL1: INC HL + RES 7,(HL) ; ensure erased files are not public + LD C,0 ; remove bits ALV buffer + ; ..fall through and return to caller + + + ; fill bit buffer from FCB in DIRBUF + ; in: C= 0 reset bit, C= 1 set bit +FILLBB: CALL CALDIR ; get directory entry + LD DE,16 ; get offset DM block + ADD HL,DE ; add offset + LD B,E ; get block counter +FILLB0: LD E,(HL) ; get LSB block number + INC HL ; increment pointer + LD D,0 ; reset MSB block counter + LD A,(MAXLEN+1) ; test >256 blocks present + OR A + JR Z,FILLB1 ; ..if not, jump + DEC B ; decrement block counter + LD D,(HL) ; get correct MSB + INC HL ; increment block counter +FILLB1: LD A,D ; test block number + OR E + JR Z,FILLB2 ; ..if zero, then get next block + PUSH HL ; save pointer + PUSH BC ; save counter and set/reset bit + LD HL,(MAXLEN) ; get maximum length ALV buffer + OR A ; reset Carry + SBC HL,DE ; test DE <= maxlen ALV buffer + JR C,FILLB3 ; ..if yes, skip insert bit + + ; set/reset bit in ALV buffer +SETBIT: PUSH BC ; save set/reset bit + CALL GETBIT ; get bit + AND 0FEH ; mask it + POP DE ; get set/reset bit + OR E ; set/reset bit +SETBT0: RRCA ; rotate bit in correct position + DJNZ SETBT0 + LD (HL),A ; save 8 bits +FILLB3: POP BC ; get counter and set/reset bit + POP HL ; get pointer +FILLB2: DJNZ FILLB0 ; repeat for all DM entries + RET ; and return to caller + + + + ;_______________________// Non-Banked // + CSEG + + ;----- + ; check file W/P bit - SEARCH called first +CHKFRO: CALL CALDIR ; get Directory entry + LD DE,WHLATT ; offset to R/O bit + ADD HL,DE ; add offset + LD DE,(WHEEL) ; get Wheel byte address + LD A,(DE) ; retrieve the actual byte + AND A ; ..and check it + JR NZ,CHKFR4 ; we have Wheel, so allow writes + BIT 7,(HL) ; else, check Wheel attribute + JR NZ,CHKFR2 ; ..if yes, then jump error +CHKFR4: INC HL ; check W/P bit + BIT 7,(HL) ; test file W/P + JR NZ,CHKFR2 ; ..if W/P, then jump +CHKFR3: BIT 7,(IX+PSFATT) ; was file accessed as Pubic or Path ? + RET Z ; ..if normal access, return + LD A,(FLAGS) ; else, test for writes allowed + AND 0010B + RET NZ ; ..if writes allowed, go ahead +CHKFR2: LD HL,(SFILRO) ; ptr file W/P message (CP/M 2.2 vector table) + LD B,3 ; file W/P error code + LD DE,MFILRO ; load file W/P message + JP JUMPHL ; display message + + + ;----- + ; check Drive Write Protect +BGCKDRO: +CHKRO: CALL CHKRO1 ; is the disk W/P ? + RET NZ ; ..if disk is R/W, then return + LD B,2 ; else, set disk W/P error code + LD DE,MRO ; load drive W/P message + LD HL,(STRO) ; ptr Drive W/P message (CP/M 2.2 vector table) + JP JUMPHL ; display message + +CHKRO1: LD HL,(DSKWP) ; get W/P drive vector + CALL SDRVB ; set the bit for this drive + SBC HL,DE ; see if extra bit added (Carry is clear) + RET + + + + ;_______________________// Banked // + COMMON /BANK2/ + + ;----- + ; search using first 12 bytes of FCB +SEAR12: LD A,12 + DEFB 21H ; trash HL and fall through + + ; search using first 15 bytes of FCB +SEAR15: LD A,15 + + ; search for File Name + ; in: A= number of bytes for which to search +SEARCH: LD (SEARNB),A ; save number of bytes + LD A,0FFH ; set exit code to 0xFF (not found) + LD (SEAREX),A + LD (DCOPY),IX ; copy FCB pointer to RAM (search next) + CALL SETFCT ; initiate file counter + + ; force directory read with call home (Floppy only) + LD HL,(NCHECK) ; is this a fixed media ? + LD A,H + OR L + CALL NZ,HOME ; if removable, invoke Bios call Home routine + + ; search next File Name +SEARCN: XOR A ; checksum Directory + LD H,A + LD L,A + LD (SEARQU),HL ; clear flags, question mark and PUBlic found + RES 7,(IX+PSFATT) ; reset PUBlic/SYStem file flag + CALL RDDIR ; get FCB from Directory + CALL TSTFCT ; test if past last entry + JR Z,JSEAR8 ; ..if yes, jump (note Carry always clear) + LD DE,(DCOPY) ; get FCB pointer + LD A,(DE) ; get first byte + CP 0E5H ; test if searching empty Directory + JR Z,SEARC1 ; ..if yes, then jump + PUSH DE ; save FCB pointer + CALL TSTLF ; test last file on this Drive + POP DE ; restore FCB pointer +JSEAR8: JR NC,SEARC8 ; ..if yes, then jump + +SEARC1: CALL CALDIR ; get entry in Directory + LD A,(HL) ; get first byte Directory entry + AND 7FH ; mask high bit + CP 21H ; test time stamp + JR Z,SEARCN ; ..if yes, then get next Directory entry + LD C,0 ; clear counter + LD A,(SEARNB) ; get number of bytes to search for + LD B,A ; save it in counter +SEARC2: LD A,B ; test if character is zero + OR A + JR Z,SEARC9 ; ..if yes, then jump + LD A,(DE) ; get byte from FCB + XOR '?' ; test if question mark + AND 7FH ; mask it + JR Z,SEARC6 ; ..if yes, then jump + LD A,C ; get FCB counter + OR A ; test first byte + JR NZ,SEARC3 ; ..if not, then jump + LD A,(FLAGS) ; get flag byte + RRA ; test PUBlic file enable + JR NC,SEARC3 ; ..if not, jump + INC HL ; get pointer to PUBlic bit + INC HL + BIT 7,(HL) ; test PUBlic bit Directory + DEC HL ; restore pointer + DEC HL + JR Z,SEARC3 ; ..if no PUBlic file, then jump + LD A,(DE) ; get first byte FCB + CP 0E5H ; test if searching empty Directory + JR Z,SEARC3 ; ..if yes, then jump + + + ; The following 3 lines of code represent a deviation from description + ; of PUBlic files as given in DDJ article by Bridger Mitchell and Derek + ; McKay of Plu*Perfect Systems. The specification states that PUBlic + ; files will _NOT_ be found by any wildcard reference, except when a + ; '?' is in the FCB+0 byte. The code here relaxes that as follows: + ; If we are in the same User area as the PUBlic file, then don't report + ; file as PUBlic, but find it. This has a nasty side effect - PUBlic + ; files can be erased if we are in the same area. However, these files + ; also show up on the directory (they wouldn't otherwise), so at least + ; we should know we're blasting them. + + XOR (HL) ; test FCB = Directory entry + AND 7FH ; mask it (setting Zero flag) + JR Z,SEARC5 ; ..if user is same, jump + + LD A,0FFH + LD (SEARPU),A ; set PUBlic file found + SET 7,(IX+PSFATT) ; set PUBlic/SYStem file flag + JR SEARC5 ; jump found + +SEARC3: LD A,C ; get FCB counter + CP 13 ; is it User code ? + JR Z,SEARC5 ; ..if so, jump (don't test) + CP 12 ; is it an extent number ? + LD A,(DE) ; get byte from FCB + JR Z,SEARC7 ; ..if extent number, then jump + XOR (HL) ; is FCB byte = Directory Entry byte ? + AND 7FH ; mask it +SEARC4: JR NZ,SEARCN ; ..if not the same, jump and get next entry +SEARC5: INC DE ; increment FCB pointer + INC HL ; increment Directory Entry pointer + INC C ; increment counter + DEC B ; decrement counter + JR SEARC2 ; test next byte + +SEARC6: DEC A ; set question mark found flag + LD (SEARQU),A + JR SEARC5 ; jump found + +SEARC7: XOR (HL) ; test extent + CALL SEARC7A ; mask extent + JR SEARC4 ; ..and test result + +SEARC7A: PUSH BC + LD B,A ; save extent + LD A,(NEXTND) ; get extent mask + CPL ; complement it + AND MAXEXT ; mask it + AND B ; mask extent + POP BC ; restore counters + RET + +SEARC8: CALL SETFCT ; error set file counter + JP RETCFF ; set return code to 0xFF and exit + +SEARC9: LD HL,(SEARQU) ; get question mark and PUBlic found flags + LD A,H + AND L + JR NZ,SEARC4 ; ..if yes, then search for next entry + CALL TSTLF ; test for last file + CALL NC,SETLF0 ; and update if so + LD HL,(RECDIR) ; set DE return to Directory record + LD (DEVAL),HL ; ..for DateStamper simulation + LD A,(FILCNT) ; get file counter + AND 3 ; mask it + LD (PEXIT),A ; and set exit code + XOR A ; clear exit code search + LD (SEAREX),A + RET ; and return to caller + + + ;----- + ; common code of DELETE, RENAME, and CSTAT + ; (coded in a manner that is compatible with Z280 in protected mode) +COMCOD: CALL CHKRO ; check disk W/P + CALL SEAR12 ; search file +COMCO1: CALL TSTFCT ; test if file found + POP HL ; routine addr to HL (in case not found) + RET Z ; ..if not, then exit + PUSH HL ; else, found so routine back to stack + PUSH HL ; ..twice as RET pops first push + LD HL,COMCO2 + EX (SP),HL ; COMCO2 to stack, routine addr to HL + JP (HL) ; ..branch to routine + +COMCO2: CALL WRFCB ; write Directory buffer on disk + CALL SEARCN ; search next entry + JR COMCO1 ; and test it + + + ;----- + ; Rename File + ; note wildcard support +RENAM: CALL COMCOD ; go to common code w/ VRENAM on stack + + ; rename core routine +VRENAM: CALL CHKFRO ; check file W/P + LD HL,(ARWORD) ; get FCB address + LD DE,16 ; offset to new name + ADD HL,DE ; add offset + EX DE,HL ; swap regs + CALL CALDIR ; get Directory entry + INC HL + INC HL + RES 7,(HL) ; make any renamed file private + DEC HL + DEC HL + LD B,11 ; set up loop counter + +RENAM1: INC HL ; increment Directory pointer + INC DE ; increment FCB pointer + LD A,(DE) ; get character from FCB + AND 7FH ; mask it + CP '?' ; test if question mark + JR NZ,RENAM2 ; ..if not, then change character on disk + LD A,(HL) ; else, no change, so get what's there +RENAM2: RLA ; clear MSB + RL (HL) ; get MSB from directory + RRA ; and move to FCB + LD (HL),A ; save in directory + DJNZ RENAM1 ; loop until done + RET + + + ;----- + ; Change Status Bits for File +CSTAT: CALL COMCOD ; got to common code w/ VCSTAT on stack + + ; change core routine +VCSTAT: PUSH IX + POP DE ; FCB pointer in DE + CALL CALDIR ; get Directory entry + LD B,11 ; set up loop counter + +CSTAT1: INC HL ; increment Directory pointer + INC DE ; increment FCB pointer + LD A,4 ; are we pointing to Wheel Attribute ? + CP B + JR NZ,CSTAT2 ; ..if not, jump + PUSH HL + LD HL,(WHEEL) ; else, do we have Wheel privileges ? + LD A,(HL) + POP HL + AND A ; set flags to show + JR NZ,CSTAT2 ; ..if we have Wheel, jump + BIT 7,(HL) ; is file Wheel protected ? + JP NZ,CHKFR2 ; ..if so, jump +CSTAT2: LD A,(DE) ; get status bit from FCB + RL (HL) ; remove MSB of Directory + RLA ; get MSB from FCB + RR (HL) ; and move into Directory char + DJNZ CSTAT1 ; loop till done + RET + + + ;----- + ; Compute File Size +FILSZ: LD BC,0 ; reset file size length + LD D,C + CALL LDRRC ; save it in FCB+33,34,35 + CALL SEAR12 ; search file +FILSZ0: CALL TSTFCT ; test if file found + RET Z ; ..if not, exit + + CALL CALDIR ; get Directory entry + EX DE,HL ; copy to DE + LD HL,15 ; offset to next record + CALL CALRRC ; calculate random record count + LD A,D ; test LSB < (IX+33) + SUB (IX+33) + LD A,C ; test ISB < (IX+34) + SBC A,(IX+34) + LD A,B ; test MSB < (IX+35) + SBC A,(IX+35) + CALL NC,LDRRC ; write new maximum + CALL SEARCN ; search next file + JR FILSZ0 ; and test it + + + ;-------------------------------------------------- + ; Find File + ; (called by CMND15) + ;-------------------------------------------------- +FINDF: CALL SRCT15 ; search file + RET NZ ; ..if found, then exit + LD A,(FLAGS) + BIT 5,A ; test if Path enabled + RET Z ; ..if not, exit + LD HL,(PATH) ; get Path address + LD A,H ; test if zero (no Path) + OR L + RET Z ; ..if so, exit + +FINDF0: CALL DUPATH ; test if current DU: is in Path + JP Z,SEARC8 ; ..if not, then jump + LD A,B ; Drive in A + PUSH BC ; save DU + PUSH HL + CALL SELDK + ; ##### PUSH HL first, then BC + ; saves POP HL + next PUSH HL (2 bytes) + POP HL + POP BC + LD A,C ; User in A + PUSH HL ; save Path pointer + CALL RESUSR ; add new User number in FCB+0 and FCB+13 + CALL SRCT15 ; search file and test if present + POP HL ; restore Path pointer + JR Z,FINDF0 ; ..if not present, then test next Path entry + PUSH HL ; save Path pointer + CALL CALDIR ; get Directory entry + LD DE,10 ; add offset SYStem bit + ADD HL,DE + BIT 7,(HL) ; test SYStem file + LD A,(FLAGS) ; test for relaxed Path definition + RLA ; ..by rotating bit + RLA ; ..into Carry flag + POP HL ; restore Path pointer + JR C,FINDF3 ; ..if Carry, SYStem attribute not required + JR Z,FINDF0 ; else, SYStem file, so test next Path entry +FINDF3: LD A,(DEFDRV) ; get current Drive + INC A ; increment Drive number + LD (FCB0),A ; save it in exit FCB0 + SET 7,(IX+PSFATT) ; set PUBlic/SYStem file flag + RET ; and return to caller + + + + ;_______________________// Non-Banked // + CSEG + + ;-------------------------------------------------- + ; fn # 15 Open File + ; enter: DE= address of FCB, exit: A= Directory Code + ;-------------------------------------------------- +CMND15: CALL SELDRV ; select Drive from FCB + ; (also switches System bank) + LD A,32 ; 32 bytes + LD (FCBBUP),A ; ..to update in FCB + LD (IX+FCBMOD),0 ; clear data module number + CALL FINDF ; find file using Path (..in Banked code) + CALL TSTFCT ; test file found (..in Banked code) + RET Z ; ..if not, then exit + +OPENF0: LD A,(IX+PSFATT) ; get PUBlic/SYStem file bit + PUSH AF ; save it + LD A,(IX+FCBEXT) ; get extent number from FCB + PUSH AF ; save it + CALL CALDIR ; get Directory entry + LD A,(HL) ; find real User number file is in + OR 80H ; set User valid flag + PUSH IX ; save FCB entry + POP DE ; get in DE + LD BC,32 ; number of bytes to move + LDIR ; move Directory to FCB + LD (IX+FCBUSR),A ; and put User byte back + SET 7,(IX+FCBMOD) ; set FCB/File not modified + LD B,(IX+FCBEXT) ; get extent number + LD C,(IX+FCBREC) ; get next record number + POP AF ; get old extent number + LD (IX+FCBEXT),A ; save it + CP B ; compare old and new extent number + JR Z,OPENF1 ; ..if same, then jump + LD C,0 ; set next record count to 0 + RR C ; record count to max (0x80) if need new extent +OPENF1: LD (IX+FCBREC),C ; save next record count + POP AF ; get PUBlic/SYStem file bit + RL (IX+PSFATT) ; remove MSB from IX+7 + RLA ; set new MSB in Carry + RR (IX+PSFATT) ; save Carry in IX+7 + LD B,1 ; mask for STFLAG (bit0 = Access stamp) + LD HL,STLA ; address of last accessed routine + JP STPMSK ; ..and continue in Banked code + + + ;-------------------------------------------------- + ; fn # 22 Make File + ; enter: DE= Address of FCB, exit: A= Directory Code + ;-------------------------------------------------- +CMND22: CALL SELDRV ; select Drive from FCB + LD (IX+FCBMOD),0 ; clear data module number + LD A,32 ; 32 bytes + LD (FCBBUP),A ; save # bytes to update in FCB +MAKES: CALL CHKRO ; check drive W/P + CALL SELSYB ; switch System bank + JP MAKESB ; ..and continue in Banked code + + + + ;_______________________// Banked // + COMMON /BANK2/ + + ;-------------------------------------------------- + ; Make File + ; (continue CMND22 / MAKES) + ;-------------------------------------------------- +MAKESB: LD HL,(ARWORD) + LD A,(HL) ; get first byte of FCB + PUSH AF ; save it + LD (HL),0E5H ; set first byte to empty file + LD A,1 ; search for 1 byte + CALL SEARCH ; search empty file + POP AF ; get first byte of FCB + LD (IX+0),A ; restore it + CALL TSTFCT ; test empty file found + RET Z ; ..if not, return error + LD HL,(ARWORD) ; get FCB pointer + CALL CKSUB ; check if this is a submit file + LD DE,15 ; prepare offset + ADD HL,DE ; add it + LD B,17 ; set counter + CALL CLRMEM ; clear FCB+15 up to FCB+31 + RES 7,(IX+PSFATT) ; reset PUBlic/SYStem file bit + RES 7,(IX+ARCATT) ; reset Archive bit if present + CALL CALDIR ; get Directory entry + PUSH IX ; save FCB entry + POP DE ; get it in DE + EX DE,HL ; exchange FCB and Directory entry + LD BC,32 ; number of bytes to copy + LDIR + CALL WRFCB ; write FCB on disk + SET 7,(IX+FCBMOD) ; set FCB/File not modified + LD B,2 ; mask for STFLAG (bit1 = Create stamp) + LD HL,STCR ; address stamp create routine + JP STPMSK ; mask type and stamp file if enabled + + + ;----- + ; open next extent +OPENEX: BIT 7,(IX+FCBMOD) ; test if FCB/File modified (write) + JR NZ,OPENX2 ; ..if not, jump + CALL CLOSE ; close current FCB + LD A,(PEXIT) ; get exit code + INC A ; test if error + RET Z ; ..if so, exit +OPENX2: CALL CALNEX ; calculate next extent + JR C,OPENX3 ; ..if error, jump + +OPENX0: CALL SRCT15 ; search for 15-char match and test presence + JR NZ,OPENX5 ; ..if yes, jump + LD A,(RDWR) ; test Read/Write flag + OR A ; test if read + JR Z,OPENX3 ; ..if yes, then error + CALL MAKES ; make new extent if write + CALL TSTFCT ; test if successful + JR NZ,OPENX6 ; ..if yes, then exit +OPENX3: SET 7,(IX+FCBMOD) ; set FCB/File not modified +RETCFF: LD A,0FFH ; set exit code +OPENX4: JP SAVEA ; and return to caller + +OPENX5: CALL OPENF0 ; open file +OPENX6: XOR A ; clear exit code + JR OPENX4 ; use same code to exit routine + + + ;----- + ; calculate next extent + ; out: Carry set (C) if overflow detected +CALNEX: CALL GETDME ; get extent number, data module number + BIT 6,B ; test error bit random record + SCF ; set error flag + RET NZ ; ..if non-zero, error exit + INC C ; increment extent number + LD A,C ; get extent number + AND MAXEXT ; mask it for max extent + LD C,A ; save it in C + JR NZ,CALNE1 ; ..if new data module not required, jump + INC B ; set next data module + LD A,B ; get it in A + AND MAXMOD ; mask it for max module + LD B,A ; save it in B + SCF ; set error flag + RET Z ; ..if file overflow, return +CALNE1: LD (IX+NXTREC),0 ; zero next record count +SETDME: LD (IX+FCBEXT),C ; save extent number + LD (IX+FCBMOD),B ; save data module number + AND A ; clear flag + RET + +GETDME: LD C,(IX+FCBEXT) ; get extent number + LD B,(IX+FCBMOD) ; get data module number + LD A,C + CALL SEARC7A ; mask extent + RES 7,B ; clear unmodified flag + OR B ; test for module and extent = 0 + RET ; ..and return to caller + + + + ;_______________________// Non-Banked // + CSEG + + ;-------------------------------------------------- + ; fn # 33 Read Random Record + ; enter: DE= Address of FCB, exit: A= Read/Write Code + ;-------------------------------------------------- +CMND33: CALL SELDR1 ; select Drive from FCB + LD A,36 + LD (FCBBUP),A ; save # bytes to update in FCB + + ; read random sector + XOR A ; set Read/Write flag + CALL LDFCB ; load FCB random record (..in Banked code) + JR Z,READS ; ..if no error, then read sector + RET + + + ;-------------------------------------------------- + ; fn # 20 Read Sequential + ; enter: DE= Address of FCB, exit: A= Read/Write Code + ;-------------------------------------------------- +CMND20: CALL SELDR1 ; select Drive from FCB + ; (also switches System bank) + LD A,33 ; 33 bytes + LD (FCBBUP),A ; save # bytes to update in FCB + + ; read sector +READS: JP READSB ; ..continue in Banked code + + + + ;_______________________// Banked // + COMMON /BANK2/ + + ;-------------------------------------------------- + ; Read Sector + ; (continue CMND20 / READS) + ;-------------------------------------------------- +READSB: XOR A ; set Read/Write flag + LD (RDWR),A ; save it + LD A,(IX+NXTREC) ; get record counter + CP 80H ; test if last record in this extent + JR Z,READSB1 ; ..if yes, then open next extent + CP (IX+FCBREC) ; test if greater than current record + JR C,READSB2 ; ..if not, then get record +READSB0: LD A,1 ; set end of file flag + JP SAVEA ; and exit + +READSB1: CALL OPNXCK ; open next extent +READSB2: CALL GETDM ; get block number from DM in FCB + JR Z,READSB0 ; ..if block number= 0, jump to end of file + CALL CALSEC ; calculate sector number (128 bytes) + CALL CALST ; calculate sector/track number + CALL READR ; read data + JP WRITS7 ; increment elsewhere if necessary + + + ;----- + ; consolidated routine to open extent and check status +OPNXCK: CALL OPENEX ; open next extent + LD A,(PEXIT) ; get exit code + OR A + RET Z ; return if open OK + POP HL ; else, pop return address to abort R/W + JR READSB0 ; ..and set error code to EOF + + + + ;_______________________// Non-Banked // + CSEG + + ;-------------------------------------------------- + ; fn # 34 Write Random + ; fn # 40 Write random with zero fill + ; enter: DE= Address of FCB, exit: A= Read/Write Code + ;-------------------------------------------------- +CMND34: +CMND40: CALL SELDR1 ; select Drive from FCB + LD A,36 ; 36 bytes + LD (FCBBUP),A ; save # bytes to update in FCB + + ; write random sector and write random with zero fill + LD A,0FFH ; set Read/Write flag + CALL LDFCB ; load FCB random record (..in Banked code) + JR Z,WRITES ; ..if no error, then write record + RET ; else, return error + + + ; ##### CHECK: unreferenced code + CALL CHKRO ; check drive W/P status + PUSH IX + LD IX,ZSFCB ; buffer internal FCB + CALL NOTUSE1 ; write sector + JP NOTUSE3 + RET + ; ##### + + + ;-------------------------------------------------- + ; fn # 21 Write Sequential + ; enter: DE= Address of FCB, exit: A= Read/Write Code + ;-------------------------------------------------- +CMND21: CALL SELDR1 ; select Drive from FCB + LD A,33 ; 33 bytes + LD (FCBBUP),A ; save # bytes to update in FCB + + ; write sector - permitted to PUBlic file and those found along Path +WRITES: LD A,0FFH ; set Read/Write flag + LD (RDWR),A ; save it + +BGPTCH1 EQU $+1 ; <--- patched location for BGii + + CALL CHKRO ; check disk W/P +NOTUSE1: CALL SELSYB ; switch System bank + JP WRITESB ; ..and continue in Banked code + + + + ;_______________________// Banked // + COMMON /BANK2/ + + ;-------------------------------------------------- + ; Write Sector + ; (continue CMND21 / WRITES) + ;-------------------------------------------------- +WRITESB: BIT 7,(IX+ROATT) ; test if file W/P + JR NZ,WRITSA ; ..if yes, then file W/P message + CALL CHKFR3 ; test W/P if Path or Public used + LD HL,(WHEEL) ; get address of Wheel byte + LD A,(HL) ; do we have Wheel privileges ? + AND A + JR NZ,WRITSB ; ..if yes, allow write + BIT 7,(IX+WHLATT) ; else, test if file is Wheel protected +WRITSA: JP NZ,CHKFR2 ; ..if so, then file W/P message +WRITSB: BIT 7,(IX+NXTREC) ; end of this extent ? + CALL NZ,OPNXCK ; open next extent and check status + CALL GETDM ; get block number from FCB + JP NZ,WRITS5 ; ..if not zero, then jump to write sector + PUSH HL ; save pointer to block number + LD A,C ; test first block number in extent + OR A + JR Z,WRITS1 ; ..if yes, then jump + DEC A ; decrement pointer to block number + CALL GETDM4 ; get previous block number + + + ; get free block from ALV buffer + ; in: DE= old block number + ; out: DE= new block number, 0 if no free block + ; (HL counts up, DE counts down) +WRITS1: LD H,D ; copy old block to HL + LD L,E +GETFR0: LD A,D ; test down counter is zero + OR E + JR Z,GETFR1 ; ..if so, jump + DEC DE ; decrement down counter + PUSH HL ; save up/down counter + PUSH DE + CALL GETBIT ; get bit from ALV buffer + RRA ; test if zero + JR NC,GETFR3 ; ..if yes, then found empty block + POP DE ; get up/down counter + POP HL +GETFR1: LD BC,(MAXLEN) ; get maximum ALV length-1 in BC + LD A,L ; is HL >= length ALV-1 ? + SUB C ; ..do while preserving HL + LD A,H + SBC A,B + JR NC,GETFR2 ; ..if end of buffer, then jump + INC HL ; increment up counter + PUSH DE ; save down/up counter + PUSH HL + EX DE,HL ; up counter in DE + CALL GETBIT ; get bit from ALV buffer + RRA ; test if zero + JR NC,GETFR3 ; ..if yes, then found empty block + POP HL ; get down/up counter + POP DE + JR GETFR0 ; and test next block + +GETFR2: LD A,D ; test if last block testet + OR E + JR NZ,GETFR0 ; ..if not, then test next block + JR WRITSG ; continue with DE= 0 + +GETFR3: SCF ; set block number used + RLA ; save bit + + ; SETBT0 code now inline +GETFR4: RRCA ; rotate bit in correct position + DJNZ GETFR4 + LD (HL),A ; save 8 bits + POP DE ; get correct counter + POP HL ; restore stack pointer + ; ..continue with (DE= block number) + +WRITSG: POP HL ; get pointer to block number + LD A,D ; test if block number = 0 + + ; WRITS8 code now inline + OR E + LD A,2 ; set disk full error + JP Z,SAVEA ; and return to caller + RES 7,(IX+FCBMOD) ; reset FCB/File modified + LD (HL),E ; save block number + LD A,(MAXLEN+1) ; get number of blocks + OR A ; is it < 256 ? + JR Z,WRITS2 ; ..if so, jump + INC HL ; increment to MSB block number + LD (HL),D ; ..and save MSB block number +WRITS2: LD C,2 ; set write new block flag + LD A,(NMASK) ; get sector mask + AND (IX+NXTREC) ; mask with record number + JR Z,WRITSX ; ..if zero, then Ok (at start new record) + LD C,0 ; else, clear new block flag +WRITSX: LD A,(FUNCT) ; get function number + SUB 40 ; test if Write Random Record with zero fill + JR NZ,WRITS6 ; ..if not, then jump + PUSH DE ; save block number + LD HL,(DIRBUF) ; use Directory buffer for zero fill + LD B,128 ; 128 bytes to clear + CALL CLRMEM ; do clear + CALL CALSEC ; calculate sector number (128 bytes) + LD A,(NMASK) ; get sector mask + LD B,A ; copy it + INC B ; increment it to get number of writes + CPL ; complement sector mask + AND E ; mask sector number + LD E,A ; and save it + LD C,2 ; set write new block flag +WRITS4: PUSH HL ; save registers + PUSH DE + PUSH BC + CALL CALST ; calculate sectors/track + CALL DMADIR ; set DMA Directory buffer + POP BC ; get write new block flag + PUSH BC ; save it again + CALL WRITER ; write record on disk + POP BC ; restore registers + POP DE + POP HL + LD C,0 ; clear write new block flag + INC E ; increment sector number + DJNZ WRITS4 ; write all blocks + CALL STDMA ; set user DMA address + POP DE ; get block number +WRITS5: LD C,0 ; clear write new block flag +WRITS6: RES 7,(IX+FCBMOD) ; reset FCB/File modified flag + PUSH BC ; save it + CALL CALSEC ; calculate sector number (128 bytes) + CALL CALST ; calculate sectors/track + POP BC ; get write new block flag + CALL WRITER ; write record on disk + LD A,(IX+NXTREC) ; get record counter + CP (IX+FCBREC) ; compare with next record + JR C,WRITS7 ; ..if less, then jump + INC A ; increment record count + LD (IX+FCBREC),A ; save it on next record position + RES 7,(IX+FCBMOD) ; reset FCB/File modified flag +WRITS7: LD A,(FUNCT) ; get function number + CP 20 + RET C ; return if < 20 + CP 21+1 + RET NC ; return if > 21 + INC (IX+NXTREC) ; increment record count + RET ; and return to caller + + + ;-------------------------------------------------- + ; Load FCB for random read/write + ; (called by CMND33 / CMND34 / CMND40) + ;-------------------------------------------------- + ; out: Zero Flag set (Z) = no error, reset (NZ) if error +LDFCB: LD (RDWR),A ; save Read/Write flag + LD A,(IX+33) ; get first byte random record + LD D,A ; save it in D + RES 7,D ; reset MSB to get next record + RLA ; shift MSB in Carry + LD A,(IX+34) ; load next byte random record + RLA ; shift Carry + PUSH AF ; save it + AND MAXEXT ; mask next extent + LD C,A ; save it in C + POP AF ; get byte + RLA ; shift 4 times + RLA + RLA + RLA + AND 00FH ; mask it + LD B,A ; save data module number + LD A,(IX+35) + LD E,6 ; set random record too large flag + CP 4 ; test random record too large + JR NC,LDFCB8 ; ..if yes, then error + RLCA ; shift 4 times + RLCA + RLCA + RLCA + ADD A,B ; add byte + LD B,A ; save data module number in B + LD (IX+NXTREC),D ; set next record count + LD D,(IX+FCBMOD) ; get data module number + BIT 6,D ; test error random record + JR NZ,LDFCB0 ; ..if yes, then jump + LD A,C ; get new extent number + CP (IX+FCBEXT) ; compare with FCB + JR NZ,LDFCB0 ; ..if not equal, then open next extent + LD A,B ; get new data module number + XOR (IX+FCBMOD) ; compare with data module number + AND MAXMOD ; mask it + JR Z,LDFCB6 ; ..if equal, then return +LDFCB0: BIT 7,D ; test FCB modified (write) + JR NZ,LDFCB1 ; ..if no, then jump + PUSH DE ; save registers + PUSH BC + CALL CLOSE ; close extent + POP BC ; restore registers + POP DE + LD E,3 ; set close error + LD A,(PEXIT) ; get exit code + INC A + JR Z,LDFCB7 ; ..if error, then exit +LDFCB1: CALL SETDME ; save data module and extent + CALL SEAR15 ; search next FCB + LD A,(PEXIT) ; get error code + INC A + JR NZ,LDFCB5 ; if no error, then exit + LD A,(RDWR) ; get Read/Write flag + LD E,4 ; set read empty record + INC A + JR NZ,LDFCB7 ; ..if read error, then jump + CALL MAKES ; make new FCB + LD E,5 ; set make error + LD A,(PEXIT) ; get error code + INC A + JR Z,LDFCB7 ; ..if error, then exit + JR LDFCB6 ; else, exit w/ zero set (no error) +LDFCB5: CALL OPENF0 ; open file +LDFCB6: JP OPENX6 ; set zero flag and clear error code +LDFCB7: LD (IX+FCBMOD),0C0H ; set random record error +LDFCB8: LD A,E ; get error code + LD (PEXIT),A ; and save it + OR A ; clear Zero flag +SETB14: SET 7,(IX+FCBMOD) ; set FCB/File not modified + RET ; and return to caller + + + + ;_______________________// Non-Banked // + CSEG + + ;----- + ; calculate random record + ; in: HL= offset in FCB + ; DE= FCB pointer + ; out: D= LSB random record + ; C= ISB + ; B= MSB +CALRRC: ADD HL,DE ; pointer to FCB+15 or FCB+32 + LD A,(HL) ; get record number + LD HL,12 ; offset to extent number + ADD HL,DE ; get pointer to extent byte + LD D,A ; save record number + LD A,(HL) ; get extent byte + AND MAXEXT ; mask it (000eeeee) + RL D ; shift MSB in Carry (Cy= R, D= rrrrrrr0) + ADC A,0 ; add Carry (00xeeeeex) + RRA ; shift 1 time (16 bits, 000xeeee) + RR D ; D= xrrrrrrr + LD C,A ; save ISB + INC HL ; increment to data module number + INC HL + LD A,(HL) ; get data module number 00mmmmmmm + RRCA ; divide module by 16 + RRCA + RRCA + RRCA + PUSH AF ; save it mmmm00mm + AND 03H ; mask for maximum module + LD B,A ; save it 000000mm + POP AF ; get LSB + AND 0F0H ; mask it mmmm0000 + ADD A,C ; add with ISB mmmxeeee + LD C,A ; save ISB + RET NC ; no Carry then return + INC B ; increment MSB 000000mm + RET ; and return to caller + ; 000000mm mmmxeeee xrrrrrrr + + + ;----- + ; clear/fill memory +CLRM4: LD B,4 ; clear memory area (used by MAKES and WRITSX) + +CLRMEM: XOR A ; clear A + + ; fill memory with byte in A + ; in: A= byte + ; B= counter (# bytes) + ; HL= destination +FILLM: LD (HL),A ; store byte + INC HL ; increment pointer + DJNZ FILLM ; and clear all bytes + RET + + + ;----- + ; check/update !!!TIME&.DAT checksum + ; calc checksum of 127 bytes, return with HL pointing to 128th byte + ; in: DIRBUF= pointer to T&D record + ; out: A= checksum + ; HL= points to checksum byte in record +CKS127: LD HL,(DIRBUF) ; directory buffer pointer + XOR A ; clear A + LD B,127 ; test first 127 bytes +CKSLP: ADD A,(HL) ; sum all bytes to A + INC HL + DJNZ CKSLP + RET + + + ;----- + ; get word (16-bit value) indirectly + ; in: HL= base addr + ; A= offset + ; out: HL= 16-bit value at offset addr + ; Z-Flag set if HL= 0 +GWHLA: CALL CALDI0 ; add A to HL + LD A,(HL) ; get low byte at memory location + INC HL + LD H,(HL) ; get high byte + LD L,A + OR H ; test if zero (set return status) + RET + + + + ;_______________________// Banked // + COMMON /BANK2/ + + ;----- + ; test if Drive is valid + ; in: B= drive number + ; out: Carry flag set (C) = ok, NC= not ok +DRVOK: LD HL,(OZ3ENV) ; B/P Bios base +0x98 (addr Z3 ENV decriptor) + LD A,H ; test if valid (<> zero) + OR L + JR Z,DRVOK1 ; ..if not, jump exit (assume drive is valid) + LD A,8 ; else, offset to Env type (ENV base +8) + CALL CALDI0 ; move ptr fwd + BIT 7,(HL) ; is it extended (=> 0x80) ? + JR Z,DRVOK1 ; ..if not, jump + LD A,44 ; move ptr fwd to DRVEC + CALL GWHLA ; ..and get vector of valid drives in HL + LD A,16 ; set up loop counter + SUB B ; adjust to drive in scope +DRVOK0: DEC A ; counter -1 + ADD HL,HL ; "shift" MSB into Carry + JR NZ,DRVOK0 ; loop + RET ; ..and return with status in Carry +DRVOK1: SCF ; set return status (Carry set = Ok) + RET + + + + ;_______________________// Non-Banked // + CSEG + + ;----- + ; test if current DU: is in Path + ; in: HL= path address + ; out: B= current drive, C= current user + ; A= 0xFF, Z-Flag clear (NZ) if match or '$$' + ; Z-Flag set if no match +DUPATH: LD BC,(USER) ; get default drive (B) and user number (C) + LD A,(HL) ; get byte of path entry + OR A ; test for end + RET Z ; ..if yes, then return with Z-Flag set + CP '$' ; test if current drive + JR Z,DUPAT0 ; ..if so, then jump + DEC A ; decrement drive number of path entry + LD B,A ; ..and save in B +DUPAT0: INC HL ; advance pointer + LD A,(HL) ; get user number + CP '$' ; test if current user + JR Z,DUPAT1 ; ..if so, then jump + LD C,A ; else, save in C +DUPAT1: INC HL ; advance pointer + OR 0FFH ; set exit code to 0xFF (match) + RET ; and return to caller + + + ;-------------------------------------------------- + ; fn # 46 Return Free Space + ; enter: E= Disk Number, exit: A= Error Code + ; Space in DMA+0..DMA+3 + ;-------------------------------------------------- +CMND46: CALL CMND14 ; select disk from E register + CALL SELSYB ; switch System bank + CALL CMD46B ; ..and continue in Banked code + JP DOSEXT1 + + + + ;_______________________// Banked // + COMMON /BANK2/ + + ;-------------------------------------------------- + ; Return Free Space + ; (continue CMND46) + ;-------------------------------------------------- +CMD46B: LD HL,DFCALC + CALL CLRM4 ; clear 4 bytes + LD DE,(MAXLEN) ; get maximum blocks-1 + INC DE ; +1 + LD HL,(ALV) ; get ptr to allocation vector + + ; process one byte of ALV - outer loop +DFREE1: LD C,(HL) ; get bit pattern of allocation byte + PUSH HL ; save pointer + LD B,8 ; process 8 bits +DFREE2: RL C ; shift MSB to Carry + CCF ; invert + JR NC,DFREE4 ; ..if MSB was 1, then jump + + ; count zeros - inner loop + PUSH BC + LD B,4 + LD HL,DFCALC +DFREE3: LD A,(HL) + ADC A,0 ; add Carry + LD (HL),A ; ..and save back + INC HL ; move ptr + DJNZ DFREE3 ; loop till done + + POP BC +DFREE4: DEC DE ; decrease number of blocks + LD A,E ; test if zero + OR D + JR Z,DFREE5 ; ..if zero, exit inner loop + DJNZ DFREE2 + POP HL ; restore ALV ptr + INC HL ; move to next byte + JR DFREE1 ; ..and loop (outer) + + ; allocation is measured in blocks, convert to kB +DFREE5: POP HL ; clear stack + LD A,(NBLOCK) ; get block shift factor + SUB 3 ; (BSH= 3 -> 1k, 4 -> 2k, ...8 -> 32k) + JR Z,DFREEX ; if BSH-3 = 0, then we're done + + ; multiply 32-bit (4 bytes) +DFREE6: LD HL,DFCALC ; set ptr to data storage + LD B,4 ; bytes to work +DFREE7: RL (HL) ; shift MSB into Carry + INC HL ; move ptr + DJNZ DFREE7 ; ..and loop + DEC A + JR NZ,DFREE6 ; if not zero, loop for next block size + ; ..else, fall through and transfer data + + + ; transfer to DMA using interbank move + ; (destination could be in a disabled memory bank) +DFREEX: LD A,(TPABNK) ; get TPA bank # + LD B,A ; ..in B + LD A,(OSYSBK) ; get SYS bank # (Bios base +0x83 SYSBNK) + LD C,A ; ..in C + CALL XMOVE ; call Bios fn #29 XMOVE, set banks for MOVE + LD HL,DFCALC ; source address + LD DE,(DMA) ; destination address + LD BC,4 ; bytes to move + JP MOVE ; ..and do it (Bios fn #25) + + + + ;_______________________// Banked Data Segment // + COMMON /B2RAM/ + + ; Disk free calculation data area (4 bytes) +DFCALC: DEFS 4 +; DEFB 0,0,0,0 + + + + ;_______________________// Non-Banked // + CSEG + + ;-------------------------------------------------- + ; fn # 152 Parse FileSpec + ; enter: DE= FCB Address, exit: A= Number of '?'s in Fn.Ft + ; String in DMA Buffer DE= Address of delimiter char + ; FCB+15= 0 if Parse Ok, 0FFH if Error(s) + ;-------------------------------------------------- +CMD152: PUSH DE ; save ptr to FCB + XOR A + LD (DE),A ; clear FCB Drive field + INC DE ; move ptr fwd + LD A,' ' ; prepare to init FCB name and type fields + LD B,8+3 +CM152A: LD (DE),A + INC DE + DJNZ CM152A + + ; destination FCB initialized + POP DE ; restore ptr to FCB + LD HL,(DMA) ; get DMA address + LD BC,(USER) ; get User number + LD A,C ; ..in A + LD (STATUS),A ; and save as status + CALL SCANF8 ; place first token (8-bytes) in name field + CP ':' ; is the delimiter a Colon ? + LD A,0 ; prepare status flag for ok DU/DIR + JP NZ,SCAN1 ; ..if only a file name, then jump + + INC HL ; point to char after Colon + PUSH HL + PUSH DE + CALL CMND49 ; get address of Z3 Environment + ; ##### CHECK: should jump further down ? (repeats CALL CMND49) + JR Z,DUSCAN ; ..if none found, jump + LD A,21 ; offset to Z3NDIR (addr Named Dir Buffer) + CALL GWHLA ; get vector at offset memory location + JR Z,DUSCAN ; ..if address not valid, jump to DU scan + INC DE + + ; scan Named Dir entries +DIRS1: CALL DUPATH ; test if current DU: in Path + JR Z,DUSCAN ; ..if not, then jump + PUSH BC ; save DU + PUSH HL ; save ptr to file name + PUSH DE ; save ptr to NDR entry + LD B,8 ; max 8 chars +DIRS2: LD A,(DE) ; get char + CP (HL) ; compare to NDR entry + JR NZ,DIRS3 ; ..if no match, exit loop + INC HL ; else, point to next char + INC DE + DJNZ DIRS2 ; loop + +DIRS3: POP DE ; restore regs + POP HL + POP BC + JR Z,CHKVVC ; ..if ok, then jump + LD BC,16 ; 8 bytes name + 8 bytes password + ADD HL,BC ; advance ptr + JR DIRS1 + + ; scan Drive/User +DUSCAN: CALL CMND49 ; get address of Z3 Environment + JR Z,DUS0 ; ..if none found, jump + + LD A,46 ; offset to DU Flag + CALL CALDI0 ; move ptr fwd + LD A,(HL) ; get byte at memory location + OR A + JR Z,DUSERR ; ..if zero, then jump + ; (1= ok to accept DU:, 0= not ok) + + ; no Z3 Envorionment, assume DU: form and scan/extract Drive/User +DUS0: LD L,C + EX DE,HL + CALL DELIM + EX DE,HL + CP ' '+1 ; legal char ? + JR C,DUSOK ; ..if only delimiter, jump w/ current DU + SUB 41H ; convert possible drive spec to number + JR C,DUS1 ; ..if less than 'A', must be digit + + ; set Drive number (0= A) + LD B,A ; save drive in B + INC DE ; point to next input char + LD A,(DE) ; get char + CP ' '+1 ; end of string ? + JR C,DUCHEK ; ..if so, jump to check limits + + ; set User number +DUS1: LD HL,2*256 ; get up to 2 digits +DUS1A: LD A,(DE) + CP ' '+1 ; is it a delimiter ? + JR C,DUS2 ; ..if so, jump to end + SUB '0' ; digit ? + JR C,DUSERR ; ..if not, jump + CP 10 ; number in range (0..9) ? + JR NC,DUSERR ; ..if not, jump + LD C,A ; save + LD A,L ; ..and multiply old digit + ADD A,A ; *2 + ADD A,A ; *4 + ADD A,L ; *5 + ADD A,A ; *10 + ADD A,C + LD L,A + INC DE ; advance to next byte + DEC H ; count down + JR NZ,DUS1A ; ..loop if more to go + LD A,(DE) +DUS2: CP ' ' ; is it the proper delimiter ? + JR NZ,DUSERR ; ..if not, jump error exit + LD C,L ; save good User in C + + + ; BC now has parsed DU:, check legality +DUCHEK: LD HL,(USER) ; get currently logged DU + OR A + SBC HL,BC ; same as that parsed ? + JR Z,DUSOK ; ..if so, take good exit + +CHKVVC: CALL SELSYB ; switch System bank + CALL DRVOK ; check if drive is valid + CALL SELTPB ; switch back to TPA bank + JR C,DUSOK + +DUSERR: LD BC,(USER) ; get current DU + DEFB 0F6H ; fall through with OR A,0AFH + +DUSOK: XOR A ; set return status OK + POP DE + POP HL + PUSH AF + LD A,B ; get drive # + INC A ; change to A= 1 base + LD (DE),A ; store in FCB+0 + LD A,C ; get User # + LD (STATUS),A ; store in mem + CALL SCANF8 ; scan token (8-byte) + POP AF ; restore A cleared + ; ..and fall through + + + ; skip to file type field + ; in: HL= ptr to next char + ; DE= ptr to DN field of FCB +SCAN1: PUSH AF ; save error flag for exit + EX DE,HL + LD BC,8 ; point to before file type field of FCB + ADD HL,BC + EX DE,HL ; Extract file type field + LD B,3 + LD A,(HL) ; get the delimiter char + CP '.' ; is it '.' ? + JR NZ,SCAN2 ; ..if no type, then jump + INC HL ; else, point to char after '.' + CALL SCANF ; ..and get file type +SCAN2: LD (DEVAL),HL + INC DE ; move ptr from last char of name to T1 + INC DE ; ..to T2 + INC DE ; ..to T3 + INC DE ; ..to EXM + XOR A ; zero + LD (DE),A ; store here at FCB+12 (EXM) + INC DE ; move to S1 + LD A,(STATUS) ; get User number + LD (DE),A ; ..and store it here at FCB+13 (S1) + INC DE ; move ptr to S2 + XOR A ; zero + LD (DE),A ; store here at FCB+14 (S2) + INC DE ; move ptr to FCB+15 + POP AF ; restore error flag + LD (DE),A ; ..and save it in FCB+15 + RET + + + ;----- + ; scan up to 8 chars +SCANF8: XOR A ; get a 0 + LD (PEXIT),A ; ..and clear question mark counter + LD B,8 ; scan for up to 8 chars + ; ..fall through to main scan routine + + ; scan token with interpreting/expanding '*' and '?' wild cards + ; in: B= max number of bytes + ; HL= ptr to token + ; DE= destination addr (FCB file name field) + ; out: HL= ptr to terminating delimiter +SCANF: PUSH DE ; preserve FCB address +SCANF0: INC DE ; ptr to next byte in FCB + CALL DELIM ; is it a delimiter ? + JR Z,SCANF2 ; ..if so, jump + INC HL ; else, point to next char + CP '*' ; is (DE) a wild card ? + JR NZ,SCANF1 ; ..if not, continue + DEC HL ; else, back up to same char + LD A,'?' ; ..and expand with '?' + +SCANF1: LD (DE),A + CP '?' ; is it wild ? + JR NZ,SCNOQ ; ..if not, jump + PUSH HL ; else, save HL + LD HL,PEXIT ; point to count storage + INC (HL) ; ..and increment + POP HL ; restore HL +SCNOQ: DJNZ SCANF0 ; ..loop till done + INC DE ; then advance to next FCB char + + ; flush to next delimiter +SCANF3: CALL DELIM + JR Z,SCANFX ; ..if delimiter found, then jump + INC HL ; point to next char + JR SCANF3 ; and loop + + ; preserve present char, and fill remaining chars in field w/ spaces +SCANF2: PUSH AF ; save char +SCANFA: LD A,' ' ; store this char + LD (DE),A ; ..in FCB field + INC DE ; point to next + DJNZ SCANFA ; loop till done + POP AF ; restore char +SCANFX: POP DE ; restore FCB address + RET ; ..and exit + + + ; capitalize char, then fall through to check for delimiter +DELIM: LD A,(HL) ; get char + CP 'a' ; less than small letter A ? + JR C,SDELM + CP 'z'+1 ; between small A and small Z ? + JR NC,SDELM + AND 5FH ; remove bit 5 to capitalize + + ; check for delimiter + ; in: HL= ptr to char + ; out: A= addressed char + ; Zero Flag set (Z) if delimiter, end-of-line or cmd separator + ; Zero Flag cleard (NZ) if char is not a delimiter +SDELM: CP '_' ; is it an Underscore ? + RET Z + CP '.' ; a Period ? + RET Z + CP ',' ; a Comma ? + RET Z + CP '>' ; greater than a Greater Sign ? + RET NC ; ..if so, return + CP ':' ; is it any of : ; < = > ? + JR NC,SDEL0 ; ..if so, jump to set status + CP ' ' ; is it less than a Space ? + RET NC ; ..if so, return (Space has zero set) + XOR A ; else, must be less than Space, + RET ; so return with zero in A +SDEL0: CP A ; set Z-Flag retaining char + RET + + + ;:::::::::::::::::::::::::::::::::::::::: + ;::::: Time and Date Routines + + + ;-------------------------------------------------- + ; fn # 98 Get time + ; enter: DE= Address to Put Time, exit: A= Time/Date Code + ;-------------------------------------------------- +CMD98A: EX DE,HL ; entry point for cmnd12 + +CMD98: LD C,0 ; set parameter to get time/date + DEFB 21H ; ..and fall through to GSTD (trashing HL) + + + ;-------------------------------------------------- + ; fn # 99 Set time + ; enter: DE= Address of Time, exit: A= Time/Date Code + ;-------------------------------------------------- +CMD99: LD C,1 ; set parameter to set time/date +GSTD: LD HL,(GSTIME) ; get time/date get/set routine address + PUSH HL ; ..to stack for pseudo 'Jump' +DOTDER: OR 0FFH ; save 1 T state while setting flags + RET ; vector to service routine + + + ;-------------------------------------------------- + ; fn # 103 Set file stamp + ; enter: DE= Address of FCB, exit: A= Time/Date Code + ; Stamp in DMA Buffer + ;-------------------------------------------------- + ; wildcards allowed in FCB + ; ##### ZSDOS-GP.Z80 (v1) refers to "10 byte stamp from DMA" ?? +CMD103: LD HL,(DMA) ; address DMA buffer + LD DE,ZSSTMP ; time stamp buffer + CALL STPCP0 ; ..and copy + + + ;-------------------------------------------------- + ; fn # 102 Get file stamp + ; enter: DE= Address of FCB, exit: A= Time/Date Code + ; Stamp in DMA Buffer + ;-------------------------------------------------- + ; wildcards allowed in FCB +CMD102: CALL SELDRV ; select Drive in FCB + ; (also switches System bank) + JP CMD103B ; copy stamp (..in Banked code) + + + + ;_______________________// Banked // + COMMON /BANK2/ + + ; ZSDOS2 supports DateStamper and P2DOS (CP/M+) file stamping. + ; Internally, the Universal T&D format is used, and converted + ; as needed when reading from / writing to disk. Similarly, + ; all stamps are converted to/from the Universal stamp format + ; (15 bytes packed BCD), and stuffed into ZSSTMP buffer. + + ;----- + ; Universal Stamp format + ; Bytes 0..4 Create 5..9 Access 10..14 Modify + ; | YY MM DD HH MM | YY MM DD HH MM | YY MM DD HH MM | + ; + ; YY MM DD HH MM SS - Universal T&D format + ; (all BCD, prefix 19 assumed for years 79-99, else 20) + + ;----- + ; P2DOS (CP/M+) Stamp format + ; Bytes 0..3 Create 4..7 Modify + ; | nn nn HH MM | nn nn HH MM | + ; + ; nnnn HH MM SS - P2DOS (CP/M+) format + ; (nnnn = binary number of das since 1 Jan 1978) + ; (HH MM SS = time in BCD) + + + ;-------------------------------------------------- + ; Get/Set file stamp + ; (continue from CMD102/CMD103) + ;-------------------------------------------------- +CMD102B: +CMD103B: CALL SRCT15 ; find the FCB + JP Z,DOTDER ; ..if not found, exit w/ error + LD HL,GETSTR ; address of get time stamp routine + LD A,(FUNCT) ; check function + CP 102 ; get stamp ? + JR Z,DOTDR3 ; ..if yes, jump + LD HL,PUTSTR ; address of put (set) time stamp routine + JR STAMPT ; mask for enabled stamp type(s) in B +STPMSK: LD A,(STFLAG) ; get time stamp flags + AND B ; mask + RET Z ; ..if not selected, then return + + ; enter here for stamp Create/Access/Modify +STAMPT: PUSH HL + CALL CHKRO1 ; test for disk W/P but avoid error trap + POP HL + JP Z,DOTDER ; no stamp if disk is W/P +DOTDR3: CALL GETDME ; get data module and extent number + JP NZ,DOTDER ; ..if not extent 0 of module 0, then quit + JP (HL) ; else, continue in GETSTR/PUTSTR routine + + + ;----- + ; Stamp Create +STCR: CALL P2CR ; call P2D Create routine + LD B,0 ; offset into stamp in B + JR STT ; Stamp Update + + ;----- + ; Stamp Modify +STUP: CALL P2UP ; call P2D Update routine + LD B,10 ; offset into stamp in B + JR STT ; Stamp Access + + ;----- + ; Stamp Access +STLA: LD B,5 ; offset into stamp in B + LD A,0FFH ; set correct value to validate status + + ; update stamp +STT: LD (STATUS),A ; save first routine status + LD C,2 ; show as stamp + LD A,(SECPNT) ; get sector pointer + ADD A,3 ; point to no date attribute + LD L,A + LD H,0 + LD DE,(DIRBUF) ; get Directory buffer pointer + ADD HL,DE ; point to Dir entry + BIT 7,(HL) + LD A,(STATUS) ; get prev routine status for possible ret + RET NZ ; ..if no date attribute, return (don't update) + JR STPSV0 ; else, jump to service routine + + + ;----- + ; get/put Stamp routines +GETSTR: CALL GSTAMP ; get file stamp in Universal format + CP 1 ; test if OK + JR Z,GETST0 ; ##### not needed if following code is removed + + ; ##### CHECK unreferenced code + LD BC,0 ; flag as read + CALL STPSVC + ; ##### + +GETST0: JP STPCPY + + + + ;_______________________// Non-Banked // + CSEG + +STPCPY: CALL SELTPB ; select TPA bank + LD HL,ZSSTMP ; time stamp buffer + LD DE,(DMA) ; address DMA buffer +STPCP0: LD BC,15 ; copy 15 bytes + LDIR + RET + + + + ;_______________________// Banked // + COMMON /BANK2/ + + RET ; ##### unreferenced, will not be executed + + ; get/put Stamp routines contd. +PUTSTR: CALL PSTAMP ; put file stamp in Universal format + LD BC,1 ; flag as write + ; ..and fall through + + + ;----- + ; Stamp service routine, combined get/put + ; in: A= index to Dir entry (00H, 20H, 40H, 60H) + ; B= offset in stamp (0, 5, 10) + ; C= function (0= read, 1= write, 2= update) +STPSVC: LD (STATUS),A ; save first routine status +STPSV0: LD (RWCODE),BC ; save function code and sector offset + LD BC,(TDFVCT) ; get T/D vector + CALL GETCDM ; get mask for current Drive in HL + LD A,H + AND B + LD H,A + LD A,L + AND C + OR H ; test if Drive has T/D vector + JR Z,STPSVE ; ..if it doesn't, jump error + + CALL DMADIR ; set DMA address to Directory buffer + LD BC,(RECDIR) ; get current Directory record + XOR A + SRL B ; calculate buffer offset + RR C ; divide record by two, lsb to carry + RRA ; place in msb of A + LD HL,SECPNT ; get sector pointer + ADD A,(HL) ; get offset to stamp in buffer + RRA ; divide by 2 (8 stamps/rec) + PUSH AF ; save index for later + PUSH BC ; ..and save relative record number + + ; now calculate record number needed + LD HL,(NDIR0) ; first entry ALV buffer + LD DE,(NMASK) ; mask number of blocks + INC E ; now is number of records per block + XOR A ; clear A (cheap zero) + LD D,A ; ..to D for 16-bit math + LD B,16 ; check all bits +STPSV1: ADD HL,HL ; shift MSB into Carry + JR NC,STPSV2 ; ..if bit was zero, then jump + EX (SP),HL ; else, get relative record + ADD HL,DE ; add records for this directory block + EX (SP),HL ; back to top-of-stack +STPSV2: DJNZ STPSV1 ; loop until done + POP DE ; has actual record number now + + CALL STDIR1 ; set track/sector and read + CALL READ + POP DE ; get index (was in A before) + AND A ; test if read ok + JR NZ,STPSVE ; ..if error, jump + CALL CKS127 ; checksum first 127 bytes + CP (HL) ; test against DS's checksum + JR NZ,STPSVE ; ..if error, jump exit + LD BC,15 ; size of Universal Stamp + LD E,D ; index in E + LD D,B ; D= 0 + LD HL,(DIRBUF) + ADD HL,DE ; now pointing to correct stamp + LD DE,ZSSTMP ; time stamp buffer + LD A,(RWCODE) ; get Read/Write code + AND A ; is it Get stamp ? + JR NZ,PUTSTP ; ..if not, we're supposed to write + LDIR ; copy bytes + JR STPSVX ; ..and exit + + + ;----- + ; copy Stamp from User DMA to local buffer +PUTSTP: SUB 2 ; is this a simple put + JR Z,UPSTMP ; ..if not, read the clock + EX DE,HL ; swap pointers +PUTS1: LDIR ; move new stamp into place + CALL CKS127 ; checksum first 127 bytes of local buffer + LD (HL),A ; ..and save checksum in last byte of record + INC C ; flag as non-deferred (0 from ldir -> 01) + CALL WRITE ; write sector to disk + AND A ; test if error + JR NZ,STPSVE +STPSVX: LD A,1 ; indicate all is well (OL status) + DEFB 01H ; ..fall through the LD A,FF with LD BC,FF3E + + ; return error status +STPSVE: LD A,0FFH ; set status + PUSH AF ; save return code + CALL STDMA ; set DMA + POP AF ; restore return code + CP 1 ; is it OK ? + RET Z ; ..if so, return + LD A,(STATUS) ; else, get first routine status + RET ; ..and return + + + ;----- + ; read Clock, place in proper Stamp field +UPSTMP: LD D,A ; reg A= 0 + LD A,(STOFF) ; get offset in stamp + LD E,A ; make word length in DE + ADD HL,DE ; pointer to target address + PUSH HL ; save it + OR A ; is it Create time ? + LD B,15 ; prepare to clear 15 bytes + CALL Z,CLRMEM ; ..if Create, then zero entire stamp entry + LD DE,ZSDOSS ; point to Time and Date buffer + PUSH DE + CALL CMD98 ; call fn 98 to read clock + POP HL ; get buffer start + POP DE ; get stamp target address + DEC A ; was the clock read OK ? + JR NZ,STPSVE ; ..if not, jump error exit + LD BC,5 ; else, move 5 bytes + JR PUTS1 ; ..and finish up + + + ;----- + ; update Create/Modify field in T&D buffer +P2CR: LD E,0 ; set to Create field in stamp + DEFB 21H ; trash HL and fall through + +P2UP: LD E,4 ; set to Modify field in stamp + CALL SETREC ; calculate offset in stamp + LD C,E ; move offset to C (B= 0) + ADD HL,BC ; destination now in HL + LD DE,ZSDOSS ; set address to read time + PUSH HL ; save destination address + PUSH DE ; ..and source address + CALL CMD98 ; call fn 98 to get time + POP DE ; restore addresses + POP HL + DEC A ; was the clock read OK ? + JR NZ,NOTIM0 ; ..if not, jump error exit + + ; ##### move label/target PSTMP1 up by one instruction + ; this CALL U2PTIM could be saved (3 bytes) + CALL U2PTIM ; else, convert DE= U-time -> HL= P-time + JR PSTMP1 ; jump to write FCB + + + ;----- + ; Put File Stamp in Universal format + ; convert Create and Modify time fields from Universal T&D format + ; to P2DOS (CP/M+) form and insert in Directory buffer, call WRFCB + ; routine to write on exit + ; in: A= index to Dir entry (00H, 20H, 40H) + ; out: A= time/date code +PSTAMP: CALL SETREC ; calculate the Stamp area address for file + LD DE,ZSSTMP ; time stamp buffer + CALL U2PTIM ; convert Create (DE= U-time -> HL= P-time) + JR NZ,NOTIM0 ; ..if invalid date, jump error exit + INC DE ; bypass Last Access field of input + INC DE + INC DE + INC DE + INC DE + CALL U2PTIM ; convert Modify field +PSTMP1: JR NZ,NOTIM0 ; ..if invalid date, jump error exit + CALL WRFCB ; write stamp +OKRET: LD A,1 ; set status ok and return + RET + +NOSTD: POP AF ; remove return address from Stack +NOTIM0: OR 0FFH ; set error flags + RET ; back to caller + + + ;----- + ; Get File Stamp in Universal format + ; read Create and Modify stamps and convert to Universal T&D format, + ; null the Access time field + ; in: A= index to Dir entry (00H, 20H, 40H) + ; out: A= time/date code +GSTAMP: CALL SETREC ; calculate source Stamp address in HL + LD DE,ZSSTMP ; time stamp buffer + CALL P2UTIM ; convert Create (HL= P-time -> DE= U-time) + LD B,5 ; zero Last Access field for this type + XOR A ; clear A +GSLOOP: LD (DE),A ; ..and poke a zero + INC DE + DJNZ GSLOOP ; ..in each location + CALL P2UTIM ; convert Modify field + JR OKRET ; ..jump to return OK status + + + ;----- + ; convert Universal T&D to P2DOS (CP/M+) form + ; in: DE= ptr to Universal T&D string + ; HL= ptr to destination buffer for P2DOS (CP/M+) T&D + ; out: A= 0, Zero Flag set (Z), if conversion OK + ; A= 0FFH, Zero Flag clear (NZ), error (dest nulled) + ; DE= ptr to Seconds byte in Universal T&D (not moved) + ; HL= ptr to Seconds byte in P2DOS (CP/M+) T&D (not filled) +U2PTIM: PUSH HL ; save destination address + LD A,(DE) ; get BCD year + LD B,A ; ..to B + INC DE ; advance to month + LD A,(DE) ; get BCD month + OR B ; is it invalid (YY = MM = 0) ? + JR Z,NODATE ; ..if invalid stamp, jump to error exit + LD A,B ; get BCD year again from B + CALL BCDBIN ; convert year to binary + CP 78 ; is it 20th century ? + JR NC,YR19 ; ..if so, jump + ADD A,100 ; else, make it 21st century +YR19: LD BC,1900 ; set base century + ADD A,C ; add current year to base + LD C,A + LD A,0 + ADC A,B + LD B,A + LD A,(DE) ; get BCD month + INC DE + CALL BCDBIN ; ..convert to binary + LD H,A + LD A,(DE) ; get day + INC DE ; point to U-hours + PUSH DE ; ..and save address on stack + CALL BCDBIN ; convert day to Binary + LD L,A ; day to L (Binary) + + ; check validity of day, month year (CHKDAT from DATE.ASM) + ; L= binary day, H= binary month, BC= binary year (1978..2077) + LD A,H ; month + DEC A ; convert to 0-11 range + CP 12 ; is it a valid month ? + JR NC,BADDAT ; ..if invalid, then jump error + PUSH HL ; save day/month + LD E,A ; month-1 in E + LD D,0 + LD HL,DMTABLE ; set lookup table for months + ADD HL,DE + LD D,(HL) ; get days in this month + POP HL ; restore day/month + CP 2-1 ; is this February ? + CALL Z,LEAPYR ; ..if so, check for leap year + JR NZ,CHKDT0 ; else, jump + INC D ; make 29 days +CHKDT0: LD A,L ; check for day within range + DEC A ; have day > 0, check for <= max. days + CP D + JR NC,BADDAT ; ..anything else is error + + ; calculate 16-bit binary date since 1978 in days, works til 2157 + PUSH HL ; save month (H) and day (L) + LD H,0 ; null out month, leaving just days + EX DE,HL ; ..move to DE + LD L,C ; year in HL + LD H,B + LD BC,1978 ; start with base year in BC +DAYS0: OR A + SBC HL,BC ; is this the starting year ? + ADD HL,BC + JR Z,DAYS1 ; ..if so, jump + PUSH HL + LD HL,365 ; add days in non-leap year + ADD HL,DE ; ..to total days count in DE + EX DE,HL ; ..and put new days total in DE + POP HL + CALL LEAPYR ; is this a leap year ? + INC BC ; advance to next year + JR NZ,DAYS0 ; ..if not leap year, then loop + INC DE ; else, add a day + JR DAYS0 ; ..then loop + + + ; error routines, destination P2DOS field nulled +NODATE: INC DE ; advance source ptr for same routine + INC DE + DEFB 3EH ; ..fall through to 2nd POP with LD A,0D1H +BADDAT: POP DE ; restore Universal T&D string (-> hours) + POP HL ; restore destination addr for P2DOS date +BADDA1: CALL CLRM4 ; fill with 4 nulls + INC DE ; ..advance ptr to exit position + INC DE + DEC A ; set error flags (A= 0FFH, Zero clear (NZ)) + RET + + + ; DE= total days (year + day), BC= binary year, (Stack)= month and day + ; first day 0001H : Su 01 Jan 1978 + ; last day 8EADH : Fr 31 Dec 2077 + ; real last day FFFFH : Su 05 Jun 2157 +DAYS1: POP HL ; restore month and day + EX DE,HL ; date to HL, month/day to DE + PUSH HL ; ..and save binary date + LD HL,DMTABLE ; address days-of-month table + LD E,1 +DAYS2: LD A,D ; check for matching month + CP E + JR Z,DAYS4 ; ..exit when match + LD A,(HL) ; get days in this month + EX (SP),HL ; put table on stack, binary date to HL + ADD A,L ; add month's days to cum binary date + LD L,A + LD A,0 + ADC A,H + LD H,A + LD A,E ; check this month + CP 2 ; is it February ? + CALL Z,LEAPYR ; ..if so, check if leap year + JR NZ,DAYS3A ; jump if not Feb and/or leap year + INC HL ; else, bump cum binary date by 29 Feb +DAYS3A: EX (SP),HL ; put cum binary date to stack + ; ..and days-of-month table to HL + INC HL ; point to next month + INC E ; bump index counter + JR DAYS2 ; ..and loop + +DAYS4: POP BC ; exit here, put cum binary date to BC + POP DE ; restore Universal T&D string (-> Hrs) + POP HL ; ..and destination address + LD (HL),C ; put binary date in string + INC HL + LD (HL),B +MOVHM: INC HL + EX DE,HL ; swap src/dest pointers + LDI ; move BCD hours + LDI ; ..and BCD minutes + EX DE,HL ; restore pointers into correct regs for exit + XOR A ; set OK flags + RET ; and return + + + ;----- + ; calculate leap year correction + ; in: BC= year (binary, leap years = xxxxxx00B) + ; out: Zero Flag set (Z) = correction necessary, reset (NZ) = no corr +LEAPYR: BIT 0,C ; get lower part of date + RET NZ ; ..if not leap year, return + BIT 1,C ; test other bit + RET ; ..and return + + + ;----- + ; convert BCD to Binary + ; in: A= BCD digit + ; out: A= binary number +BCDBIN: OR A ; test if zero + RET Z ; ..if so, return (it's the same) + PUSH BC ; save register + LD B,0 ; set counter +BCDBI0: INC B ; bump counter + SUB 1 ; count down BCD + DAA + JR NZ,BCDBI0 ; ..till all gone + LD A,B + POP BC + RET + + + ;---- + ; convert Binary to BCD + ; in: A= byte to be converted + ; out: A= two packed BCD digits + ; Convert byte in A register to two packed BCD digits +BINBCD: PUSH BC ; save register + LD B,0FFH ; preset counter +BINBCL: INC B ; bump counter output + SUB 10 + JR NC,BINBCL ; loop bumping counter till no more 10's + ADD A,10 ; ..correct for underflow + LD C,A ; save low nybble here for a while + LD A,B ; ..and bring high nybble in A + ADD A,A ; move it into position + ADD A,A + ADD A,A + ADD A,A + ADD A,C ; add in low nybble + POP BC ; restore regs + RET + + + ;----- + ; convert P2DOS (CP/M+) form to Universal T&D string + ; in: HL= ptr to P2DOS (CP/M+) T&D + ; DE= ptr to destination buffer for Universal T&D + ; out: A= 0, Zero Flag set (Z), if conversion OK + ; A= 0FFH, Zero Flag clear (NZ), error (dest nulled) + ; HL= ptr to Seconds byte in P2DOS (CP/M+) T&D (not moved) + ; DE= ptr to Seconds byte in Universal T&D (not filled) +P2UTIM: PUSH DE ; save destination addr + LD E,(HL) ; get binary date to DE + INC HL + LD D,(HL) + INC HL + EX DE,HL ; put binary day/date in HL, P2D ptr in DE + LD A,H ; check for valid entry + OR L ; is date present ? + JR NZ,P2UTI0 ; ..if not null, then jump + POP HL ; get destination addr back + LD B,5 + CALL BADDA1 ; ..and null the U-time field + EX DE,HL ; put pointers in correct regs + RET ; ..and return to caller + +P2UTI0: PUSH DE ; save P2D pointer (-> Min) + LD BC,1978 ; beginning year +DMJ0: LD DE,365 ; set days in normal year + CALL LEAPYR ; check for leap year + JR NZ,DMJ1 ; ..if not leap year, then jump + INC DE ; else, add one day +DMJ1: OR A ; when # of days left.. + SBC HL,DE ; ..is less than days in year.. + JR C,DMJ2 ; ..year is in HL, so exit + JR Z,DMJ2 ; ..or if last day of year + INC BC ; bump starting year + JR DMJ0 ; ..and back for another try + + ; BC= binary year, HL= remaining days +DMJ2: ADD HL,DE ; compensate for underflow + LD A,1 ; start with month 1 (Jan) + LD D,0 ; prepare for 16-bit math + PUSH HL ; save days remaining + LD HL,DMTABLE ; address days-of-month table +DMJ3: LD E,(HL) ; get days in current month to E + CP 2 ; is it February ? + CALL Z,LEAPYR ; ..if so, check for leap year + JR NZ,DMJ4 ; ..if not leap year, then jump + INC E ; else, make 29 days +DMJ4: EX (SP),HL ; swap ptr (HL) with days remaining (Stack) + OR A + SBC HL,DE ; subtract days in month from remaining days + JR C,DMJ5 ; ..if we've gone too far, then exit + JR Z,DMJ5 ; ..or just far enough (last day of month) + EX (SP),HL ; swap back + INC HL ; point to next month in table + INC A ; bump month counter + JR DMJ3 ; ..and try again + + ; arrive here with binary year on Stack, relative month in A (Jan = 1), + ; days in that month in E, and binary year in BC +DMJ5: ADD HL,DE ; compensate for underflow + EX (SP),HL ; ..and put back on Stack + POP HL ; restore day in L + CALL BINBCD ; convert month (in A) to BCD + LD H,B ; ..moving year to HL + LD B,A + LD A,L ; convert day + LD L,C + CALL BINBCD ; ..to BCD + LD C,A + LD DE,100 ; subtract centuries, one by one.. +DMJ7A: OR A + SBC HL,DE + JR NC,DMJ7A ; ..until we go too far + ADD HL,DE ; then correct for underflow + LD A,L ; get year (tens and ones) + CALL BINBCD ; ..to BCD + POP DE ; restore P2D pointer (-> Min) + POP HL ; get Universal T&D string address + LD (HL),A ; store years + INC HL + LD (HL),B ; ..months + INC HL + LD (HL),C ; ..days + CALL MOVHM ; store hours and minutes, and set flags + EX DE,HL ; put U-time exit address in DE + RET ; ..and finish up elsewhere + + + ;------ + ; calculate offset within T&D entry, if one exists + ; out: HL= ptr to first byte of Create field +SETREC: LD HL,(DIRBUF) + LD BC,60H ; offset to Time and Date fields + ADD HL,BC + LD A,(HL) ; get byte + SUB 21H ; is TimeStamping present + JP NZ,NOSTD ; ..if not, quit here + + LD A,(SECPNT) ; get sector pointer + RRCA ; shift 2 times + RRCA + LD C,A ; save temporarily + RRCA ; shift 2 more times + RRCA + ADD A,C ; ..and add in again + LD C,A ; set for offset (C= 0, 10, 20) + ADD HL,BC ; add offset + INC HL ; ..and bump to Create Time start + XOR A ; set return status OK + RET + + ; day-of-month table +DMTABLE: DEFB 31,28,31,30,31,30,31,31,30,31,30,31 + + + + ;_______________________// Non-Banked // + CSEG + + ;----- + ; JP (HL) with bank context switching +JUMPHL: CALL RETMEM ; get current mem bank (BIOS fn #39 RETMEM) + LD (CURBNK),A ; save it + CALL SELTPB ; select TPA bank + CALL JPHL ; do the actual JP (HL) + LD A,(CURBNK) ; get bank # back + JP SELMEM ; select mem bank again (BIOS fn #27 SELMEM) + ; ..and let return from there +JPHL: JP (HL) + +CURBNK: DEFS 1 + + + + ;_______________________// Non-Banked // + CSEG ; technically not needed + ; but necessary to assemble identical REL file + + ;:::::::::::::::::::::::::::::::::::::::: + ;::::: Memory Bank Switching Routines + + ; bring SYSBNK into context (Banked mode) +SELSYB: PUSH AF + LD A,(OSYSBK) ; B/P Bios base +0x83 (offset SYSBNK) + JR SELBNK ; switch bank + + ; bring TPABNK into context (Non-banked mode) +SELTPB: PUSH AF + LD A,(TPABNK) ; get TPA bank number + ; ..and fall through + + ; select memory bank +SELBNK: CALL SELMEM ; BIOS fn #27 SELMEM (A= bank #) + POP AF + RET + + +;::::: DATA AREA (in CSEG) + +PATHAD: DEFB 1,0 ; Internal path - Drive A, User 0 + DEFB 0,0 ; blank entry + DEFB 0,0 ; blank entry + DEFB 0 ; ..and ending null + + ;----- + +TDFVCT: DEFW 0 ; time and date vector + + ;----- + +LOGIN: DEFW 0 ; Login vector +DSKWP: DEFW 0 ; Disk write protect vector +HDLOG: DEFW 0 ; Fixed disk login vector + + + END + + +;************************************************************************ +; Remarks jxl: +; When assembled as M-REL, this source file produces an _exact_ copy +; of ZS227G.ZRL included in available B/P Bios package(s). +; Compared to v1 (ZSDOS-GP.Z80) many code portions are unaltered, or +; show only slight modifications. Major changes result from banking and +; addition of universal T&D stamp routines, supporting DateStamper +; as well as P2DOS (CP/M+) stamps. +; Besides basic functionality (e.g. error handling), all I/O routines +; are located in non-banked memory. Many Disk routines begin in non-banked +; memory with just a small footprint, and are continued in banked memory. +; This is also the case for T&D stamp routines. With the exception of +; 4 bytes stored in /B2RAM/, all data bytes are located in non-banked +; CSEG code segment. +; +; A comment on function 152 Parse FileSpec: ZCPR 4.1 (Z41.ZRL) relies +; on that function. Thus, it cannot be removed. Even though most probably +; no other application might use it. Currently, the entire function is +; located in non-banked memory. A considerable amount of space could be +; reclaimed by moving this function (or parts of it) to banked memory. +; +; Possible optimisations noticed during disassembly are marked with +; "#####" in the comment. Speaking of which - non-banked and banked parts +; need to be sector-aligned, ie. BPBUILD fills the remainder of the last +; 128-byte block with zeros. In its current state, the non-banked part +; leaves 71 bytes unused. Or, in other words, a block could be saved +; if 57 bytes could be eliminated and/or moved to banked code section. +;************************************************************************ diff --git a/Tools/cpm/lib80/DSLIB.REL b/Tools/cpm/lib80/DSLIB.REL new file mode 100644 index 00000000..9fc51506 Binary files /dev/null and b/Tools/cpm/lib80/DSLIB.REL differ diff --git a/Tools/cpm/lib80/DSLIBS.REL b/Tools/cpm/lib80/DSLIBS.REL new file mode 100644 index 00000000..c1ad9618 Binary files /dev/null and b/Tools/cpm/lib80/DSLIBS.REL differ diff --git a/Tools/cpm/lib80/LIBS45.NOT b/Tools/cpm/lib80/LIBS45.NOT new file mode 100644 index 00000000..55ea363f --- /dev/null +++ b/Tools/cpm/lib80/LIBS45.NOT @@ -0,0 +1,7 @@ + 11 October 1993 +This library contains the REL versions of SYSLIB, Z3LIB, VLIB, and DSLIB +in both Microsoft REL and SLR REL form. The names have an "S" appended +to signify the libraries in SLR form. All libraries are of the 4.5 +release level. + Harold F. Bower + \ No newline at end of file diff --git a/Tools/cpm/lib80/SLINK0.REL b/Tools/cpm/lib80/SLINK0.REL new file mode 100644 index 00000000..acbc8358 Binary files /dev/null and b/Tools/cpm/lib80/SLINK0.REL differ diff --git a/Tools/cpm/lib80/SYSLIB.REL b/Tools/cpm/lib80/SYSLIB.REL new file mode 100644 index 00000000..23a57a4a Binary files /dev/null and b/Tools/cpm/lib80/SYSLIB.REL differ diff --git a/Tools/cpm/lib80/SYSLIBS.REL b/Tools/cpm/lib80/SYSLIBS.REL new file mode 100644 index 00000000..6659ff64 Binary files /dev/null and b/Tools/cpm/lib80/SYSLIBS.REL differ diff --git a/Tools/cpm/lib80/VLIB.REL b/Tools/cpm/lib80/VLIB.REL new file mode 100644 index 00000000..8b9c5c91 Binary files /dev/null and b/Tools/cpm/lib80/VLIB.REL differ diff --git a/Tools/cpm/lib80/VLIBS.REL b/Tools/cpm/lib80/VLIBS.REL new file mode 100644 index 00000000..a2af0edd Binary files /dev/null and b/Tools/cpm/lib80/VLIBS.REL differ diff --git a/Tools/cpm/lib80/Z3LIB.REL b/Tools/cpm/lib80/Z3LIB.REL new file mode 100644 index 00000000..cb7e0b35 Binary files /dev/null and b/Tools/cpm/lib80/Z3LIB.REL differ diff --git a/Tools/cpm/lib80/Z3LIBS.REL b/Tools/cpm/lib80/Z3LIBS.REL new file mode 100644 index 00000000..a5394582 Binary files /dev/null and b/Tools/cpm/lib80/Z3LIBS.REL differ