IM0/1/2
— это инструкции, устанавливающие ЦП Z80 в режим прерывания 0/1/2
. Каждый режим обрабатывает маскируемые прерывания по-разному. В свои годы я использую те, но IIRC:
IM0
выполняет opc, размещенный на шине данных внешним аппаратным обеспечением
IM1
вызывает фиксированный ISR на 38h
IM2
вызывает ISR из таблицы точек входа ISR, которая находится там, где i
точки регистра
Вот соответствующий код прерывания C++, извлеченный из моего эмулятора:
//---------------------------------------------------------------------------
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
}
//---------------------------------------------------------------------------
Вот все инструкции IM по порядку, извлеченные отсюда Какова правильная реализация аппаратной эмуляции?:
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
Как видите, это:
IM value: 0 0 1 2 0 0 1 2
И ваша связанная страница:
IM value: 0 0/1 1 2 0 0/1 1 2
поэтому я ожидаю, что это просто означает, как кодируется opc
, но вы правы, таблицы не очень очевидны.
IM0/1 являются дубликатами IM0, поэтому я предполагаю, что их не было в исходной документации, и они были обнаружены только позже ... без точного знания поведения в то время вашей таблицы был создан... Существует множество изначально недокументированных (секретных) инструкций, поэтому, если ваш источник информации не содержит их точно, возможно, вам не следует его использовать и перейти к более качественным документам, чтобы избежать проблем и несовместимостей в будущем...
person
Spektre
schedule
13.02.2020