From 5b13d3e893e0eb085260b2ec10b544ef1cc755f7 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 19 Apr 2024 21:30:15 -0400 Subject: [PATCH] Attempt the prefetch portion of a pipeline. --- InstructionSets/ARM/Registers.hpp | 9 +- Machines/Acorn/Archimedes/Archimedes.cpp | 101 +++++++++++++++++++---- 2 files changed, 93 insertions(+), 17 deletions(-) diff --git a/InstructionSets/ARM/Registers.hpp b/InstructionSets/ARM/Registers.hpp index 31bab96ab..1e4fcc6ab 100644 --- a/InstructionSets/ARM/Registers.hpp +++ b/InstructionSets/ARM/Registers.hpp @@ -209,6 +209,13 @@ struct Registers { /// Otherwise returns @c false. template bool interrupt() { + if(!would_interrupt()) return false; + exception(); + return true; + } + + template + bool would_interrupt() { switch(type) { case Exception::IRQ: if(interrupt_flags_ & ConditionCode::IRQDisable) { @@ -224,8 +231,6 @@ struct Registers { default: return false; } - - exception(); return true; } diff --git a/Machines/Acorn/Archimedes/Archimedes.cpp b/Machines/Acorn/Archimedes/Archimedes.cpp index 0c33202a9..703c02489 100644 --- a/Machines/Acorn/Archimedes/Archimedes.cpp +++ b/Machines/Acorn/Archimedes/Archimedes.cpp @@ -402,29 +402,57 @@ class ConcreteMachine: executor_.bus.set_rom(roms.find(risc_os)->second); insert_media(target.media); + + fill_pipeline(0); } void update_interrupts() { using Exception = InstructionSet::ARM::Registers::Exception; const int requests = executor_.bus.interrupt_mask(); - if((requests & InterruptRequests::FIQ) && executor_.registers().interrupt()) { + if((requests & InterruptRequests::FIQ) && executor_.registers().would_interrupt()) { + pipeline_.reschedule(Pipeline::SWISubversion::FIQ); return; } - if(requests & InterruptRequests::IRQ) { - executor_.registers().interrupt(); + if((requests & InterruptRequests::IRQ) && executor_.registers().would_interrupt()) { + pipeline_.reschedule(Pipeline::SWISubversion::IRQ); } } void did_set_status() { + // This might have been a change of mode, so... + fill_pipeline(executor_.pc()); update_interrupts(); } void did_set_pc() { + fill_pipeline(executor_.pc()); } bool should_swi(uint32_t) { - return true; + using Exception = InstructionSet::ARM::Registers::Exception; + using SWISubversion = Pipeline::SWISubversion; + + switch(pipeline_.swi_subversion()) { + case Pipeline::SWISubversion::None: + return true; + + case SWISubversion::DataAbort: +// executor_.set_pc(executor_.pc() - 4); + executor_.registers().interrupt(); + break; + case SWISubversion::FIQ: + executor_.set_pc(executor_.pc() - 4); + executor_.registers().interrupt(); + break; + case SWISubversion::IRQ: + executor_.set_pc(executor_.pc() - 4); + executor_.registers().interrupt(); + break; + } + + did_set_pc(); + return false; } void update_clock_rates() { @@ -457,16 +485,7 @@ class ConcreteMachine: int video_divider_ = 1; void tick_cpu() { - uint32_t instruction = 0; - 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? - + const uint32_t instruction = advance_pipeline(executor_.pc() + 8); debugger_.notify(executor_.pc(), instruction, executor_); InstructionSet::ARM::execute(instruction, executor_); } @@ -514,11 +533,63 @@ class ConcreteMachine: return executor_.bus.keyboard().mouse(); } - // MARK: - ARM execution + // MARK: - ARM execution. static constexpr auto arm_model = InstructionSet::ARM::Model::ARMv2; using Executor = InstructionSet::ARM::Executor, ConcreteMachine>; 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. HackyDebugger debugger_; };