mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-10 11:25:23 +00:00
Add banked registers.
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "OperationMapper.hpp"
|
#include "OperationMapper.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace InstructionSet::ARM {
|
namespace InstructionSet::ARM {
|
||||||
@@ -90,7 +91,7 @@ struct Registers {
|
|||||||
zero_result_ = ~status & ConditionCode::Zero;
|
zero_result_ = ~status & ConditionCode::Zero;
|
||||||
|
|
||||||
if(mode_ != Mode::User) {
|
if(mode_ != Mode::User) {
|
||||||
mode_ = Mode(status & 3);
|
set_mode(Mode(status & 3));
|
||||||
interrupt_flags_ = status & (ConditionCode::IRQDisable | ConditionCode::FIQDisable);
|
interrupt_flags_ = status & (ConditionCode::IRQDisable | ConditionCode::FIQDisable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,7 +151,7 @@ struct Registers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t active[16]; // TODO: register swaps with mode.
|
std::array<uint32_t, 16> active;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Mode mode_ = Mode::Supervisor;
|
Mode mode_ = Mode::Supervisor;
|
||||||
@@ -160,6 +161,60 @@ struct Registers {
|
|||||||
uint32_t interrupt_flags_ = 0;
|
uint32_t interrupt_flags_ = 0;
|
||||||
uint32_t carry_flag_ = 0;
|
uint32_t carry_flag_ = 0;
|
||||||
uint32_t overflow_flag_ = 0;
|
uint32_t overflow_flag_ = 0;
|
||||||
|
|
||||||
|
// Various shadow registers.
|
||||||
|
std::array<uint32_t, 7> user_registers_;
|
||||||
|
std::array<uint32_t, 7> fiq_registers_;
|
||||||
|
std::array<uint32_t, 2> irq_registers_;
|
||||||
|
std::array<uint32_t, 2> supervisor_registers_;
|
||||||
|
|
||||||
|
void set_mode(Mode target_mode) {
|
||||||
|
if(mode_ == target_mode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For outgoing modes other than FIQ, only save the final two registers for now;
|
||||||
|
// if the incoming mode is FIQ then the other five will be saved in the next switch.
|
||||||
|
switch(mode_) {
|
||||||
|
case Mode::FIQ:
|
||||||
|
std::copy(active.begin() + 8, active.begin() + 15, fiq_registers_.begin());
|
||||||
|
break;
|
||||||
|
case Mode::User:
|
||||||
|
std::copy(active.begin() + 13, active.begin() + 15, user_registers_.begin() + 5);
|
||||||
|
break;
|
||||||
|
case Mode::Supervisor:
|
||||||
|
std::copy(active.begin() + 13, active.begin() + 15, supervisor_registers_.begin());
|
||||||
|
break;
|
||||||
|
case Mode::IRQ:
|
||||||
|
std::copy(active.begin() + 13, active.begin() + 15, irq_registers_.begin());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For all modes except FIQ: restore the final two registers to their appropriate values.
|
||||||
|
// For FIQ: save an additional five, then overwrite seven.
|
||||||
|
switch(target_mode) {
|
||||||
|
case Mode::FIQ:
|
||||||
|
std::copy(active.begin() + 8, active.begin() + 13, user_registers_.begin());
|
||||||
|
std::copy(fiq_registers_.begin(), fiq_registers_.end(), active.begin() + 8);
|
||||||
|
break;
|
||||||
|
case Mode::User:
|
||||||
|
std::copy(user_registers_.begin() + 5, user_registers_.end(), active.begin() + 13);
|
||||||
|
break;
|
||||||
|
case Mode::Supervisor:
|
||||||
|
std::copy(supervisor_registers_.begin(), supervisor_registers_.end(), active.begin() + 13);
|
||||||
|
break;
|
||||||
|
case Mode::IRQ:
|
||||||
|
std::copy(irq_registers_.begin(), irq_registers_.end(), active.begin() + 13);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If FIQ is outgoing then there's another five registers to restore.
|
||||||
|
if(mode_ == Mode::FIQ) {
|
||||||
|
std::copy(user_registers_.begin(), user_registers_.begin() + 5, active.begin() + 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
mode_ = target_mode;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user