From 9fd7d5c10fe9e7111b174a6f8cc33fe9bc80ae26 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 3 Mar 2024 14:34:21 -0500 Subject: [PATCH 1/4] Switch test and meaning. --- InstructionSets/ARM/Executor.hpp | 6 +++--- InstructionSets/ARM/OperationMapper.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/InstructionSets/ARM/Executor.hpp b/InstructionSets/ARM/Executor.hpp index bfb0f36b0..afd97b748 100644 --- a/InstructionSets/ARM/Executor.hpp +++ b/InstructionSets/ARM/Executor.hpp @@ -248,14 +248,14 @@ struct Executor { // Calculate offset. uint32_t offset; - if constexpr (flags.offset_is_immediate()) { - offset = transfer.immediate(); - } else { + if constexpr (flags.offset_is_register()) { // The 8 shift control bits are described in 6.2.3, but // the register specified shift amounts are not available // in this instruction class. uint32_t carry = registers_.c(); offset = decode_shift(transfer, carry, 4); + } else { + offset = transfer.immediate(); } // Obtain base address. diff --git a/InstructionSets/ARM/OperationMapper.hpp b/InstructionSets/ARM/OperationMapper.hpp index e60b07c40..23fe41c5b 100644 --- a/InstructionSets/ARM/OperationMapper.hpp +++ b/InstructionSets/ARM/OperationMapper.hpp @@ -232,7 +232,7 @@ struct SingleDataTransferFlags { return flag_bit<20>(flags_) ? Operation::LDR : Operation::STR; } - constexpr bool offset_is_immediate() const { return !flag_bit<25>(flags_); } + constexpr bool offset_is_register() const { return flag_bit<25>(flags_); } constexpr bool pre_index() const { return flag_bit<24>(flags_); } constexpr bool add_offset() const { return flag_bit<23>(flags_); } constexpr bool transfer_byte() const { return flag_bit<22>(flags_); } From 8a83d7156077b53591fc578ee85a8408c9ede155 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 3 Mar 2024 14:40:05 -0500 Subject: [PATCH 2/4] Fix condition. --- InstructionSets/ARM/OperationMapper.hpp | 2 +- OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/InstructionSets/ARM/OperationMapper.hpp b/InstructionSets/ARM/OperationMapper.hpp index 23fe41c5b..1898b14b7 100644 --- a/InstructionSets/ARM/OperationMapper.hpp +++ b/InstructionSets/ARM/OperationMapper.hpp @@ -254,7 +254,7 @@ struct SingleDataTransfer: public WithShiftControlBits { /// The base register index. i.e. 'Rn'. int base() const { return (opcode_ >> 16) & 0xf; } - /// The immediate offset, if @c offset_is_immediate() was @c true; meaningless otherwise. + /// The immediate offset, if @c offset_is_register() was @c false; meaningless otherwise. int immediate() const { return opcode_ & 0xfff; } }; diff --git a/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm index f82a61ab6..9ce934b60 100644 --- a/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm +++ b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm @@ -30,7 +30,7 @@ struct Memory { template bool read(uint32_t address, IntT &source, Mode mode, bool trans) { - if(address > 0x3800000) { + if(address >= 0x3800000) { has_moved_rom_ = true; source = *reinterpret_cast(&rom[address - 0x3800000]); } else if(!has_moved_rom_) { @@ -202,7 +202,7 @@ struct Memory { } // TODO: turn the below into a trace-driven test case. -/*- (void)testROM319 { +- (void)testROM319 { constexpr ROM::Name rom_name = ROM::Name::AcornRISCOS319; ROM::Request request(rom_name); const auto roms = CSROMFetcher()(request); @@ -217,6 +217,6 @@ struct Memory { printf("%08x: %08x\n", executor.pc(), instruction); execute(instruction, executor); } -}*/ +} @end From b42a6e447d871ffc3587b130876c59109051663a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 3 Mar 2024 21:29:53 -0500 Subject: [PATCH 3/4] Tie down more corners. --- InstructionSets/ARM/Executor.hpp | 15 ++++---- InstructionSets/ARM/Registers.hpp | 26 +++++++------ .../Mac/Clock SignalTests/ARMDecoderTests.mm | 37 +++++++++++++------ 3 files changed, 47 insertions(+), 31 deletions(-) diff --git a/InstructionSets/ARM/Executor.hpp b/InstructionSets/ARM/Executor.hpp index bfb0f36b0..79ca01435 100644 --- a/InstructionSets/ARM/Executor.hpp +++ b/InstructionSets/ARM/Executor.hpp @@ -248,14 +248,14 @@ struct Executor { // Calculate offset. uint32_t offset; - if constexpr (flags.offset_is_immediate()) { - offset = transfer.immediate(); - } else { + if constexpr (!flags.offset_is_immediate()) { // The 8 shift control bits are described in 6.2.3, but // the register specified shift amounts are not available // in this instruction class. uint32_t carry = registers_.c(); offset = decode_shift(transfer, carry, 4); + } else { + offset = transfer.immediate(); } // Obtain base address. @@ -546,6 +546,10 @@ struct Executor { MemoryT bus; + const Registers ®isters() const { + return registers_; + } + /// Sets the expected address of the instruction after whichever is about to be executed. /// So it's PC+4 compared to most other systems. void set_pc(uint32_t pc) { @@ -559,11 +563,6 @@ struct Executor { return registers_.pc(0); } - /// @returns The current processor mode. - Mode mode() const { - return registers_.mode(); - } - private: Registers registers_; }; diff --git a/InstructionSets/ARM/Registers.hpp b/InstructionSets/ARM/Registers.hpp index 7b0fb4db5..91589a472 100644 --- a/InstructionSets/ARM/Registers.hpp +++ b/InstructionSets/ARM/Registers.hpp @@ -66,11 +66,9 @@ struct Registers { overflow_flag_ = value; } - /// @returns The full PC + status bits. - uint32_t pc_status(uint32_t offset) const { + uint32_t status() const { return uint32_t(mode_) | - ((active[15] + offset) & ConditionCode::Address) | (negative_flag_ & ConditionCode::Negative) | (zero_result_ ? 0 : ConditionCode::Zero) | (carry_flag_ ? ConditionCode::Carry : 0) | @@ -78,6 +76,13 @@ struct Registers { interrupt_flags_; } + /// @returns The full PC + status bits. + uint32_t pc_status(uint32_t offset) const { + return + ((active[15] + offset) & ConditionCode::Address) | + status(); + } + /// Sets status bits only, subject to mode. void set_status(uint32_t status) { // ... in user mode the other flags (I, F, M1, M0) are protected from direct change @@ -100,7 +105,6 @@ struct Registers { } /// Sets a new PC. - /// TODO: communicate this onward. void set_pc(uint32_t value) { active[15] = value & ConditionCode::Address; } @@ -204,7 +208,7 @@ struct Registers { } } - std::array active; + std::array active{}; void set_mode(Mode target_mode) { if(mode_ == target_mode) { @@ -257,17 +261,17 @@ struct Registers { private: Mode mode_ = Mode::Supervisor; - uint32_t zero_result_ = 0; + uint32_t zero_result_ = 1; uint32_t negative_flag_ = 0; - uint32_t interrupt_flags_ = 0; + uint32_t interrupt_flags_ = ConditionCode::IRQDisable | ConditionCode::FIQDisable; uint32_t carry_flag_ = 0; uint32_t overflow_flag_ = 0; // Various shadow registers. - std::array user_registers_; - std::array fiq_registers_; - std::array irq_registers_; - std::array supervisor_registers_; + std::array user_registers_{}; + std::array fiq_registers_{}; + std::array irq_registers_{}; + std::array supervisor_registers_{}; }; } diff --git a/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm index f82a61ab6..cb1d4030c 100644 --- a/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm +++ b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm @@ -20,33 +20,42 @@ struct Memory { template bool write(uint32_t address, IntT source, Mode mode, bool trans) { - (void)address; - (void)source; (void)mode; (void)trans; + printf("W of %08x to %08x [%lu]\n", source, address, sizeof(IntT)); + + if(has_moved_rom_ && address < ram_.size()) { + *reinterpret_cast(&ram_[address]) = source; + } + return true; } template bool read(uint32_t address, IntT &source, Mode mode, bool trans) { - if(address > 0x3800000) { + (void)mode; + (void)trans; + + if(address >= 0x3800000) { has_moved_rom_ = true; source = *reinterpret_cast(&rom[address - 0x3800000]); } else if(!has_moved_rom_) { // TODO: this is true only very transiently. source = *reinterpret_cast(&rom[address]); + } else if(address < ram_.size()) { + source = *reinterpret_cast(&ram_[address]); } else { + source = 0; printf("Unknown read from %08x [%lu]\n", address, sizeof(IntT)); } - (void)mode; - (void)trans; return true; } private: bool has_moved_rom_ = false; + std::array ram_{}; }; } @@ -202,21 +211,25 @@ struct Memory { } // TODO: turn the below into a trace-driven test case. -/*- (void)testROM319 { +- (void)testROM319 { constexpr ROM::Name rom_name = ROM::Name::AcornRISCOS319; ROM::Request request(rom_name); const auto roms = CSROMFetcher()(request); - Executor executor; - executor.bus.rom = roms.find(rom_name)->second; + auto executor = std::make_unique>(); + executor->bus.rom = roms.find(rom_name)->second; for(int c = 0; c < 1000; c++) { uint32_t instruction; - executor.bus.read(executor.pc(), instruction, executor.mode(), false); + executor->bus.read(executor->pc(), instruction, executor->registers().mode(), false); - printf("%08x: %08x\n", executor.pc(), instruction); - execute(instruction, executor); + printf("%08x: %08x [", executor->pc(), instruction); + for(int c = 0; c < 15; c++) { + printf("r%d:%08x ", c, executor->registers().active[c]); + } + printf("psr:%08x]\n", executor->registers().status()); + execute(instruction, *executor); } -}*/ +} @end From 11c4d2f09e96293bf47039980aa720fc8e7a4279 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 3 Mar 2024 21:38:27 -0500 Subject: [PATCH 4/4] Add further exposition. --- InstructionSets/ARM/Executor.hpp | 9 +++-- InstructionSets/ARM/Registers.hpp | 12 +++++- .../Mac/Clock SignalTests/ARMDecoderTests.mm | 40 +++++++++---------- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/InstructionSets/ARM/Executor.hpp b/InstructionSets/ARM/Executor.hpp index 9c20adb93..0650371b2 100644 --- a/InstructionSets/ARM/Executor.hpp +++ b/InstructionSets/ARM/Executor.hpp @@ -544,8 +544,7 @@ struct Executor { registers_.exception(); } - MemoryT bus; - + /// @returns The current registers state. const Registers ®isters() const { return registers_; } @@ -563,12 +562,14 @@ struct Executor { return registers_.pc(0); } + MemoryT bus; + private: Registers registers_; }; -/// Provides an analogue of the @c OperationMapper -affiliated @c dispatch that also updates the -/// executor's program counter appropriately. +/// Executes the instruction @c instruction which should have been fetched from @c executor.pc(), +/// modifying @c executor. template void execute(uint32_t instruction, Executor &executor) { executor.set_pc(executor.pc() + 4); diff --git a/InstructionSets/ARM/Registers.hpp b/InstructionSets/ARM/Registers.hpp index 91589a472..a39c39228 100644 --- a/InstructionSets/ARM/Registers.hpp +++ b/InstructionSets/ARM/Registers.hpp @@ -66,6 +66,7 @@ struct Registers { overflow_flag_ = value; } + /// @returns The current status bits, separate from the PC — mode, NVCZ and the two interrupt flags. uint32_t status() const { return uint32_t(mode_) | @@ -100,6 +101,7 @@ struct Registers { } } + /// @returns The current mode. Mode mode() const { return mode_; } @@ -109,6 +111,7 @@ struct Registers { 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; } @@ -136,6 +139,7 @@ struct Registers { FIQ = 0x1c, }; + /// Updates the program counter, interupt flags and link register if applicable to begin @c exception. template void exception() { interrupt_flags_ |= ConditionCode::IRQDisable; @@ -163,6 +167,7 @@ struct Registers { // MARK: - Condition tests. + /// @returns @c true if @c condition tests as true; @c false otherwise. bool test(Condition condition) { const auto ne = [&]() -> bool { return zero_result_; @@ -208,8 +213,7 @@ struct Registers { } } - std::array active{}; - + /// Sets current execution mode. void set_mode(Mode target_mode) { if(mode_ == target_mode) { return; @@ -258,6 +262,10 @@ struct Registers { 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 active{}; + private: Mode mode_ = Mode::Supervisor; diff --git a/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm index cb1d4030c..576979694 100644 --- a/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm +++ b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm @@ -211,25 +211,25 @@ struct Memory { } // TODO: turn the below into a trace-driven test case. -- (void)testROM319 { - constexpr ROM::Name rom_name = ROM::Name::AcornRISCOS319; - ROM::Request request(rom_name); - const auto roms = CSROMFetcher()(request); - - auto executor = std::make_unique>(); - executor->bus.rom = roms.find(rom_name)->second; - - for(int c = 0; c < 1000; c++) { - uint32_t instruction; - executor->bus.read(executor->pc(), instruction, executor->registers().mode(), false); - - printf("%08x: %08x [", executor->pc(), instruction); - for(int c = 0; c < 15; c++) { - printf("r%d:%08x ", c, executor->registers().active[c]); - } - printf("psr:%08x]\n", executor->registers().status()); - execute(instruction, *executor); - } -} +//- (void)testROM319 { +// constexpr ROM::Name rom_name = ROM::Name::AcornRISCOS319; +// ROM::Request request(rom_name); +// const auto roms = CSROMFetcher()(request); +// +// auto executor = std::make_unique>(); +// executor->bus.rom = roms.find(rom_name)->second; +// +// for(int c = 0; c < 1000; c++) { +// uint32_t instruction; +// executor->bus.read(executor->pc(), instruction, executor->registers().mode(), false); +// +// printf("%08x: %08x [", executor->pc(), instruction); +// for(int c = 0; c < 15; c++) { +// printf("r%d:%08x ", c, executor->registers().active[c]); +// } +// printf("psr:%08x]\n", executor->registers().status()); +// execute(instruction, *executor); +// } +//} @end