Building an emulator is an endless project. There is always work to do with code optimization, modernization, accuracy, features, debugging etc. My focus has largely been on accuracy because it presents interesting - and admittedly sometimes frustrating - challenges. But I also want my emulator to have useful features. Being able to playback RZX files (recordings of ZX Spectrum sessions, mostly used for game walkthroughs) is a nice feature, and the ideas behind the file format are interesting, so I decided to try implementing it. Principles During RZX playback, the RZX file supplies the emulator with IN-port values and information about when to start a new frame and when to trigger interrupts. The emulator doing the playback therefore only needs to emulate the Z80 accurately (or at least in the same way as the recording emulator) and handle display and sound. Timing is not an issue since it will be fully controlled by the RZX playback process. And external hardware doesn't have to be emulated since all IN-port data is provided in the file. File Format An RZX file consists of several blocks of data including a snapshot with the initial state of the machine and a recording block with information about IN-port data and frame lengths (measured by the number of instruction fetches per frame). The snapshot and recording blocks can optionally be compressed. It seems that the snapshot can be in any format, but I have only found examples with Z80 and SZX snapshots. Additionally, there are blocks with information about the RZX revision and the file origin. An optional security block is used to ensure that the file hasn’t been tampered with. Considerations It is important to understand that a frame in an RZX file does not always correspond to a display frame in the emulator (which is controlled by the imagined video signal). This is because the RZX format specifies that there can only be one interrupt during a RZX frame. So, if interrupt is retriggered during a display frame, this frame will correspond to two RZX frames. Another thing to note is that interrupts can only be triggered if IFF1 was already enabled before the first instruction in the RZX frame, and then it will be triggered first thing. So if IFF1 was disabled and the first instruction of the frame is EI, there will be no interrupt during the frame. During testing I noticed that when playing back the WEC Le Mans recording in the RZX Archive, the program got stuck at the HALT instruction at address $8192 during frame 20854. This was because the previous frame ended with an EI instruction at $8191. The emulator then applied the rule that an interrupt can’t be triggered directly after EI, which led to a delayed interrupt. This rule must therefore be ignored during RZX playback so that an interrupt is always triggered first thing in a new frame (provided that interrupt is enabled). Finally, note that when counting instruction fetches until it is time to start a new frame, prefixed instructions must be allowed to be completed before ending the frame, even if it means that the number fetches in the frame is exceeded. This should be obvious but I missed it at first. Implementation in SoftSpectrum 48 To implement RZX playback functionality i added the RZXFile class, which interprets and stores the RZX file data in arrays for easy access. During playback this class provides IN-port data to the Z80 class and publishes events for the playback status (used to update the GUI and to control the emulator behavior) During playback, the TStateCounter class is relieved of its responsibility for deciding when a frame should end. This is instead handled by the Controller class, which counts the number of instruction fetches during each frame, and - when the maximum number for the frame has been reached - triggers a new RZX frame, initiates an interrupt window (provided IFF1 is true) and a new display frame (except when interrupt is retriggered). The Z80 class is only affected in that it gets its IN-port data from the RZXfile class during playback. Also, it updates an instruction fetch counter each time the R-register is updated during the instruction fetch process. The MainWindow class displays playback information (current and total frames) from the RZXFile. I have implemented support for RZX revision 0.12 and 0.13 excluding security information blocks. Only Z80 and SZX snapshots are supported. The specification also allows for external snapshots, but I haven't implemented support for this. I have tested quite a few RZX files and I think that everything works as it should (with the limitations mentioned above). If not, I would be glad to learn of any RZX file that isn't handled correctly. Links A specification for the RZX format can be found here: WWR - RZX technical specifications (worldofspectrum.net).
RZX recordings can be found in the RZX Archive.
0 Comments
Leave a Reply. |
Archives
November 2020
Categories
All
|