0

I am in the process of writing (yet another) Z80 simulator. I am using the decoding page on the z80.info site.

In the section with the lookup/disssambly tables it says that for index 1 and 5 the Interrupt Mode is IM0/1. This table is referred to from the IM instruction (ED) X=1, Z=6.

What does IM0/1 mean exactly?

I know it's not an official instruction but I am also trying to support undocumented instructions.

obiwanjacobi
  • 2,413
  • 17
  • 27

2 Answers2

2

As found here, quoting from Gerton Lunter:

The instructions ED 4E and ED 6E are IM 0 equivalents: when FF was put on the bus (physically) at interrupt time, the Spectrum continued to execute normally, whereas when an EF (RST 28h) was put on the bus it crashed, just as it does in that case when the Z80 is in the official interrupt mode 0. In IM 1 the Z80 just executes a RST 38h (opcode FF) no matter what is on the bus.

So it pretty much means IM 0, and I'm not sure where the commonly seen /1 comes from.

harold
  • 61,398
  • 6
  • 86
  • 164
  • 2
    The "/1" indicates that it may be either "IM 0" or "IM 1". – Ignacio Vazquez-Abrams Sep 11 '16 at 13:15
  • 1
    @IgnacioVazquez-Abrams well that's what I used to think, but that isn't how that instruction actually behaves according to anything I can actually find about it. – harold Sep 11 '16 at 13:27
  • 1
    I assume it means: was originally tested by somebody with a machine that didn't load the bus. Therefore that tester could not determine which interrupt mode they had entered and necessarily had to document the operation vaguely, and that propagated widely. Gerton appears to have discovered them definitely to be IM 0. So they're IM 0 but may still be documented as 1/0 because for a long time the mode was unknown. – Tommy Sep 12 '16 at 15:48
  • How fool-proof would testing this on a spectrum be? I mean could the spectrum's ULA intervene with the behavior of accepting and processing the interrupt and therefor make it crash? – obiwanjacobi Sep 14 '16 at 08:07
  • 1
    @Tommy Think I agree as `IM0/1` are duplicates of `IM0` so I am guessing they were not in original documentation and was discovered only latter ... without the exact behavior knowledge at that time ... – Spektre Feb 13 '20 at 20:45
0

IM0/1/2 are instructions setting the Z80 CPU int interrupt mode 0/1/2. Each mode handles the maskable interrupts differently. Its years I use those but IIRC:

  1. IM0

    executes opc placed on databus by external HW

  2. IM1

    calls fixed ISR at 38h

  3. IM2

    calls ISR from ISR entry point table which is placed where i register points

Here relevant interrupt C++ code extracted from my emulator:

//---------------------------------------------------------------------------
void Z80::_reset()
    {
    im=0;
    iff1=0;
    iff2=0;
    reg.r16.pc =0x0000;
    reg.r16.af =0xFFFF;
    reg.r16.bc =0xFFFF;
    reg.r16.de =0xFFFF;
    reg.r16.hl =0xFFFF;
    reg.r16.ix =0xFFFF;
    reg.r16.iy =0xFFFF;
    reg.r16.ir =0xFFFF;
    reg.r16.sp =0xFFFF;
    reg.r16._af=0xFFFF;
    reg.r16._bc=0xFFFF;
    reg.r16._de=0xFFFF;
    reg.r16._hl=0xFFFF;
    reg.r16.alu=0xFFFF;
    reg.r16.mem=0xFFFF;
    reg.r16.io =0xFFFF;
    reg.r16.nn =0xFFFF;
    time=0; time0=0; dtime=0;
    busrq=false;
    busack=false;
    }
//---------------------------------------------------------------------------
void Z80::_int()
    {
    if (!_enable_int) return;
    if (!iff1) return;
    if (actual->ins==_z80_ins_HALT) reg.r16.pc+=actual->size;
    if ((actual->ins==_z80_ins_EI)||(actual->ins==_z80_ins_DI)) execute();

    iff1=0;
    iff2=0;

    if (im==0)
        {
        // execute instruction on databus db from peripherials
        mc=0;
        actual=&ins_int0;
        time+=actual->mc[mc]; mc++;     // fetch INT
        BYTE db[4];
        db[0]=db8;
        db[1]=db8;
        db[2]=db8;
        db[3]=db8;
        execute(db);
        }
    else if (im==1)
        {
        mc=0;
        actual=&ins_int1;
        time+=actual->mc[mc]; mc++;     // fetch INT
        _push(reg.r16.pc);
        reg.r16.pc=0x0038;              // fixed vector 38h
        }
    else if (im==2)
        {
        mc=0;
        actual=&ins_int2;
        time+=actual->mc[mc]; mc++;     // fetch INT
        _push(reg.r16.pc);

        union { BYTE db[2]; WORD dw; } ubw;
        ubw.db[1]=reg.r8.i;             // H
        ubw.db[0]=db8;                  // L
        reg.r16.pc=_readw(ubw.dw);      // vector from mem[i+db8]
        }
    }
//---------------------------------------------------------------------------
void Z80::_nmi()
    {
    if (actual->ins==_z80_ins_HALT) reg.r16.pc+=actual->size;
    if ((actual->ins==_z80_ins_EI)||(actual->ins==_z80_ins_DI)) execute();

    iff2=iff1;      // iff2 ide do flagov po ld a,i alebo ld a,r
    iff1=0;

    mc=0;
    actual=&ins_nmi;
    time+=actual->mc[mc]; mc++;     // fetch NMI
    _push(reg.r16.pc);
    reg.r16.pc=0x0066;              // fixed vector 66h
    }
//---------------------------------------------------------------------------

Here all the IM instructions in order extracted from here What's the proper implementation for hardware emulation?:

opc      T0 T1 MC1   MC2   MC3   MC4   MC5   MC6   MC7   mnemonic
ED46     08 00 M1R 4 M1R 4 ... 0 ... 0 ... 0 ... 0 ... 0 IM0
ED4E     08 00 M1R 4 M1R 4 ... 0 ... 0 ... 0 ... 0 ... 0 IM0
ED56     08 00 M1R 4 M1R 4 ... 0 ... 0 ... 0 ... 0 ... 0 IM1
ED5E     08 00 M1R 4 M1R 4 ... 0 ... 0 ... 0 ... 0 ... 0 IM2
ED66     08 00 M1R 4 M1R 4 ... 0 ... 0 ... 0 ... 0 ... 0 IM0
ED6E     08 00 M1R 4 M1R 4 ... 0 ... 0 ... 0 ... 0 ... 0 IM0
ED76     08 00 M1R 4 M1R 4 ... 0 ... 0 ... 0 ... 0 ... 0 IM1
ED7E     08 00 M1R 4 M1R 4 ... 0 ... 0 ... 0 ... 0 ... 0 IM2

As you can see its:

IM value: 0  0  1 2 0  0  1 2

And your linked page:

IM value: 0 0/1 1 2 0 0/1 1 2

so I expect it just mean how the opc is encoded but you right the tables there are not very obvious.

The IM0/1 are duplicates of IM0 so I am guessing they were not in original documentation and was discovered only latter ... without the exact behavior knowledge at that time your table was created... There are a lot of originally undocumented (secret) instructions so if your source of info does not contain them accurately maybe you should not use it and move to better docs to avoid problems and incompatibilities in future...

Community
  • 1
  • 1
Spektre
  • 49,595
  • 11
  • 110
  • 380