Sinclair ZX Spectrum Emulator V0.6 23 Apr 1991 ---------------------------------- This program emulates a Sinclair ZX Spectrum 48-kbyte z80-based computer on any Amiga computer. +-------------------------------------------------------------------+ | IMPORTANT: You need to already own a Spectrum to be able to use | | this program. This is because I am not taking the risk of | | distributing the Spectrum ROM code. I think that would probably | | be illegal. Therefore this archive does not include the Spectrum | | ROM code. --- You should supply it independently. | +-------------------------------------------------------------------+ The files in this archive may be distributed anywhere provided they are unmodified and are not sold for profit. Ownership remains with the author, Peter McGavin, 86 Totara Crescent, Lower Hutt, New Zealand. e-mail: srwmpnm@wnv.dsir.govt.nz . I assume you have enough knowledge to manipulate binary files and to transfer data over a serial line without help. If you don't know what I'm talking about, don't try this program. Spectrum-sr is an executable for 68000-based Amigas. Spectrum-ccr is for 68010/20/30/40/50...-based Amigas. Both the programs require the file "spectrum.rom" (not supplied) in the current directory, or they will not load. The emulator uses the dreaded move-sr instruction after almost every z80 instruction emulated. It ran 30-40% slower when I tried replacing the move-sr instruction with a call to GetCC()! This is quite exceptional --- with most programs you wouldn't notice the difference. Therefore I have supplied a second executable which uses move-ccr instead of move-sr for 68010/20/30/40-based Amigas. I don't see any reason why one or the other shouldn't run on all Amiga models. I have not yet had the opportunity to test v0.6 of spectrum-ccr. (I've had reports that the 0.3 version of spectrum-ccr works ok on a 68010, 68020 and Amiga 3000.) If you have an accelerated Amiga, please let me know how well spectrum-ccr performs. I developed the code, entirely in assembler, in my spare time using z80 emulation code based on Ulf Nordquist's CP/M emulator (Fred Fish disk 165). I have fixed several bugs in the emulation code, and made it faster, but there are still some bugs. General Notes: o As already mentioned, a vital file is missing. You must supply an image of the Spectrum's ROM in the file "spectrum.rom". The file must be exactly 16384 bytes long and must contain exactly the same byte sequence as memory locations 0..16383 in the Spectrum. The easiest way I know of to get this to your Amiga is via the Sinclair Interface 1 serial port. An alternative is to use a Spectrum disk drive system that writes IBM-format sectors, then read a Spectrum diskette using MSH (Fred Fish disk 382) and a sector editor like DiskX (Fred Fish 158). You can do that with an MGT PLUS D disk drive. I'll leave it up to you to figure out how to get the data across. You could always type it in :-) There are several third-party books that list the code, e.g, "The Complete Spectrum ROM Disassembly" by Dr Ian Logan and Dr Frank O'Hara, Melbourne House Software Ltd, ISBN 0 86161 116 0, or ISBN 0 86759 117 X, 1983; "The Spectrum Machine Code Reference Guide" by Richard Ross-Langley, Interface Publications, ISBN 0 907563 51 1, September 1983. In fact you can supply any 16384-byte file containing valid z80 code and called spectrum.rom. The emulator will transfer z80 control to location 0. Screen and keyboard hardware is programmed the same as a real Spectrum. (Once loaded, the first 16384 memory locations are readonly.) o Please don't ask me to e-mail spectrum.rom to you, because I won't. o If the emulator can't find spectrum.rom, then it will display a requester saying so, and it will not run. o The following Spectrum features are implemented: screen output in the same resolution and colours as a real Spectrum --- includes bright, reverse and flash attributes (looks much better than the old TV!) keyboard implemented at the z80 "in" instruction level. Note that like a real Spectrum you have to hold the key down until it registers. Because the emulator is running slower, you might have to hold keys down longer. Make sure the Spectrum window is active when you start to type. See Appendix 1 for key map. sound implemented by trapping calls to the "beeper" routine at $03b5 in the Spectrum rom. Sound works with all Basic programs and some machine code programs, but it won't work with machine code programs that bang on the hardware to make sounds. o The emulator runs in its own custom screen and window. To quit, click the close box (any time). o The emulator does not disable multitasking. Except for move-sr, I don't know of any of Commodore's rules that it breaks. If you find any, please tell me. o The emulator runs about 3 to 10 times slower than a real Spectrum on a standard 68000-based A500. Most things are about 5 times slower. I'm afraid the 68000 doesn't have a built-in z80 emulation mode, and a z80 is much harder to emulate than a 6502 as used in the Commodore 64 and BBC microcomputers. A 28 MHz 68030 should keep up. The Spectrum NEW command takes 11.5 seconds on my Amiga, compared with about 2 seconds on a real Spectrum. o This version of Spectrum uses the blitter to refresh the screen in parallel with the emulator. That is, it uses multi-processing. Thus, the overhead of a z80 instruction writing to the Spectrum's display file is minimised. o I've just about run out of ideas on how to significantly speed up the code from what it is now. One thought is to code some common ROM routines in pure 68000. Obvious candidates are the text output and scrolling routines. Of course this would only speed up programs that call the ROM, which excludes most games. Overall, the major bottleneck seems to be the z80 instruction decode, and I've got that as fast as I can get it. o In version 0.6, the following Spectrum features are NOT implemented yet: joystick; border colour; cassette tape; bank roms (e.g, Interface 1); the timer interrupt occurs after every 5000 machine instructions instead of every 20 ms. updating of the flash attribute occurs every 80000 machine instructions instead of every 320 ms. because the emulator is not real-time, the real interval between timer interrupts and flash attribute updates depends on the type of z80 instructions being emulated. o The following z80 features are NOT properly implemented: the z80 h and n processor flags; the z80 daa instruction (decimal adjust a) --- daa works properly only immediately after adc or sbc; the z80 halt instruction *causes* an immediate timer interrupt (instead of waiting up to 20 ms for the next one to occur); there might still be rare problems executing certain long, self-modifying z80 instructions located at exactly 32763..32766 in z80 memory, because of the 68000 addressing modes used to load instruction operands; there is at least one other bug I haven't been able to track down yet. o If you have arp.library installed in the libs: directory, you can press F2 to save the current state of the emulator in a file. (This uses the arp file name requestor.) Press F1 to load a saved file back again. The entire state of the system is saved, including all 48 kbytes of Spectrum RAM and the state of the z80 processor. Load and save work in less than 1 second on a hard drive. o The format of a snapshot file (loaded with F1 and saved with F2) is listed in Appendix 2. If you have a Mirage Microdriver or equivalent you can transfer any Spectrum program to the Amiga. o If you don't have arp.library installed in the libs: directory, F1 and F2 bring up a "You need libs:arp.library" requester. o Because it's running slower, maybe now you can get past that "impossible" level in your favourite game. o Now you can print Spectrum graphics by transferring to your Amiga. o If you're cross-developing Spectrum software, now you can see which parts need speeding up. o I've tested it with several Sinclair Basic programs and all ran perfectly. o I've tried several machine-code programs and had mixed success. The following programs seem to work ok in the emulator: Zeus Assembler and Monitor Scrabble Jetset Willy no sound Atic Atac no sound Jetpac no sound Tron full sound The Train Game no sound Backgammon PSSST some sound Horace and the Spiders Sam Spade full sound effects Draughts Sam Stoat some sound 3D Deathchase no sound Technician Ted no sound Kosmic Kanga Monty Mole Talk Chess no speech, sorry Horace Goes Skiing some sound Hungry Horace some sound Star Raid no sound Cyclone some sound Wheelie no sound Full Throttle no sound Penetrator scrolls garbage onto the screen. Gyron now renders circles correctly, but eventually garbles the screen and crashes (stack overflow?) Alien8 crashes unpredictably. (BCD arithmetic for time left perhaps?) Tomahawk locks up when it tries to render scenery. St Bernard resets the Spectrum after a long, long pause. Cyberun works ok until there is a collision, then it freezes. KnightLore crashes after a few seconds. Fighter Pilot works until you try to turn left or right, then it displays the horizon wrong. Note: The Amiga doesn't crash. If a Spectrum program crashes, you can either: Quit the emulator and continue working on the Amiga, or: Press F1 and load another snapshot. o One problem I have had with snapshotting games is as follows: If there is non-standard hardware in your real Spectrum (like a special joystick or disk drive), and the program knows about the special hardware, then the program might have already done a hardware test (before you made the snapshot) that makes it believe the special hardware exists permanently. Then, when run under the emulator, the program tries to access the non-existent hardware and behaves erratically. What is wrong is that the program was started in one environment (the real Spectrum with add-ons) and is now running in another (the plain Spectrum emulator). For example, if your program behaves as if the joystick button is continuously pressed (when run in the emulator), maybe it is because you made the original snapshot from a Spectrum which has special joystick hardware. See if you can disconnect the joystick interface and reload the original program from tape before you make a snapshot. o I am not supplying the source of the emulator yet. o Please report bugs to srwmpnm@windy.dsir.govt.nz. I'd much prefer bug reports like "the `or' instruction doesn't zero the carry flag" to "Dan Dare doesn't work". Appendix 1: The keyboard: The Spectrum has a weird way of mapping functions to keys that doesn't translate nicely to the Amiga. To get a "[" on a real Spectrum, for example, you press CAPS-SHIFT and SYMBOL-SHIFT together followed by SYMBOL-SHIFT and F. In the emulator, you do the same thing except CAPS-SHIFT is either of the SHIFT keys and SYMBOL-SHIFT is either of the ALT keys. Pressing "[" on the Amiga keyboard won't work. The following table lists the Amiga key(s) corresponding to each Spectrum key: Spectrum key Amiga key 0..9 either 0..9, arrow keys also map to 5,6,7,8 A..Z A..Z SPACE SPACE ENTER RETURN or ENTER CAPS-SHIFT either SHIFT key SYMBOL-SHIFT either ALT key In addition, the Amiga full-stop, comma and delete keys behave like the Spectrum SYMBOL-SHIFT M, SYMBOL-SHIFT N and CAPS-SHIFT 0 key combinations. All the other Amiga keys (except F1 and F2) do nothing. Appendix 2: Snapshot file format (as used by F1 and F2 keys): This format is based on the format used by the Mirage Microdriver "Dump" command. Snapshot files are always 49179 bytes long. Note that in the table, the byte offset starts from 0, not 1. Byte offset into file Value 0 i register 1 l' register 2 h' register 3 e' register 4 d' register 5 c' register 6 b' register 7 f' register 8 a' register 9 l register 10 h register 11 e register 12 d register 13 c register 14 b register 15 iy low register 16 iy high register 17 ix low register 18 ix high register 19 bit 2 is set if interrupts are enabled 20 r register 21 flags register 22 a register 23 sp low register 24 sp high register 25 interrupt mode (0, 1 or 2) 26 filler (not used) 27..49178 48 kbytes RAM dump Appendix 3: Update Notes: v0.0 22 Oct 1990 First release. v0.1 15 Nov 1990 Sped up display code slightly. Also sped up main instruction decode slightly. Display flash attribute as reverse. v0.2 30 Dec 1990 Now use double buffered display and implemented flash attribute properly. Added error requesters. Used pc-relative jump tables in z80 emulator --- slightly faster, and much, much smaller. v0.3 20 Jan 1991 Changed display routines to update screen periodically instead of after every z80 instruction that pokes the Spectrum's display file. Used the blitter for this, running in parallel with the z80 emulator. (Only character rows that have changed since the last screen update are redrawn.) Reverted to single buffer display and used blitter to implement flash. (It's smaller and faster this way.) Fixed bug where couldn't use path string in arp file requester. v0.4 Changed the z80 emulator to use threaded code. Now all that is executed between each pair of z80 instructions is "move.w (a3)+,d6; jmp table(pc,d6.w)" instead of about ten 68000 instructions to decode the next z80 opcode byte. Overheads introduced are a new 128 kbyte table giving the routine offset for every byte in z80 RAM, and the necessity to write a zero word into this table every time the emulator writes to z80 RAM. The overall speed increase is about 20%. Expanded some subroutines to macros and expanded $dd and $fd prefix instructions to independent code for a slight speed increase. A side-effect is that the executable increased in size from 27k to over 40k. Introduced some bugs during the systematic changes that are proving hard to track down. v0.5 7 Apr 1991 Fixed bug in "sra a" instruction. Fixed bugs in rotate and shift (ix+d) and (iy+d) instructions. Fixed bugs where used "offset(a4,rr.w)" to address z80 memory space where offset is -2, -1, 1 or 2. (Can't use that mode because of the unlikely event of rr.w being near $8000.) Implemented mode 2 interrupts. Low byte of interrupt vector (normally provided by an external peripheral device) is assumed to be 0. Increased the interrupt interval from 2500 instructions to every 5000 instructions, because otherwise some programs with their own (mode 2) interrupt routines overflowed the stack. v0.6 23 Apr 1991 Fixed bugs in the following z80 instructions: ld ixh,b ld ixh,d rl (ix+dd) rr (ix+dd) sla (ix+dd) cpdr and iy equivalents of the above instructions. Implemented ini, outi, ind, outd, inir, otir, indr, otdr. (Out instructions do nothing). Now preserve (otherwise) unused flag bits in push af, pop af and ex af,af' (instead of setting them all to 0). Changed layout of vector table for threaded code (origin now in middle). Fixed bug in vector table wraparound code (when pc incremented from 32767 to 32768). Sped up ram writes by optimising macro for writing a byte to ram. Added processor type check. Now you get a requester when you try to run the wrong version for your processor type, instead of "Software Error, Task Held". Implemented sound by opening audio.device and trapping calls to the "beeper" subroutine at $03b5 in Spectrum ROM.