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
|
/// 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
|
/// 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.
|
/// memory. No hooks are currently provided for applying realistic timing.
|
||||||
template <typename MemoryT>
|
template <Model model, typename MemoryT>
|
||||||
struct Executor {
|
struct Executor {
|
||||||
bool should_schedule(Condition condition) {
|
bool should_schedule(Condition condition) {
|
||||||
return registers_.test(condition);
|
return registers_.test(condition);
|
||||||
@ -49,7 +49,7 @@ struct Executor {
|
|||||||
// PC will be 8 bytes ahead when used as Rs."
|
// PC will be 8 bytes ahead when used as Rs."
|
||||||
shift_amount =
|
shift_amount =
|
||||||
fields.shift_register() == 15 ?
|
fields.shift_register() == 15 ?
|
||||||
registers_.pc(8) :
|
registers_.pc(4) :
|
||||||
registers_.active[fields.shift_register()];
|
registers_.active[fields.shift_register()];
|
||||||
|
|
||||||
// A register shift amount of 0 has a different meaning than an in-instruction
|
// 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."
|
// when used as Rn or Rm."
|
||||||
const uint32_t operand1 =
|
const uint32_t operand1 =
|
||||||
(fields.operand1() == 15) ?
|
(fields.operand1() == 15) ?
|
||||||
registers_.pc(shift_by_register ? 12 : 8) :
|
registers_.pc(shift_by_register ? 8 : 4) :
|
||||||
registers_.active[fields.operand1()];
|
registers_.active[fields.operand1()];
|
||||||
|
|
||||||
uint32_t operand2;
|
uint32_t operand2;
|
||||||
@ -100,7 +100,7 @@ struct Executor {
|
|||||||
shift<ShiftType::RotateRight, shift_sets_carry>(operand2, fields.rotate(), rotate_carry);
|
shift<ShiftType::RotateRight, shift_sets_carry>(operand2, fields.rotate(), rotate_carry);
|
||||||
}
|
}
|
||||||
} else {
|
} 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.
|
// Perform the data processing operation.
|
||||||
@ -216,11 +216,11 @@ struct Executor {
|
|||||||
// * Rn: with PSR, 8 bytes ahead;
|
// * Rn: with PSR, 8 bytes ahead;
|
||||||
// * Rm: with PSR, 12 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 multiplicand = fields.multiplicand() == 15 ? registers_.pc(4) : registers_.active[fields.multiplicand()];
|
||||||
const uint32_t multiplier = fields.multiplier() == 15 ? registers_.pc_status(8) : registers_.active[fields.multiplier()];
|
const uint32_t multiplier = fields.multiplier() == 15 ? registers_.pc_status(4) : registers_.active[fields.multiplier()];
|
||||||
const uint32_t accumulator =
|
const uint32_t accumulator =
|
||||||
flags.operation() == MultiplyFlags::Operation::MUL ? 0 :
|
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;
|
const uint32_t result = multiplicand * multiplier + accumulator;
|
||||||
|
|
||||||
@ -238,9 +238,9 @@ struct Executor {
|
|||||||
constexpr BranchFlags flags(f);
|
constexpr BranchFlags flags(f);
|
||||||
|
|
||||||
if constexpr (flags.operation() == BranchFlags::Operation::BL) {
|
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) {
|
template <Flags f> void perform(SingleDataTransfer transfer) {
|
||||||
@ -255,13 +255,13 @@ struct Executor {
|
|||||||
// the register specified shift amounts are not available
|
// the register specified shift amounts are not available
|
||||||
// in this instruction class.
|
// in this instruction class.
|
||||||
uint32_t carry = registers_.c();
|
uint32_t carry = registers_.c();
|
||||||
offset = decode_shift<false, false>(transfer, carry, 8);
|
offset = decode_shift<false, false>(transfer, carry, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtain base address.
|
// Obtain base address.
|
||||||
uint32_t address =
|
uint32_t address =
|
||||||
transfer.base() == 15 ?
|
transfer.base() == 15 ?
|
||||||
registers_.pc(8) :
|
registers_.pc(4) :
|
||||||
registers_.active[transfer.base()];
|
registers_.active[transfer.base()];
|
||||||
|
|
||||||
// Determine what the address will be after offsetting.
|
// Determine what the address will be after offsetting.
|
||||||
@ -287,7 +287,7 @@ struct Executor {
|
|||||||
if constexpr (flags.operation() == SingleDataTransferFlags::Operation::STR) {
|
if constexpr (flags.operation() == SingleDataTransferFlags::Operation::STR) {
|
||||||
const uint32_t source =
|
const uint32_t source =
|
||||||
transfer.source() == 15 ?
|
transfer.source() == 15 ?
|
||||||
registers_.pc_status(12) :
|
registers_.pc_status(8) :
|
||||||
registers_.active[transfer.source()];
|
registers_.active[transfer.source()];
|
||||||
|
|
||||||
bool did_write;
|
bool did_write;
|
||||||
@ -354,7 +354,7 @@ struct Executor {
|
|||||||
// it has to be restored later, and to write that value rather than
|
// 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.
|
// the final address if the base register is first in the write-out list.
|
||||||
uint32_t address = transfer.base() == 15 ?
|
uint32_t address = transfer.base() == 15 ?
|
||||||
registers_.pc_status(8) :
|
registers_.pc_status(4) :
|
||||||
registers_.active[transfer.base()];
|
registers_.active[transfer.base()];
|
||||||
const uint32_t initial_address = address;
|
const uint32_t initial_address = address;
|
||||||
|
|
||||||
@ -501,7 +501,7 @@ struct Executor {
|
|||||||
if(list & (1 << 15)) {
|
if(list & (1 << 15)) {
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
if constexpr (flags.operation() == BlockDataTransferFlags::Operation::STM) {
|
if constexpr (flags.operation() == BlockDataTransferFlags::Operation::STM) {
|
||||||
value = registers_.pc_status(12);
|
value = registers_.pc_status(8);
|
||||||
access(value);
|
access(value);
|
||||||
} else {
|
} else {
|
||||||
access(value);
|
access(value);
|
||||||
@ -550,6 +550,10 @@ struct Executor {
|
|||||||
registers_.set_pc(pc);
|
registers_.set_pc(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t pc() const {
|
||||||
|
return registers_.pc(0);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Registers registers_;
|
Registers registers_;
|
||||||
};
|
};
|
||||||
@ -557,9 +561,11 @@ private:
|
|||||||
/// Provides an analogue of the @c OperationMapper -affiliated @c dispatch that also updates the
|
/// Provides an analogue of the @c OperationMapper -affiliated @c dispatch that also updates the
|
||||||
/// program counter in an executor's register bank appropriately.
|
/// program counter in an executor's register bank appropriately.
|
||||||
template <Model model, typename MemoryT>
|
template <Model model, typename MemoryT>
|
||||||
void dispatch(uint32_t pc, uint32_t instruction, Executor<MemoryT> &executor) {
|
void dispatch(uint32_t &pc, uint32_t instruction, Executor<model, MemoryT> &executor) {
|
||||||
executor.set_pc(pc);
|
// TODO: avoid PC gymnastics below.
|
||||||
|
executor.set_pc(pc + 4);
|
||||||
dispatch<model>(instruction, executor);
|
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
|
/// 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.
|
/// 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**,
|
/// The PC contained here is always taken to be **the address of the current instruction + 4**,
|
||||||
/// i.e. disregarding pipeline differences. Appropriate prefetch offsets are left to other code to handle.
|
/// 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.
|
/// This is to try to keep this structure independent of a specific ARM implementation.
|
||||||
struct Registers {
|
struct Registers {
|
||||||
public:
|
public:
|
||||||
|
@ -192,7 +192,22 @@ struct Memory {
|
|||||||
ROM::Request request(rom_name);
|
ROM::Request request(rom_name);
|
||||||
const auto roms = CSROMFetcher()(request);
|
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
|
@end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user