1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-05 10:28:58 +00:00

Switches prescale logic, the better to deal with changes in prescaler.

According to my assumptions about the behaviour, anyway.
This commit is contained in:
Thomas Harte 2019-12-20 23:33:14 -05:00
parent 47508d50a7
commit 57ce10418f
3 changed files with 29 additions and 8 deletions

View File

@ -8,6 +8,7 @@
#include "MFP68901.hpp"
#include <algorithm>
#include <cstring>
#define LOG_PREFIX "[MFP] "
@ -179,12 +180,26 @@ void MFP68901::run_for(HalfCycles time) {
cycles_left_ += time;
const int cycles = int(cycles_left_.flush<Cycles>().as_integral());
if(!cycles) return;
for(int c = 0; c < 4; ++c) {
if(timers_[c].mode >= TimerMode::Delay) {
const int dividend = (cycles + timers_[c].prescale - timers_[c].divisor);
const int decrements = dividend / timers_[c].prescale;
timers_[c].divisor = timers_[c].prescale - (dividend % timers_[c].prescale);
if(decrements) decrement_timer(c, decrements);
// This code applies the timer prescaling only. prescale_count is used to count
// upwards rather than downwards for simplicity, but on the real hardware it's
// pretty safe to assume it actually counted downwards. So the clamp to 0 is
// because gymnastics may need to occur when the prescale value is altered, e.g.
// if a prescale of 256 is set and the prescale_count is currently 2 then the
// counter should roll over in 254 cycles. If the user at that point changes the
// prescale_count to 1 then the counter will need to be altered to -253 and
// allowed to keep counting up until it crosses both 0 and 1.
const int dividend = timers_[c].prescale_count + cycles;
const int decrements = std::max(dividend / timers_[c].prescale, 0);
if(decrements) {
decrement_timer(c, decrements);
timers_[c].prescale_count = dividend % timers_[c].prescale;
} else {
timers_[c].prescale_count += cycles;
}
}
}
}
@ -198,11 +213,17 @@ HalfCycles MFP68901::get_next_sequence_point() {
void MFP68901::set_timer_mode(int timer, TimerMode mode, int prescale, bool reset_timer) {
LOG("Timer " << timer << " mode set: " << int(mode) << "; prescale: " << prescale);
timers_[timer].mode = mode;
timers_[timer].prescale = prescale;
if(reset_timer) {
timers_[timer].divisor = prescale;
timers_[timer].prescale_count = 0;
timers_[timer].value = timers_[timer].reload_value;
} else {
// This hoop is because the prescale_count here goes upward but I'm assuming it goes downward in
// real hardware. Therefore this deals with the "switched to a lower prescaling" case whereby the
// old cycle should be allowed naturally to expire.
timers_[timer].prescale_count = prescale - (timers_[timer].prescale - timers_[timer].prescale_count);
}
timers_[timer].prescale = prescale;
}
void MFP68901::set_timer_data(int timer, uint8_t value) {

View File

@ -93,7 +93,7 @@ class MFP68901: public ClockingHint::Source {
uint8_t value = 0;
uint8_t reload_value = 0;
int prescale = 1;
int divisor = 1;
int prescale_count = 1;
bool event_input = false;
} timers_[4];
uint8_t timer_ab_control_[2] = { 0, 0 };

View File

@ -4916,7 +4916,7 @@
"$(USER_LIBRARY_DIR)/Frameworks",
);
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_OPTIMIZATION_LEVEL = 3;
GCC_OPTIMIZATION_LEVEL = fast;
MACOSX_DEPLOYMENT_TARGET = 10.12;
PRODUCT_NAME = "$(TARGET_NAME)";
};