1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-11 08:30:55 +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 "MFP68901.hpp"
#include <algorithm>
#include <cstring> #include <cstring>
#define LOG_PREFIX "[MFP] " #define LOG_PREFIX "[MFP] "
@ -179,12 +180,26 @@ void MFP68901::run_for(HalfCycles time) {
cycles_left_ += time; cycles_left_ += time;
const int cycles = int(cycles_left_.flush<Cycles>().as_integral()); const int cycles = int(cycles_left_.flush<Cycles>().as_integral());
if(!cycles) return;
for(int c = 0; c < 4; ++c) { for(int c = 0; c < 4; ++c) {
if(timers_[c].mode >= TimerMode::Delay) { if(timers_[c].mode >= TimerMode::Delay) {
const int dividend = (cycles + timers_[c].prescale - timers_[c].divisor); // This code applies the timer prescaling only. prescale_count is used to count
const int decrements = dividend / timers_[c].prescale; // upwards rather than downwards for simplicity, but on the real hardware it's
timers_[c].divisor = timers_[c].prescale - (dividend % timers_[c].prescale); // pretty safe to assume it actually counted downwards. So the clamp to 0 is
if(decrements) decrement_timer(c, decrements); // 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) { void MFP68901::set_timer_mode(int timer, TimerMode mode, int prescale, bool reset_timer) {
LOG("Timer " << timer << " mode set: " << int(mode) << "; prescale: " << prescale); LOG("Timer " << timer << " mode set: " << int(mode) << "; prescale: " << prescale);
timers_[timer].mode = mode; timers_[timer].mode = mode;
timers_[timer].prescale = prescale;
if(reset_timer) { if(reset_timer) {
timers_[timer].divisor = prescale; timers_[timer].prescale_count = 0;
timers_[timer].value = timers_[timer].reload_value; 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) { 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 value = 0;
uint8_t reload_value = 0; uint8_t reload_value = 0;
int prescale = 1; int prescale = 1;
int divisor = 1; int prescale_count = 1;
bool event_input = false; bool event_input = false;
} timers_[4]; } timers_[4];
uint8_t timer_ab_control_[2] = { 0, 0 }; uint8_t timer_ab_control_[2] = { 0, 0 };

View File

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