This is perhaps one of the most complex projects I have ported to the MikroElektronika Multimedia platform (MMB-MX4) so far. In fact it does combine in a single application the following components:
- FreeRTOS, real time operating system
- USB library, HID keyboard interface
- MMD File System with SD card interface
- Graphics library (v2.0)
These four components are then customized to provide emulation of the specific hardware features of the (Timex/Sinclair) ZX Spectrum personal computer.
If you have never heard of the ZX Spectrum, it probably means you are too young as this was in the mid-eighties (yes, more than 20 years ago) one of the first personal computers or, better I should say, “home” computers, sold at a fraction of the cost of the IBM XT PC (introduced almost exactly in the same year).
At the time it spurred a very strong community of developers and thousands of educational and gaming applications were developed for it and distributed in cassette tapes. Now if you ask me what a cassette tape is… well, forget it!
Why would you ever want to emulate such an old computer?
The honest answer is: nostalgia!
The pragmatic answer is: to play thousands of games still available for download today!
The engineer’s answer is: for the challenge of it!
After all, this is the platform I learned programming on (and I played a good number of videogames too). This is were I had my first encounter with BASIC, Z80 assembly and later Pascal.
More seriously, it is interesting to see how far microcontroller technology has gone in these 20 years. A PIC32 running at 80MHz can, as you will see, emulate in real time not just the Z80 processor of the times, but the ULA (ASIC) chip that was assisting the CPU with video output, sound, keyboard and tape interfaces. One modern (general purpose) chip replaces the entire system (all ROM and RAM included) with pure software and, perhaps even more amazingly, it does so using only C language, not a single line of assembly!
Eventually you will realize that the MMB is a far superior system to the ZX Spectrum it is emulating. More colors are available, the QVGA display has a higher resolution too, sound is 16-bit stereo and the SD card interface can provide GigaBytes of storage, but then how would you be able to play Jet Set Willi?
The ZX Spectrum Architecture
The Spectrum was a relatively simple yet clever machine designed by Clive Sinclairaround the Zilog Z80 processor. It was an evolution of the previous ZX80 and ZX81home computers and with them it shared a minimalistic approach to computing. The main difference being the use of an ASIC (often referred to in literature as theUncommitted Logic Array or ULA) responsible for all the interfaces (tape, sound, video) and helping to reduce the component count (down to four ICs, plus the RAM chips) while adding for the first time color graphics, or an approximation of it.
Needless to say, emulating correctly the ULA in this project turned out just as complex and processor intensive as the Z80 CPU emulation itself.
The graphic capabilities of the ZX Spectrum were limited to a resolution of 256 pixel horizontal x 192 pixel vertical. Only 16 colors were available (truly 8 colors, each available in two intensities) but not every pixel color could be specified independently. Pixels were grouped in boxes of 8×8, each box could then have a foreground and a background color. In practice this was good to provide color text, as long as an 8×8 font was used, nonetheless many game designers figured clever ways to make the most of it providing a compelling graphical output. Notice that such limitations were fairly common at the time. Commodore 64, VIC20 and many other competing systems in those years had to take the same compromises to save what used to be a very expensive resource: RAM.
The screen buffer was composed as follows:
- A pixel addressable area, containing monochromatic information (on/off) for each pixel (256*192 => 6144 bytes large).
- A color attributes area, containing color information for each 8×8 block (32*24=768 byetes).
To further simplify (from the ULA perspective) the color block / pixel association, pixel lines were not strictly sequential. The screen was divided in three parts grouping 8 text lines each. Within each part, pixel lines were reordered as follows:
- First pixel line of the character line 1
- First pixel line of the character line 2
- First pixel line of the character line 8
- Second pixel line of the character line 1
You get the picture (pun intended). From the sw point of view this was clearly a bit of a mess, but then, as long as you were staying within your BASIC interpreter, it was all hidden from your view.
The ULA would scan the video buffer in between the CPU access to the same memory bank. To prevent conflicts, the ULA was effectively stretching the CPU clock when necessary while mux-ing the address lines.
An ASTEC PAL modulator (NTSC in the Timex versions) converted the ULA 4-bit output into a signal that could be directly fed into your home TV set.
The ZX Spectrum worst feature was perhaps the keyboard. It was made of a rubber membrane and provided very poor tactile feedback but it was cheap and eventually proved to be very durable. It included only 40 keys, connected in a matrix of 4 rows.
The actual contact matrix underneath was different though, each row was divided in two halves so that a keyboard scan required 8 (half) rows providing 5-bit each.
Audio was generated in the most rudimentary yet effective way. A single digital output pin was connected to an RC low pass filter providing a DAC of sorts. Clever sw design could produce a PWM signal (no hw support) so effectively that some advanced video games featured voice output.
A similar technique was applied to the Tape Cassette Input and Output. Respectively a single digital input and output pin of the ULA were used to produce a recordable signal and to read it back to provide “mass” storage.
The ZX Spectrum had a 16K byte ROM that contained all the BASIC interpreter, math libraries, and low level interfaces required (graphic, tape, audio, fonts).
The original ZX Spectrum had 16K byte RAM, of which the first ~7K bytes where occupied by the video buffer (see above) and the remaining 9K were available for stack and BASIC / application code. Later a 48K model was introduced expanding considerably the application space. This turned out to be the most popular model.
In the late 80’s a 128K RAM model was introduced, adding a banking scheme to overcome the 64K total addressable space typical of the Z80 processor.
The Z80 processor was operating at a frequency of 4MHz (actually a slightly lower value convenient for the video PAL encoder PLL input), but the performance was affected by the continuous ULA access to the RAM buffer when both devices were using the same RAM bank (lower 16K bytes).
The Emulator Design
As anticipated in the overview, the emulator takes advantage of the multitasking capabilities offered by FreeRTOS to simplify quite a bit the design of the application.
Dividing the entire project in three tasks, communicating among each other via well defined interfaces, I managed to reduce the complexity to a reasonable level.
The tasks are:
- CPU emulator (taskZ80.c), this is essentially a very simple loop where the PIC32 reads each Z80 instruction to be executed and calls the interpreter (Z80.c). The latter is perhaps the largest C source file module, responsible for correctly decoding each one of the 700+ valid instructions. This tasks access the ROM content (as an array of bytes in flash). The original ZXSpectrum ROMcode was obtained from enthusiast web sites that are helping preserve the legacy. This task contains several additional debugging and testing features that were necessary to prove the proper functioning of the system, but also a Trap system to substitute the tape interface with access to an SD card file system.
- Keyboard (taskUSB.c), it encapsulates the entire USB HID Keyboard functionality providing emulation for the Spectrum keyboard via a standard USB Keyboard. The USB keyboard scan codes are converted in a I/O map available to the CPU task for transparent emulation.
- Video (taskLCD.c), it encapsulates all the video mapping and access to the MMB QVGA screen. It provides a (timed) periodic refresh of the QVGA screen based on the contents of the RAM buffer after performing the correct (line) scrambling and block color emulation. The update frequency can be modified to provide the required video responsiveness while balancing the PIC32 performance to obtain an almost real time behavior of the emulator.
Empirical measurements appear to indicate that the resulting emulation is actually slightly faster than the original system.
Source Code Download
You will need to download and install the Microchip Application Library (version 2.0 NOT later) and a recent version of the FreeRTOS for PIC32 Real Time Operating system. These libraries/tools are NOT included in the download files below.
You will also need to download the MMB library, presented on this site.
You can download and program into your PIC32MX4-MMB the following HEX image:
Also you can copy the following tape file on an SD card (root directory) to play a little demonstration game.
Support and Future Developments
With the introduction of the PIC32MX7-MMB, we have the possibility now to emulate a full Spectrum 48K model and perhaps even a 128K model (with limitations).
Porting to a PIC32 microMMB model would also be possible with minimal modifications and a USB A to B adapter for the keyboard input. While I have long abandoned the development of this project, I would appreciate if you could share with me and the rest of the community any bug fix or feature improvement that you could identify.