Amstrad Extended BIOS Internals
Any Amstrad CP/M Plus system (meaning those created by Locomotive Software for the CPC, PCW and Spectrum +3) has an XBIOS, which lives at 80h in CP/M bank 0. It exposes a number of functions for things like reading, writing and formatting floppy discs, reassigning keys on the keyboard, setting options for the serial port, and so on.
In a conventional banked CP/M Plus system, bank 0 holds only the banked BDOS, a BIOS to manage the hardware, and possibly some disc buffers. In an Amstrad/Locomotive CP/M Plus system, the banked BIOS is small and pretty much hardware-independent; all it does is wrap the XBIOS calls in CP/M character and disc devices.
Internally, the XBIOS is divided into modules (this is why some functions in the jumpblock have names starting DD, some starting CD, some starting TE and so on). I have given these modules names based on the functions in them, on other sources where available, and invented my own names if necessary. When disassembling, it's often quite easy to tell where one module stops and another starts (at least in early versions) because the modules are aligned on 8- or 16- byte boundaries.
I have derived the information in this document from the following CP/M boot files:System fileMachineVersion C10CPM3.EMS CPC 1.0 CPM3SEMI.EMS CPC 1.0 (patched to include driver for Dk'tronics Silicon Disc) S10CPM3.EMS Spectrum +3 1.0 J11CPM3.EMS PCW 8000 1.1 J12SCPM3.EMS PCW 8000 1.2 (Spanish) J14CPM3.EMS PCW 8000 1.4 J14FCPM3.EMS PCW 8000 1.4 (French) J14GCPM3.EMS PCW 8000 1.4 (German) J14SCPM3.EMS PCW 8000 1.4 (Spanish) J17CPM3.EMS PCW 8000 1.7 J17CPM3.EMS PCW 8000 1.7H J11CPM3.EMT PCW 8000, 9256, 10 1.11 J12CPM3.EMS PCW 8000, 9256, 10 1.12 J14CPM3.EMT PCW 8000, 9256, 10 1.14 J15CPM3.EMT PCW 8000, 9256, 10 1.15 J21CPM3.EMS PCW 9512 2.1 J29CPM3.EMS PCW 9512 2.9 J21CPM3.EMT PCW 9512, 9512+ 2.11 J22CPM3.EMS PCW 9512, 9512+ 2.12 J25CPM3.EMS PCW 9512, 9512+ 2.15 J25CPM3.EMT
If you have any other versions of the system file, feel free to share them with me.
On the CPC, CP/M Plus runs as an application under the CPC's ROM firmware. This is the memory layout of bank 0 (with areas owned by the XBIOS shown thus):0000-007F Used by CPC firmware 0080-01FF
The XBIOS jumpblock.
Also contains initialisation code and displays the sign-on message.0200-03FF
CD: Character Devices (code segment)
Routes character I/O to/from the screen, keyboard, printer and serial interface. Drives the serial interface at the hardware level; the printer and keyboard are handled by the firmware, and the screen by TE below.0400-0AEF
TE: Terminal Emulator (code segment)
Interprets ESCape sequences sent to the screen device and converts them into
SCR_* calls to the CPC firmware.
All floppy access, including reading, writing and formatting discs. 0F00-3CFF CP/M banked BDOS 3D00-3FFF CP/M banked BIOS 4000-7FFF Video RAM 8000-87FF Font 8800-89FF System message table. 8A00-B0CF CP/M disc buffers B0D0-B0FF DD data segment. B100-BE3F Used by CPC firmware. BE40-BEEF CD and TE data segments. BEF0-BFFF Used by CPC firmware. C000-F5FF The top of the TPA. F600-FBFF CP/M resident BDOS. FC00-FF9F CP/M resident BIOS. FFA0-FFDF
Floppy transfer code.
Used when reading and writing floppy data. This code has to be in common memory because the data may be coming from or going to any CP/M bank.FFE0-FFFF
XBIOS data transfer area.
Used by XBIOS calls to return data structures to code that might be in different banks. Used to return floppy results (for
DD_L_* calls), addresses of data buffers (for
CD_INFO call) and so on.
Also contains a flag to say whether keyboard input is ready. This allows a fast check by the resident BIOS, without needing to do a bank switch.
The PCW (Old World)
The original versions of CP/M supplied with the PCW8256 (versions 1.2, 1.4) have a similar layout to the CPC version (give or take the constraints of hardware, such as the position and size of video RAM). However, the PCW doesn't have a firmware ROM, so it has to provide modules of its own to do the same job.
The addresses in this table come from BIOS 1.2. Those in the more common 1.4 are slightly different, but the arrangement of modules is the same.0000-007F
Zero Page (see below).
Contains the Z80 Restart vectors, which on the PCW are used to call code in other memory banks. Also contains current memory paging status and memory size.0080-022F XBIOS jumpblock and initialisation code. 0230-043F CD: Character Devices 0440-08CF TE: Terminal Emulator 08D0-0ACF
MSG: Displays system messages.
In the CPC version, this is found about halfway through TE rather than being a separate module.0AD0-100F DD: Disk Devices 1010-13EF
KM: Keyboard Manager
This handles scanning the PCW's memory-mapped keyboard, allows keys to be redefined, and provides the required
KM_* functions that (on a CPC) would be provided by the firmware.
As with KM, this performs screen access (drawing characters, scrolling or blanking areas, and so on) that on the CPC would have been provided by the firmware.1690-182F Default keyboard layout. 1830-1B2F System messages. As for the CPC, but also adds all the printer status messages. 1B30-1D3F
NMI: Non-Maskable Interrupt handler
The PCW uses the Z80 Non-Maskable Interrupt to handle floppy disc reads and writes. This module contains the NMI handlers, and code to notify the rest of the system when disc access is about to begin or end.1D40-203F KL: Kernel (Part 1) 2040-261F
KL: Kernel (Part 2)
KM_ functions, the KL module provides the kernel functions used by CP/M. In fact, it provides more than are used by CP/M; CPC functions such as
KL_TIME_SET are present even though CP/M doesn't use them.
The kernel is divided into two modules. The first one handles interrupts, processes and semaphores; the second one manages events, tickers and kernel memory allocation.2620-286F Data segments, in the order KL, CD, TE, MSG, NMI, DD, KM, SCR. 2870-58FF CP/M disc buffers 5900-5903 Buffer control block linked list: head pointers. 5904-592F Unused 5930-7FFF
Though the screen can display 32 lines of text, the XBIOS allocates memory for 33. The extra line is used to display the printer status bar; using the Roller-RAM system, it gets swapped in/out instead of the bottom line of the screen.
Not all the video RAM is visible in bank 0. The remainder, plus the font, are only visible in the 'screen environment' memory configuration.8000-8BFF CP/M disc buffers 8C00-B9FF CP/M banked BDOS BA00-BFEF CP/M banked BIOS BFF0-BFFF Memory-mapped keyboard. C000-F5FF The top of the TPA. F600-FBFF CP/M resident BDOS. FC00-FF9F CP/M resident BIOS. FFE0-FFFF XBIOS data transfer area.
The process and semaphore features in the kernel are used for dot-matrix printer support. Semaphores are used to block disc access while the printer is active (or vice versa), while processes manage different aspects of the printer. In a PCW8256 CP/M system, four processes will be in existence, at different priority levels:
Priority 32: CP/M Priority 48: Printer control state Priority 56: Screen dump Priority 60: Printer hardware driver
Normally, the three printer processes will be blocked on semaphores. If they are invoked (eg, by the right key combination, or by sending output to the printer) the appropriate semaphore will be raised. The corresponding process will then have a higher priority than CP/M, and so will run until it next becomes blocked.
The PCW (New World)
By the time of 8512 CP/M version 1.7, the XBIOS memory map had been rearranged to support loadable drivers. This organisation was subsequently used by BIOS 2.1 on the PCW 9512 and all subsequent releases.
I have seen two versions of 1.7: 1.7, which can't load drivers, and 1.7H, which can. The two are identical in all other aspects. My guess is that at this time, the BIOS could be built in two versions: vanilla, which couldn't load drivers, and 'H', which could. Likewise, BIOS 2.1 can't load drivers; according to my theory, 2.1H, if it ever existed, would have been able to.
The addresses in this table come from BIOS 2.9. Other versions differ.0000-007F
Zero Page (see below).0080-01D7 XBIOS jumpblock and initialisation code. 01D8-024F Helper code for the daisywheel printer. 0250-067F
On a daisywheel system, the message area is 256 bytes larger than on a dot-matrix system. So NMI is at 0680h in version 2.9, but at 0580h in version 1.9.0680-08BF NMI code segment 08C0-114F KL code segment 1150-1213 Data segments for KL and NMI 1214-3D7F Available for loadable drivers or disc buffers. 3D80-3F4F
CD: General character device management.3F50-41A7
CD: CPS8256 serial port driver41A8-4567 KM: Keyboard Manager 4568-485F SCR: Screen functions 4860-49FF Default keyboard layout 4A00-4ECF TE: Terminal emulator 4ED0-5137 MSG: System message display 5138-56FF DD: Disk Devices 5700-58DF Data segments for the internal device drivers, in the order MSG, KM, SCR, TE, DD, CD 58E0-5907 Device driver tables 5904-592F Unused 5930-7FFF Video RAM. 8000-8BFF Available for loadable drivers or disc buffers. 8C00-B9FF CP/M banked BDOS BA00-BEFF CP/M banked BIOS BFF0-BFFF Memory-mapped keyboard. C000-F5FF The top of the TPA. F600-FBFF CP/M resident BDOS. FC00-FF50 CP/M resident BIOS. FF51-FFDF Available for loadable drivers: additional disc DPBs. FFE0-FFFF XBIOS data transfer area.
The new layout keeps the kernel in the bottom 16k (where it needs to be in order to access other memory banks) but pushes all the hardware drivers up so that they grow down from 58E0h — and, importantly, come down below 4000h. This is because, when disc transfers are done, the area from 4000h-7FFFh contains the source/target memory. Since any bank could be present in that area when the driver is called, the driver itself can't be allowed to occupy that space. Having the built-in CP/M drivers live there gets round the problem nicely.
(Note that NMI, which handles data transfers for the built-in floppy driver, is not in that area. It's down at the bottom of memory with the kernel).
Loadable device drivers cause a big change to the undocumented areas of the XBIOS jumpblock. Previously, the BIOS would do character I/O by calling the jumpblock with a device number. Now, it looks up the device's character device jumpblock in the table of character devices at 58E0h, and jumps straight to it.
At boot time, a loadable device manager is present in memory (for BIOS 2.9, at 0EDA0h; this varies depending on version). The device manager searches the boot disc for files ending in .FID. If any are found, it loads them into memory and allows them to add themselves to the BIOS as a character or disc device. The XBIOS registers its built-in character devices (screen, keyboard etc.) with this manager at boot time.
The Spectrum +3
Spectrum +3 CP/M appears to have branched off the PCW tree at about version 2.8 (with a few fragments, such as scrolling error messages, coming from CPC CP/M).
Like the 'new-world' PCW XBIOS, the Spectrum XBIOS comes in two parts, with the first half containing the jumpblock and messages, and the second half holding device drivers. Though the two parts are stored separately in the EMS file, they end up in a contiguous block of memory.
The major difference in +3 CP/M is that there is no KL (kernel) module. Rather than individual modules registering timers, event blocks, interrupt handlers and so forth, the 50Hz ticker interrupt handler is hardwired to perform the necessary functions.0000-007F
Zero Page (see below).
Contains the hard-wired timer interrupt handler.0080-016F XBIOS jumpblock and initialisation code. 0170-01EF The same library of helper routines as on the PCW9512. This despite the fact that they're only used by the 9512 daisywheel printer driver, which the Spectrum doesn't have. 01F0-039F
CD: General character device management.04D0-05AF
CD: RS232 serial port driver05B0-08FF KM: Keyboard Manager 0900-0F5F SCR: Screen functions 0F60-100F Default keyboard layout 1010-1517 TE: Terminal emulator 1518-178F MSG: System message display 1790-1DDF DD: Disk Devices 1DE0-21C7 Data segments for the internal device drivers, in the order MSG, KM, SCR, TE, DD, CD 21C8-21ED Device driver tables 21EE-2417 Unknown 2418-2FFF Available for loadable drivers or disc buffers. 3000-3FFF Fonts 4000-5AFF
There is a second page of video RAM in CP/M bank 2 for the right-hand half of the 24×80 video mode.5B00-8BFF Available for loadable drivers or disc buffers. 8C00-B9FF CP/M banked BDOS BA00-BFFF CP/M banked BIOS C000-F3FF The top of the TPA. F400-F9FF CP/M resident BDOS. FA00-FD4C CP/M resident BIOS. FD4D-FDDB Available for loadable drivers: additional disc DPBs. FDDC-FF53 Serial port driver routines. These are timing-critical and need to run in uncontended memory. FF54-FFDF Floppy transfer code. FFE0-FFFF XBIOS data transfer area. On the +3 this contains, inter alia, the BANKM and BANK678 variables.
In PCW CP/M, the first 128 bytes of bank 0 are laid out like this:0000 RST 0: Jump to a function in the bank 2 environment. Takes the address as an inline parameter. 0003 (2.9+) Jump to the address in BC 0005 (2.9+) Jump to the address in DE 0007 (2.9+) Jump to the address in HL 0008 RST 8: Jump to a function in the screen environment. Takes the address as an inline parameter. 000B (2.9+) Jump to the address in IX 000D (2.9+) Jump to the address in IY 0010 (2.1+) RST 10. Does nothing. 0018 (2.1+) RST 18. Does nothing. 0020 RST 20. Jump to code in an arbitrary memory environment. Takes a word as an inline parameter, which points to a 4-byte structure:
DEFW address DEFB bank to page in at 4000h DEFB bank to page in at 8000h0028 RST 28. As RST 20, but the 4-byte structure directly follows the RST. 002B As RST 20, but the address of the 4-byte structure is passed in HL. 0030 (1.4+) RST 30: Kernel panic. Disables interrupts and enters a tight loop. Presumably used when debugging new versions. 0033 Ascii 'BREAK' 0038 RST 38: Z80 mode 1 interrupt handler. 003B Ascii 'Patch' 0040 (2.1+) Hardware bitflags (returned in L by CD INFO) 0042 (2.1+) 0FFh if second drive present, otherwise 0. In version 1.7H (only) this is at 40h. 004C (2.11+) Bit 5 set if Shift+Extra+Relay pressed. 0060 Memory bank paged in at 0000h 0061 Memory bank paged in at 4000h 0062 Memory bank paged in at 8000h 0063 Memory bank paged in at C000h 0064 Frame flyback counter 0065 Frame flyback maximum (6 on a UK PCW, 5 on a US model) 0066 NMI handler 007F Number of 16k memory banks in system
For comparison, the same area of memory in Spectrum +3 CP/M looks like this:0000 RST 0: Default timer interrupt handler. 0020 RST 20: SVC_CATCHUP — perform a subset of timer interrupt functions. 0030 RST 30: Kernel panic 0038 IM 1 interrupt handler. 003B Step down the 50Hz system clock to a 1Hz ticker for CP/M. 0054 Set the border colour to A. 0075 0FFh if a second floppy drive is present, else 0.
Disk Parameter Headers
Amstrad CP/M uses an extended version of the standard CP/M Plus DPH. There are two variants, for Old World and New World memory layouts:
In an Old World memory layout, the standard DPH is preceded by ten bytes. These match the Extended Disk Parameter Header in the Digital Research sample BIOS, described in §4.7.3 of the CP/M 3 System Guide:
-00A Word Write function -008 Word Read function -006 Word Select function -004 Word Init function -002 Byte Physical drive number (floppies only) -001 Byte Drive type (always 0?) 0000-0018 Standard CP/M Plus DPH
The first three functions should return results in the same format as their BIOS counterparts WRITE, READ and SELDSK respectively. On entry IX will hold the address of the drive DPB, and DE will hold the address of the DPH.
The fourth function appears to have been intended for drive initialisation, but is never called.
The track, sector and transfer address used by these functions are in a data structure at 0BEF0h [CPC] or 0BDF0h [PCW]. This corresponds to the structure beginning @adrv in the CP/M 3 sample BIOS:
0 DB @adrv ;Selected logical drive 1 DB @rdrv ;Selected physical drive (from the byte at DPH-2) 2 DW @trk ;Track passed to SETTRK. 4 DW @eect ;Sector passed to SETSEC. 6 DW @dma ;DMA address passed to SETDMA. 8 DB @cnt ;Multiple I/O count passed to MULTIO 9 DB @dbnk ;DMA bank passed to SETBNK
In the New World memory layout, the list of functions is replaced by a single reference to a jump table:
-004 Word Address of Block device jump table -002 Byte Physical drive number (floppies only) -001 Byte Drive type (always 0FFh?) 0000-0018 Standard CP/M Plus DPH
A rough outline of development
Based on the CP/M versions I have, here are my best guesses at the order of the versions, and what changed when:
- CPC 1.0
- The original.
- PCW 1.1
- The first version I have for the PCW, though it's likely that version 1.0 existed as well.
- PCW 1.2
- Most of the changes appear to be to support the creation of foreign-language CP/M versions:
- The keystrokes used for Retry, Ignore and Cancel can now be localised; in 1.1 they were hardcoded.
- The default screen language and the default matrix printer language are localised, rather than hardcoded.
- System messages can contain accented characters.
- Some changes to the keyboard layout. Shift+STOP now generates expansion token 80h, not a literal Control-C; and Alt+STOP is ignored, rather than generating ESCape.
- Some tweaks to paper feeds in the dot-matrix printer driver.
- PCW 1.4
- The most common version for the 8256/8512, supplied with many of the machines, and was used to provide illustrations for the manual.
- Change to the dot-matrix printer font: The " and ' characters are chisel-like, not curly.
- The CPS8256 can now be driven in interrupt mode.
- The floppy driver uses a semaphore to signal completion, not a simple on/off flag.
- There is a kernel panic (RST 30h) which is invoked if the kernel runs out of memory or a process descriptor gets corrupted.
- PCW 1.7
- New World memory layout.
- New escape code in the terminal emulator:
ESC @(insert character)
- PCW 1.7H
- Supplied with the ASD HD20 hard drive.
- Includes code to load external device drivers (*.FID)
- In all other respects identical to 1.7.
- PCW 2.1
- Supplied with the PCW9512.
- Support added for the PCW9512 and its daisywheel printer.
- Does not include code to load *.FID drivers.
- Floppy drive support altered to support a system with a 720k drive A:. Also some tweaks made to floppy interrupt handling, perhaps to cope with slight hardware differences.
- Spectrum 1.0
- My best guess is that +3 CP/M was derived from the PCW CP/M codebase somewhere around here.
- PCW 2.9
- Now supports the PCW9512 sheet feeder.
- FIDs now enabled again.
- The "Drive is A:" message moves four characters to the left (!)
ESC 4 1/
ESC 4 0sequences to disable / enable screen scrolling.
- PCW 1.11 / 2.11
- Supplied with the PcW 9256 (1.11) and the PcW 9512+ (2.11).
- Somewhere between 1.7 and 1.11, the 1.x and 2.x version numbers were synchronised. This probably means some 2.x versions were skipped. My guess is that 1.7 corresponds to 2.0, 1.8 to 2.1, and the sync was done at 1.9 = 2.9.
- The dot-matrix printer driver allows redefinition of arbitrary characters, using jumps at FFF9h and FFFCh.
- Support added for second-generation PCWs: 9256, 9512+.
- Support added for booting the LocoScript installer (insert the boot floppy and press SHIFT+EXTRA+RELAY. Only applies to second-generation PCWs).
- Allows the floppy drives to be stepped at different rates.
- PCW 1.12 / 2.12
- Support added for the standalone Centronics port accessory.
- PCW 1.14 / 2.14
- Support for loading drive parameters from *.FIB files.
- Improved Centronics port detection.
- If the memory test reports 256k, reset the memory read/write register and try again.
- SHIFT+EXTRA+RELAY now works on first-generation PCWs as well.
- PCW 1.15 / 2.15
- A single change: When doing a SHIFT+EXTRA+RELAY reboot, takes all devices out of interrupt mode so that they don't interrupt at an awkward moment.
Some versions I haven't got, but which probably existed:
- PCW 1.0: Screenshots in the PCW8256 manual at archive.org show J10CPM3.EMS, which would correspond to a 1.0 release.
- PCW 1.5-1.6: I'd guess these were released to support early hard drives such as the Timatic Winchester (possibly with hardware-specific drivers rather than the generic FID mechanism).
- PCW 1.8: Mentioned in '8000 Plus' as supplied with an add-on hard drive.
- PCW 2.5: Seen in a screenshot in '8000 Plus'; though the screenshot was inaccurate in at least one other respect, and so may not have been genuine.
- PCW 1.13 / 2.13: Mentioned online here.
- Spectrum 0.1: The screenshots in the Spectrum +3 manual show S01CPM3.EMS, which would likely have been an early build for internal use.
The modules in other systems
At least some of the modules are shared between CP/M and other Amstrad / Locomotive operating systems. LocoScript 1.20, for example, has its own versions of NMI, KL and DD, and so does the LocoLink server for the PCW. The main difference is that another module or set of modules (probably called "DOS") handles file access. The code in this module resembles +3DOS on the Spectrum +3 (give or take certain register usage conventions) — or, more probably, +3DOS was created from DOS, DD, and a few bits of MSG.
I suspect that SCR is also shared with LocoScript, since it has at least one feature (right-to-left text output) which is completely unused in CP/M.
The LocoLink server in LocoLink 2.02 is somewhere between versions 2.9 and 2.11 of the CP/M BIOS; it supports separate drive parameters for each drive, but not the Shift+Extra+Relay boot sequence.
John Elliott, 9 May 2018