1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-09-29 16:55:59 +00:00

Use less branchy inner loop.

This commit is contained in:
Thomas Harte 2023-11-21 22:42:53 -05:00
parent bcd4a2216a
commit 1828a10885

View File

@ -578,10 +578,6 @@ class ConcreteMachine:
public MachineTypes::ScanProducer public MachineTypes::ScanProducer
{ {
public: public:
// i.e. CPU clock rate is 1/3 * ~1.19Mhz ~= 0.4 MIPS.
static constexpr int CPUMultiplier = 1;
static constexpr int CPUDivisor = 3;
ConcreteMachine( ConcreteMachine(
[[maybe_unused]] const Analyser::Static::Target &target, [[maybe_unused]] const Analyser::Static::Target &target,
const ROMMachine::ROMFetcher &rom_fetcher const ROMMachine::ROMFetcher &rom_fetcher
@ -618,77 +614,80 @@ class ConcreteMachine:
// bool log = false; // bool log = false;
// std::string previous; // std::string previous;
void run_for(const Cycles duration) override { void run_for(const Cycles duration) override {
auto pit_ticks = duration.as_integral(); const auto pit_ticks = duration.as_integral();
while(pit_ticks--) { cpu_divisor_ += pit_ticks;
int ticks = cpu_divisor_ / 3;
cpu_divisor_ %= 3;
while(ticks--) {
// //
// First draft: all hardware runs in lockstep, as a multiple or divisor of the PIT frequency. // First draft: all hardware runs in lockstep, as a multiple or divisor of the PIT frequency.
// //
// Advance the PIT. //
// Advance the PIT and audio.
//
pit_.run_for(1);
++speaker_.cycles_since_update;
pit_.run_for(1);
++speaker_.cycles_since_update;
pit_.run_for(1); pit_.run_for(1);
// Advance audio clock.
++speaker_.cycles_since_update; ++speaker_.cycles_since_update;
// Advance the CPU. //
cpu_divisor_ += CPUMultiplier; // Perform one CPU instruction every three PIT cycles.
int cycles = cpu_divisor_ / CPUDivisor; // i.e. CPU instruction rate is 1/3 * ~1.19Mhz ~= 0.4 MIPS.
cycles %= CPUDivisor; //
// To consider: a Duff-esque switch table calling into a function templated on clock phase // Query for interrupts and apply if pending.
// might alleviate a large part of the conditionality here? if(pic_.pending() && context.flags.flag<InstructionSet::x86::Flag::Interrupt>()) {
// Regress the IP if a REP is in-progress so as to resume it later.
while(cycles--) { if(context.flow_controller.should_repeat()) {
// Query for interrupts and apply if pending. context.registers.ip() = decoded_ip_;
if(pic_.pending() && context.flags.flag<InstructionSet::x86::Flag::Interrupt>()) {
// Regress the IP if a REP is in-progress so as to resume it later.
if(context.flow_controller.should_repeat()) {
context.registers.ip() = decoded_ip_;
context.flow_controller.begin_instruction();
}
// Signal interrupt.
InstructionSet::x86::interrupt(
pic_.acknowledge(),
context
);
}
// Get the next thing to execute.
if(!context.flow_controller.should_repeat()) {
// Decode from the current IP.
decoded_ip_ = context.registers.ip();
const auto remainder = context.memory.next_code();
decoded = decoder.decode(remainder.first, remainder.second);
// If that didn't yield a whole instruction then the end of memory must have been hit;
// continue from the beginning.
if(decoded.first <= 0) {
const auto all = context.memory.all();
decoded = decoder.decode(all.first, all.second);
}
context.registers.ip() += decoded.first;
// log |= decoded.second.operation() == InstructionSet::x86::Operation::STI;
} else {
context.flow_controller.begin_instruction(); context.flow_controller.begin_instruction();
} }
// if(log) { // Signal interrupt.
// const auto next = to_string(decoded, InstructionSet::x86::Model::i8086); InstructionSet::x86::interrupt(
// if(next != previous) { pic_.acknowledge(),
// std::cout << next << std::endl;
// previous = next;
// }
// }
// Execute it.
InstructionSet::x86::perform(
decoded.second,
context context
); );
} }
// Get the next thing to execute.
if(!context.flow_controller.should_repeat()) {
// Decode from the current IP.
decoded_ip_ = context.registers.ip();
const auto remainder = context.memory.next_code();
decoded = decoder.decode(remainder.first, remainder.second);
// If that didn't yield a whole instruction then the end of memory must have been hit;
// continue from the beginning.
if(decoded.first <= 0) {
const auto all = context.memory.all();
decoded = decoder.decode(all.first, all.second);
}
context.registers.ip() += decoded.first;
// log |= decoded.second.operation() == InstructionSet::x86::Operation::STI;
} else {
context.flow_controller.begin_instruction();
}
// if(log) {
// const auto next = to_string(decoded, InstructionSet::x86::Model::i8086);
// if(next != previous) {
// std::cout << next << std::endl;
// previous = next;
// }
// }
// Execute it.
InstructionSet::x86::perform(
decoded.second,
context
);
} }
} }