mirror of
https://github.com/TomHarte/CLK.git
synced 2024-06-25 18:30:07 +00:00
Put interrupts into pipeline, without delay.
This commit is contained in:
parent
83eac172c9
commit
ea3eef3817
|
@ -205,17 +205,8 @@ struct Registers {
|
||||||
set_pc(uint32_t(type));
|
set_pc(uint32_t(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies an exception of @c type and returns @c true if: (i) it is IRQ or FIQ; (ii) the processor is currently accepting such interrupts.
|
/// Returns @c true if: (i) the exception type is IRQ or FIQ; and (ii) the processor is currently accepting such interrupts.
|
||||||
/// Otherwise returns @c false.
|
/// Otherwise returns @c false.
|
||||||
template <Exception type>
|
|
||||||
bool interrupt() {
|
|
||||||
if(!would_interrupt<type>()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
exception<type>();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <Exception type>
|
template <Exception type>
|
||||||
bool would_interrupt() {
|
bool would_interrupt() {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
|
|
|
@ -410,23 +410,13 @@ class ConcreteMachine:
|
||||||
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>()) {
|
||||||
did_set_pc();
|
pipeline_.reschedule(Pipeline::SWISubversion::FIQ);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if((requests & InterruptRequests::IRQ) && executor_.registers().interrupt<Exception::IRQ>()) {
|
if((requests & InterruptRequests::IRQ) && executor_.registers().would_interrupt<Exception::IRQ>()) {
|
||||||
did_set_pc();
|
pipeline_.reschedule(Pipeline::SWISubversion::IRQ);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// const int requests = executor_.bus.interrupt_mask();
|
|
||||||
// if((requests & InterruptRequests::FIQ) && executor_.registers().would_interrupt<Exception::FIQ>()) {
|
|
||||||
// pipeline_.reschedule(Pipeline::SWISubversion::FIQ);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// if((requests & InterruptRequests::IRQ) && executor_.registers().would_interrupt<Exception::IRQ>()) {
|
|
||||||
// pipeline_.reschedule(Pipeline::SWISubversion::IRQ);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void did_set_status() {
|
void did_set_status() {
|
||||||
|
@ -449,16 +439,19 @@ class ConcreteMachine:
|
||||||
|
|
||||||
case SWISubversion::DataAbort:
|
case SWISubversion::DataAbort:
|
||||||
// executor_.set_pc(executor_.pc() - 4);
|
// executor_.set_pc(executor_.pc() - 4);
|
||||||
executor_.registers().interrupt<Exception::DataAbort>();
|
executor_.registers().exception<Exception::DataAbort>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// FIQ and IRQ decrement the PC because their apperance in the pipeline causes
|
||||||
|
// it to look as though they were fetched, but they weren't.
|
||||||
|
case SWISubversion::FIQ:
|
||||||
|
executor_.set_pc(executor_.pc() - 4);
|
||||||
|
executor_.registers().exception<Exception::FIQ>();
|
||||||
|
break;
|
||||||
|
case SWISubversion::IRQ:
|
||||||
|
executor_.set_pc(executor_.pc() - 4);
|
||||||
|
executor_.registers().exception<Exception::IRQ>();
|
||||||
break;
|
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();
|
did_set_pc();
|
||||||
|
@ -549,7 +542,7 @@ class ConcreteMachine:
|
||||||
Executor executor_;
|
Executor executor_;
|
||||||
|
|
||||||
void fill_pipeline(uint32_t pc) {
|
void fill_pipeline(uint32_t pc) {
|
||||||
// if(pipeline_.interrupt_next()) return;
|
if(pipeline_.interrupt_next()) return;
|
||||||
advance_pipeline(pc);
|
advance_pipeline(pc);
|
||||||
advance_pipeline(pc + 4);
|
advance_pipeline(pc + 4);
|
||||||
}
|
}
|
||||||
|
@ -566,8 +559,8 @@ class ConcreteMachine:
|
||||||
enum SWISubversion: uint8_t {
|
enum SWISubversion: uint8_t {
|
||||||
None,
|
None,
|
||||||
DataAbort,
|
DataAbort,
|
||||||
// IRQ,
|
IRQ,
|
||||||
// FIQ,
|
FIQ,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t exchange(uint32_t next, SWISubversion subversion) {
|
uint32_t exchange(uint32_t next, SWISubversion subversion) {
|
||||||
|
@ -581,18 +574,25 @@ class ConcreteMachine:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// void reschedule(SWISubversion subversion) {
|
|
||||||
// upcoming_[active_ ^ 1].opcode = 0xef'000000;
|
|
||||||
// upcoming_[active_ ^ 1].subversion = subversion;
|
|
||||||
// }
|
|
||||||
|
|
||||||
SWISubversion swi_subversion() const {
|
SWISubversion swi_subversion() const {
|
||||||
return latched_subversion_;
|
return latched_subversion_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bool interrupt_next() const {
|
// TODO: one day, possibly: schedule the subversion one slot further into the future
|
||||||
// return upcoming_[active_].subversion == SWISubversion::IRQ || upcoming_[active_].subversion == SWISubversion::FIQ;
|
// (i.e. active_ ^ 1) to allow one further instruction to occur as usual before the
|
||||||
// }
|
// action paplies. That is, if interrupts take effect one instruction later after a flags
|
||||||
|
// change, which I don't yet know.
|
||||||
|
//
|
||||||
|
// In practice I got into a bit of a race condition between interrupt scheduling and
|
||||||
|
// flags changes, so have backed off for now.
|
||||||
|
void reschedule(SWISubversion subversion) {
|
||||||
|
upcoming_[active_].opcode = 0xef'000000;
|
||||||
|
upcoming_[active_].subversion = subversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool interrupt_next() const {
|
||||||
|
return upcoming_[active_].subversion == SWISubversion::IRQ || upcoming_[active_].subversion == SWISubversion::FIQ;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Stage {
|
struct Stage {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user