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:
parent
bcd4a2216a
commit
1828a10885
@ -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
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user