My entry for RetroChallenge 2021/10 is to publish reverse engineered versions of the Amstrad CPC firmware ROMs which can be modified and assembled. In this post I want to explain why why I’m doing this.
The first reason is a personal one: I have several projects on the go which would benefit from this. The ability to build modified ROMs with additional features would be a very useful one to me. As would the ability to run the Amstrad firmware on other machines.
All of which begs the question of why I think the Amstrad firmware is a good choice for projects.
I’ve always considered the Amstrad firmware to be very well designed. All of the firmware’s functions are exposed and documented. And the firmware fully supports all of the Amstrad hardware. There are routines to add event handlers, query screen dimensions, play sounds and read the keyboard. There are also undocumented routines for text editing and floating point maths.1
And the firmware’s functionality can be accessed by called one of a number of ‘jumpblocks’. These jumpblocks are placed in RAM and can be easily accessed from machine code. Many home computers required software to call directly into the ROM to access features, which meant that future versions of the ROMs either had to break backwards compatibility or take steps to keep the old addresses functional. The jumpblocks in the CPC meant that upgraded versions of the firmware just needed to alter the addresses called by the jumpblocks to retain compatibility.
But that’s not the only advantage of the jumpblocks. They could also be patched by other software to intercept and modify the computer’s behaviour. So you could patch the text output routine to copy characters to the printer, or patch the cassette routines to access a RAM disc. And that’s exactly what the official disc interface did, redirecting the tape routines to the disc.
And those routines could be switch between tape and disc with the |TAPE and |DISC commands. Which leads me to another feature – RSX commands. These are additional commands which can be added by sideways ROMs or machine code in RAM. Similar to ‘star commands’ on the BBC micro, this makes it easy to add extra functions in ROMs which can easily be accessed from BASIC (or, indeed machine code or other languages) via firmware support.
And speaking of sideways ROMs, the firmware includes support for ROM banking. So additional ROMs can be installed (if you have the hardware) and accessed from machine code. There’s support for ROMs (or code in RAM) to seamlessly call other ROMs, even though all ROMs are mapped into the same address space. The firmware calls to do this simply need a ROM number and address with all the bank witching handled seamlessly. There’s even support for software to stretch across up to four ROMs (16kb each) and call between them without needing to know their physical ROM number in the system.
So if the firmware can be modified to run on other hardware it opens up a world of possibilities to re-use Amstrad software. Obviously anything which writes directly to the hardware or the video RAM would be incompatible with different hardware, which rules out the vast majority of games, but there’s plenty of assemblers, compilers, text editors and other text based software which should be able to run unmodified on any system running the firmware.
Now, obviously the same can be said for CP/M – a large base of readily available software for running on Z80 systems. But the downside of CP/M is it’s lack of graphics support. So both pre-written software and end-user written software (e.g. BASIC code) is confined to the text world. Software designed for the Amstrad, on the other hand, is designed to make use of the Amstrad’s graphics. So, with the firmware modified to access whatever video hardware the system may have such code will automatically have access to it.
And, because of the jumpblock system it becomes possible to add extra hardware and patch the jumpblocks to use it without needing to rebuild the firmware.
(And the same could also be said about sound hardware).
And then we can discuss the Amstrad BASIC. This is a very rich flavour of the language with some support for structured programming (WHILE … WEND) as well as pretty complete support for the hardware (through those wonderful jumpblocks). Sadly it doesn’t have the user defined function support of BBC BASIC, or indeed the build in assembler (although there are ROMs which add the latter).
The options for modifying and extending BASIC are left largely to the reader to contemplate, but the original code is well written and adding an extra function or statement shouldn’t be overly complex for a competent Z80 coder.
So those are the reasons why I’ve spent so much time on this. That and the pure technical challenge. It’s been a fun experience and I’ve learned a few Z80 coding tricks. I just hope others will be able to use the end results and built some interesting projects off the back of my work.
- Sadly the addresses with the jumpblocks for these changed between computer versions, but they would make life a lot easier for languages or other software which uses floating point maths.