1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-24 12:30:17 +00:00

Expanded 6532 tests substantially, beefing up implementation to match.

This commit is contained in:
Thomas Harte 2016-06-20 21:02:42 -04:00
parent 88e2b382e5
commit fe17d1778c
3 changed files with 115 additions and 7 deletions

View File

@ -38,10 +38,12 @@ template <class T> class MOS6532 {
case 0x00: case 0x02:
_port[decodedAddress / 2].output = value;
static_cast<T *>(this)->set_port_output(decodedAddress / 2, _port[decodedAddress/2].output, _port[decodedAddress / 2].output_mask);
set_port_did_change(decodedAddress / 2);
break;
case 0x01: case 0x03:
_port[decodedAddress / 2].output_mask = value;
static_cast<T *>(this)->set_port_output(decodedAddress / 2, _port[decodedAddress/2].output, _port[decodedAddress / 2].output_mask);
set_port_did_change(decodedAddress / 2);
break;
// The timer and edge detect control
@ -125,7 +127,10 @@ template <class T> class MOS6532 {
}
MOS6532() :
_interrupt_status(0), _port{{.output_mask = 0, .output = 0}, {.output_mask = 0, .output = 0}}, _a7_interrupt({.last_port_value = 0, .enabled = false})
_interrupt_status(0),
_port{{.output_mask = 0, .output = 0}, {.output_mask = 0, .output = 0}},
_a7_interrupt({.last_port_value = 0, .enabled = false}),
_interrupt_line(false)
{}
inline void set_port_did_change(int port)
@ -149,6 +154,11 @@ template <class T> class MOS6532 {
}
}
inline bool get_inerrupt_line()
{
return _interrupt_line;
}
private:
uint8_t _ram[128];
@ -173,6 +183,7 @@ template <class T> class MOS6532 {
Timer = 0x80,
PA7 = 0x40
};
bool _interrupt_line;
// expected to be overridden
uint8_t get_port_input(int port) { return 0xff; }
@ -181,10 +192,10 @@ template <class T> class MOS6532 {
inline void evaluate_interrupts()
{
set_irq_line(
_interrupt_line =
((_interrupt_status&InterruptFlag::Timer) && _timer.interrupt_enabled) ||
((_interrupt_status&InterruptFlag::PA7) && _a7_interrupt.enabled)
);
((_interrupt_status&InterruptFlag::PA7) && _a7_interrupt.enabled);
set_irq_line(_interrupt_line);
}
};

View File

@ -20,7 +20,7 @@ class MOS6532Tests: XCTestCase {
func testOneTickTimer() {
with6532 {
// set a count of 128 at single-clock intervals
$0.setValue(128, forRegister:4)
$0.setValue(128, forRegister:0x14)
// run for one clock and the count should now be 127
$0.runForCycles(1)
@ -32,11 +32,11 @@ class MOS6532Tests: XCTestCase {
}
}
// TODO: the test below makes the assumption that divider phase is flexible; verify
// TODO: the tests below makes the assumption that divider phase is flexible; verify
func testEightTickTimer() {
with6532 {
// set a count of 28 at eight-clock intervals
$0.setValue(28, forRegister:5)
$0.setValue(28, forRegister:0x15)
// run for seven clock and the count should still be 28
$0.runForCycles(7)
@ -59,4 +59,96 @@ class MOS6532Tests: XCTestCase {
XCTAssert($0.valueForRegister(4) == 0xfa, "Timer should decrement after eighth cycle")
}
}
func testTimerInterrupt() {
with6532 {
// set a count of 1 at single-clock intervals
$0.setValue(1, forRegister:0x1c)
// run for one clock and the count should now be zero
$0.runForCycles(1)
// interrupt shouldn't be signalled yet, bit should not be set
XCTAssert(!$0.irqLine, "IRQ line should not be set")
XCTAssert($0.valueForRegister(5) == 0x00, "Counter interrupt should not be set")
// run for one more clock
$0.runForCycles(1)
// the interrupt line and bit should now be set
XCTAssert($0.irqLine, "IRQ line should be set")
XCTAssert($0.valueForRegister(5) == 0x80, "Counter interrupt should be set")
// writing again to the timer should clear both
$0.setValue(1, forRegister:0x1c)
XCTAssert(!$0.irqLine, "IRQ line should be clear")
XCTAssert($0.valueForRegister(5) == 0x00, "Counter interrupt should not be set")
}
}
// MARK: PA7 interrupt tests
func testPA7InterruptDisabled() {
with6532 {
// disable edge detection
$0.setValue(0, forRegister:4)
// set output mode for port a
$0.setValue(0xff, forRegister:1)
// toggle bit 7 of port a in both directions
$0.setValue(0x80, forRegister:0)
$0.setValue(0x00, forRegister:0)
$0.setValue(0x80, forRegister:0)
// confirm that the interrupt flag is set but the line is not
XCTAssert(!$0.irqLine, "IRQ line should not be set")
XCTAssert($0.valueForRegister(5) == 0x40, "Timer interrupt bit should be set")
// reading the status register should have reset the interrupt flag
XCTAssert($0.valueForRegister(5) == 0x00, "Timer interrupt bit should be reset")
}
}
func testPA7LeadingEdge() {
with6532 {
// seed port a is high; ensure interrupt bit is clear
$0.setValue(0x00, forRegister:0)
$0.valueForRegister(5)
// enable leading edge detection
$0.setValue(0, forRegister:7)
// set output mode for port a
$0.setValue(0xff, forRegister:1)
// toggle bit 7 of port a in a leading direction
$0.setValue(0x80, forRegister:0)
// confirm that both the interrupt flag are the line are set
XCTAssert($0.irqLine, "IRQ line should be set")
XCTAssert($0.valueForRegister(5) == 0x40, "Timer interrupt bit should be set")
}
}
func testPA7TrailingEdge() {
with6532 {
// seed port a is high; ensure interrupt bit is clear
$0.setValue(0x80, forRegister:0)
$0.valueForRegister(5)
// enable trailing edge detection
$0.setValue(0, forRegister:6)
// set output mode for port a
$0.setValue(0xff, forRegister:1)
// toggle bit 7 of port a in a rising direction
$0.setValue(0x00, forRegister:0)
// confirm that both the interrupt flag are the line are set
XCTAssert($0.irqLine, "IRQ line should be set")
XCTAssert($0.valueForRegister(5) == 0x40, "Timer interrupt bit should be set")
}
}
}

View File

@ -32,4 +32,9 @@ class VanillaRIOT: public MOS::MOS6532<VanillaRIOT> {
_riot.run_for_cycles((int)numberOfCycles);
}
- (BOOL)irqLine
{
return _riot.get_inerrupt_line();
}
@end