So I got bored of implementing instructions and decided, instead, to start implementing the actual Spectrum. This may seem a bit presumptuous, but it’s more fun than just slogging through implementing instructions that nobody ever uses.
To start, I decided to reuse the main window and memory window from my Z80Diagnostic app. This meant refactoring their views and controllers into a new framework called Z80UI. A byproduct of this was the necessity to abstract away the the CPM machine that the MainWindowController builds. Now, instead of directly creating a Z80 and hooking in a class that triggers on the CPU executing the instruction at location 0x0005, it asks its application delegate for a machine. In Z80Diagnostic, the app delegate vends the same simple CP/M simulator. In Spectrum, the app delegate vends an instance of Spectrum.
Apart from the different machine created, the other main difference between the initial version of the Spectrum app and the Z80Diagnostic app, is the ROM that is loaded. I found a copy of the Spectrum 48K ROM online (note that Amstrad currently holds the copyright on this and allows downloading and copying for non commercial purposes) and loaded it into the bottom 16K of RAM of the Spectrum machine.
The next thing needed is a display. For the first iteration, I have created a ScreenView and a ScreenViewController. All of the logic involved in translating he Spectrum’s video memory into an intelligible picture is in the controller and it simply renders the display every time MacOS asks it to. This is somewhat simplistic and means that meany of the effects Spectrum owners are familiar with will not happen. For example, the famous stripy border on tape load is a side effect of changing the border colour multiple times while the ULA is rendering a frame. At this point, I fire up the emulation and this is what I get.
The Z80 is executing a fairly tight busy loop because there is currently no interrupt generator. The Spectrum generates an interrupt on the vertical refresh and I have not implemented this yet. Because there is no interrupt, the invalidate button is needed to force the screen view to update itself.
The next stage is to implemented the vertical retrace interrupt. At that point I expect to see a few more issues with the Z80 since I have done nothing yet to implement the interrupt mechanism. Also, I expect a few more unimplemented instructions to become apparent.