mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-06 13:31:55 +00:00
Introduce disaster of an attempted test run.
This commit is contained in:
parent
37499d493a
commit
1663d3d9d1
@ -18,7 +18,7 @@ namespace InstructionSet::ARM {
|
||||
/// A class compatible with the @c OperationMapper definition of a scheduler which applies all actions
|
||||
/// immediately, updating either a set of @c Registers or using the templated @c MemoryT to access
|
||||
/// memory. No hooks are currently provided for applying realistic timing.
|
||||
template <typename MemoryT>
|
||||
template <Model model, typename MemoryT>
|
||||
struct Executor {
|
||||
bool should_schedule(Condition condition) {
|
||||
return registers_.test(condition);
|
||||
@ -49,7 +49,7 @@ struct Executor {
|
||||
// PC will be 8 bytes ahead when used as Rs."
|
||||
shift_amount =
|
||||
fields.shift_register() == 15 ?
|
||||
registers_.pc(8) :
|
||||
registers_.pc(4) :
|
||||
registers_.active[fields.shift_register()];
|
||||
|
||||
// A register shift amount of 0 has a different meaning than an in-instruction
|
||||
@ -84,7 +84,7 @@ struct Executor {
|
||||
// when used as Rn or Rm."
|
||||
const uint32_t operand1 =
|
||||
(fields.operand1() == 15) ?
|
||||
registers_.pc(shift_by_register ? 12 : 8) :
|
||||
registers_.pc(shift_by_register ? 8 : 4) :
|
||||
registers_.active[fields.operand1()];
|
||||
|
||||
uint32_t operand2;
|
||||
@ -100,7 +100,7 @@ struct Executor {
|
||||
shift<ShiftType::RotateRight, shift_sets_carry>(operand2, fields.rotate(), rotate_carry);
|
||||
}
|
||||
} else {
|
||||
operand2 = decode_shift<true, shift_sets_carry>(fields, rotate_carry, shift_by_register ? 12 : 8);
|
||||
operand2 = decode_shift<true, shift_sets_carry>(fields, rotate_carry, shift_by_register ? 8 : 4);
|
||||
}
|
||||
|
||||
// Perform the data processing operation.
|
||||
@ -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(8) : registers_.active[fields.multiplicand()];
|
||||
const uint32_t multiplier = fields.multiplier() == 15 ? registers_.pc_status(8) : registers_.active[fields.multiplier()];
|
||||
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 accumulator =
|
||||
flags.operation() == MultiplyFlags::Operation::MUL ? 0 :
|
||||
(fields.multiplicand() == 15 ? registers_.pc_status(12) : registers_.active[fields.accumulator()]);
|
||||
(fields.multiplicand() == 15 ? registers_.pc_status(8) : registers_.active[fields.accumulator()]);
|
||||
|
||||
const uint32_t result = multiplicand * multiplier + accumulator;
|
||||
|
||||
@ -238,9 +238,9 @@ struct Executor {
|
||||
constexpr BranchFlags flags(f);
|
||||
|
||||
if constexpr (flags.operation() == BranchFlags::Operation::BL) {
|
||||
registers_.active[14] = registers_.pc(4);
|
||||
registers_.active[14] = registers_.pc(0);
|
||||
}
|
||||
registers_.set_pc(registers_.pc(8) + branch.offset());
|
||||
registers_.set_pc(registers_.pc(4) + branch.offset());
|
||||
}
|
||||
|
||||
template <Flags f> void perform(SingleDataTransfer transfer) {
|
||||
@ -255,13 +255,13 @@ struct Executor {
|
||||
// the register specified shift amounts are not available
|
||||
// in this instruction class.
|
||||
uint32_t carry = registers_.c();
|
||||
offset = decode_shift<false, false>(transfer, carry, 8);
|
||||
offset = decode_shift<false, false>(transfer, carry, 4);
|
||||
}
|
||||
|
||||
// Obtain base address.
|
||||
uint32_t address =
|
||||
transfer.base() == 15 ?
|
||||
registers_.pc(8) :
|
||||
registers_.pc(4) :
|
||||
registers_.active[transfer.base()];
|
||||
|
||||
// Determine what the address will be after offsetting.
|
||||
@ -287,7 +287,7 @@ struct Executor {
|
||||
if constexpr (flags.operation() == SingleDataTransferFlags::Operation::STR) {
|
||||
const uint32_t source =
|
||||
transfer.source() == 15 ?
|
||||
registers_.pc_status(12) :
|
||||
registers_.pc_status(8) :
|
||||
registers_.active[transfer.source()];
|
||||
|
||||
bool did_write;
|
||||
@ -354,7 +354,7 @@ struct Executor {
|
||||
// it has to be restored later, and to write that value rather than
|
||||
// the final address if the base register is first in the write-out list.
|
||||
uint32_t address = transfer.base() == 15 ?
|
||||
registers_.pc_status(8) :
|
||||
registers_.pc_status(4) :
|
||||
registers_.active[transfer.base()];
|
||||
const uint32_t initial_address = address;
|
||||
|
||||
@ -501,7 +501,7 @@ struct Executor {
|
||||
if(list & (1 << 15)) {
|
||||
uint32_t value;
|
||||
if constexpr (flags.operation() == BlockDataTransferFlags::Operation::STM) {
|
||||
value = registers_.pc_status(12);
|
||||
value = registers_.pc_status(8);
|
||||
access(value);
|
||||
} else {
|
||||
access(value);
|
||||
@ -550,6 +550,10 @@ struct Executor {
|
||||
registers_.set_pc(pc);
|
||||
}
|
||||
|
||||
uint32_t pc() const {
|
||||
return registers_.pc(0);
|
||||
}
|
||||
|
||||
private:
|
||||
Registers registers_;
|
||||
};
|
||||
@ -557,9 +561,11 @@ private:
|
||||
/// Provides an analogue of the @c OperationMapper -affiliated @c dispatch that also updates the
|
||||
/// program counter in an executor's register bank appropriately.
|
||||
template <Model model, typename MemoryT>
|
||||
void dispatch(uint32_t pc, uint32_t instruction, Executor<MemoryT> &executor) {
|
||||
executor.set_pc(pc);
|
||||
void dispatch(uint32_t &pc, uint32_t instruction, Executor<model, MemoryT> &executor) {
|
||||
// TODO: avoid PC gymnastics below.
|
||||
executor.set_pc(pc + 4);
|
||||
dispatch<model>(instruction, executor);
|
||||
pc = executor.pc();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,8 +39,10 @@ enum class Mode {
|
||||
/// Combines the ARM registers and status flags into a single whole, given that the architecture
|
||||
/// doesn't have the same degree of separation as others.
|
||||
///
|
||||
/// The PC contained here is always taken to be **the address of the current instruction**,
|
||||
/// i.e. disregarding pipeline differences. Appropriate prefetch offsets are left to other code to handle.
|
||||
/// The PC contained here is always taken to be **the address of the current instruction + 4**,
|
||||
/// i.e. whatever should be executed next, disregarding pipeline differences.
|
||||
///
|
||||
/// Appropriate prefetch offsets are left to other code to handle.
|
||||
/// This is to try to keep this structure independent of a specific ARM implementation.
|
||||
struct Registers {
|
||||
public:
|
||||
|
@ -192,7 +192,22 @@ struct Memory {
|
||||
ROM::Request request(rom_name);
|
||||
const auto roms = CSROMFetcher()(request);
|
||||
|
||||
NSLog(@"");
|
||||
const auto rom = roms.find(rom_name)->second;
|
||||
|
||||
uint32_t pc = 0;
|
||||
Executor<Model::ARMv2, Memory> executor;
|
||||
for(int c = 0; c < 100; c++) {
|
||||
uint32_t instruction;
|
||||
|
||||
if(pc > 0x3800000) {
|
||||
instruction = *reinterpret_cast<const uint32_t *>(&rom[pc - 0x3800000]);
|
||||
} else {
|
||||
instruction = *reinterpret_cast<const uint32_t *>(&rom[pc]);
|
||||
}
|
||||
|
||||
printf("%08x: %08x\n", pc, instruction);
|
||||
dispatch<Model::ARMv2>(pc, instruction, executor);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
Loading…
x
Reference in New Issue
Block a user