1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 23:52:26 +00:00

Wrote test case for what appears to be correct timer behaviour if those were acting in isolation. Ensured implementation matches test case.

This commit is contained in:
Thomas Harte 2016-06-18 14:30:23 -04:00
parent 394902f409
commit 5d26cd85a3
3 changed files with 67 additions and 11 deletions

View File

@ -150,28 +150,39 @@ template <class T> class MOS6522 {
{
if(_is_phase2)
{
_registers.timer[0] --;
_registers.timer[1] --;
_registers.last_timer[0] = _registers.timer[0];
_registers.last_timer[1] = _registers.timer[1];
if(!_registers.timer[1] && _timer_is_running[1])
if(_registers.timer_needs_reload)
{
_registers.timer_needs_reload = false;
_registers.timer[0] = _registers.timer_latch[0];
}
else
_registers.timer[0] --;
_registers.timer[1] --;
}
else
{
// IRQ is raised on the half cycle after overflow
if((_registers.timer[1] == 0xffff) && !_registers.last_timer[1] && _timer_is_running[1])
{
_timer_is_running[1] = false;
_registers.interrupt_flags |= InterruptFlag::Timer2;
reevaluate_interrupts();
}
if(!_registers.timer[0] && _timer_is_running[0])
if((_registers.timer[0] == 0xffff) && !_registers.last_timer[0] && _timer_is_running[0])
{
_registers.interrupt_flags |= InterruptFlag::Timer1;
reevaluate_interrupts();
// TODO: reload shouldn't occur for a further 1.5 cycles
if(_registers.auxiliary_control&0x40)
_registers.timer[0] = _registers.timer_latch[0];
_registers.timer_needs_reload = true;
else
_timer_is_running[0] = false;
}
// TODO: lots of other status effects
}
_is_phase2 ^= true;
@ -214,16 +225,18 @@ template <class T> class MOS6522 {
// The registers
struct Registers {
uint8_t output[2], input[2], data_direction[2];
uint16_t timer[2], timer_latch[2];
uint16_t timer[2], timer_latch[2], last_timer[2];
uint8_t shift;
uint8_t auxiliary_control, peripheral_control;
uint8_t interrupt_flags, interrupt_enable;
bool timer_needs_reload;
// "A low reset (RES) input clears all R6522 internal registers to logic 0"
Registers() :
output{0, 0}, input{0, 0}, data_direction{0, 0},
auxiliary_control(0), peripheral_control(0),
interrupt_flags(0), interrupt_enable(0) {}
interrupt_flags(0), interrupt_enable(0),
last_timer{0, 0}, timer_needs_reload(false) {}
} _registers;
// Internal state other than the registers

View File

@ -18,13 +18,51 @@ class MOS6522Tests: XCTestCase {
func testTimerCount() {
with6522 {
// set timer 1 to a value of $000a
$0.setValue(10, forRegister: 4)
$0.setValue(0, forRegister: 5)
// run for 5 cycles
$0.runForHalfCycles(10)
// check that the timer has gone down by 5
XCTAssert($0.valueForRegister(4) == 5, "Low order byte of timer should be 5; was \($0.valueForRegister(4))")
XCTAssert($0.valueForRegister(5) == 0, "High order byte of timer should be 5; was \($0.valueForRegister(5))")
XCTAssert($0.valueForRegister(5) == 0, "High order byte of timer should be 0; was \($0.valueForRegister(5))")
}
}
func testTimerReload() {
with6522 {
// set timer 1 to a value of $0010, enable repeating mode
$0.setValue(16, forRegister: 4)
$0.setValue(0, forRegister: 5)
$0.setValue(0x40, forRegister: 11)
$0.setValue(0x40 | 0x80, forRegister: 14)
// run for 16 cycles
$0.runForHalfCycles(32)
// check that the timer has gone down to 0 but not yet triggered an interrupt
XCTAssert($0.valueForRegister(4) == 0, "Low order byte of timer should be 0; was \($0.valueForRegister(4))")
XCTAssert($0.valueForRegister(5) == 0, "High order byte of timer should be 0; was \($0.valueForRegister(5))")
XCTAssert(!$0.irqLine, "IRQ should not yet be active")
// check that two half-cycles later the timer is $ffff but IRQ still hasn't triggered
$0.runForHalfCycles(2)
XCTAssert($0.valueForRegister(4) == 0xff, "Low order byte of timer should be 0xff; was \($0.valueForRegister(4))")
XCTAssert($0.valueForRegister(5) == 0xff, "High order byte of timer should be 0xff; was \($0.valueForRegister(5))")
XCTAssert(!$0.irqLine, "IRQ should not yet be active")
// check that one half-cycle later the timer is still $ffff and IRQ has triggered
$0.runForHalfCycles(1)
XCTAssert($0.irqLine, "IRQ should be active")
XCTAssert($0.valueForRegister(4) == 0xff, "Low order byte of timer should be 0xff; was \($0.valueForRegister(4))")
XCTAssert($0.valueForRegister(5) == 0xff, "High order byte of timer should be 0xff; was \($0.valueForRegister(5))")
// check that one half-cycles later the timer has reloaded
$0.runForHalfCycles(1)
XCTAssert($0.valueForRegister(4) == 0x10, "Low order byte of timer should be 0x10; was \($0.valueForRegister(4))")
XCTAssert($0.valueForRegister(5) == 0x00, "High order byte of timer should be 0x00; was \($0.valueForRegister(5))")
}
}
}

View File

@ -49,7 +49,12 @@ class VanillaVIA: public MOS::MOS6522<VanillaVIA> {
- (void)runForHalfCycles:(NSUInteger)numberOfHalfCycles
{
_via.run_for_half_cycles(numberOfHalfCycles);
_via.run_for_half_cycles((int)numberOfHalfCycles);
}
- (BOOL)irqLine
{
return _via.irq_line;
}
@end