mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-16 18:30:32 +00:00
Deal with downward write order.
This commit is contained in:
parent
ab1dd7f57e
commit
5759798ad7
@ -204,21 +204,6 @@ struct Registers {
|
|||||||
|
|
||||||
std::array<uint32_t, 16> active;
|
std::array<uint32_t, 16> active;
|
||||||
|
|
||||||
private:
|
|
||||||
Mode mode_ = Mode::Supervisor;
|
|
||||||
|
|
||||||
uint32_t zero_result_ = 0;
|
|
||||||
uint32_t negative_flag_ = 0;
|
|
||||||
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) {
|
void set_mode(Mode target_mode) {
|
||||||
if(mode_ == target_mode) {
|
if(mode_ == target_mode) {
|
||||||
return;
|
return;
|
||||||
@ -266,6 +251,23 @@ struct Registers {
|
|||||||
|
|
||||||
mode_ = target_mode;
|
mode_ = target_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Mode mode_ = Mode::Supervisor;
|
||||||
|
|
||||||
|
uint32_t zero_result_ = 0;
|
||||||
|
uint32_t negative_flag_ = 0;
|
||||||
|
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_;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -360,32 +360,57 @@ struct Scheduler {
|
|||||||
template <Flags f> void perform(BlockDataTransfer transfer) {
|
template <Flags f> void perform(BlockDataTransfer transfer) {
|
||||||
constexpr BlockDataTransferFlags flags(f);
|
constexpr BlockDataTransferFlags flags(f);
|
||||||
|
|
||||||
uint32_t address = transfer.base() == 15 ?
|
|
||||||
registers_.pc_status(8) :
|
|
||||||
registers_.active[transfer.base()];
|
|
||||||
constexpr uint32_t step = flags.add_offset() ? 4 : -4;
|
|
||||||
|
|
||||||
// TODO: forcing transfer of the user bank.
|
|
||||||
// TODO: inclusion of the base in the register list.
|
// TODO: inclusion of the base in the register list.
|
||||||
// TODO: data aborts.
|
// TODO: data aborts.
|
||||||
|
|
||||||
|
uint32_t address = transfer.base() == 15 ?
|
||||||
|
registers_.pc_status(8) :
|
||||||
|
registers_.active[transfer.base()];
|
||||||
|
|
||||||
|
const uint16_t list = transfer.register_list();
|
||||||
|
|
||||||
|
// Writes are always from lowest address to highest; asking for storage downward
|
||||||
|
// just results in predecrementation of the address.
|
||||||
|
if constexpr (!flags.add_offset()) {
|
||||||
|
uint32_t total = ((list & 0xa) >> 1) + (list & 0x5);
|
||||||
|
total = ((list & 0xc) >> 2) + (list & 0x3);
|
||||||
|
address -= total * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] uint32_t final_address = address;
|
||||||
|
|
||||||
|
bool completed_all_visits = true;
|
||||||
const auto visit = [&](uint32_t &value) {
|
const auto visit = [&](uint32_t &value) {
|
||||||
if constexpr (flags.pre_index()) {
|
if constexpr (flags.pre_index() == flags.add_offset()) {
|
||||||
address += step;
|
address += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if constexpr (flags.operation() == BlockDataTransferFlags::Operation::STM) {
|
if constexpr (flags.operation() == BlockDataTransferFlags::Operation::STM) {
|
||||||
bus_.template read<uint32_t>(address, value, registers_.mode(), false);
|
bus_.template read<uint32_t>(address, value, registers_.mode(), false);
|
||||||
} else {
|
} else {
|
||||||
bus_.template write<uint32_t>(address, value, registers_.mode(), false);
|
completed_all_visits &= bus_.template write<uint32_t>(address, value, registers_.mode(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if constexpr (!flags.pre_index()) {
|
if constexpr (!flags.pre_index() != flags.add_offset()) {
|
||||||
address += step;
|
address += 4;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint16_t list = transfer.register_list();
|
// Handle forcing transfer of the user bank.
|
||||||
|
Mode original_mode = registers_.mode();
|
||||||
|
const bool adopt_user_mode =
|
||||||
|
(
|
||||||
|
flags.operation() == BlockDataTransferFlags::Operation::STM &&
|
||||||
|
flags.load_psr()
|
||||||
|
) ||
|
||||||
|
(
|
||||||
|
flags.operation() == BlockDataTransferFlags::Operation::LDM &&
|
||||||
|
!(list & (1 << 15))
|
||||||
|
);
|
||||||
|
if(adopt_user_mode) {
|
||||||
|
registers_.set_mode(Mode::User);
|
||||||
|
}
|
||||||
|
|
||||||
for(int c = 0; c < 15; c++) {
|
for(int c = 0; c < 15; c++) {
|
||||||
if(list & (1 << c)) {
|
if(list & (1 << c)) {
|
||||||
visit(registers_.active[c]);
|
visit(registers_.active[c]);
|
||||||
@ -400,21 +425,25 @@ struct Scheduler {
|
|||||||
} else {
|
} else {
|
||||||
visit(value);
|
visit(value);
|
||||||
registers_.set_pc(value);
|
registers_.set_pc(value);
|
||||||
|
|
||||||
if constexpr (flags.load_psr()) {
|
if constexpr (flags.load_psr()) {
|
||||||
// TODO: [T]he PSR will be overwritten by the corresponding bits of the loaded value.
|
registers_.set_status(value);
|
||||||
// In user mode, however, the I, F, M0 and M1 bits are protected from change
|
|
||||||
// ... The mode at the start of the instruction determines whether these bits
|
|
||||||
// are protected.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if constexpr (flags.write_back_address()) {
|
if constexpr (flags.write_back_address()) {
|
||||||
if(transfer.base() != 15) {
|
if(transfer.base() != 15) {
|
||||||
registers_.active[transfer.base()] = address;
|
if constexpr (flags.add_offset()) {
|
||||||
|
registers_.active[transfer.base()] = address;
|
||||||
|
} else {
|
||||||
|
registers_.active[transfer.base()] = final_address;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(adopt_user_mode) {
|
||||||
|
registers_.set_mode(original_mode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void software_interrupt() {
|
void software_interrupt() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user