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:
IM0
executes opc placed on databus by external HW
IM1
calls fixed ISR at 38h
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...