The simulator uses Z80 processor simulator from my other project. As you may have heard, ZX Spectrum was extremely simplified computer so the actual simulator needs only:
- an actual processor with memory
- a dedicated I/O system for interaction with keyboard and external storage (no, I am not going to use old school tapes)
- a graphics interpreter to display the contents of pixel memory
ZX Spectrum made use of only one IO port: 0xFE. Different bits were responsible for keyboard scan and tape read and write. I have rebuilt the LOAD and SAVE routines in order to make use of serial communication with my diy replica so it reused the same concept here. Only the communication is simpler - I do not need a special protocol to talk to ZX SIO chip since I can simply read and write bytes one by one.
For keyboard, I did not need to modify ROM, instead I read keyboard input and map keyboard codes to 5 bits of 0xFE port. If you want to know mode about how ZX Spectrum reads the keyboard, see this article.
For external storage I use tap files for input and output. You can load a given file with LOAD ""
,
you can also save your basic program with SAVE "prog_name"
. You cannot select files at runtime, I hope this is not a problem.
ZX Spectrum has a non-intuitive way of holding the graphics information. In order to show the actual screen we need to read the graphic memory and periodically draw the picture. Nowadays, since we have plenty of memory to waste I can easily replicate the part of RAM into a separate array and show it on screen instead of sharing the memory between processor and graphics routines. I did the same in my diy FPGA graphics card.
The whole screen is repainted every 50ms.
ZX Spectrum uses one interrupt type (IM 1). It is triggered by the ULA chip every 50ms (or 60ms in the US). I simulate it every given number of cycles, which theoretically should be an equivalent of 50ms if the simulator runs at 100%. However, after making some performance improvements the simulator is several times faster now. If you are time-constrained (e.g. you want to play Knight Lore) the simulator needs some delay. You can specify the number of milliseconds between interrupt cycles that the simulator should stick to. I recommend ~30ms.
NOTE: 30ms x 50 is more than a second! But keep in mind that the processor in real ZX Spectrum does not run all the time. It is being periodically suspended by the famous ULA chip in order for graphics chip to read the pixel memory and show it on the TV screen. Since we do not hold the processor but sniff memory operations instead, we have to account for it and add a few milliseconds every interrupt cycle.
You can run a fat jar (created with sbt assembly
command). Before you build this repo you need to provide
your copy of Z80 simulator. You can download it from the simulator repo or
clone the code and run sbt command publishLocal
.
In the main project directory you will find the run.bat script with some examples for Windows. The parameters are:
--tap-file : a *.tap file to be loaded with LOAD instruction
--save-tap-prefix : a prefix to the *.tap file that can be saved with SAVE instruction
--save-tap-timestamp : an option to include a timestamp in the .tap file name
--wait-ms : number of milliseconds required between each interrupt cycle
All parameters are optional.
ZX.Spectrum.scala.simulator.2023-03-09.18-20-51.mp4
ZX.Spectrum.scala.simulator.2023-03-10.08-16-39.mp4
ZX.Spectrum.scala.simulator.2023-03-10.15-42-20.mp4
ZX.Spectrum.scala.simulator.2023-03-10.18-51-49.mp4
ZX Spectrum ROM is copyright of Amstrad plc. According to: this message it can be freely used for emulators and personal use.
The ROM disassembly was published in 1983 in The Complete Spectrum ROM Disassembly so I believe it can be used for personal use as well.
Knight Lore is copyright of Ultimate Play the Game (see: Wikipedia page). It is downloadable from number of places in a form of a TAP file or as a source, but I do not include it here.
All sample videos are my copyright and you cannot use them for any commercial purposes.