CP/M-3 BIOS ROUTINES ------ ---- -------- FOR A THINKER TOYS/MORROW DESIGNS DISK-JOCKEY DISK CONTROLLER. --- - ------- ---- ------ ------- ----------- ---- ---------- This disk contains the bios routines I have used for running CP/M-3 on my computer. I hope they may be useful for someone implementing CP/M-3 on their machine although they will have to make some modifications. My system has a Z80 cpu, a Thinker Toys/Morrow Designs 'Disk Jockey' disk controller (the memory mapped version, 1980 vintage) driving a single DSDD 8 inch disk drive, a 512 kbyte semidisk, a Microangelo display board, a Thinker Toys/Morrow Designs 'switchboard' io board, Tarbell tape handler, and 3 memory boards, 2 with 64K and one with 16K. I have a 4K common memory. If your computer looks something like this then these routines should be very useful if you are wanting to implement CP/M-3. Otherwise they might still save you some of the detective work I had to do. CP/M-3 fitted in well with my system and I now have just over 60K of memory available for programs despite the memory mapped disk controller board. Note that memory mapped part of the disk-controller board must not overlap the top 4K of memory which is used for common memory. The 4K of memory on my SSM cpu board (model CB2) provides the common memory and is especially convenient since it is accessible only by the Z80 and won't interfere with a second processor or require the blanking out of the corresponding blocks of the main memory boards - but note that the bank select code on the CB2 may be wrong, two bits being reversed on my one. As well as the routines supplied by DR you will need Microsoft's M80 macro assembler, or you will have to translate my Zilog mnemonics to the Intel ones which can then be assembled using RMAC supplied with CP/M-3. To build the CP/M-3 bios one needs to build a series of modules which are assembled and then linked together. The first of these modules, BIOSKRNL.ASM, is supplied by DR and is not modified except to set 'banked' to false if one is building the unbanked version. (You must build the unbanked version first, get it debugged, then modify it to get the banked version - some routines such as Morrow's FORMT# will run only under the unbanked version so you will need it anyway). The source for the rest of the modules I have used are on this disk and I will describe how they work and what modifications you might need to make. In many cases you must set 'banked' to false at the top of these routines when you want the unbanked version. SCB.ASM This defines the locations in the System Control Block for the rest of the bios. The version here is the same as DR's except that I have added the locations of the variables that determine the disk search order, the temporary default disk, and whether .COM or .SUB files are executed. You need make no change to this. MOVE.MAC This contains the routines for copying blocks of data and setting banks. This includes the routines ?move, ?xmove, ?bank described by DR and also ?bank0 for switching to bank 0 and setting up a temporary stack, ?rbank for returning to the current bank and ?trans for transferring large blocks of data from one bank to another. A buffer is set up in common memory for doing the transfers. Only ?move is required in the unbanked version. The only change you will need to make is to the routine ?bank. My processor board can switch the extended address and this is done with an 'out' instruction. The disk controller has bank select and so can be turned on if bank 0 is required, otherwise switched off. You may need different code here. If your system uses interrupts it would be advisable to disable them when switching to a bank other than bank 1. CHARIO.MAC This contains the io routines for the console, keyboard, printer, auxiliary devices, etc. DR's version is for a computer that can switch baud rates and is much more complicated than is required for a simple machine like mine. I have still set up a table containing the baud rates so that DR's system programs can look at them but do not need facilities for changing them. Five routines are required: ?cinit to initialize devices, ?ci for inputing characters, ?co for outputing characters, ?cist for getting input status, ?cost for getting output status. Each of these routines involves a call to a routine 'jump' which, together with a table following that call transfers control to the code appropriate for the particular device and function. Note that ?cist and ?cost must not change register bc. I have implemented 3 versions of the code to drive the Micro-Angelo board (including double size output) and this will be of no interest to people who don't have a Micro-Angelo board. Much of the code is for interfacing the MA board and everything looks a lot simpler when this is deleted. The standard Thinker Toys console input/output is the second device. This routine jumps into the middle of the disk controller code to get input characters (so that bit 8 is not stripped off) and you might need to change this. You may also need to modify the printer interface - which is attached to a parallel port - and the port numbers. (Its probably better to access a tape and switchboard directly with 'in' and 'out' instructions since access via the bios may be too slow and characters may be lost). You will also want to change what the devices are called to what you have attached to the various ports (I have a MODEM and a MOUSE attached to the switchboard serial ports). DISKDEFN.ASM This contains the disk definitions to be generated with DR macros in CPM3.LIB. Although I have only one disk I want to be able to call it drive A, B or C and so have defined dph-s for each of these. Drive D is the semidisk, so delete references to drive D and semidisk if you don't have a semidisk. The dph-s and skew tables are for the various formats used by Thinker Toys. The order of the names in the table 'dskdef' is intended to fit in with the format code returned by the disk-controller. DISKHNDL.MAC This contains the disk handling routines and includes the routines for reading, writing, disk selection, and determining the format of the disk. I assume the disk jockey memory has its origin at E000H and in the banked case that there is real memory from E800H to EBFFH. Numerous changes would have to be made in this routine for other disk controllers and different versions of the disk-jockey might require different equates. 'djleav' and 'djprep' point to routines which enable one to determine the format of a disk without doing a read or write and in effect define the code which is common to read and write. If you can't find equivalent routines in your system, just read into a spare piece of memory to determine the disk format. The main problems which must be solved in this module are determination of the disk format, requesting that the disk be changed when a different drive is requested and reading to or writing from a memory bank other than bank 0. The disk jockey codes returned for indicating the disk format (bit 5 = 1 for double sided, bits 2,3 = 0 for 128 byte sectors, 1 for 256 byte sectors, 2 for 512 byte sectors, 3 for 1024 byte sectors) mesh with the order of the tables given in DISKDEFN.ASM. Divide this code by two, add the address, 'dskdef' to get the address of the appropriate skew table, add a further 8 to get the appropriate dpb table. Some rewriting will be required for a different format code. Note that for double sided disks, we pretend that the disk has 154 tracks the 0th track on side 0 being called track 0 and the 0th on side 1 being call track 1 etc. If 'check' is set to true details of each disk operation are returned to the console. For multidisk systems, delete the drive select code following entry 'finita' and replace the code following entry 'dsk' with code that picks up the drive name and selects that drive. Different disk controllers may have different error codes and hence may require different code following the calls to djread, djwrite, djleav (Disk-jockey read and writes return a status variable in register A with bit 7 set if the drive door is open, bit 6 set if a write is attempted to a write protected disk, bit 5 set for an illegal dma address, bit 4 set for an illegal sector, and bits 0,1,2 or 3 set for various read or write errors). SEMIHNDL.MAC The semidisk handling routines - good only for a 512K semidisk, version I (ie parity checking must be done with software). Do not include if you haven't got a semidisk. The routines here are adapted from those supplied by Semidisk and are given here with the permission of Semidisk. BOOT.MAC This is for firing up the system after CP/M-3 is loaded. It has two jobs - setting up a variety of constants and loading the CCP into a spare bit of memory (in the present case above the disk-jockey's memory in the unbanked case and the bottom of memory bank 2 in the banked case). You will need to make the following changes: console out and console in etc will be different and you probably won't want disk D being your temporary disk (leave out that assignment). For a start, unless you have the same memory arrangements as mine, I suggest you always load the CCP from disk, by deleting the code following ?rlccp and simply jumping to ?ldccp and also delete the code following 'if banked' in the section following ?ldccp, replacing it with ret. If you have a clock, you can implement the entry ?time. This concludes the description of the bios routines and you can now assemble and load them, and then use GENCPM.COM to form CPM3.SYS. In the unbanked case use a submit file like the following rmac.com bioskrnl m80.com = boot m80.com = move m80.com = chario rmac.com diskdefn m80.com = diskhndl m80.com = semihndl rmac.com scb link.com bios3[os,q]=bioskrnl,boot,move,chario,diskdefn,diskhndl,semihndl,scb era cpm3.bak ren cpm3.bak=cpm3.sys gencpm.com and in the banked case use rmac.com bioskrnl m80.com = boot m80.com = move m80.com = chario rmac.com diskdefn m80.com = diskhndl m80.com = semihndl rmac.com scb link.com bnkbios3[b,q]=bioskrnl,boot,move,chario,diskdefn,diskhndl,semihndl,scb era cpm3.bak ren cpm3.bak=cpm3.sys gencpm.com I include the file GENCPM.DAT for my system for the banked case which might give some indication as to the answers to the questions GENCPM will ask. Note that in the banked case you must give the bottom of the disk-controller memory as the bottom of common memory (even though this is a lie). However, you are not yet ready. You must also build CPMLDR which is a cut down CP/M used for loading CPM3.SYS. In my system two modules are required. DDLDR.ASM This is a cut down version of DISDEFN.ASM and only drive A need be defined. LDRBIOS.MAC This is a cut down version of the rest. It starts with a CP/M-3 jump vector and by disassembling a trial version of CPMLDR I was able to find which entries were actually used. The remarks made under DISKHNDL.MAC also apply here. One can now assemble CPMLDR.COM link.com cpmldr[L100]=cpmldr,ldrbios,ddldr One is now ready to go since CPMLDR can be called from CP/M-2 (or unbanked CP/M-3). The manual gives some instructions for debugging using SID (remember, SID will get upset if it hits a Z80 instruction). However the main moral is to start up with the simplest possible version. Unless you are almost exactly following mine, initially forget disk swapping or variable density, or even multiple drives if you have these. LOADSYS.MAC You want CP/M-3 to boot directly on switch on rather than getting CP/M-2 and then running CPMLDR. I have written a routine LOADSYS.MAC to load CPMLDR onto track 1 of the disk and a preliminary loader onto track 0. This works for the 4 disk formats recognised by the disk-jockey. Because slightly different versions are required for the different disk formats part of the routine is used for identifying the disk format from the disk tables. The actual loading process is as follows. On switch on the cpu starts executing code in the disk-jockey rom. This loads the first record from track 0, side 0 of the disk in drive A to memory starting at, in my case, location E700H. Control is then transferred to E700H where, hopefully, there is now a routine for loading CPMLDR from track 1 of the disk. Apart from possible adjusting location E700H, there should be almost no modifications to the bulk of this routine for a standard disk-jockey disk controller. This version allows CPMLDR to be loaded onto drive A, B, or C. You may wish to change this by changing the 'cp 3' following the label 'uc'. However the disk controller calls in the primary loader rdcpm must be checked. This routine should be compiled with M80 and then linked with Microsoft's L80. I have also included several other files to help you implement or run CP/M-3. REBOOT.MAC This does the same job as a reset key and is unnecessary if you have a reset key. It is used for restarting your system after building a new version of CPM3.SYS, CPMLDR, or LOADSYS. You will need to rewrite the bank select and the boot location. Assemble and link with M80 and L80. SEESCB.RAT, ACCSCB.MAC A ratfor routine and M80 subroutine for displaying the contents of the System Control Block. BARB2.MAC This is for checking that you have memory banks where you think you have them. It relocates itself in common memory then requests a bank number (control-c will cause a reboot at this stage) and then a range of memory to be tested. This routine is very untidy if a whole block of memory is missing and you might like to tidy it up. Nevertheless, it is very useful for checking that bank select is working and your memory is really there. You will need to change the console input and output routines, the reboot location, and the bank select routine. IF.MAC Used for putting simple conditional statements into submit files. For example IF $1=YES :PROG1 IF $1#YES :PROG2 in a submit file will run PROG1 if the first parameter is the submit call is YES, otherwise it will run PROG2. OVLMNGR.MAC DR's LINK can produce overlayed programs. However to use this facility you need a routine in DR's PL1 runtime library. OVLMNGR is an attempt to simulate this routine for use with, say, Fortran programs with Microsoft conventions. Only overlay method 1 is implemented and an additional restriction is that a maximum of two parameters may be passed to the subroutine heading the overlay. PRINT.MAC This is an RSX for printing a file while allowing most normal computer operations to continue simultaneously. That is, it is a CPM-3 translation of the 'unspool' program that is available for CPM-2. To form the code file, one needs to go through the following sequence of instructions. m80.com = print link.com print [op] rename print.rsx=print.prl era print.com gencom.com print [null]  you have a reset key. It is used for restarting your system after building .