1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-20 21:30:59 +00:00

Add banked registers.

This commit is contained in:
Thomas Harte 2024-02-28 14:09:05 -05:00
parent c49b26701f
commit 474f9da3c2

View File

@ -10,6 +10,7 @@
#include "OperationMapper.hpp"
#include <array>
#include <cstdint>
namespace InstructionSet::ARM {
@ -90,7 +91,7 @@ struct Registers {
zero_result_ = ~status & ConditionCode::Zero;
if(mode_ != Mode::User) {
mode_ = Mode(status & 3);
set_mode(Mode(status & 3));
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:
Mode mode_ = Mode::Supervisor;
@ -160,6 +161,60 @@ struct Registers {
uint32_t interrupt_flags_ = 0;
uint32_t carry_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;
}
};
}