1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-01 22:41:32 +00:00

Merge pull request #1352 from TomHarte/ByeByeActive

Obscure storage for active registers.
This commit is contained in:
Thomas Harte 2024-03-03 22:09:34 -05:00 committed by GitHub
commit 95cc34ba23
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 46 additions and 39 deletions

View File

@ -36,7 +36,7 @@ struct Executor {
if(fields.operand2() == 15) {
operand2 = registers_.pc_status(pc_offset);
} else {
operand2 = registers_.active[fields.operand2()];
operand2 = registers_[fields.operand2()];
}
uint32_t shift_amount;
@ -50,7 +50,7 @@ struct Executor {
shift_amount =
fields.shift_register() == 15 ?
registers_.pc(4) :
registers_.active[fields.shift_register()];
registers_[fields.shift_register()];
// A register shift amount of 0 has a different meaning than an in-instruction
// shift amount of 0.
@ -74,7 +74,7 @@ struct Executor {
// Write a raw result into the PC proxy if the target is R15; it'll be stored properly later.
uint32_t pc_proxy = 0;
auto &destination = fields.destination() == 15 ? pc_proxy : registers_.active[fields.destination()];
auto &destination = fields.destination() == 15 ? pc_proxy : registers_[fields.destination()];
// "When R15 appears in either of the Rn or Rs positions it will give the value
// of the PC alone, with the PSR bits replaced by zeroes. ...
@ -85,7 +85,7 @@ struct Executor {
const uint32_t operand1 =
(fields.operand1() == 15) ?
registers_.pc(shift_by_register ? 8 : 4) :
registers_.active[fields.operand1()];
registers_[fields.operand1()];
uint32_t operand2;
uint32_t rotate_carry = registers_.c();
@ -216,11 +216,11 @@ struct Executor {
// * Rn: with PSR, 8 bytes ahead;
// * Rm: with PSR, 12 bytes ahead.
const uint32_t multiplicand = fields.multiplicand() == 15 ? registers_.pc(4) : registers_.active[fields.multiplicand()];
const uint32_t multiplier = fields.multiplier() == 15 ? registers_.pc_status(4) : registers_.active[fields.multiplier()];
const uint32_t multiplicand = fields.multiplicand() == 15 ? registers_.pc(4) : registers_[fields.multiplicand()];
const uint32_t multiplier = fields.multiplier() == 15 ? registers_.pc_status(4) : registers_[fields.multiplier()];
const uint32_t accumulator =
flags.operation() == MultiplyFlags::Operation::MUL ? 0 :
(fields.multiplicand() == 15 ? registers_.pc_status(8) : registers_.active[fields.accumulator()]);
(fields.multiplicand() == 15 ? registers_.pc_status(8) : registers_[fields.accumulator()]);
const uint32_t result = multiplicand * multiplier + accumulator;
@ -230,7 +230,7 @@ struct Executor {
}
if(fields.destination() != 15) {
registers_.active[fields.destination()] = result;
registers_[fields.destination()] = result;
}
}
@ -238,7 +238,7 @@ struct Executor {
constexpr BranchFlags flags(f);
if constexpr (flags.operation() == BranchFlags::Operation::BL) {
registers_.active[14] = registers_.pc(0);
registers_[14] = registers_.pc(0);
}
registers_.set_pc(registers_.pc(4) + branch.offset());
}
@ -262,7 +262,7 @@ struct Executor {
uint32_t address =
transfer.base() == 15 ?
registers_.pc(4) :
registers_.active[transfer.base()];
registers_[transfer.base()];
// Determine what the address will be after offsetting.
uint32_t offsetted_address = address;
@ -288,7 +288,7 @@ struct Executor {
const uint32_t source =
transfer.source() == 15 ?
registers_.pc_status(8) :
registers_.active[transfer.source()];
registers_[transfer.source()];
bool did_write;
if constexpr (flags.transfer_byte()) {
@ -331,7 +331,7 @@ struct Executor {
if(transfer.destination() == 15) {
registers_.set_pc(value);
} else {
registers_.active[transfer.destination()] = value;
registers_[transfer.destination()] = value;
}
}
@ -340,7 +340,7 @@ struct Executor {
if(transfer.base() == 15) {
registers_.set_pc(offsetted_address);
} else {
registers_.active[transfer.base()] = offsetted_address;
registers_[transfer.base()] = offsetted_address;
}
}
}
@ -355,7 +355,7 @@ struct Executor {
// the final address if the base register is first in the write-out list.
uint32_t address = transfer.base() == 15 ?
registers_.pc_status(4) :
registers_.active[transfer.base()];
registers_[transfer.base()];
const uint32_t initial_address = address;
// Figure out what the final address will be, since that's what'll be
@ -449,9 +449,9 @@ struct Executor {
// Also restore the base register.
if(transfer.base() != 15) {
if constexpr (flags.write_back_address()) {
registers_.active[transfer.base()] = final_address;
registers_[transfer.base()] = final_address;
} else {
registers_.active[transfer.base()] = initial_address;
registers_[transfer.base()] = initial_address;
}
}
}
@ -476,14 +476,14 @@ struct Executor {
// Write out registers 1 to 14.
for(int c = 0; c < 15; c++) {
if(list & (1 << c)) {
access(registers_.active[c]);
access(registers_[c]);
// Modify base register after each write if writeback is enabled.
// This'll ensure the unmodified value goes out if it was the
// first-selected register only.
if constexpr (flags.write_back_address()) {
if(transfer.base() != 15) {
registers_.active[transfer.base()] = final_address;
registers_[transfer.base()] = final_address;
}
}
}
@ -493,7 +493,7 @@ struct Executor {
// was empty.
if constexpr (flags.write_back_address()) {
if(transfer.base() != 15) {
registers_.active[transfer.base()] = final_address;
registers_[transfer.base()] = final_address;
}
}

View File

@ -80,7 +80,7 @@ struct Registers {
/// @returns The full PC + status bits.
uint32_t pc_status(uint32_t offset) const {
return
((active[15] + offset) & ConditionCode::Address) |
((active_[15] + offset) & ConditionCode::Address) |
status();
}
@ -108,12 +108,12 @@ struct Registers {
/// Sets a new PC.
void set_pc(uint32_t value) {
active[15] = value & ConditionCode::Address;
active_[15] = value & ConditionCode::Address;
}
/// @returns The stored PC plus @c offset limited to 26 bits.
uint32_t pc(uint32_t offset) const {
return (active[15] + offset) & ConditionCode::Address;
return (active_[15] + offset) & ConditionCode::Address;
}
// MARK: - Exceptions.
@ -150,15 +150,15 @@ struct Registers {
switch(exception) {
case Exception::IRQ:
set_mode(Mode::IRQ);
active[14] = pc(8);
active_[14] = pc(8);
break;
case Exception::FIQ:
set_mode(Mode::FIQ);
active[14] = pc(8);
active_[14] = pc(8);
break;
default:
set_mode(Mode::Supervisor);
active[14] = pc(4);
active_[14] = pc(4);
break;
}
@ -223,16 +223,16 @@ struct Registers {
// 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());
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);
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());
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());
std::copy(active_.begin() + 13, active_.begin() + 15, irq_registers_.begin());
break;
}
@ -240,31 +240,35 @@ struct Registers {
// 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);
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);
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);
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);
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);
std::copy(user_registers_.begin(), user_registers_.begin() + 5, active_.begin() + 8);
}
mode_ = target_mode;
}
/// The active register set. TODO: switch to an implementation of operator[], hiding the
/// current implementation decision to maintain this as a linear block of memory.
std::array<uint32_t, 16> active{};
uint32_t &operator[](int offset) {
return active_[offset];
}
const uint32_t operator[](int offset) const {
return active_[offset];
}
private:
Mode mode_ = Mode::Supervisor;
@ -280,6 +284,9 @@ struct Registers {
std::array<uint32_t, 7> fiq_registers_{};
std::array<uint32_t, 2> irq_registers_{};
std::array<uint32_t, 2> supervisor_registers_{};
// The active register set.
std::array<uint32_t, 16> active_{};
};
}

View File

@ -225,7 +225,7 @@ struct Memory {
//
// printf("%08x: %08x [", executor->pc(), instruction);
// for(int c = 0; c < 15; c++) {
// printf("r%d:%08x ", c, executor->registers().active[c]);
// printf("r%d:%08x ", c, executor->registers()[c]);
// }
// printf("psr:%08x]\n", executor->registers().status());
// execute<Model::ARMv2>(instruction, *executor);