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.
Sources
I have derived the information in this document from the following CP/M boot files:
System file | Machine | Version |
---|---|---|
C10CPM3.EMS | CPC | 1.0 |
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.
The CPC
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 |
0AD0-0EFF | DD: Disk Devices (code segment) 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 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 |
13F0-168F | SCR: Screen 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) As with 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 | Video RAM. 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 | System messages. 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 driver |
41A8-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 | System messages. |
03A0-04CF | CD: General character device management. |
04D0-05AF | CD: RS232 serial port driver |
05B0-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 | Video RAM. 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. |
Zero Page
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 8000h |
0028 | 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. |
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 presumably 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 (!)
- New
ESC 4 1
/ESC 4 0
sequences 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:
- 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).
- 1.8: Mentioned in '8000 Plus' as supplied with an add-on hard drive.
- 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.
- 1.13 / 2.13: Mentioned online here.
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.
John Elliott, 4 April 2015