A plugin for the CSpect ZX Spectrum Next emulator by Mike Dailly that fixes some incompatibilities between CSpect and games for the Next.
It is used by CSpect Launcher, a game launcher for CSpect (Windows, Linux and macOS) where each fix can be turned on per game from the right-click menu.
The fixes are chosen per game with the CSPECT_COMPAT environment variable (a comma-separated list
of options). Without the variable, they come from Compat.ini, a
list of games found by the MD5 of their file. Without either, the plugin does nothing, so it can stay
installed for all games.
| Option | What it does | Games |
|---|---|---|
l2bank9 |
Layer 2 starts at 16K bank 9 (Next register $12). CSpect sets it to 8 when it loads a .snx file, so games that never set it and expect 9 draw over their own data. |
Montana Mike, Dweebs Drop |
nodivmmc |
DivMMC automap off (bit 4 of Next register $0A). CSpect maps the DivMMC memory when the CPU reaches $0038 even when RAM is paged in place of the ROM, so a game that calls code there runs the DivMMC memory instead (random values: the game starts only sometimes). Loading files with esxDOS still works, as CSpect serves it itself. |
Deltas Shadow |
dd01nop |
DD 01 in the game's .nex becomes a 2-byte NOP. These bytes are breakpoints left in a game by its developer; CSpect runs them as LD BC,nn, which swallows the next instruction. The .nex is the one in CSPECT_COMPAT_FILE, or else the one CSpect has loaded; only the memory is changed, before the game starts, and only where the bytes are still DD 01. The bytes are searched in all the banks, data included, so use it only for games that need it. |
Elite Next |
zeroram |
The RAM outside the 128K snapshot (8K pages 16-255) is cleared before the game starts. CSpect fills it with random values, so a game that shows Layer 2 without clearing it shows them. Only for .snx/.sna games: a .nex can load its banks there. |
Spice Invaderz |
divfirst |
DivMMC memory comes before the Layer 2 mapping, as on the Next. When Layer 2 is mapped for writing at $0000 (port $123B bit 0), CSpect sends the writes of DivMMC code (NextZXOS's interrupt handler and tape loader) to Layer 2, so NextZXOS loses its saved stack pointer and the machine resets. While DivMMC code runs, the plugin keeps those writes and gives them back when they are read. |
4K Race Next (loaded from tape with NextZXOS) |
im2ff |
The IM 2 vector is read at I*256+$FF, as on the Next, where the data bus reads $FF. CSpect reads it at I*256+$00, so a game that sets only the vector at $xxFF jumps to a random address at the first interrupt. Right after CSpect has taken the frame interrupt, the plugin sends the CPU through the vector at $xxFF; the game's memory is not changed. |
4K Race Next, Manic Miner Trick Or Treat AY, Space Racing |
sdstream |
Streaming from the SD card done by the plugin instead of NextZXOS. NextZXOS's DISK_STRMSTART can fail in CSpect, so a game that streams its music from the SD card stops on a black screen. RST $08 DISK_STRMSTART / DISK_STRMEND return at once without error; while the stream is on, the game's own reads of the SD card port $EB get the blocks of the file it mapped with DISK_FILEMAP, read from the game's folder on the PC (CSPECT_COMPAT_FILE gives the folder, else the current one; silence if the file is not there). NextZXOS's own SD card reads are not changed. The game must be started with NextZXOS. |
The Way of the Exploding Fist |
divnmi |
DivMMC NMIs (Next register $02 bit 2) page in the DivMMC memory, as on the Next: from $0066 to the RETN, $0000-$1FFF is the DivMMC ROM and $2000-$3FFF the DivMMC RAM bank of port $E3, as the game wrote them (the RAM with CONMEM, port $E3 bit 7; the ROM in config mode, Next registers $03 and $04), and a new request while it is paged in is ignored. CSpect runs the game's RAM at $0066 instead, so a game that plays its sound from DivMMC NMIs crashes, or stays on the title screen waiting for the sound. The plugin keeps its own copy of that memory. If the game lets NMIs break the DMA (Next register $CC bit 7, ignored by CSpect), long DMA transfers from memory to memory or to the sprite ports are done at once by the plugin, so the NMIs are not lost and the sound does not crackle. |
Atic Atac Next |
notemu |
Next register $00 (machine ID) reads as a Next instead of an emulator, for the game's code only (code at $4000 and above). For a game that treats emulators differently. |
The Way of the Exploding Fist (2023 version: with -60 too, its music has only 60 Hz data) |
pal44 |
A palette colour written through Next register $44 changes only at the second of its two writes, as on the Next. CSpect changes it at the first, so a game that writes $44 once and then moves on gets a wrong colour (black specks on the title screen). |
The Way of the Exploding Fist |
ctcirq |
CTC interrupts turned off (Next register $C5) and on again work as on the Next. In CSpect they do not come back without programming the CTC again, so a game that only turns them on again loses the sound played from them. When a channel comes back without having been programmed, the plugin has the CPU program it again, with the game's last values, in a few instructions of its own; the game's registers are then restored. |
The Way of the Exploding Fist (2024 version: fanfare of the SpecNext screen) |
Several options can be combined, e.g. CSPECT_COMPAT=l2bank9,nodivmmc.
-
Build
Compat.dll(see below) or download it from the Releases page. -
Copy it into the CSpect folder, next to
CSpect.exe(withCompat.ini, to use it without CSpect Launcher). -
Start CSpect with the variable set, for example from a command prompt:
set CSPECT_COMPAT=l2bank9 CSpect.exe -w3 -vsync -zxnext -mmc=.\ MontanaMike.snx
For dd01nop, CSPECT_COMPAT_FILE can give the path of the game's .nex; without it, the plugin uses
the file loaded by CSpect.
When the plugin is active, the CSpect console shows Compat added (l2bank9).
CSpect Launcher sets the variable for the games that need it.
To start games straight from CSpect, without setting a variable each time, copy
Compat.ini next to Compat.dll. When CSpect loads a .nex, .snx or .sna file, the
plugin computes its MD5 and uses the options listed for it:
; Montana Mike (MontanaMike.snx / MontanaMike.sna)
4d94f98ab1ee9e3bdf879c5599f78a36=l2bank9
The file already lists the games above that need a fix when they are loaded by CSpect (Elite Next is
left out: dd01nop is better turned on by hand). A renamed file is still found; a different version of
a game has another MD5 and must be added. The CSpect console shows the MD5 of each file it loads
(Compat: MontanaMike.snx MD5 4d94...); on Windows it can also be found with
certutil -hashfile <file> MD5.
default= gives the options for every file not listed. Games started from NextZXOS (the Browser, or a
tape loaded with the Tape Loader) are not found by MD5, because CSpect has loaded the SD card image, not
the game: for those, put the options in default=, e.g. default=divfirst,im2ff for 4K Race Next.
Compat.ini is not used when CSPECT_COMPAT is set: CSpect Launcher's choices come first.
build.bat compiles the plugin with the C# compiler included in Windows (.NET Framework 4); it needs
Plugin.dll from the CSpect folder:
build.bat "C:\path\to\CSpect"
The result is bin\Compat.dll.
Some fixes cannot be made from a separate plugin, because they are in the esxDOS emulation of CSpect,
which is itself a plugin (esxDOS.dll, open source). The esxDOS folder holds Mike
Dailly's esxDOS plugin source from CSpectPlugins
with these changes in CRST8.cs:
| Change | Why | Games |
|---|---|---|
DISK_FILEMAP ($85) returns HL = address after the last entry, instead of 6 bytes further |
games that check the length of the map (e.g. one entry for a file in one piece) stopped | Dreamworld Pogie Demo |
Game reads of the SD card (CMD18, after DISK_FILEMAP): the 2 CRC bytes after each 512-byte block, instead of over the block's bytes 508-509 |
the first block of each read had two $FF bytes in it: in music streamed from the SD card, a click every block (a constant whine) |
Atic Atac Next |
eCPUFlags : UInt16 written as : ushort |
same type, so that the C# 5 compiler included in Windows accepts it | - |
To install it, rename CSpect's esxDOS.dll (e.g. to esxDOS.dll.orig, to go back to it later) and copy
the fixed one next to CSpect.exe. It is used by every game, with or without CSPECT_COMPAT.
Download esxDOS.dll from the Releases page, or build it with build-esxdos.bat,
which also needs Plugin.dll from the CSpect folder:
build-esxdos.bat "C:\path\to\CSpect"
The result is bin\esxDOS.dll.
Known limit, not fixable from a plugin: CSpect does not pass block I/O instructions (INI, INIR,
OTIR...) to plugins, so games that read streamed data with them (e.g. Dreamworld Pogie Demo's music)
get no data from the esxDOS streaming.
- CSpect Launcher: game launcher for CSpect, with covers,
ratings and favourites; it sets
CSPECT_COMPATandCSPECT_COMPAT_FILEfor the games that need a fix - CSpect Scanlines: TV-style scanlines over the CSpect window
GPL-3.0, see LICENSE. The CSpect plugin interface (Plugin.dll) is by Mike Dailly,
MIT licensed: https://github.com/mikedailly/CSpectPlugins
The files in the esxDOS folder are Mike Dailly's esxDOS plugin with the changes listed above, MIT licensed: see esxDOS/LICENSE.