From 1663d3d9d156ff086960fbfcab77b1fdc2f4e4cd Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 2 Mar 2024 22:40:12 -0500 Subject: [PATCH] Introduce disaster of an attempted test run. --- InstructionSets/ARM/Executor.hpp | 38 +++++++++++-------- InstructionSets/ARM/Registers.hpp | 6 ++- .../Mac/Clock SignalTests/ARMDecoderTests.mm | 17 ++++++++- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/InstructionSets/ARM/Executor.hpp b/InstructionSets/ARM/Executor.hpp index a8c27deae..170f7e891 100644 --- a/InstructionSets/ARM/Executor.hpp +++ b/InstructionSets/ARM/Executor.hpp @@ -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 +template 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(operand2, fields.rotate(), rotate_carry); } } else { - operand2 = decode_shift(fields, rotate_carry, shift_by_register ? 12 : 8); + operand2 = decode_shift(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 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(transfer, carry, 8); + offset = decode_shift(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 -void dispatch(uint32_t pc, uint32_t instruction, Executor &executor) { - executor.set_pc(pc); +void dispatch(uint32_t &pc, uint32_t instruction, Executor &executor) { + // TODO: avoid PC gymnastics below. + executor.set_pc(pc + 4); dispatch(instruction, executor); + pc = executor.pc(); } } diff --git a/InstructionSets/ARM/Registers.hpp b/InstructionSets/ARM/Registers.hpp index 752db79a8..76717228e 100644 --- a/InstructionSets/ARM/Registers.hpp +++ b/InstructionSets/ARM/Registers.hpp @@ -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: diff --git a/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm index e0456aed6..6d5a98073 100644 --- a/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm +++ b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm @@ -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 executor; + for(int c = 0; c < 100; c++) { + uint32_t instruction; + + if(pc > 0x3800000) { + instruction = *reinterpret_cast(&rom[pc - 0x3800000]); + } else { + instruction = *reinterpret_cast(&rom[pc]); + } + + printf("%08x: %08x\n", pc, instruction); + dispatch(pc, instruction, executor); + } } @end