The BIOS is the machine-dependent part of CP/M. In theory, all you need to do is change the BIOS and CP/M will work on a different machine. The same used to be true of MSDOS...
The BIOS begins with the following jumps to service routines:
JMP BOOT ;Cold start routine JMP WBOOT ;Warm boot - reload command processor JMP CONST ;Console status JMP CONIN ;Console input JMP CONOUT ;Console output JMP LIST ;Printer output JMP PUNCH ;Paper tape punch output JMP READER ;Paper tape reader input JMP HOME ;Move disc head to track 0 JMP SELDSK ;Select disc drive JMP SETTRK ;Set track number JMP SETSEC ;Set sector number JMP SETDMA ;Set DMA address JMP READ ;Read a sector JMP WRITE ;Write a sector
In CP/M 2 and later, the following extra jumps appear:
JMP LISTST ;Status of list device JMP SECTRAN ;Sector translation for skewing
In CP/M 3, a further set of jumps is present:
JMP CONOST ;Status of console output JMP AUXIST ;Status of auxiliary input JMP AUXOST ;Status of auxiliary output JMP DEVTBL ;Address of devices table JMP DEVINI ;Initialise a device JMP DRVTBL ;Address of discs table JMP MULTIO ;Read/write multiple sectors JMP FLUSH ;Flush host buffers JMP MOVE ;Move a block of memory JMP TIME ;Real time clock JMP SELMEM ;Select memory bank JMP SETBNK ;Select bank for DMA operation JMP XMOVE ;Preload banks for MOVE JMP USERF ;System-depedent functions JMP RESERV1 ;Reserved JMP RESERV2 ;Reserved
This function is completely implementation-dependent and should never be called from user code.
Reloads the command processor and (on some systems) the BDOS as well. How it does this is implementation-dependent; it may use the reserved tracks of a floppy disc or extra memory.
Returns its status in A; 0 if no character is ready, 0FFh if one is.
Wait until the keyboard is ready to provide a character, and return it in A.
Write the character in C to the screen.
Write the character in C to the printer. If the printer isn't ready, wait until it is.
Write the character in C to the "paper tape punch" - or whatever the current auxiliary device is. If the device isn't ready, wait until it is.
Read a character from the "paper tape reader" - or whatever the current auxiliary device is. If the device isn't ready, wait until it is. The character will be returned in A. If this device isn't implemented, return character 26 (^Z).
Move the current drive to track 0.
Select the disc drive in register C (0=A:, 1=B: ...). Entered with DE=0 or FFFFh. If DE=0, the disc will be logged in; if it is FFFFh, no attempt will be made to read it.
SELDSK returns the address of a Disc Parameter Header in HL.
Set the track in BC - 0 based.
Set the sector in BC. Under CP/M 1 and 2 a sector is 128 bytes. Under CP/M 3 the sector size is given in the Disk Parameter Block.
There has been discussion in comp.os.cpm about whether the parameter to this function is a byte or a word. The conclusion (based on examining the BDOS source) was that it is a word.
The next disc operation will read its data from (or write its data to) the address given in BC.
Read the currently set track and sector
Write the currently set track and sector. C contains a deblocking code:
C=0 - Write can be deferred C=1 - Write must be immediate C=2 - Write can be deferred, no pre-read is necessary.
Return status of current printer device.
Returns A=0 (not ready) or A=0FFh (ready).
Translate sector numbers to take account of skewing.
On entry, BC=logical sector number (zero based) and DE=address of translation table. On exit, HL contains physical sector number.
Return status of current screen output device.
Returns A=0 (not ready) or A=0FFh (ready).
Return status of current auxiliary input device.
Returns A=0 (not ready) or A=0FFh (ready).
Return status of current auxiliary output device.
Returns A=0 (not ready) or A=0FFh (ready).
Return in HL the address of the devices table, or 0 if the devices table isn't implemented.
The devices table will be visible to programs without the need for bank switching, ie. it will be in common memory.
The device table contains one entry for each character device. Each entry is formed:
DEFB 'NAME ' ;Name, 6 bytes. If the first byte is zero, ;this is the end of the table. DEFB mode ;Bitmapped value: ;Bit 0 set => can input from this device ;Bit 1 set => can output to this device ;Bit 2 set => can change the baud rate ;Bit 3 set => supports XON/XOFF ;Bit 4 set => is using XON/XOFF ;Bits 5,6,7 set to 0. ; Amstrad extension: If bit 7 is set, output ;to the device does not time out. DEFB baudrate ;Coded speed, 1-15 or 0 if speed can't be ;changed. ;Rates are 50,75,110,134.5,150,300,600,1200, ; 1800,2400,3600,4800,7200,9600,19200.
The maximum number of devices allowed in CP/M Plus is unclear. The documentation variously says there can be 12 or 13, while the DEVICE.COM source code suggests 15.
Reinitialise character device number C - called when the device's settings (baud rate, mode etc.) are changed.
Return in HL the address of the drive table, or 0 (or 0FFFFh, or 0FFFEh) if the drive table isn't implemented. The drive table contains 16 pointers to the Disc Parameter Headers of the 16 disc drives A-P; if a pointer is 0 it means that the corresponding drive does not exist.
The drive table is usually (but not always) in common memory (ie accessible by user programs).
Notify the BIOS that the BDOS is intending to transfer a number of consecutive disc sectors with READ or WRITE. Entered with C = number of calls that will be made; up to 16k of data will be transferred.
The idea is that after the MULTIO call, the BIOS can choose to transfer all the data in the first READ/WRITE operation, and then not to do anything on the subsequent (n-1) operations.
Write any pending data to disc.
Returns A=0 if successful, 1 for physical disc error, 2 for drive R/O.
This function is only useful when the BIOS is doing the deblocking - ie, the physical sector size is not the size that the BIOS reports to the BDOS.
Move BC bytes of memory, from the address in HL to the address in DE. Should return HL and DE pointing to the first addresses not copied. If XMOVE is used before this function, data are moved between two memory banks.
Get the current date and time into the SCB (at CBOOT-0Ch). HL and DE must be preserved. If C=0FFh, then set the time from the SCB instead.
The format of the 5-byte buffer is:
DW day ;Day 1 is 1 Jan 1978 DB hour ;packed BCD DB minute ;packed BCD DB second ;packed BCD
Set the current bank to the number in A. Bank 1 is the bank in which user programs run (the TPA); Bank 0 and any other banks are used by CP/M for disc buffers or as a RAMdisc.
Set the bank to be used for the next read/write sector operation. The bank number is passed in A.
After XMOVE, the next call to MOVE will move data between different memory banks. Call XMOVE with C=source bank and B=destination bank.
This function is reserved for the author of the BIOS to add any extra features. On Amstrad computers, for example, this call accesses the extended BIOS functions.
These calls are reserved and contain JMP 0
instructions.