mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-16 18:30:32 +00:00
Obscure active
.
This commit is contained in:
parent
11c4d2f09e
commit
230e9c6327
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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_{};
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user