Is there a skeleton for handling the interrupt on the ZX Spectrum? Can I read it?

I need the ZX Spectrum to handle an interrupt from a device and I have no idea where to start from.

I like the idea of handling a maskable interrupt, but it seems to already be used by the ULA. The other option would be the /NMI input, which I understand to be free for use.

  • You could argue that the NMI handling is a blunder, but maybe the spectrum developers decided that certain critical sections in the code would be unsafe if NMIs were allowed (for example midway through a device driver), so they made sure that NMI could only ever be equivalent to a reset.
    – jrrk
    Commented Apr 10, 2023 at 8:22
  • 2
    @jrrk, the Spectrum ROM's NMI scheme wasn't the result of some deep planning session with a cryptic good idea coming out of it. It's pretty clearly just muck-up. Look into the history of the ZX Spectrum ROM development, it was done flat out for little reward by poor old Nine Tiles, as were its predecessors it evolves from. As I put in my answer below, ...no-one has been seen to have found an application for that (way of doing NMI) and publicised it in the last 40 years, so it can safely be called useless. Most often, things really just are what they look like. No exciting backstory.
    – TonyM
    Commented Apr 10, 2023 at 17:52

2 Answers 2


To use the maskable interrupt request /INT on a Spectrum, you need a program that does the following:

  • Implements your Interrupt Service Routine (ISR). This should include a RST 56h instruction to call the ROM's ISR so keyboard scanning etc. keeps working.
  • Disables maskable interrupts with a DI instruction.
  • Sets up an interrupt service address table in RAM on a page (256 byte) address boundary.
  • Loads the I register with the high byte of the table address.
  • Loads the table's highest vector (xxFEh) with your ISR address.
  • Changes the Interrupt Mode to 2 with an IM 2 instruction.
  • Enables maskable interrupts with an EI instruction.

Because of a somewhat tragic mistake in the Spectrum's ROM software, the Non-Maskable Interrupt /NMI pin and function cannot be used, without extra hardware to overlay the existing ROM.

In the standard Spectrum, the idea was that the NMI ISR address would be stored in system variable NMIADDR and on an NMI the ROM would jump to NMIADDR unless it held 0000h as an 'unused' marker. Tragically, the ROM's ISR at 0066h gets the test upside-down: if NMIADDR is zero, it jumps to address NMIADDR, instead of if NMIADDR is non-zero.

That single mistake (a JR NZ instead of a JR Z) renders the Spectrum's NMI and NMIADDR useless. (It could be argued that it can be used to conditionally reset the Spectrum based on NMIADDR. But no-one has been seen to have found an application for that and publicised it in the last 40 years, so it can safely be called useless.)

  • 1
    Well, when you're fiddling with hardware anyways, you could do what the IF1 does - replace the Spectrum ROM entirely as reaction to RST8 - While the shadow ROM is paged in, you own he RST and interrupt vectors. Obviously, that could be a bit of a limitation.
    – tofro
    Commented Apr 9, 2023 at 23:25
  • 3
    @tofro, when you say 'fiddling with hardware' though, adding an overlay EPROM and programming it is far more work and cost than connecting a single wire up, it's not just a little extra. I know because I've built both for the Spectrum. Do it in software, nice and easy and that's what software's flexibility is for. I did this a load of times, too.
    – TonyM
    Commented Apr 9, 2023 at 23:39
  • 1
    This answer is slightly wrong. There are circumstances where the value on the bus from the im2 int ack cycle will be random (it's also FF not FE) and your software will crash. Instead you point I at one of the page sized blocks of FF in the ROM, set FFFF to a JR, and put your code from FFF4.
    – Alan Cox
    Commented Apr 15, 2023 at 23:58
  • 1
    @AlanCox pointing I into ROM will work to get an FFFF vector on the 48k ROM but not when the 128k ROM is paged-in (and with external hardware connected which may drive the data bus during INT-asserted) which doesn't have a 257-byte span of FF bytes, in that case I think the answer's method would be most portable between different Spectrum models and hardware, and even other Z80-based systems.
    – matja
    Commented Jun 21, 2023 at 16:09
  • True but nobody ever needed the 128K ROM paged in for a game or the magic rst8 ball
    – Alan Cox
    Commented Jun 22, 2023 at 17:53

I managed to bypass the firmware error with some fiddling with hardware connected to the ZX Spectrum. Non-maskable interrupt was triggered manually with a pushbutton. No need to load any NMI driver, everything worked with the original ZX Spectrum ROM.

My hardware decoded the value 0068h on address bus, which was activated whenever NMI request arrived. This value temporarily blocked ROMCS and at the same time forced 0 on data lines D4, D5. This simulated the instruction CFh, i.e. RST 8.

Unfortunately this solution doesn't work in mode IM2 (most games), but it had saved me many times from having to reset during program development.

Whenever my computer got frozen, I pressed NMI pushbutton which activated maskable interrupt RST 8 instead of NMI. That invoked the code ERROR_RESTART. Message CONTINUE e, 30:1 appeared at the bottom and I could continue with Basic commands, keeping the memory unerased.

  • 3
    Very interesting.
    – ozw1z5rd
    Commented Apr 12, 2023 at 6:55

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .