interrupt method
Simulates pulsing the processor's INT (or NMI) pin
nonMaskable
- true if this is a non-maskable interrupt
data
- the value to be placed on the data bus, if needed
Implementation
void interrupt(bool nonMaskable, int data) {
if (nonMaskable) {
// The high bit of R is not affected by this increment,
// it can only be changed using the LD R, A instruction.
_r = (_r & 0x80) | (((_r & 0x7f) + 1) & 0x7f);
// Non-maskable interrupts are always handled the same way;
// clear IFF1 and then do a CALL 0x0066.
// Also, all interrupts reset the HALT state.
_halted = false;
_iff2 = _iff1;
_iff1 = 0;
_pushWord(_pc);
_pc = 0x66;
_cycleCounter += 11;
} else if (_iff1 != 0) {
// The high bit of R is not affected by this increment,
// it can only be changed using the LD R, A instruction.
_r = (_r & 0x80) | (((_r & 0x7f) + 1) & 0x7f);
_halted = false;
_iff1 = 0;
_iff2 = 0;
if (_interruptMode == 0) {
// In the 8080-compatible interrupt mode,
// decode the content of the data bus as an instruction and run it.
// it's probably a RST instruction, which pushes (PC+1) onto the stack
// so we should decrement PC before we decode the instruction
_pc = (_pc - 1) & 0xffff;
_decodeInstruction(data);
_pc = (_pc + 1) & 0xffff; // increment PC upon return
_cycleCounter += 2;
} else if (_interruptMode == 1) {
// Mode 1 is always just RST 0x38.
_pushWord(_pc);
_pc = 0x38;
_cycleCounter += 13;
} else if (_interruptMode == 2) {
// Mode 2 uses the value on the data bus as in index
// into the vector table pointer to by the I register.
_pushWord(_pc);
// The Z80 manual says that this address must be 2-byte aligned,
// but it doesn't appear that this is actually the case on the hardware,
// so we don't attempt to enforce that here.
var vectorAddress = ((_i << 8) | data);
_pc = _core.memRead(vectorAddress) |
(_core.memRead((vectorAddress + 1) & 0xffff) << 8);
_cycleCounter += 19;
}
}
}