mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-25 18:30:21 +00:00
Merge pull request #102 from TomHarte/6532Accuracy
Improves 6532 counting accuracy
This commit is contained in:
commit
cccdc558e7
@ -51,7 +51,7 @@ template <class T> class MOS6532 {
|
|||||||
if(address & 0x10)
|
if(address & 0x10)
|
||||||
{
|
{
|
||||||
timer_.writtenShift = timer_.activeShift = (decodedAddress - 0x04) * 3 + (decodedAddress / 0x07); // i.e. 0, 3, 6, 10
|
timer_.writtenShift = timer_.activeShift = (decodedAddress - 0x04) * 3 + (decodedAddress / 0x07); // i.e. 0, 3, 6, 10
|
||||||
timer_.value = ((unsigned int)(value) << timer_.activeShift) | ((1 << timer_.activeShift)-1);
|
timer_.value = ((unsigned int)value << timer_.activeShift) ;
|
||||||
timer_.interrupt_enabled = !!(address&0x08);
|
timer_.interrupt_enabled = !!(address&0x08);
|
||||||
interrupt_status_ &= ~InterruptFlag::Timer;
|
interrupt_status_ &= ~InterruptFlag::Timer;
|
||||||
evaluate_interrupts();
|
evaluate_interrupts();
|
||||||
@ -119,7 +119,7 @@ template <class T> class MOS6532 {
|
|||||||
timer_.value -= number_of_cycles;
|
timer_.value -= number_of_cycles;
|
||||||
} else {
|
} else {
|
||||||
number_of_cycles -= timer_.value;
|
number_of_cycles -= timer_.value;
|
||||||
timer_.value = 0x100 - number_of_cycles;
|
timer_.value = (0x100 - number_of_cycles) & 0xff;
|
||||||
timer_.activeShift = 0;
|
timer_.activeShift = 0;
|
||||||
interrupt_status_ |= InterruptFlag::Timer;
|
interrupt_status_ |= InterruptFlag::Timer;
|
||||||
evaluate_interrupts();
|
evaluate_interrupts();
|
||||||
|
@ -22,6 +22,7 @@ Machine::Machine() :
|
|||||||
tia_input_value_{0xff, 0xff},
|
tia_input_value_{0xff, 0xff},
|
||||||
cycles_since_speaker_update_(0),
|
cycles_since_speaker_update_(0),
|
||||||
cycles_since_video_update_(0),
|
cycles_since_video_update_(0),
|
||||||
|
cycles_since_6532_update_(0),
|
||||||
frame_record_pointer_(0),
|
frame_record_pointer_(0),
|
||||||
is_ntsc_(true)
|
is_ntsc_(true)
|
||||||
{
|
{
|
||||||
@ -62,6 +63,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
|||||||
|
|
||||||
cycles_since_speaker_update_ += cycles_run_for;
|
cycles_since_speaker_update_ += cycles_run_for;
|
||||||
cycles_since_video_update_ += cycles_run_for;
|
cycles_since_video_update_ += cycles_run_for;
|
||||||
|
cycles_since_6532_update_ += (cycles_run_for / 3);
|
||||||
|
|
||||||
if(operation != CPU6502::BusOperation::Ready) {
|
if(operation != CPU6502::BusOperation::Ready) {
|
||||||
|
|
||||||
@ -203,6 +205,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
|||||||
|
|
||||||
// check for a PIA access
|
// check for a PIA access
|
||||||
if((address&0x1280) == 0x280) {
|
if((address&0x1280) == 0x280) {
|
||||||
|
update_6532();
|
||||||
if(isReadOperation(operation)) {
|
if(isReadOperation(operation)) {
|
||||||
returnValue &= mos6532_.get_register(address);
|
returnValue &= mos6532_.get_register(address);
|
||||||
} else {
|
} else {
|
||||||
@ -216,7 +219,6 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!tia_->get_cycles_until_horizontal_blank(cycles_since_video_update_)) set_ready_line(false);
|
if(!tia_->get_cycles_until_horizontal_blank(cycles_since_video_update_)) set_ready_line(false);
|
||||||
mos6532_.run_for_cycles(cycles_run_for / 3);
|
|
||||||
|
|
||||||
return cycles_run_for / 3;
|
return cycles_run_for / 3;
|
||||||
}
|
}
|
||||||
@ -321,6 +323,12 @@ void Machine::update_video()
|
|||||||
cycles_since_video_update_ = 0;
|
cycles_since_video_update_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Machine::update_6532()
|
||||||
|
{
|
||||||
|
mos6532_.run_for_cycles(cycles_since_6532_update_);
|
||||||
|
cycles_since_6532_update_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void Machine::synchronise()
|
void Machine::synchronise()
|
||||||
{
|
{
|
||||||
update_audio();
|
update_audio();
|
||||||
|
@ -77,11 +77,15 @@ class Machine:
|
|||||||
|
|
||||||
// speaker backlog accumlation counter
|
// speaker backlog accumlation counter
|
||||||
unsigned int cycles_since_speaker_update_;
|
unsigned int cycles_since_speaker_update_;
|
||||||
void update_audio();
|
inline void update_audio();
|
||||||
|
|
||||||
// video backlog accumulation counter
|
// video backlog accumulation counter
|
||||||
unsigned int cycles_since_video_update_;
|
unsigned int cycles_since_video_update_;
|
||||||
void update_video();
|
inline void update_video();
|
||||||
|
|
||||||
|
// RIOT backlog accumulation counter
|
||||||
|
unsigned int cycles_since_6532_update_;
|
||||||
|
inline void update_6532();
|
||||||
|
|
||||||
// output frame rate tracker
|
// output frame rate tracker
|
||||||
struct FrameRecord
|
struct FrameRecord
|
||||||
|
@ -21,14 +21,25 @@ class MOS6532Tests: XCTestCase {
|
|||||||
with6532 {
|
with6532 {
|
||||||
// set a count of 128 at single-clock intervals
|
// set a count of 128 at single-clock intervals
|
||||||
$0.setValue(128, forRegister:0x14)
|
$0.setValue(128, forRegister:0x14)
|
||||||
|
XCTAssertEqual($0.value(forRegister: 4), 128)
|
||||||
|
|
||||||
// run for one clock and the count should now be 127
|
// run for one more clock and the count should now be 127
|
||||||
$0.run(forCycles: 1)
|
$0.run(forCycles: 1)
|
||||||
XCTAssert($0.value(forRegister: 4) == 127, "A single tick should decrease the counter once")
|
XCTAssertEqual($0.value(forRegister: 4), 127)
|
||||||
|
|
||||||
// run for a further 200 clock counts; timer should reach -73 = 183
|
// run for 127 clocks and the timer should be zero, but the timer flag will not yet be set
|
||||||
$0.run(forCycles: 200)
|
$0.run(forCycles: 127)
|
||||||
XCTAssert($0.value(forRegister: 4) == 183, "Timer should underflow and keep counting")
|
XCTAssertEqual($0.value(forRegister: 5) & 0x80, 0)
|
||||||
|
XCTAssertEqual($0.value(forRegister: 4), 0)
|
||||||
|
|
||||||
|
// after one more cycle the counter should be 255 and the timer flag will now be set
|
||||||
|
$0.run(forCycles: 1)
|
||||||
|
XCTAssertEqual($0.value(forRegister: 5) & 0x80, 0x80)
|
||||||
|
XCTAssertEqual($0.value(forRegister: 4), 255)
|
||||||
|
|
||||||
|
// run for a further 55 clock counts; timer should reach -200
|
||||||
|
$0.run(forCycles: 55)
|
||||||
|
XCTAssertEqual($0.value(forRegister: 4), 200)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,26 +48,40 @@ class MOS6532Tests: XCTestCase {
|
|||||||
with6532 {
|
with6532 {
|
||||||
// set a count of 28 at eight-clock intervals
|
// set a count of 28 at eight-clock intervals
|
||||||
$0.setValue(28, forRegister:0x15)
|
$0.setValue(28, forRegister:0x15)
|
||||||
|
XCTAssertEqual($0.value(forRegister: 4), 28)
|
||||||
|
|
||||||
// run for seven clock and the count should still be 28
|
// one further cycle and the timer should hit 27
|
||||||
$0.run(forCycles: 7)
|
|
||||||
XCTAssert($0.value(forRegister: 4) == 28, "The timer should remain unchanged for seven clocks")
|
|
||||||
|
|
||||||
// run for a further clock and the count should now be 27
|
|
||||||
$0.run(forCycles: 1)
|
$0.run(forCycles: 1)
|
||||||
XCTAssert($0.value(forRegister: 4) == 27, "The timer should have decremented once after 8 cycles")
|
XCTAssertEqual($0.value(forRegister: 4), 27)
|
||||||
|
|
||||||
// run for a further 7 + 27*8 + 5 = 228 clock counts; timer should reach -5 = 0xfb
|
// run for seven clock and the count should still be 27
|
||||||
$0.run(forCycles: 228)
|
$0.run(forCycles: 7)
|
||||||
XCTAssert($0.value(forRegister: 4) == 0xfb, "Timer should underflow and start counting at single-clock pace")
|
XCTAssertEqual($0.value(forRegister: 4), 27)
|
||||||
|
|
||||||
|
// run for a further clock and the count should now be 26
|
||||||
|
$0.run(forCycles: 1)
|
||||||
|
XCTAssertEqual($0.value(forRegister: 4), 26)
|
||||||
|
|
||||||
|
// run for another 26 * 8 = 208 cycles and the count should hit zero without setting the timer flag, and
|
||||||
|
// stay there for seven more cycles
|
||||||
|
$0.run(forCycles: 208)
|
||||||
|
for _ in 0 ..< 8 {
|
||||||
|
XCTAssertEqual($0.value(forRegister: 5) & 0x80, 0)
|
||||||
|
XCTAssertEqual($0.value(forRegister: 4), 0)
|
||||||
|
$0.run(forCycles: 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// run six more, and the timer should reach 249, with the interrupt flag set
|
||||||
|
$0.run(forCycles: 6)
|
||||||
|
XCTAssertEqual($0.value(forRegister: 5) & 0x80, 0x80)
|
||||||
|
XCTAssertEqual($0.value(forRegister: 4), 249)
|
||||||
|
|
||||||
// timer should now resume dividing by eight
|
// timer should now resume dividing by eight
|
||||||
$0.run(forCycles: 7)
|
$0.run(forCycles: 7)
|
||||||
XCTAssert($0.value(forRegister: 4) == 0xfb, "Timer should remain unchanged for seven cycles")
|
XCTAssertEqual($0.value(forRegister: 4), 249)
|
||||||
|
|
||||||
// timer should now resume dividing by eight
|
|
||||||
$0.run(forCycles: 1)
|
$0.run(forCycles: 1)
|
||||||
XCTAssert($0.value(forRegister: 4) == 0xfa, "Timer should decrement after eighth cycle")
|
XCTAssertEqual($0.value(forRegister: 4), 248)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,8 +89,6 @@ class MOS6532Tests: XCTestCase {
|
|||||||
with6532 {
|
with6532 {
|
||||||
// set a count of 1 at single-clock intervals
|
// set a count of 1 at single-clock intervals
|
||||||
$0.setValue(1, forRegister:0x1c)
|
$0.setValue(1, forRegister:0x1c)
|
||||||
|
|
||||||
// run for one clock and the count should now be zero
|
|
||||||
$0.run(forCycles: 1)
|
$0.run(forCycles: 1)
|
||||||
|
|
||||||
// interrupt shouldn't be signalled yet, bit should not be set
|
// interrupt shouldn't be signalled yet, bit should not be set
|
||||||
|
Loading…
Reference in New Issue
Block a user