1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-26 08:29:33 +00:00

Add a compiletime 'turbo' flag for sort-of-80286 speeds.

This commit is contained in:
Thomas Harte 2023-12-08 09:38:55 -05:00
parent e55a09962f
commit 3a103217d1

View File

@ -908,7 +908,7 @@ class FlowController {
bool halted_ = false;
};
template <VideoAdaptor video>
template <VideoAdaptor video, bool turbo>
class ConcreteMachine:
public Machine,
public MachineTypes::TimedMachine,
@ -975,9 +975,15 @@ class ConcreteMachine:
// MARK: - TimedMachine.
void run_for(const Cycles duration) override {
const auto pit_ticks = duration.as_integral();
int ticks;
if constexpr (!turbo) {
cpu_divisor_ += pit_ticks;
int ticks = cpu_divisor_ / 3;
ticks = cpu_divisor_ / 3;
cpu_divisor_ %= 3;
} else {
ticks = pit_ticks;
}
while(ticks--) {
//
@ -989,23 +995,30 @@ class ConcreteMachine:
//
pit_.run_for(1);
++speaker_.cycles_since_update;
if constexpr (!turbo) {
pit_.run_for(1);
++speaker_.cycles_since_update;
pit_.run_for(1);
++speaker_.cycles_since_update;
}
//
// Advance CRTC at a more approximate rate.
//
video_.run_for(Cycles(3));
video_.run_for(turbo ? Cycles(1) : Cycles(3));
//
// Give the keyboard a notification of passing time; it's very approximately clocked,
// really just including 'some' delays to avoid being instant.
//
keyboard_.run_for(Cycles(1));
//
// Perform one CPU instruction every three PIT cycles.
// i.e. CPU instruction rate is 1/3 * ~1.19Mhz ~= 0.4 MIPS.
//
keyboard_.run_for(Cycles(1));
// Query for interrupts and apply if pending.
if(pic_.pending() && context.flags.template flag<InstructionSet::x86::Flag::Interrupt>()) {
// Regress the IP if a REP is in-progress so as to resume it later.
@ -1022,11 +1035,31 @@ class ConcreteMachine:
);
}
// Do nothing if halted.
// Do nothing if currently halted.
if(context.flow_controller.halted()) {
continue;
}
if constexpr (turbo) {
// There's no divider applied, so this makes for 2*PI = around 2.4 MIPS.
// That's broadly 80286 speed, if MIPS were a valid measure.
perform_instruction();
perform_instruction();
} else {
// With the clock divider above, this makes for a net of PIT/3 = around 0.4 MIPS.
// i.e. a shade more than 8086 speed, if MIPS were meaningful.
perform_instruction();
}
// Other inevitably broad and fuzzy and inconsistent MIPS counts for my own potential future play:
//
// 80386 @ 20Mhz: 45 MIPS.
// 80486 @ 66Mhz: 25 MIPS.
// Pentium @ 100Mhz: 188 MIPS.
}
}
void perform_instruction() {
// Get the next thing to execute.
if(!context.flow_controller.should_repeat()) {
// Decode from the current IP.
@ -1072,7 +1105,6 @@ class ConcreteMachine:
context
);
}
}
// MARK: - ScanProducer.
void set_scan_target(Outputs::Display::ScanTarget *scan_target) override {
@ -1205,8 +1237,8 @@ Machine *Machine::PCCompatible(const Analyser::Static::Target *target, const ROM
const Target *const pc_target = dynamic_cast<const Target *>(target);
switch(pc_target->adaptor) {
case VideoAdaptor::MDA: return new PCCompatible::ConcreteMachine<VideoAdaptor::MDA>(*pc_target, rom_fetcher);
case VideoAdaptor::CGA: return new PCCompatible::ConcreteMachine<VideoAdaptor::CGA>(*pc_target, rom_fetcher);
case VideoAdaptor::MDA: return new PCCompatible::ConcreteMachine<VideoAdaptor::MDA, false>(*pc_target, rom_fetcher);
case VideoAdaptor::CGA: return new PCCompatible::ConcreteMachine<VideoAdaptor::CGA, false>(*pc_target, rom_fetcher);
default: return nullptr;
}
}