1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-22 12:33:29 +00:00

Attempt the prefetch portion of a pipeline.

This commit is contained in:
Thomas Harte 2024-04-19 21:30:15 -04:00
parent 807835b9fe
commit 5b13d3e893
2 changed files with 93 additions and 17 deletions

View File

@ -209,6 +209,13 @@ struct Registers {
/// Otherwise returns @c false. /// Otherwise returns @c false.
template <Exception type> template <Exception type>
bool interrupt() { bool interrupt() {
if(!would_interrupt<type>()) return false;
exception<type>();
return true;
}
template <Exception type>
bool would_interrupt() {
switch(type) { switch(type) {
case Exception::IRQ: case Exception::IRQ:
if(interrupt_flags_ & ConditionCode::IRQDisable) { if(interrupt_flags_ & ConditionCode::IRQDisable) {
@ -224,8 +231,6 @@ struct Registers {
default: return false; default: return false;
} }
exception<type>();
return true; return true;
} }

View File

@ -402,29 +402,57 @@ class ConcreteMachine:
executor_.bus.set_rom(roms.find(risc_os)->second); executor_.bus.set_rom(roms.find(risc_os)->second);
insert_media(target.media); insert_media(target.media);
fill_pipeline(0);
} }
void update_interrupts() { void update_interrupts() {
using Exception = InstructionSet::ARM::Registers::Exception; using Exception = InstructionSet::ARM::Registers::Exception;
const int requests = executor_.bus.interrupt_mask(); const int requests = executor_.bus.interrupt_mask();
if((requests & InterruptRequests::FIQ) && executor_.registers().interrupt<Exception::FIQ>()) { if((requests & InterruptRequests::FIQ) && executor_.registers().would_interrupt<Exception::FIQ>()) {
pipeline_.reschedule(Pipeline::SWISubversion::FIQ);
return; return;
} }
if(requests & InterruptRequests::IRQ) { if((requests & InterruptRequests::IRQ) && executor_.registers().would_interrupt<Exception::IRQ>()) {
executor_.registers().interrupt<Exception::IRQ>(); pipeline_.reschedule(Pipeline::SWISubversion::IRQ);
} }
} }
void did_set_status() { void did_set_status() {
// This might have been a change of mode, so...
fill_pipeline(executor_.pc());
update_interrupts(); update_interrupts();
} }
void did_set_pc() { void did_set_pc() {
fill_pipeline(executor_.pc());
} }
bool should_swi(uint32_t) { bool should_swi(uint32_t) {
using Exception = InstructionSet::ARM::Registers::Exception;
using SWISubversion = Pipeline::SWISubversion;
switch(pipeline_.swi_subversion()) {
case Pipeline::SWISubversion::None:
return true; return true;
case SWISubversion::DataAbort:
// executor_.set_pc(executor_.pc() - 4);
executor_.registers().interrupt<Exception::DataAbort>();
break;
case SWISubversion::FIQ:
executor_.set_pc(executor_.pc() - 4);
executor_.registers().interrupt<Exception::FIQ>();
break;
case SWISubversion::IRQ:
executor_.set_pc(executor_.pc() - 4);
executor_.registers().interrupt<Exception::IRQ>();
break;
}
did_set_pc();
return false;
} }
void update_clock_rates() { void update_clock_rates() {
@ -457,16 +485,7 @@ class ConcreteMachine:
int video_divider_ = 1; int video_divider_ = 1;
void tick_cpu() { void tick_cpu() {
uint32_t instruction = 0; const uint32_t instruction = advance_pipeline(executor_.pc() + 8);
if(!executor_.bus.read(executor_.pc(), instruction, executor_.registers().mode(), false)) {
// logger.info().append("Prefetch abort at %08x; last good was at %08x", executor_.pc(), last_pc);
executor_.prefetch_abort();
// TODO: does a double abort cause a reset?
executor_.bus.read(executor_.pc(), instruction, executor_.registers().mode(), false);
}
// TODO: pipeline prefetch?
debugger_.notify(executor_.pc(), instruction, executor_); debugger_.notify(executor_.pc(), instruction, executor_);
InstructionSet::ARM::execute(instruction, executor_); InstructionSet::ARM::execute(instruction, executor_);
} }
@ -514,11 +533,63 @@ class ConcreteMachine:
return executor_.bus.keyboard().mouse(); return executor_.bus.keyboard().mouse();
} }
// MARK: - ARM execution // MARK: - ARM execution.
static constexpr auto arm_model = InstructionSet::ARM::Model::ARMv2; static constexpr auto arm_model = InstructionSet::ARM::Model::ARMv2;
using Executor = InstructionSet::ARM::Executor<arm_model, MemoryController<ConcreteMachine, ConcreteMachine>, ConcreteMachine>; using Executor = InstructionSet::ARM::Executor<arm_model, MemoryController<ConcreteMachine, ConcreteMachine>, ConcreteMachine>;
Executor executor_; Executor executor_;
void fill_pipeline(uint32_t pc) {
advance_pipeline(pc);
advance_pipeline(pc + 4);
}
uint32_t advance_pipeline(uint32_t pc) {
uint32_t instruction;
const bool did_read = executor_.bus.read(pc, instruction, executor_.registers().mode(), false);
return pipeline_.exchange(
instruction,
did_read ? Pipeline::SWISubversion::None : Pipeline::SWISubversion::DataAbort);
}
struct Pipeline {
enum SWISubversion: uint8_t {
None,
DataAbort,
IRQ,
FIQ,
};
uint32_t exchange(uint32_t next, SWISubversion subversion) {
const uint32_t result = upcoming_[active_].opcode;
latched_subversion_ = upcoming_[active_].subversion;
upcoming_[active_].opcode = next;
upcoming_[active_].subversion = subversion;
active_ ^= 1;
return result;
}
void reschedule(SWISubversion subversion) {
upcoming_[active_ ^ 1].opcode = 0xef'000000;
upcoming_[active_ ^ 1].subversion = subversion;
}
SWISubversion swi_subversion() const {
return latched_subversion_;
}
private:
struct Stage {
uint32_t opcode;
SWISubversion subversion;
};
Stage upcoming_[2];
int active_ = 0;
SWISubversion latched_subversion_;
} pipeline_;
// MARK: - Yucky, temporary junk. // MARK: - Yucky, temporary junk.
HackyDebugger<arm_model, Executor> debugger_; HackyDebugger<arm_model, Executor> debugger_;
}; };