1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-19 08:31:11 +00:00

Tweaked timing of mode 0, per contradictory information. Wrote a failing test of mode 2.

This commit is contained in:
Thomas Harte 2017-06-03 18:42:54 -04:00
parent e52892f75b
commit b3da16911f
2 changed files with 83 additions and 1 deletions

View File

@ -73,7 +73,46 @@ class Z80InterruptTests: XCTestCase {
XCTAssertEqual(machine.value(for: .programCounter), 0x0105) XCTAssertEqual(machine.value(for: .programCounter), 0x0105)
} }
func testIRQMode0() {
// In interrupt mode 0, receipt of an IRQ causes an instruction to be read from the bus and
// executed, with a two-cycle penalty. The test machine posts 0x21 during an interrupt acknowledge
// cycle so the instruction that is executed will be LD HL, nnnn
let machine = CSTestMachineZ80()
// start the PC at 0x0100 and install two NOPs for it and then one copy of 0x83, then
// something that isn't 0x83, and ensuring interrupts are enabled and in mode 1
machine.setValue(0x0100, for: .programCounter)
machine.setValue(1, for: .IFF1)
machine.setValue(0, for: .IM)
machine.setValue(0x1010, for: .HL)
machine.setValue(0x00, atAddress: 0x0100)
machine.setValue(0x00, atAddress: 0x0101)
machine.setValue(0x83, atAddress: 0x0102)
machine.setValue(0x9b, atAddress: 0x0103)
// run for four cycles, and signal an IRQ
machine.runForNumber(ofCycles: 4)
machine.irqLine = true
// run for four more cycles to get to where the IRQ should be recognised
machine.runForNumber(ofCycles: 4)
XCTAssertEqual(machine.value(for: .programCounter), 0x0102)
// run for twelve more cycles, to complete a LD HL, nnnn with the additional two cycles
// of cost for it being an IRQ program
machine.runForNumber(ofCycles: 12)
// confirm that the PC is still where it was, but HL is now 0x8383, and interrupts are disabled
XCTAssertEqual(machine.value(for: .programCounter), 0x0102)
XCTAssertEqual(machine.value(for: .HL), 0x8383)
XCTAssertEqual(machine.value(for: .IFF1), 0)
}
func testIRQMode1() { func testIRQMode1() {
// In interrupt mode 1, receipt of an IRQ means that the interrupt flag is disabled,
// the PC is pushed to the stack and execution resumes at 0x38.
let machine = CSTestMachineZ80() let machine = CSTestMachineZ80()
// start the PC at 0x0100 and install three NOPs for it, ensuring interrupts are enabled // start the PC at 0x0100 and install three NOPs for it, ensuring interrupts are enabled
@ -106,4 +145,47 @@ class Z80InterruptTests: XCTestCase {
XCTAssertEqual(machine.value(atAddress: 0xfffe), 0x02) XCTAssertEqual(machine.value(atAddress: 0xfffe), 0x02)
XCTAssertEqual(machine.value(for: .IFF1), 0) XCTAssertEqual(machine.value(for: .IFF1), 0)
} }
func testIRQMode2() {
// In interrupt mode 2, the current bus value is combined with the I register to look
// up a vector from memory; the PC calls that vector. Total cost: 19 cycles.
let machine = CSTestMachineZ80()
// start the PC at 0x0100 and install two NOPs for it and then one copy of 0x83, then
// something that isn't 0x83, and ensuring interrupts are enabled and in mode 1
machine.setValue(0x0100, for: .programCounter)
machine.setValue(1, for: .IFF1)
machine.setValue(2, for: .IM)
machine.setValue(0x00, atAddress: 0x0100)
machine.setValue(0x00, atAddress: 0x0101)
// set I to 0x0200 to establish the location of our vector table, and because the test
// machine will post a 0x21 in response to the interrupt cycle, at 0x0221 put the
// arbitrarily-chosen address 0x8049
machine.setValue(0x02, for: .I)
machine.setValue(0x49, atAddress: 0x0221)
machine.setValue(0x80, atAddress: 0x0222)
// put the stack at the top of memory
machine.setValue(0, for: .stackPointer)
// run for four cycles, and signal an IRQ
machine.runForNumber(ofCycles: 4)
machine.irqLine = true
// run for four more cycles to get to where the IRQ should be recognised
machine.runForNumber(ofCycles: 4)
XCTAssertEqual(machine.value(for: .programCounter), 0x0102)
// run for nineteen more cycles, to complete the interrupt beginning
machine.runForNumber(ofCycles: 19)
// confirm that the PC is now at 0x8049, the old is on the stack, and interrupts
// are disabled
XCTAssertEqual(machine.value(for: .programCounter), 0x8049)
XCTAssertEqual(machine.value(atAddress: 0xffff), 0x01)
XCTAssertEqual(machine.value(atAddress: 0xfffe), 0x02)
XCTAssertEqual(machine.value(for: .IFF1), 0)
}
} }

View File

@ -707,7 +707,7 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
}; };
MicroOp irq_mode0_program[] = { MicroOp irq_mode0_program[] = {
{ MicroOp::BeginIRQMode0 }, { MicroOp::BeginIRQMode0 },
{ MicroOp::BusOperation, nullptr, nullptr, {BusOperation::Interrupt, 7, nullptr, &operation_}}, { MicroOp::BusOperation, nullptr, nullptr, {BusOperation::Interrupt, 6, nullptr, &operation_}},
{ MicroOp::DecodeOperationNoRChange } { MicroOp::DecodeOperationNoRChange }
}; };
MicroOp irq_mode1_program[] = { MicroOp irq_mode1_program[] = {