21

The Multiface One was a memory dumper for the ZX Spectrum 48K with a button that generated an NMI to run code in its ROM that could dump the machine state to mass storage (CMT/cassette tape, diskette, etc.). This could later be reloaded, and was often used to pirate games. Wikipedia mentions that, "later revisions contained a switch that effectively 'hid' the device from software."

In It's Behind You, Bob Pape (the programmer of the R-Type port) mentions, on page 65:

It was the same when [Rob Hylands] told me of his way to defeat the Multiface 1, it was so obvious but so impractical that you wouldn't have even given it a second thought had it crossed your mind but Rob had, and he had the ability and sheer nerve to pull it off. Rob put his protection system into play in the only Spectrum game he wrote, Super Wonder Boy (in Monsterland), a multi-load version of the SEGA sequel to their 1986 Wonder Boy game released by Activision in 1989.

To see if the method still worked I recently go hold of a copy of the game to run on a PC emulator, set the emulator up to mimic the presence of a Multiface 1, loaded the game and pressed the key to invoke the Multiface. Doing nothing else I exited the Multiface and returned to the game where, just as it had with the cassette original in 1989, the game tore itself apart for several seconds and then completely crashed. The brilliance of Rob's method was that even if I had saved off the game to cassette it was already tainted and loading it back in would have led to the same result, a totally unplayable game.... No, I'm not going to tell you what the method was, since if you know nothing about Spectrum Z80 coding it won't mean a thing to you and if you do then think of it as a puzzle to try and solve yourself.

So how did the Multiface hide itself from software, and how did Hylands defeat it?

7
  • 1
    Speculating wildly, perhaps establishing a known value below the stack pointer upon entry of each subroutine and checking that either it is still there upon exit, with the game's IRQ handler doing appropriate gymnastics to fix things up at exit? That's given that nothing in the base hardware causes an NMI.
    – Tommy
    Jul 27, 2023 at 19:40
  • 1
    Alternatively: disable interrupts, point the stack pointer at the ROM so the Multiface NMI can't push its return address, and write your code not to use the Z80's stack at all.
    – john_e
    Jul 27, 2023 at 21:11
  • 1
    What is CMT? I've never heard that term before and neither Googling or the AI chatbots are helping. Jul 28, 2023 at 3:15
  • 1
    From context, "cassette magnetic tape?"
    – john_e
    Jul 28, 2023 at 7:07
  • 2
    @hippietrail Yes, I guess it's only ever called "cassette" in North America. "CMT" is the standard term here in Japan.
    – cjs
    Jul 28, 2023 at 8:01

1 Answer 1

9

A partial answer: the Multiface provides both its own ROM and its own work RAM which it pages in just below the screen area.

Per the For UNIX Spectrum Emulator ('FUSE') source code this 8kb of RAM can be paged in and out in software if a jumper allows it; FUSE internally calls disabling this stealth mode.

I think it's therefore a reasonable conclusion that:

  • by default the Multiface allows its work RAM to be paged in by software, not only by the use of its hardware NMI button;
  • this provides a simple means to check for the presence of a Multiface; but
  • as of later revisions — from 1986 per The Multiface ROM Collection Project assuming that's what they call 'the HW Switch' — software paging of that additional RAM can be disabled.

Re: defeating it, my bet is on exploitation of the fact that the NMI a multiface uses to branch into its own ROM will leave a return address on the stack. So you can determine that an interrupt has occurred if you set a known value just below the stack, don't use the stack in between and test it again later. Of course you'd need your own IRQ handler to be aware of the conceit and to arrange appropriately.

4
  • The detection doesn't seem to be something that could be done after the NMI had returned, since: "The brilliance of Rob's method was that even if I had saved off the game to cassette it was already tainted...."
    – cjs
    Jul 28, 2023 at 8:03
  • 2
    @cjs, unless there was some change made by the NMI itself which could be detected after reloading. This could happen on each function return to detect and violently exit. For example, if every function call was proxied through a hook function, this could clear 20 bytes below the stack pointer that would exist for the function, before calling the function. The proxy return could check and act on that before return to the real caller. An NMI in the interim would have pushed a return address in that block. A little more difficult to ensure non-NMI IRQs worked but certainly doable.
    – paxdiablo
    Jul 28, 2023 at 11:12
  • 2
    For example, cobrasov.com/CoBra%20Project/basic+nmi.html discusses the fact that the memory content of the bytes overwritten by the NMI itself (for the return address) are unrecoverable. Hence a program could check for this.
    – paxdiablo
    Jul 28, 2023 at 11:45
  • 1
    Your bet seems plausible to me; but I wouldn't call it "so impractical that you wouldn't even have given it a second thought", like OP's quote. Although, that quote seems so dramatic. I can't take it too seriously. Aug 1, 2023 at 12:46

You must log in to answer this question.

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