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:
parent
807835b9fe
commit
5b13d3e893
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user