From 394fe0f1f1a79f1fa8d7a06ab48084e220ab26f4 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 1 Dec 2024 08:20:24 -0500 Subject: [PATCH 1/4] Improve formatting, `const`ness in 68k and ARM instruction set implementations. --- InstructionSets/ARM/BarrelShifter.hpp | 4 +- InstructionSets/ARM/Disassembler.hpp | 15 +- InstructionSets/ARM/Executor.hpp | 31 +-- InstructionSets/ARM/OperationMapper.hpp | 44 ++-- InstructionSets/ARM/Registers.hpp | 26 +-- InstructionSets/CachingExecutor.hpp | 214 ++++++++--------- InstructionSets/Disassembler.hpp | 89 +++---- InstructionSets/M68k/Decoder.cpp | 58 ++--- InstructionSets/M68k/Decoder.hpp | 140 +++++------ InstructionSets/M68k/Executor.hpp | 160 ++++++------- .../Implementation/ExecutorImplementation.hpp | 2 +- InstructionSets/M68k/Instruction.hpp | 218 +++++++++--------- InstructionSets/M68k/Perform.hpp | 2 +- 13 files changed, 508 insertions(+), 495 deletions(-) diff --git a/InstructionSets/ARM/BarrelShifter.hpp b/InstructionSets/ARM/BarrelShifter.hpp index 575388c7e..fab54a6a9 100644 --- a/InstructionSets/ARM/BarrelShifter.hpp +++ b/InstructionSets/ARM/BarrelShifter.hpp @@ -31,7 +31,7 @@ template <> struct Carry { /// /// Shift amounts of 0 are given the meaning attributed to them for immediate shift counts. template -void shift(uint32_t &source, uint32_t amount, typename Carry::type carry) { +void shift(uint32_t &source, uint32_t amount, const typename Carry::type carry) { switch(type) { case ShiftType::LogicalLeft: if(amount > 32) { @@ -113,7 +113,7 @@ void shift(uint32_t &source, uint32_t amount, typename Carry::type ca /// Acts as per @c shift above, but applies runtime shift-type selection. template -void shift(ShiftType type, uint32_t &source, uint32_t amount, typename Carry::type carry) { +void shift(const ShiftType type, uint32_t &source, const uint32_t amount, const typename Carry::type carry) { switch(type) { case ShiftType::LogicalLeft: shift(source, amount, carry); diff --git a/InstructionSets/ARM/Disassembler.hpp b/InstructionSets/ARM/Disassembler.hpp index 5dfc4b5ee..57e24ec0d 100644 --- a/InstructionSets/ARM/Disassembler.hpp +++ b/InstructionSets/ARM/Disassembler.hpp @@ -74,7 +74,7 @@ struct Instruction { bool sets_flags = false; bool is_byte = false; - std::string to_string(uint32_t address) const { + std::string to_string(const uint32_t address) const { std::ostringstream result; // Treat all nevers as nops. @@ -161,17 +161,17 @@ struct Instruction { /// able to vend it later via @c last(). template struct Disassembler { - Instruction last() { + Instruction last() const { return instruction_; } - bool should_schedule(Condition condition) { + bool should_schedule(const Condition condition) { instruction_ = Instruction(); instruction_.condition = condition; return true; } - template void perform(DataProcessing fields) { + template void perform(const DataProcessing fields) { constexpr DataProcessingFlags flags(f); instruction_.operand1.type = Operand::Type::Register; @@ -214,7 +214,7 @@ struct Disassembler { } template void perform(Multiply) {} - template void perform(SingleDataTransfer fields) { + template void perform(const SingleDataTransfer fields) { constexpr SingleDataTransferFlags flags(f); instruction_.operation = (flags.operation() == SingleDataTransferFlags::Operation::STR) ? @@ -226,7 +226,7 @@ struct Disassembler { instruction_.operand1.type = Operand::Type::Register; instruction_.operand1.value = fields.base(); } - template void perform(BlockDataTransfer fields) { + template void perform(const BlockDataTransfer fields) { constexpr BlockDataTransferFlags flags(f); instruction_.operation = (flags.operation() == BlockDataTransferFlags::Operation::STM) ? @@ -238,7 +238,7 @@ struct Disassembler { instruction_.operand1.type = Operand::Type::RegisterList; instruction_.operand1.value = fields.register_list(); } - template void perform(Branch fields) { + template void perform(const Branch fields) { constexpr BranchFlags flags(f); instruction_.operation = (flags.operation() == BranchFlags::Operation::BL) ? @@ -264,7 +264,6 @@ struct Disassembler { private: Instruction instruction_; - }; } diff --git a/InstructionSets/ARM/Executor.hpp b/InstructionSets/ARM/Executor.hpp index e7951563f..6bc8b1d03 100644 --- a/InstructionSets/ARM/Executor.hpp +++ b/InstructionSets/ARM/Executor.hpp @@ -18,7 +18,7 @@ namespace InstructionSet::ARM { /// Maps from a semantic ARM read of type @c SourceT to either the 8- or 32-bit value observed /// by watching the low 8 bits or all 32 bits of the data bus. template -DestinationT read_bus(SourceT value) { +DestinationT read_bus(const SourceT value) { if constexpr (std::is_same_v) { return value; } @@ -57,14 +57,14 @@ struct Executor { /// @returns @c true if @c condition implies an appropriate perform call should be made for this instruction, /// @c false otherwise. - bool should_schedule(Condition condition) { + bool should_schedule(const Condition condition) { // This short-circuit of registers_.test provides the necessary compiler clue that // Condition::AL is not only [[likely]] but [[exceedingly likely]]. return condition == Condition::AL ? true : registers_.test(condition); } template - uint32_t decode_shift(FieldsT fields, uint32_t &rotate_carry, uint32_t pc_offset) { + uint32_t decode_shift(const FieldsT fields, uint32_t &rotate_carry, const uint32_t pc_offset) { // "When R15 appears in the Rm position it will give the value of the PC together // with the PSR flags to the barrel shifter. ... // @@ -105,7 +105,7 @@ struct Executor { return operand2; } - template void perform(DataProcessing fields) { + template void perform(const DataProcessing fields) { constexpr DataProcessingFlags flags(f); const bool shift_by_register = !flags.operand2_is_immediate() && fields.shift_count_is_register(); @@ -142,7 +142,10 @@ struct Executor { const auto sub = [&](uint32_t lhs, uint32_t rhs) { conditions = lhs - rhs; - if constexpr (flags.operation() == DataProcessingOperation::SBC || flags.operation() == DataProcessingOperation::RSC) { + if constexpr ( + flags.operation() == DataProcessingOperation::SBC || + flags.operation() == DataProcessingOperation::RSC + ) { conditions += registers_.c() - 1; } @@ -225,7 +228,7 @@ struct Executor { } } - template void perform(Multiply fields) { + template void perform(const Multiply fields) { constexpr MultiplyFlags flags(f); // R15 rules: @@ -252,7 +255,7 @@ struct Executor { } } - template void perform(Branch branch) { + template void perform(const Branch branch) { constexpr BranchFlags flags(f); if constexpr (flags.operation() == BranchFlags::Operation::BL) { @@ -261,7 +264,7 @@ struct Executor { set_pc(registers_.pc(4) + branch.offset()); } - template void perform(SingleDataTransfer transfer) { + template void perform(const SingleDataTransfer transfer) { constexpr SingleDataTransferFlags flags(f); // Calculate offset. @@ -386,7 +389,7 @@ struct Executor { } } } - template void perform(BlockDataTransfer transfer) { + template void perform(const BlockDataTransfer transfer) { constexpr BlockDataTransferFlags flags(f); constexpr bool is_ldm = flags.operation() == BlockDataTransferFlags::Operation::LDM; @@ -573,7 +576,7 @@ struct Executor { } } - void software_interrupt(SoftwareInterrupt swi) { + void software_interrupt(const SoftwareInterrupt swi) { if(control_flow_handler_.should_swi(swi.comment())) { exception(); } @@ -614,7 +617,7 @@ struct Executor { /// /// By default this is not forwarded to the control-flow handler. template - void set_pc(uint32_t pc) { + void set_pc(const uint32_t pc) { registers_.set_pc(pc); if constexpr (notify) { control_flow_handler_.did_set_pc(); @@ -637,7 +640,7 @@ private: control_flow_handler_.did_set_pc(); } - void set_status(uint32_t status) { + void set_status(const uint32_t status) { registers_.set_status(status); control_flow_handler_.did_set_status(); } @@ -650,7 +653,7 @@ private: ControlFlowHandlerTStorage control_flow_handler_; Registers registers_; - static bool is_invalid_address(uint32_t address) { + static bool is_invalid_address(const uint32_t address) { if constexpr (model == Model::ARMv2with32bitAddressing) { return false; } @@ -661,7 +664,7 @@ private: /// 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) { +void execute(const uint32_t instruction, Executor &executor) { executor.set_pc(executor.pc() + 4); dispatch(instruction, executor); } diff --git a/InstructionSets/ARM/OperationMapper.hpp b/InstructionSets/ARM/OperationMapper.hpp index c136abbbe..0e19e10fe 100644 --- a/InstructionSets/ARM/OperationMapper.hpp +++ b/InstructionSets/ARM/OperationMapper.hpp @@ -35,7 +35,7 @@ static constexpr int FlagsStartBit = 20; using Flags = uint8_t; template -constexpr bool flag_bit(uint8_t flags) { +constexpr bool flag_bit(const uint8_t flags) { static_assert(position >= 20 && position < 28); return flags & (1 << (position - FlagsStartBit)); } @@ -44,7 +44,7 @@ constexpr bool flag_bit(uint8_t flags) { // Methods common to data processing and data transfer. // struct WithShiftControlBits { - constexpr WithShiftControlBits(uint32_t opcode) noexcept : opcode_(opcode) {} + constexpr WithShiftControlBits(const uint32_t opcode) noexcept : opcode_(opcode) {} /// The operand 2 register index if @c operand2_is_immediate() is @c false; meaningless otherwise. uint32_t operand2() const { return opcode_ & 0xf; } @@ -65,7 +65,7 @@ protected: // Branch (i.e. B and BL). // struct BranchFlags { - constexpr BranchFlags(uint8_t flags) noexcept : flags_(flags) {} + constexpr BranchFlags(const uint8_t flags) noexcept : flags_(flags) {} enum class Operation { B, /// Add offset to PC; programmer allows for PC being two words ahead. @@ -82,7 +82,7 @@ private: }; struct Branch { - constexpr Branch(uint32_t opcode) noexcept : opcode_(opcode) {} + constexpr Branch(const uint32_t opcode) noexcept : opcode_(opcode) {} /// The 26-bit offset to add to the PC. uint32_t offset() const { return (opcode_ & 0xff'ffff) << 2; } @@ -113,7 +113,7 @@ enum class DataProcessingOperation { MVN, /// Rd = NOT Op2. }; -constexpr bool is_logical(DataProcessingOperation operation) { +constexpr bool is_logical(const DataProcessingOperation operation) { switch(operation) { case DataProcessingOperation::AND: case DataProcessingOperation::EOR: @@ -129,7 +129,7 @@ constexpr bool is_logical(DataProcessingOperation operation) { } } -constexpr bool is_comparison(DataProcessingOperation operation) { +constexpr bool is_comparison(const DataProcessingOperation operation) { switch(operation) { case DataProcessingOperation::TST: case DataProcessingOperation::TEQ: @@ -142,7 +142,7 @@ constexpr bool is_comparison(DataProcessingOperation operation) { } struct DataProcessingFlags { - constexpr DataProcessingFlags(uint8_t flags) noexcept : flags_(flags) {} + constexpr DataProcessingFlags(const uint8_t flags) noexcept : flags_(flags) {} /// @returns The operation to apply. constexpr DataProcessingOperation operation() const { @@ -183,7 +183,7 @@ struct DataProcessing: public WithShiftControlBits { // MUL and MLA. // struct MultiplyFlags { - constexpr MultiplyFlags(uint8_t flags) noexcept : flags_(flags) {} + constexpr MultiplyFlags(const uint8_t flags) noexcept : flags_(flags) {} /// @c true if the status register should be updated; @c false otherwise. constexpr bool set_condition_codes() const { return flag_bit<20>(flags_); } @@ -203,7 +203,7 @@ private: }; struct Multiply { - constexpr Multiply(uint32_t opcode) noexcept : opcode_(opcode) {} + constexpr Multiply(const uint32_t opcode) noexcept : opcode_(opcode) {} /// The destination register index. i.e. 'Rd'. uint32_t destination() const { return (opcode_ >> 16) & 0xf; } @@ -225,7 +225,7 @@ private: // Single data transfer (LDR, STR). // struct SingleDataTransferFlags { - constexpr SingleDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {} + constexpr SingleDataTransferFlags(const uint8_t flags) noexcept : flags_(flags) {} enum class Operation { LDR, /// Read single byte or word from [base + offset], possibly mutating the base. @@ -266,7 +266,7 @@ struct SingleDataTransfer: public WithShiftControlBits { // Block data transfer (LDR, STR). // struct BlockDataTransferFlags { - constexpr BlockDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {} + constexpr BlockDataTransferFlags(const uint8_t flags) noexcept : flags_(flags) {} enum class Operation { LDM, /// Read 1–16 words from [base], possibly mutating it. @@ -311,7 +311,7 @@ struct BlockDataTransfer: public WithShiftControlBits { // Coprocessor data operation. // struct CoprocessorDataOperationFlags { - constexpr CoprocessorDataOperationFlags(uint8_t flags) noexcept : flags_(flags) {} + constexpr CoprocessorDataOperationFlags(const uint8_t flags) noexcept : flags_(flags) {} constexpr int coprocessor_operation() const { return (flags_ >> (FlagsStartBit - 20)) & 0xf; } @@ -320,7 +320,7 @@ private: }; struct CoprocessorDataOperation { - constexpr CoprocessorDataOperation(uint32_t opcode) noexcept : opcode_(opcode) {} + constexpr CoprocessorDataOperation(const uint32_t opcode) noexcept : opcode_(opcode) {} uint32_t operand1() const { return (opcode_ >> 16) & 0xf; } uint32_t operand2() const { return opcode_ & 0xf; } @@ -336,7 +336,7 @@ private: // Coprocessor register transfer. // struct CoprocessorRegisterTransferFlags { - constexpr CoprocessorRegisterTransferFlags(uint8_t flags) noexcept : flags_(flags) {} + constexpr CoprocessorRegisterTransferFlags(const uint8_t flags) noexcept : flags_(flags) {} enum class Operation { MRC, /// Move from coprocessor register to ARM register. @@ -353,7 +353,7 @@ private: }; struct CoprocessorRegisterTransfer { - constexpr CoprocessorRegisterTransfer(uint32_t opcode) noexcept : opcode_(opcode) {} + constexpr CoprocessorRegisterTransfer(const uint32_t opcode) noexcept : opcode_(opcode) {} uint32_t operand1() const { return (opcode_ >> 16) & 0xf; } uint32_t operand2() const { return opcode_ & 0xf; } @@ -369,7 +369,7 @@ private: // Coprocessor data transfer. // struct CoprocessorDataTransferFlags { - constexpr CoprocessorDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {} + constexpr CoprocessorDataTransferFlags(const uint8_t flags) noexcept : flags_(flags) {} enum class Operation { LDC, /// Coprocessor data transfer load. @@ -392,7 +392,7 @@ private: // Software interrupt. // struct SoftwareInterrupt { - constexpr SoftwareInterrupt(uint32_t opcode) noexcept : opcode_(opcode) {} + constexpr SoftwareInterrupt(const uint32_t opcode) noexcept : opcode_(opcode) {} /// The 24-bit comment field, often decoded by the receiver of an SWI. uint32_t comment() const { return opcode_ & 0xff'ffff; } @@ -402,7 +402,7 @@ private: }; struct CoprocessorDataTransfer { - constexpr CoprocessorDataTransfer(uint32_t opcode) noexcept : opcode_(opcode) {} + constexpr CoprocessorDataTransfer(const uint32_t opcode) noexcept : opcode_(opcode) {} int base() const { return (opcode_ >> 16) & 0xf; } @@ -419,12 +419,12 @@ private: /// Operation mapper; use the free function @c dispatch as defined below. template struct OperationMapper { - static Condition condition(uint32_t instruction) { + static Condition condition(const uint32_t instruction) { return Condition(instruction >> 28); } template - static void dispatch(uint32_t instruction, SchedulerT &scheduler) { + static void dispatch(const uint32_t instruction, SchedulerT &scheduler) { // Put the 8-bit segment of instruction back into its proper place; // this allows all the tests below to be written so as to coordinate // properly with the data sheet, and since it's all compile-time work @@ -507,7 +507,7 @@ struct OperationMapper { struct SampleScheduler { /// @returns @c true if the rest of the instruction should be decoded and supplied /// to the scheduler as defined below; @c false otherwise. - bool should_schedule(Condition condition); + bool should_schedule(Condition); // Template argument: // @@ -537,7 +537,7 @@ struct SampleScheduler { /// Decodes @c instruction, making an appropriate call into @c scheduler. /// /// In lieu of C++20, see the sample definition of SampleScheduler above for the expected interface. -template void dispatch(uint32_t instruction, SchedulerT &scheduler) { +template void dispatch(const uint32_t instruction, SchedulerT &scheduler) { OperationMapper mapper; // Test condition. diff --git a/InstructionSets/ARM/Registers.hpp b/InstructionSets/ARM/Registers.hpp index 5c7bba41a..71513293d 100644 --- a/InstructionSets/ARM/Registers.hpp +++ b/InstructionSets/ARM/Registers.hpp @@ -52,12 +52,12 @@ struct Registers { Registers() = default; /// Sets the N and Z flags according to the value of @c result. - void set_nz(uint32_t value) { + void set_nz(const uint32_t value) { zero_result_ = negative_flag_ = value; } /// Sets C if @c value is non-zero; resets it otherwise. - void set_c(uint32_t value) { + void set_c(const uint32_t value) { carry_flag_ = value; } @@ -67,7 +67,7 @@ struct Registers { } /// Sets V if the highest bit of @c value is set; resets it otherwise. - void set_v(uint32_t value) { + void set_v(const uint32_t value) { overflow_flag_ = value; } @@ -83,14 +83,14 @@ struct Registers { } /// @returns The full PC + status bits. - uint32_t pc_status(uint32_t offset) const { + uint32_t pc_status(const uint32_t offset) const { return ((active_[15] + offset) & ConditionCode::Address) | status(); } /// Sets status bits only, subject to mode. - void set_status(uint32_t status) { + void set_status(const uint32_t status) { // ... in user mode the other flags (I, F, M1, M0) are protected from direct change // but in non-user modes these will also be affected, accepting copies of bits 27, 26, // 1 and 0 of the result respectively. @@ -112,12 +112,12 @@ struct Registers { } /// Sets a new PC. - void set_pc(uint32_t value) { + void set_pc(const uint32_t value) { active_[15] = value & ConditionCode::Address; } /// @returns The stored PC plus @c offset limited to 26 bits. - uint32_t pc(uint32_t offset) const { + uint32_t pc(const uint32_t offset) const { return (active_[15] + offset) & ConditionCode::Address; } @@ -143,7 +143,7 @@ struct Registers { /// The FIQ went low at least one cycle ago and ConditionCode::FIQDisable was not set. FIQ = 0x1c, }; - static constexpr uint32_t pc_offset_during(Exception exception) { + static constexpr uint32_t pc_offset_during(const Exception exception) { // The below is somewhat convoluted by the assumed execution model: // // * exceptions occuring during execution of an instruction are taken @@ -231,7 +231,7 @@ struct Registers { // MARK: - Condition tests. /// @returns @c true if @c condition tests as true; @c false otherwise. - bool test(Condition condition) const { + bool test(const Condition condition) const { const auto ne = [&]() -> bool { return zero_result_; }; @@ -279,7 +279,7 @@ struct Registers { } /// Sets current execution mode. - void set_mode(Mode target_mode) { + void set_mode(const Mode target_mode) { if(mode_ == target_mode) { return; } @@ -335,18 +335,18 @@ struct Registers { mode_ = target_mode; } - uint32_t &operator[](uint32_t offset) { + uint32_t &operator[](const uint32_t offset) { return active_[static_cast(offset)]; } - uint32_t operator[](uint32_t offset) const { + uint32_t operator[](const uint32_t offset) const { return active_[static_cast(offset)]; } /// @returns A reference to the register at @c offset. If @c force_user_mode is true, /// this will the the user-mode register. Otherwise it'll be that for the current mode. These references /// are guaranteed to remain valid only until the next mode change. - uint32_t ®(bool force_user_mode, uint32_t offset) { + uint32_t ®(const bool force_user_mode, const uint32_t offset) { switch(mode_) { default: case Mode::User: return active_[offset]; diff --git a/InstructionSets/CachingExecutor.hpp b/InstructionSets/CachingExecutor.hpp index ac6f8b4e0..160b3ecfc 100644 --- a/InstructionSets/CachingExecutor.hpp +++ b/InstructionSets/CachingExecutor.hpp @@ -44,50 +44,50 @@ template < /// Indicates whether instructions should be treated as ephemeral or included in the cache. bool retain_instructions > class CachingExecutor { - public: - using Performer = void (Executor::*)(); - using PerformerIndex = typename MinIntTypeValue::type; - using ProgramCounterType = typename MinIntTypeValue::type; +public: + using Performer = void (Executor::*)(); + using PerformerIndex = typename MinIntTypeValue::type; + using ProgramCounterType = typename MinIntTypeValue::type; - // MARK: - Parser call-ins. + // MARK: - Parser call-ins. - void announce_overflow(ProgramCounterType) { - /* - Should be impossible for now; this is intended to provide information - when page caching. - */ - } - void announce_instruction(ProgramCounterType, InstructionType instruction) { - // Dutifully map the instruction to a performer and keep it. - program_.push_back(static_cast(this)->action_for(instruction)); - - if constexpr (retain_instructions) { - // TODO. - } - } - - protected: - - // Storage for the statically-allocated list of performers. It's a bit more - // work for executors to fill this array, but subsequently performers can be - // indexed by array position, which is a lot more compact than a generic pointer. - std::array performers_; - ProgramCounterType program_counter_; - - /*! - Moves the current point of execution to @c address, updating necessary performer caches - and doing any translation as is necessary. + void announce_overflow(ProgramCounterType) { + /* + Should be impossible for now; this is intended to provide information + when page caching. */ - void set_program_counter(ProgramCounterType address) { - // Set flag to terminate any inner loop currently running through - // previously-parsed content. - has_branched_ = true; - program_counter_ = address; + } + void announce_instruction(ProgramCounterType, const InstructionType instruction) { + // Dutifully map the instruction to a performer and keep it. + program_.push_back(static_cast(this)->action_for(instruction)); - // Temporary implementation: just interpret. - program_.clear(); - program_index_ = 0; - static_cast(this)->parse(address, ProgramCounterType(max_address)); + if constexpr (retain_instructions) { + // TODO. + } + } + +protected: + + // Storage for the statically-allocated list of performers. It's a bit more + // work for executors to fill this array, but subsequently performers can be + // indexed by array position, which is a lot more compact than a generic pointer. + std::array performers_; + ProgramCounterType program_counter_; + + /*! + Moves the current point of execution to @c address, updating necessary performer caches + and doing any translation as is necessary. + */ + void set_program_counter(ProgramCounterType address) { + // Set flag to terminate any inner loop currently running through + // previously-parsed content. + has_branched_ = true; + program_counter_ = address; + + // Temporary implementation: just interpret. + program_.clear(); + program_index_ = 0; + static_cast(this)->parse(address, ProgramCounterType(max_address)); // const auto page = find_page(address); // const auto entry = page->entry_points.find(address); @@ -96,102 +96,102 @@ template < // // within the recently translated list and otherwise // // translate it. // } + } + + /*! + Indicates whether the processor is currently 'stopped', i.e. whether all attempts to run + should produce no activity. Some processors have such a state when waiting for + interrupts or for a reset. + */ + void set_is_stopped(bool) {} + + /*! + Executes up to the next branch. + */ + void run_to_branch() { + has_branched_ = false; + for(auto index: program_) { + const auto performer = performers_[index]; + (static_cast(this)->*performer)(); + if(has_branched_) break; } + } - /*! - Indicates whether the processor is currently 'stopped', i.e. whether all attempts to run - should produce no activity. Some processors have such a state when waiting for - interrupts or for a reset. - */ - void set_is_stopped(bool) {} + /*! + Runs for @c duration; the intention is that subclasses provide a method + that is clear about units, and call this to count down in whatever units they + count down in. + */ + void run_for(int duration) { + remaining_duration_ += duration; - /*! - Executes up to the next branch. - */ - void run_to_branch() { + while(remaining_duration_ > 0) { has_branched_ = false; - for(auto index: program_) { - const auto performer = performers_[index]; - (static_cast(this)->*performer)(); - if(has_branched_) break; + Executor *const executor = static_cast(this); + while(remaining_duration_ > 0 && !has_branched_) { + const auto performer = performers_[program_[program_index_]]; + ++program_index_; + + (executor->*performer)(); } } + } - /*! - Runs for @c duration; the intention is that subclasses provide a method - that is clear about units, and call this to count down in whatever units they - count down in. - */ - void run_for(int duration) { - remaining_duration_ += duration; + /*! + Should be called by a specific executor to subtract from the remaining + running duration. + */ + inline void subtract_duration(int duration) { + remaining_duration_ -= duration; + } - while(remaining_duration_ > 0) { - has_branched_ = false; - Executor *const executor = static_cast(this); - while(remaining_duration_ > 0 && !has_branched_) { - const auto performer = performers_[program_[program_index_]]; - ++program_index_; +private: + bool has_branched_ = false; + int remaining_duration_ = 0; + std::vector program_; + size_t program_index_ = 0; - (executor->*performer)(); - } - } - } - - /*! - Should be called by a specific executor to subtract from the remaining - running duration. - */ - inline void subtract_duration(int duration) { - remaining_duration_ -= duration; - } - - private: - bool has_branched_ = false; - int remaining_duration_ = 0; - std::vector program_; - size_t program_index_ = 0; - - /* TODO: almost below here can be shoved off into an LRUCache object, or similar. */ + /* TODO: almost below here can be shoved off into an LRUCache object, or similar. */ // static constexpr size_t max_cached_pages = 64; // struct Page { // std::map entry_points; - // TODO: can I statically these two? Should I? + // TODO: can I statically these two? Should I? // std::vector actions_; // std::vector::value, InstructionType>::type> instructions_; // }; // std::array pages_; - // Maps from page numbers to pages. + // Maps from page numbers to pages. // std::unordered_map cached_pages_; - // Maintains an LRU of recently-used pages in case of a need for reuse. + // Maintains an LRU of recently-used pages in case of a need for reuse. // std::list touched_pages_; - /*! - Finds or creates the page that contains @c address. - */ + /*! + Finds or creates the page that contains @c address. + */ /* Page *find_page(ProgramCounterType address) { - // TODO: are 1kb pages always appropriate? Is 64 the correct amount to keep? - const auto page_address = ProgramCounterType(address >> 10); + // TODO: are 1kb pages always appropriate? Is 64 the correct amount to keep? + const auto page_address = ProgramCounterType(address >> 10); - auto page = cached_pages_.find(page_address); - if(page == cached_pages_.end()) { - // Page wasn't found; either allocate a new one or - // reuse one that already exists. - if(cached_pages_.size() == max_cached_pages) { + auto page = cached_pages_.find(page_address); + if(page == cached_pages_.end()) { + // Page wasn't found; either allocate a new one or + // reuse one that already exists. + if(cached_pages_.size() == max_cached_pages) { - } else { - - } } else { - // Page was found; LRU shuffle it. - } - return nullptr; - }*/ + } + } else { + // Page was found; LRU shuffle it. + } + + return nullptr; + }*/ }; } diff --git a/InstructionSets/Disassembler.hpp b/InstructionSets/Disassembler.hpp index 59cd9557f..79d3bf603 100644 --- a/InstructionSets/Disassembler.hpp +++ b/InstructionSets/Disassembler.hpp @@ -28,59 +28,64 @@ template < /// Provides the addressing range of memory. typename AddressType > class Disassembler { - public: - using ProgramCounterType = typename MinIntTypeValue::type; +public: + using ProgramCounterType = typename MinIntTypeValue::type; - /*! - Adds the result of disassembling @c memory which is @c length @c MemoryWords long from @c start_address - to the current net total of instructions and recorded memory accesses. - */ - void disassemble(const MemoryWord *memory, ProgramCounterType location, ProgramCounterType length, ProgramCounterType start_address) { - // TODO: possibly, move some of this stuff to instruction-set specific disassemblers, analogous to - // the Executor's ownership of the Parser. That would allow handling of stateful parsing. - ParserType parser; - pending_entry_points_.push_back(start_address); - entry_points_.insert(start_address); + /*! + Adds the result of disassembling @c memory which is @c length @c MemoryWords long from @c start_address + to the current net total of instructions and recorded memory accesses. + */ + void disassemble( + const MemoryWord *const memory, + const ProgramCounterType location, + const ProgramCounterType length, + const ProgramCounterType start_address + ) { + // TODO: possibly, move some of this stuff to instruction-set specific disassemblers, analogous to + // the Executor's ownership of the Parser. That would allow handling of stateful parsing. + ParserType parser; + pending_entry_points_.push_back(start_address); + entry_points_.insert(start_address); - while(!pending_entry_points_.empty()) { - const auto next_entry_point = pending_entry_points_.front(); - pending_entry_points_.pop_front(); + while(!pending_entry_points_.empty()) { + const auto next_entry_point = pending_entry_points_.front(); + pending_entry_points_.pop_front(); - if(next_entry_point >= location) { - parser.parse(*this, memory - location, next_entry_point & max_address, length + location); - } + if(next_entry_point >= location) { + parser.parse(*this, memory - location, next_entry_point & max_address, length + location); } } + } - const std::map &instructions() const { - return instructions_; - } + const std::map &instructions() const { + return instructions_; + } - const std::set &entry_points() const { - return entry_points_; - } + const std::set &entry_points() const { + return entry_points_; + } - void announce_overflow(ProgramCounterType) {} - void announce_instruction(ProgramCounterType address, InstructionType instruction) { - instructions_[address] = instruction; - } - void add_entry(ProgramCounterType address) { - if(entry_points_.find(address) == entry_points_.end()) { - pending_entry_points_.push_back(address); - entry_points_.insert(address); - } - } - void add_access(AddressType address, AccessType access_type) { - // TODO. - (void)address; - (void)access_type; + void announce_overflow(ProgramCounterType) {} + void announce_instruction(const ProgramCounterType address, const InstructionType instruction) { + instructions_[address] = instruction; + } + void add_entry(const ProgramCounterType address) { + if(entry_points_.find(address) == entry_points_.end()) { + pending_entry_points_.push_back(address); + entry_points_.insert(address); } + } + void add_access(const AddressType address, const AccessType access_type) { + // TODO. + (void)address; + (void)access_type; + } - private: - std::map instructions_; - std::set entry_points_; +private: + std::map instructions_; + std::set entry_points_; - std::list pending_entry_points_; + std::list pending_entry_points_; }; } diff --git a/InstructionSets/M68k/Decoder.cpp b/InstructionSets/M68k/Decoder.cpp index be2cba10c..4a2d1ca48 100644 --- a/InstructionSets/M68k/Decoder.cpp +++ b/InstructionSets/M68k/Decoder.cpp @@ -140,7 +140,8 @@ constexpr Operation Predecoder::operation(const OpT op) { } template -template ::OpT op> uint32_t Predecoder::invalid_operands() { +template ::OpT op> +constexpr uint32_t Predecoder::invalid_operands() { constexpr auto Dn = Mask< AddressingMode::DataRegisterDirect >::value; constexpr auto An = Mask< AddressingMode::AddressRegisterDirect >::value; constexpr auto Ind = Mask< AddressingMode::AddressRegisterIndirect >::value; @@ -162,24 +163,25 @@ template ::OpT op> uint32_t Predecoder::invali // // All modes: the complete set (other than Quick). // - static constexpr auto AllModes = Dn | An | Ind | PostInc | PreDec | d16An | d8AnXn | XXXw | XXXl | Imm | d16PC | d8PCXn; - static constexpr auto AllModesNoAn = AllModes & ~An; + constexpr auto AllModes = Dn | An | Ind | PostInc | PreDec | d16An | + d8AnXn | XXXw | XXXl | Imm | d16PC | d8PCXn; + constexpr auto AllModesNoAn = AllModes & ~An; // // Alterable addressing modes (with and without AddressRegisterDirect). // - static constexpr auto AlterableAddressingModes = Dn | An | Ind | PostInc | PreDec | d16An | d8AnXn | XXXw | XXXl; - static constexpr auto AlterableAddressingModesNoAn = AlterableAddressingModes & ~An; + constexpr auto AlterableAddressingModes = Dn | An | Ind | PostInc | PreDec | d16An | d8AnXn | XXXw | XXXl; + constexpr auto AlterableAddressingModesNoAn = AlterableAddressingModes & ~An; // // Control [flow] addressing modes. // - static constexpr auto ControlAddressingModes = Ind | d16An | d8AnXn | XXXw | XXXl | d16PC | d8PCXn; + constexpr auto ControlAddressingModes = Ind | d16An | d8AnXn | XXXw | XXXl | d16PC | d8PCXn; // // An invalid response, used as the default case. // - static constexpr auto InvalidOperands = uint32_t(~0); + constexpr auto InvalidOperands = uint32_t(~0); switch(op) { default: break; @@ -620,7 +622,8 @@ template ::OpT op> uint32_t Predecoder::invali /// Provides a post-decoding validation step — primarily ensures that the prima facie addressing modes are supported by the operation. template -template ::OpT op, bool validate> Preinstruction Predecoder::validated( +template ::OpT op, bool validate> +constexpr Preinstruction Predecoder::validated( const AddressingMode op1_mode, const int op1_reg, const AddressingMode op2_mode, const int op2_reg, const Condition condition, @@ -656,7 +659,10 @@ template ::OpT op, bool validate> Preinstruction Pred /// Decodes the fields within an instruction and constructs a `Preinstruction`, given that the operation has already been /// decoded. Optionally applies validation template -template ::OpT op, bool validate> Preinstruction Predecoder::decode(const uint16_t instruction) { +template ::OpT op, bool validate> +constexpr Preinstruction Predecoder::decode( + const uint16_t instruction +) { // Fields used pervasively below. // // Underlying assumption: the compiler will discard whatever of these @@ -1269,11 +1275,11 @@ template ::OpT op, bool validate> Preinstruction Pred // MARK: - Page decoders. -#define Decode(y) return decode(instruction) +#define Decode(y) return decode(instruction) #define DecodeReq(x, y) if constexpr (x) Decode(y); break; template -Preinstruction Predecoder::decode0(const uint16_t instruction) { +constexpr Preinstruction Predecoder::decode0(const uint16_t instruction) { using Op = Operation; switch(instruction & 0xfff) { @@ -1386,7 +1392,7 @@ Preinstruction Predecoder::decode0(const uint16_t instruction) { } template -Preinstruction Predecoder::decode1(const uint16_t instruction) { +constexpr Preinstruction Predecoder::decode1(const uint16_t instruction) { using Op = Operation; // 4-116 (p220) @@ -1394,7 +1400,7 @@ Preinstruction Predecoder::decode1(const uint16_t instruction) { } template -Preinstruction Predecoder::decode2(const uint16_t instruction) { +constexpr Preinstruction Predecoder::decode2(const uint16_t instruction) { using Op = Operation; // 4-116 (p220) @@ -1405,7 +1411,7 @@ Preinstruction Predecoder::decode2(const uint16_t instruction) { } template -Preinstruction Predecoder::decode3(const uint16_t instruction) { +constexpr Preinstruction Predecoder::decode3(const uint16_t instruction) { using Op = Operation; // 4-116 (p220) @@ -1416,7 +1422,7 @@ Preinstruction Predecoder::decode3(const uint16_t instruction) { } template -Preinstruction Predecoder::decode4(const uint16_t instruction) { +constexpr Preinstruction Predecoder::decode4(const uint16_t instruction) { using Op = Operation; switch(instruction & 0xfff) { @@ -1539,7 +1545,7 @@ Preinstruction Predecoder::decode4(const uint16_t instruction) { } template -Preinstruction Predecoder::decode5(const uint16_t instruction) { +constexpr Preinstruction Predecoder::decode5(const uint16_t instruction) { using Op = Operation; switch(instruction & 0x1f8) { @@ -1617,7 +1623,7 @@ Preinstruction Predecoder::decode5(const uint16_t instruction) { } template -Preinstruction Predecoder::decode6(const uint16_t instruction) { +constexpr Preinstruction Predecoder::decode6(const uint16_t instruction) { using Op = Operation; switch(instruction & 0xf00) { @@ -1649,7 +1655,7 @@ Preinstruction Predecoder::decode6(const uint16_t instruction) { } template -Preinstruction Predecoder::decode7(const uint16_t instruction) { +constexpr Preinstruction Predecoder::decode7(const uint16_t instruction) { // 4-134 (p238) if(!(instruction & 0x100)) { Decode(MOVEQ); @@ -1659,7 +1665,7 @@ Preinstruction Predecoder::decode7(const uint16_t instruction) { } template -Preinstruction Predecoder::decode8(const uint16_t instruction) { +constexpr Preinstruction Predecoder::decode8(const uint16_t instruction) { using Op = Operation; switch(instruction & 0x1f0) { @@ -1689,7 +1695,7 @@ Preinstruction Predecoder::decode8(const uint16_t instruction) { } template -Preinstruction Predecoder::decode9(const uint16_t instruction) { +constexpr Preinstruction Predecoder::decode9(const uint16_t instruction) { using Op = Operation; switch(instruction & 0x1f0) { @@ -1721,12 +1727,12 @@ Preinstruction Predecoder::decode9(const uint16_t instruction) { } template -Preinstruction Predecoder::decodeA(const uint16_t) { +constexpr Preinstruction Predecoder::decodeA(const uint16_t) { return Preinstruction(); } template -Preinstruction Predecoder::decodeB(const uint16_t instruction) { +constexpr Preinstruction Predecoder::decodeB(const uint16_t instruction) { using Op = Operation; switch(instruction & 0x1f8) { @@ -1760,7 +1766,7 @@ Preinstruction Predecoder::decodeB(const uint16_t instruction) { } template -Preinstruction Predecoder::decodeC(const uint16_t instruction) { +constexpr Preinstruction Predecoder::decodeC(const uint16_t instruction) { using Op = Operation; // 4-105 (p209) @@ -1795,7 +1801,7 @@ Preinstruction Predecoder::decodeC(const uint16_t instruction) { } template -Preinstruction Predecoder::decodeD(const uint16_t instruction) { +constexpr Preinstruction Predecoder::decodeD(const uint16_t instruction) { using Op = Operation; switch(instruction & 0x1f0) { @@ -1827,7 +1833,7 @@ Preinstruction Predecoder::decodeD(const uint16_t instruction) { } template -Preinstruction Predecoder::decodeE(const uint16_t instruction) { +constexpr Preinstruction Predecoder::decodeE(const uint16_t instruction) { using Op = Operation; switch(instruction & 0xfc0) { @@ -1900,7 +1906,7 @@ Preinstruction Predecoder::decodeE(const uint16_t instruction) { } template -Preinstruction Predecoder::decodeF(const uint16_t) { +constexpr Preinstruction Predecoder::decodeF(const uint16_t) { return Preinstruction(); } diff --git a/InstructionSets/M68k/Decoder.hpp b/InstructionSets/M68k/Decoder.hpp index 5282b8181..5ace4220b 100644 --- a/InstructionSets/M68k/Decoder.hpp +++ b/InstructionSets/M68k/Decoder.hpp @@ -26,91 +26,91 @@ namespace InstructionSet::M68k { But it does not yet decode any operations which were not present on the 68000. */ template class Predecoder { - public: - Preinstruction decode(uint16_t instruction); +public: + static Preinstruction decode(uint16_t); - private: - // Page by page decoders; each gets a bit ad hoc so - // it is neater to separate them. - Preinstruction decode0(uint16_t instruction); - Preinstruction decode1(uint16_t instruction); - Preinstruction decode2(uint16_t instruction); - Preinstruction decode3(uint16_t instruction); - Preinstruction decode4(uint16_t instruction); - Preinstruction decode5(uint16_t instruction); - Preinstruction decode6(uint16_t instruction); - Preinstruction decode7(uint16_t instruction); - Preinstruction decode8(uint16_t instruction); - Preinstruction decode9(uint16_t instruction); - Preinstruction decodeA(uint16_t instruction); - Preinstruction decodeB(uint16_t instruction); - Preinstruction decodeC(uint16_t instruction); - Preinstruction decodeD(uint16_t instruction); - Preinstruction decodeE(uint16_t instruction); - Preinstruction decodeF(uint16_t instruction); +private: + // Page by page decoders; each gets a bit ad hoc so + // it is neater to separate them. + static constexpr Preinstruction decode0(uint16_t); + static constexpr Preinstruction decode1(uint16_t); + static constexpr Preinstruction decode2(uint16_t); + static constexpr Preinstruction decode3(uint16_t); + static constexpr Preinstruction decode4(uint16_t); + static constexpr Preinstruction decode5(uint16_t); + static constexpr Preinstruction decode6(uint16_t); + static constexpr Preinstruction decode7(uint16_t); + static constexpr Preinstruction decode8(uint16_t); + static constexpr Preinstruction decode9(uint16_t); + static constexpr Preinstruction decodeA(uint16_t); + static constexpr Preinstruction decodeB(uint16_t); + static constexpr Preinstruction decodeC(uint16_t); + static constexpr Preinstruction decodeD(uint16_t); + static constexpr Preinstruction decodeE(uint16_t); + static constexpr Preinstruction decodeF(uint16_t); - // Yuckiness here: 67 is a count of the number of things contained below in - // ExtendedOperation; this acts to ensure ExtendedOperation is the minimum - // integer size large enough to hold all actual operations plus the ephemeral - // ones used here. Intention is to support table-based decoding, which will mean - // making those integers less ephemeral, hence the desire to pick a minimum size. - using OpT = typename MinIntTypeValue< - uint64_t(OperationMax::value) + 67 - >::type; - static constexpr auto OpMax = OpT(OperationMax::value); + // Yuckiness here: 67 is a count of the number of things contained below in + // ExtendedOperation; this acts to ensure ExtendedOperation is the minimum + // integer size large enough to hold all actual operations plus the ephemeral + // ones used here. Intention is to support table-based decoding, which will mean + // making those integers less ephemeral, hence the desire to pick a minimum size. + using OpT = typename MinIntTypeValue< + uint64_t(OperationMax::value) + 67 + >::type; + static constexpr auto OpMax = OpT(OperationMax::value); - // Specific instruction decoders. - template Preinstruction decode(uint16_t instruction); - template Preinstruction validated( - AddressingMode op1_mode = AddressingMode::None, int op1_reg = 0, - AddressingMode op2_mode = AddressingMode::None, int op2_reg = 0, - Condition condition = Condition::True, - int further_extension_words = 0 - ); - template uint32_t invalid_operands(); + // Specific instruction decoders. + template static constexpr Preinstruction decode(uint16_t instruction); + template static constexpr Preinstruction validated( + AddressingMode op1_mode = AddressingMode::None, int op1_reg = 0, + AddressingMode op2_mode = AddressingMode::None, int op2_reg = 0, + Condition condition = Condition::True, + int further_extension_words = 0 + ); + template static constexpr uint32_t invalid_operands(); - // Extended operation list; collapses into a single byte enough information to - // know both the type of operation and how to decode the operands. Most of the - // time that's knowable from the Operation alone, hence the rather awkward - // extension of @c Operation. - enum ExtendedOperation: OpT { - MOVEPtoRl = OpMax + 1, MOVEPtoRw, - MOVEPtoMl, MOVEPtoMw, + // Extended operation list; collapses into a single byte enough information to + // know both the type of operation and how to decode the operands. Most of the + // time that's knowable from the Operation alone, hence the rather awkward + // extension of @c Operation. + enum ExtendedOperation: OpT { + MOVEPtoRl = OpMax + 1, MOVEPtoRw, + MOVEPtoMl, MOVEPtoMw, - MOVEQ, + MOVEQ, - ADDQb, ADDQw, ADDQl, - ADDQAw, ADDQAl, - SUBQb, SUBQw, SUBQl, - SUBQAw, SUBQAl, + ADDQb, ADDQw, ADDQl, + ADDQAw, ADDQAl, + SUBQb, SUBQw, SUBQl, + SUBQAw, SUBQAl, - ADDIb, ADDIw, ADDIl, - ORIb, ORIw, ORIl, - SUBIb, SUBIw, SUBIl, - ANDIb, ANDIw, ANDIl, - EORIb, EORIw, EORIl, - CMPIb, CMPIw, CMPIl, + ADDIb, ADDIw, ADDIl, + ORIb, ORIw, ORIl, + SUBIb, SUBIw, SUBIl, + ANDIb, ANDIw, ANDIl, + EORIb, EORIw, EORIl, + CMPIb, CMPIw, CMPIl, - BTSTI, BCHGI, BCLRI, BSETI, + BTSTI, BCHGI, BCLRI, BSETI, - CMPMb, CMPMw, CMPMl, + CMPMb, CMPMw, CMPMl, - ADDtoMb, ADDtoMw, ADDtoMl, - ADDtoRb, ADDtoRw, ADDtoRl, + ADDtoMb, ADDtoMw, ADDtoMl, + ADDtoRb, ADDtoRw, ADDtoRl, - SUBtoMb, SUBtoMw, SUBtoMl, - SUBtoRb, SUBtoRw, SUBtoRl, + SUBtoMb, SUBtoMw, SUBtoMl, + SUBtoRb, SUBtoRw, SUBtoRl, - ANDtoMb, ANDtoMw, ANDtoMl, - ANDtoRb, ANDtoRw, ANDtoRl, + ANDtoMb, ANDtoMw, ANDtoMl, + ANDtoRb, ANDtoRw, ANDtoRl, - ORtoMb, ORtoMw, ORtoMl, - ORtoRb, ORtoRw, ORtoRl, + ORtoMb, ORtoMw, ORtoMl, + ORtoRb, ORtoRw, ORtoRl, - EXGRtoR, EXGAtoA, EXGRtoA, - }; + EXGRtoR, EXGAtoA, EXGRtoA, + }; - static constexpr Operation operation(OpT op); + static constexpr Operation operation(OpT op); }; } diff --git a/InstructionSets/M68k/Executor.hpp b/InstructionSets/M68k/Executor.hpp index 7d0f58169..53e8c0c21 100644 --- a/InstructionSets/M68k/Executor.hpp +++ b/InstructionSets/M68k/Executor.hpp @@ -37,12 +37,12 @@ struct BusHandler { /// Write @c value of type/size @c IntT to @c address with the processor signalling /// a FunctionCode of @c function. @c IntT will be one of @c uint8_t, @c uint16_t /// or @c uint32_t. - template void write(uint32_t address, IntT value, FunctionCode function); + template void write(uint32_t address, IntT value, FunctionCode); /// Read and return a value of type/size @c IntT from @c address with the processor signalling /// a FunctionCode of @c function. @c IntT will be one of @c uint8_t, @c uint16_t /// or @c uint32_t. - template IntT read(uint32_t address, FunctionCode function); + template IntT read(uint32_t address, FunctionCode); /// React to the processor programmatically strobing its RESET output. void reset(); @@ -59,106 +59,106 @@ struct BusHandler { /// As is standard for these executors, no bus- or cache-level fidelity to any real 680x0 is attempted. This is /// simply an executor of 680x0 code. template class Executor { - public: - Executor(BusHandler &); +public: + Executor(BusHandler &); - /// Reset the processor, back to a state as if just externally reset. - void reset(); + /// Reset the processor, back to a state as if just externally reset. + void reset(); - /// Executes the number of instructions specified; - /// other events — such as initial reset or branching - /// to exceptions — may be zero costed, and interrupts - /// will not necessarily take effect immediately when signalled. - void run_for_instructions(int); + /// Executes the number of instructions specified; + /// other events — such as initial reset or branching + /// to exceptions — may be zero costed, and interrupts + /// will not necessarily take effect immediately when signalled. + void run_for_instructions(int); - /// Call this at any time to interrupt processing with a bus error; - /// the function code and address must be provided. Internally - /// this will raise a C++ exception, and therefore doesn't return. - [[noreturn]] void signal_bus_error(FunctionCode, uint32_t address); + /// Call this at any time to interrupt processing with a bus error; + /// the function code and address must be provided. Internally + /// this will raise a C++ exception, and therefore doesn't return. + [[noreturn]] void signal_bus_error(FunctionCode, uint32_t address); - /// Sets the current input interrupt level. - void set_interrupt_level(int); + /// Sets the current input interrupt level. + void set_interrupt_level(int); - // State for the executor is just the register set. - RegisterSet get_state(); - void set_state(const RegisterSet &); + // State for the executor is just the register set. + RegisterSet get_state() const; + void set_state(const RegisterSet &); - private: - class State: public NullFlowController { - public: - State(BusHandler &handler) : bus_handler_(handler) {} +private: + class State: public NullFlowController { + public: + State(BusHandler &handler) : bus_handler_(handler) {} - void run(int &); - bool stopped = false; + void run(int &); + bool stopped = false; - void read(DataSize size, uint32_t address, CPU::SlicedInt32 &value); - void write(DataSize size, uint32_t address, CPU::SlicedInt32 value); - template IntT read(uint32_t address, bool is_from_pc = false); - template void write(uint32_t address, IntT value); + void read(DataSize size, uint32_t address, CPU::SlicedInt32 &value); + void write(DataSize size, uint32_t address, CPU::SlicedInt32 value); + template IntT read(uint32_t address, bool is_from_pc = false); + template void write(uint32_t address, IntT value); - template IntT read_pc(); + template IntT read_pc(); - // Processor state. - Status status; - CPU::SlicedInt32 program_counter; - CPU::SlicedInt32 registers[16]; // D0–D7 followed by A0–A7. - CPU::SlicedInt32 stack_pointers[2]; - uint32_t instruction_address; - uint16_t instruction_opcode; + // Processor state. + Status status; + CPU::SlicedInt32 program_counter; + CPU::SlicedInt32 registers[16]; // D0–D7 followed by A0–A7. + CPU::SlicedInt32 stack_pointers[2]; + uint32_t instruction_address; + uint16_t instruction_opcode; - // Things that are ephemerally duplicative of Status. - int active_stack_pointer = 0; - Status::FlagT should_trace = 0; + // Things that are ephemerally duplicative of Status. + int active_stack_pointer = 0; + Status::FlagT should_trace = 0; - // Bus state. - int interrupt_input = 0; + // Bus state. + int interrupt_input = 0; - // A lookup table to ensure that A7 is adjusted by 2 rather than 1 in - // postincrement and predecrement mode. - static constexpr uint32_t byte_increments[] = { - 1, 1, 1, 1, 1, 1, 1, 2 - }; + // A lookup table to ensure that A7 is adjusted by 2 rather than 1 in + // postincrement and predecrement mode. + static constexpr uint32_t byte_increments[] = { + 1, 1, 1, 1, 1, 1, 1, 2 + }; - // Flow control; Cf. Perform.hpp. - template void raise_exception(int); + // Flow control; Cf. Perform.hpp. + template void raise_exception(int); - void did_update_status(); + void did_update_status(); - template void complete_bcc(bool matched_condition, IntT offset); - void complete_dbcc(bool matched_condition, bool overflowed, int16_t offset); - void bsr(uint32_t offset); - void jmp(uint32_t); - void jsr(uint32_t offset); - void rtr(); - void rts(); - void rte(); - void stop(); - void reset(); + template void complete_bcc(bool matched_condition, IntT offset); + void complete_dbcc(bool matched_condition, bool overflowed, int16_t offset); + void bsr(uint32_t offset); + void jmp(uint32_t); + void jsr(uint32_t offset); + void rtr(); + void rts(); + void rte(); + void stop(); + void reset(); - void link(Preinstruction instruction, uint32_t offset); - void unlink(uint32_t &address); - void pea(uint32_t address); + void link(Preinstruction instruction, uint32_t offset); + void unlink(uint32_t &address); + void pea(uint32_t address); - void move_to_usp(uint32_t address); - void move_from_usp(uint32_t &address); + void move_to_usp(uint32_t address); + void move_from_usp(uint32_t &address); - template void movep(Preinstruction instruction, uint32_t source, uint32_t dest); - template void movem_toM(Preinstruction instruction, uint32_t source, uint32_t dest); - template void movem_toR(Preinstruction instruction, uint32_t source, uint32_t dest); + template void movep(Preinstruction instruction, uint32_t source, uint32_t dest); + template void movem_toM(Preinstruction instruction, uint32_t source, uint32_t dest); + template void movem_toR(Preinstruction instruction, uint32_t source, uint32_t dest); - void tas(Preinstruction instruction, uint32_t address); + void tas(Preinstruction instruction, uint32_t address); - private: - BusHandler &bus_handler_; - Predecoder decoder_; + private: + BusHandler &bus_handler_; + Predecoder decoder_; - struct EffectiveAddress { - CPU::SlicedInt32 value; - bool requires_fetch; - }; - EffectiveAddress calculate_effective_address(Preinstruction instruction, uint16_t opcode, int index); - uint32_t index_8bitdisplacement(uint32_t); - } state_; + struct EffectiveAddress { + CPU::SlicedInt32 value; + bool requires_fetch; + }; + EffectiveAddress calculate_effective_address(Preinstruction instruction, uint16_t opcode, int index); + uint32_t index_8bitdisplacement(uint32_t); + } state_; }; } diff --git a/InstructionSets/M68k/Implementation/ExecutorImplementation.hpp b/InstructionSets/M68k/Implementation/ExecutorImplementation.hpp index 7d5b018aa..4696ab6b8 100644 --- a/InstructionSets/M68k/Implementation/ExecutorImplementation.hpp +++ b/InstructionSets/M68k/Implementation/ExecutorImplementation.hpp @@ -101,7 +101,7 @@ void Executor::run_for_instructions(int count) { } template -RegisterSet Executor::get_state() { +RegisterSet Executor::get_state() const { RegisterSet result; for(int c = 0; c < 8; c++) { diff --git a/InstructionSets/M68k/Instruction.hpp b/InstructionSets/M68k/Instruction.hpp index dcad8d70c..75b7b6c4a 100644 --- a/InstructionSets/M68k/Instruction.hpp +++ b/InstructionSets/M68k/Instruction.hpp @@ -367,133 +367,133 @@ static constexpr int AddressingModeCount = 0b10'110; the notes on @c AddressingMode for potential aliasing. */ class Preinstruction { - public: - Operation operation = Operation::Undefined; +public: + Operation operation = Operation::Undefined; - // Instructions come with 0, 1 or 2 operands; - // the getters below act to provide a list of operands - // that is terminated by an AddressingMode::None. - // - // For two-operand instructions, argument 0 is a source - // and argument 1 is a destination. - // - // For one-operand instructions, only argument 0 will - // be provided, and will be a source and/or destination as - // per the semantics of the operation. - // - // The versions templated on index do a range check; - // if using the runtime versions then results for indices - // other than 0 and 1 are undefined. + // Instructions come with 0, 1 or 2 operands; + // the getters below act to provide a list of operands + // that is terminated by an AddressingMode::None. + // + // For two-operand instructions, argument 0 is a source + // and argument 1 is a destination. + // + // For one-operand instructions, only argument 0 will + // be provided, and will be a source and/or destination as + // per the semantics of the operation. + // + // The versions templated on index do a range check; + // if using the runtime versions then results for indices + // other than 0 and 1 are undefined. - AddressingMode mode(const int index) const { - return AddressingMode(operands_[index] >> 3); + AddressingMode mode(const int index) const { + return AddressingMode(operands_[index] >> 3); + } + template AddressingMode mode() const { + if constexpr (index > 1) { + return AddressingMode::None; } - template AddressingMode mode() const { - if constexpr (index > 1) { - return AddressingMode::None; - } - return mode(index); - } - int reg(const int index) const { - return operands_[index] & 7; - } - template int reg() const { - if constexpr (index > 1) { - return 0; - } - return reg(index); + return mode(index); + } + int reg(const int index) const { + return operands_[index] & 7; + } + template int reg() const { + if constexpr (index > 1) { + return 0; } + return reg(index); + } - /// @returns 0–7 to indicate data registers 0 to 7, or 8–15 to indicate address registers 0 to 7 respectively. - /// Provides undefined results if the addressing mode is not either @c DataRegisterDirect or - /// @c AddressRegisterDirect. - int lreg(const int index) const { - return operands_[index] & 0xf; - } + /// @returns 0–7 to indicate data registers 0 to 7, or 8–15 to indicate address registers 0 to 7 respectively. + /// Provides undefined results if the addressing mode is not either @c DataRegisterDirect or + /// @c AddressRegisterDirect. + int lreg(const int index) const { + return operands_[index] & 0xf; + } - /// @returns @c true if this instruction requires supervisor privileges; @c false otherwise. - bool requires_supervisor() const { - return flags_ & Flags::IsSupervisor; - } + /// @returns @c true if this instruction requires supervisor privileges; @c false otherwise. + bool requires_supervisor() const { + return flags_ & Flags::IsSupervisor; + } - /// @returns @c true if this instruction will require further fetching than can be encoded in a - /// @c Preinstruction. In practice this means it is one of a very small quantity of 68020+ - /// instructions; those that can rationalise extension words into one of the two operands will - /// do so. Use the free function @c extension_words(instruction.operation) to - /// look up the number of additional words required. - /// - /// (specifically affected, at least: PACK, UNPK, CAS, CAS2) - bool requires_further_extension() const { - return flags_ & Flags::RequiresFurtherExtension; - } + /// @returns @c true if this instruction will require further fetching than can be encoded in a + /// @c Preinstruction. In practice this means it is one of a very small quantity of 68020+ + /// instructions; those that can rationalise extension words into one of the two operands will + /// do so. Use the free function @c extension_words(instruction.operation) to + /// look up the number of additional words required. + /// + /// (specifically affected, at least: PACK, UNPK, CAS, CAS2) + bool requires_further_extension() const { + return flags_ & Flags::RequiresFurtherExtension; + } - /// @returns The number of additional extension words required, beyond those encoded as operands. - int additional_extension_words() const { - return flags_ & Flags::RequiresFurtherExtension ? (flags_ & Flags::ConditionMask) >> Flags::ConditionShift : 0; - } + /// @returns The number of additional extension words required, beyond those encoded as operands. + int additional_extension_words() const { + return flags_ & Flags::RequiresFurtherExtension ? (flags_ & Flags::ConditionMask) >> Flags::ConditionShift : 0; + } - /// @returns The @c DataSize used for operands of this instruction, i.e. byte, word or longword. - DataSize operand_size() const { - return DataSize((flags_ & Flags::SizeMask) >> Flags::SizeShift); - } + /// @returns The @c DataSize used for operands of this instruction, i.e. byte, word or longword. + DataSize operand_size() const { + return DataSize((flags_ & Flags::SizeMask) >> Flags::SizeShift); + } - /// @returns The condition code evaluated by this instruction if applicable. If this instruction is not - /// conditional, the result is undefined. - Condition condition() const { - return Condition((flags_ & Flags::ConditionMask) >> Flags::ConditionShift); - } + /// @returns The condition code evaluated by this instruction if applicable. If this instruction is not + /// conditional, the result is undefined. + Condition condition() const { + return Condition((flags_ & Flags::ConditionMask) >> Flags::ConditionShift); + } - private: - uint8_t operands_[2] = { uint8_t(AddressingMode::None), uint8_t(AddressingMode::None)}; - uint8_t flags_ = 0; +private: + uint8_t operands_[2] = { uint8_t(AddressingMode::None), uint8_t(AddressingMode::None)}; + uint8_t flags_ = 0; - std::string operand_description(int index, int opcode) const; + std::string operand_description(int index, int opcode) const; - public: - Preinstruction( - Operation operation, - AddressingMode op1_mode, int op1_reg, - AddressingMode op2_mode, int op2_reg, - bool is_supervisor, - int extension_words, - DataSize size, - Condition condition) : operation(operation) - { - operands_[0] = uint8_t((uint8_t(op1_mode) << 3) | op1_reg); - operands_[1] = uint8_t((uint8_t(op2_mode) << 3) | op2_reg); - flags_ = uint8_t( - (is_supervisor ? Flags::IsSupervisor : 0x00) | - (extension_words ? Flags::RequiresFurtherExtension : 0x00) | - (int(condition) << Flags::ConditionShift) | - (extension_words << Flags::ConditionShift) | - (int(size) << Flags::SizeShift) - ); - } +public: + Preinstruction( + Operation operation, + AddressingMode op1_mode, int op1_reg, + AddressingMode op2_mode, int op2_reg, + bool is_supervisor, + int extension_words, + DataSize size, + Condition condition) : operation(operation) + { + operands_[0] = uint8_t((uint8_t(op1_mode) << 3) | op1_reg); + operands_[1] = uint8_t((uint8_t(op2_mode) << 3) | op2_reg); + flags_ = uint8_t( + (is_supervisor ? Flags::IsSupervisor : 0x00) | + (extension_words ? Flags::RequiresFurtherExtension : 0x00) | + (int(condition) << Flags::ConditionShift) | + (extension_words << Flags::ConditionShift) | + (int(size) << Flags::SizeShift) + ); + } - struct Flags { - static constexpr uint8_t IsSupervisor = 0b1000'0000; - static constexpr uint8_t RequiresFurtherExtension = 0b0100'0000; - static constexpr uint8_t ConditionMask = 0b0011'1100; - static constexpr uint8_t SizeMask = 0b0000'0011; + struct Flags { + static constexpr uint8_t IsSupervisor = 0b1000'0000; + static constexpr uint8_t RequiresFurtherExtension = 0b0100'0000; + static constexpr uint8_t ConditionMask = 0b0011'1100; + static constexpr uint8_t SizeMask = 0b0000'0011; - static constexpr int IsSupervisorShift = 7; - static constexpr int RequiresFurtherExtensionShift = 6; - static constexpr int ConditionShift = 2; - static constexpr int SizeShift = 0; - }; + static constexpr int IsSupervisorShift = 7; + static constexpr int RequiresFurtherExtensionShift = 6; + static constexpr int ConditionShift = 2; + static constexpr int SizeShift = 0; + }; - Preinstruction() = default; + Preinstruction() = default; - /// Produces a string description of this instruction; if @c opcode - /// is supplied then any quick fields in this instruction will be decoded; - /// otherwise they'll be printed as just 'Q'. - std::string to_string(int opcode = -1) const; + /// Produces a string description of this instruction; if @c opcode + /// is supplied then any quick fields in this instruction will be decoded; + /// otherwise they'll be printed as just 'Q'. + std::string to_string(int opcode = -1) const; - /// Produces a slightly-more-idiomatic version of the operation name than - /// a direct to_string(instruction.operation) would, given that this decoder - /// sometimes aliases operations, disambiguating based on addressing mode - /// (e.g. MOVEQ is MOVE.l with the Q addressing mode). - const char *operation_string() const; + /// Produces a slightly-more-idiomatic version of the operation name than + /// a direct to_string(instruction.operation) would, given that this decoder + /// sometimes aliases operations, disambiguating based on addressing mode + /// (e.g. MOVEQ is MOVE.l with the Q addressing mode). + const char *operation_string() const; }; } diff --git a/InstructionSets/M68k/Perform.hpp b/InstructionSets/M68k/Perform.hpp index b2d2d47ef..98594aaa6 100644 --- a/InstructionSets/M68k/Perform.hpp +++ b/InstructionSets/M68k/Perform.hpp @@ -163,7 +163,7 @@ template < Model model, typename FlowController, Operation operation = Operation::Undefined -> void perform(Preinstruction instruction, CPU::RegisterPair32 &source, CPU::RegisterPair32 &dest, Status &status, FlowController &flow_controller); +> void perform(Preinstruction, CPU::RegisterPair32 &source, CPU::RegisterPair32 &dest, Status &, FlowController &); } From 43fcf46d693aaeda61c73a4a80434d98dd4444f3 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 1 Dec 2024 09:00:29 -0500 Subject: [PATCH 2/4] Limit line lengths. --- InstructionSets/M68k/Decoder.cpp | 7 +- .../Implementation/ExecutorImplementation.hpp | 18 +++- .../Implementation/PerformImplementation.hpp | 83 ++++++++++++++----- 3 files changed, 83 insertions(+), 25 deletions(-) diff --git a/InstructionSets/M68k/Decoder.cpp b/InstructionSets/M68k/Decoder.cpp index 4a2d1ca48..d8ac61521 100644 --- a/InstructionSets/M68k/Decoder.cpp +++ b/InstructionSets/M68k/Decoder.cpp @@ -1006,7 +1006,8 @@ constexpr Preinstruction Predecoder::decode( // MARK: ASR, LSR, ROXR, ROR, ASL, LSL, ROXL, ROL // // b0–b2: a register to shift (the source here, for consistency with the memory operations); - // b8: 0 => b9–b11 are a direct count of bits to shift; 1 => b9–b11 identify a register containing the shift count; + // b8: 0 => b9–b11 are a direct count of bits to shift; + // 1 => b9–b11 identify register containing the shift count; // b9–b11: either a quick value or a register. // case OpT(Operation::ASRb): case OpT(Operation::ASRw): case OpT(Operation::ASRl): @@ -1851,10 +1852,12 @@ constexpr Preinstruction Predecoder::decodeE(const uint16_t instruction) case 0xac0: DecodeReq(model >= Model::M68020, Op::BFCHG); // 4-33 (p137) case 0xbc0: DecodeReq(model >= Model::M68020, Op::BFEXTS); // 4-37 (p141) case 0xcc0: DecodeReq(model >= Model::M68020, Op::BFCLR); // 4-35 (p139) - case 0xdc0: DecodeReq(model >= Model::M68020, Op::BFFFO); // 4-43 (p147) [though the given opcode is wrong; listed same as BFEXTU] + case 0xdc0: DecodeReq(model >= Model::M68020, Op::BFFFO); // 4-43 (p147)* case 0xec0: DecodeReq(model >= Model::M68020, Op::BFSET); // 4-49 (p153) case 0xfc0: DecodeReq(model >= Model::M68020, Op::BFINS); // 4-46 (p150) + // * [though the given opcode is wrong; listed same as BFEXTU] + default: break; } diff --git a/InstructionSets/M68k/Implementation/ExecutorImplementation.hpp b/InstructionSets/M68k/Implementation/ExecutorImplementation.hpp index 4696ab6b8..4ca9dd2e5 100644 --- a/InstructionSets/M68k/Implementation/ExecutorImplementation.hpp +++ b/InstructionSets/M68k/Implementation/ExecutorImplementation.hpp @@ -266,7 +266,11 @@ uint32_t Executor::State::index_8bitdisplacement(uint32_t bas template typename Executor::State::EffectiveAddress -Executor::State::calculate_effective_address(const Preinstruction instruction, const uint16_t opcode, const int index) { +Executor::State::calculate_effective_address( + const Preinstruction instruction, + const uint16_t opcode, + const int index +) { EffectiveAddress ea; switch(instruction.mode(index)) { @@ -531,7 +535,11 @@ template void Executor::State::complete_bcc(c } template -void Executor::State::complete_dbcc(const bool matched_condition, const bool overflowed, const int16_t offset) { +void Executor::State::complete_dbcc( + const bool matched_condition, + const bool overflowed, + const int16_t offset +) { if(!matched_condition && !overflowed) { program_counter.l = instruction_address + offset + 2; } @@ -622,7 +630,11 @@ void Executor::State::move_from_usp(uint32_t &address) { template template -void Executor::State::movep(const Preinstruction instruction, const uint32_t source, const uint32_t dest) { +void Executor::State::movep( + const Preinstruction instruction, + const uint32_t source, + const uint32_t dest +) { if(instruction.mode<0>() == AddressingMode::DataRegisterDirect) { // Move register to memory. const uint32_t reg = source; diff --git a/InstructionSets/M68k/Implementation/PerformImplementation.hpp b/InstructionSets/M68k/Implementation/PerformImplementation.hpp index 94000ecfa..cf597ff54 100644 --- a/InstructionSets/M68k/Implementation/PerformImplementation.hpp +++ b/InstructionSets/M68k/Implementation/PerformImplementation.hpp @@ -130,10 +130,18 @@ inline uint32_t mask_bit(const Preinstruction &instruction, const uint32_t sourc return source & (instruction.mode<1>() == AddressingMode::DataRegisterDirect ? 31 : 7); } -/// Perform a BCLR, BCHG or BSET as specified by @c operation and described by @c instruction, @c source and @c destination, updating @c destination and @c status. +/// Perform a BCLR, BCHG or BSET as specified by @c operation and described by @c instruction, @c source +/// and @c destination, updating @c destination and @c status. +/// /// Also makes an appropriate notification to the @c flow_controller. template -void bit_manipulate(const Preinstruction &instruction, const uint32_t source, uint32_t &destination, Status &status, FlowController &flow_controller) { +void bit_manipulate( + const Preinstruction &instruction, + const uint32_t source, + uint32_t &destination, + Status &status, + FlowController &flow_controller +) { static_assert( operation == Operation::BCLR || operation == Operation::BCHG || @@ -283,14 +291,18 @@ template void test(const IntT source, Status &status) { } /// Decodes the proper shift distance from @c source, notifying the @c flow_controller. -template int shift_count(const uint8_t source, FlowController &flow_controller) { +template int shift_count( + const uint8_t source, + FlowController &flow_controller +) { const int count = source & 63; flow_controller.template did_shift(count); return count; } /// Perform an arithmetic or logical shift, i.e. any of LSL, LSR, ASL or ASR. -template void shift(const uint32_t source, IntT &destination, Status &status, FlowController &flow_controller) { +template +void shift(const uint32_t source, IntT &destination, Status &status, FlowController &flow_controller) { static_assert( operation == Operation::ASLb || operation == Operation::ASLw || operation == Operation::ASLl || operation == Operation::ASRb || operation == Operation::ASRw || operation == Operation::ASRl || @@ -347,7 +359,9 @@ template void shif ); // e.g. shift = 1 => ~((0x80 >> 1) - 1) = ~(0x40 - 1) = ~0x3f = 0xc0, i.e. if shift is // 1 then the top two bits are relevant to whether there was overflow. If they have the // same value, i.e. are both 0 or are both 1, then there wasn't. Otherwise there was. - status.overflow_flag = (destination & affected_bits) && (destination & affected_bits) != affected_bits; + status.overflow_flag = + (destination & affected_bits) && + (destination & affected_bits) != affected_bits; } } @@ -384,7 +398,8 @@ template void shif } /// Perform a rotate without extend, i.e. any of RO[L/R].[b/w/l]. -template void rotate(const uint32_t source, IntT &destination, Status &status, FlowController &flow_controller) { +template +void rotate(const uint32_t source, IntT &destination, Status &status, FlowController &flow_controller) { static_assert( operation == Operation::ROLb || operation == Operation::ROLw || operation == Operation::ROLl || operation == Operation::RORb || operation == Operation::RORw || operation == Operation::RORl @@ -425,7 +440,8 @@ template void rota } /// Perform a rotate-through-extend, i.e. any of ROX[L/R].[b/w/l]. -template void rox(const uint32_t source, IntT &destination, Status &status, FlowController &flow_controller) { +template +void rox(const uint32_t source, IntT &destination, Status &status, FlowController &flow_controller) { static_assert( operation == Operation::ROXLb || operation == Operation::ROXLw || operation == Operation::ROXLl || operation == Operation::ROXRb || operation == Operation::ROXRw || operation == Operation::ROXRl @@ -496,8 +512,13 @@ template < Model model, typename FlowController, Operation operation = Operation::Undefined -> void perform(const Preinstruction instruction, CPU::SlicedInt32 &src, CPU::SlicedInt32 &dest, Status &status, FlowController &flow_controller) { - +> void perform( + const Preinstruction instruction, + CPU::SlicedInt32 &src, + CPU::SlicedInt32 &dest, + Status &status, + FlowController &flow_controller +) { switch((operation != Operation::Undefined) ? operation : instruction.operation) { /* ABCD adds the lowest bytes from the source and destination using BCD arithmetic, @@ -554,9 +575,15 @@ template < case Operation::BTST: status.zero_result = dest.l & (1 << Primitive::mask_bit(instruction, src.l)); break; - case Operation::BCLR: Primitive::bit_manipulate(instruction, src.l, dest.l, status, flow_controller); break; - case Operation::BCHG: Primitive::bit_manipulate(instruction, src.l, dest.l, status, flow_controller); break; - case Operation::BSET: Primitive::bit_manipulate(instruction, src.l, dest.l, status, flow_controller); break; + case Operation::BCLR: + Primitive::bit_manipulate(instruction, src.l, dest.l, status, flow_controller); + break; + case Operation::BCHG: + Primitive::bit_manipulate(instruction, src.l, dest.l, status, flow_controller); + break; + case Operation::BSET: + Primitive::bit_manipulate(instruction, src.l, dest.l, status, flow_controller); + break; case Operation::Bccb: flow_controller.template complete_bcc( @@ -703,12 +730,24 @@ template < status.set_neg_zero(src.l); break; - case Operation::ANDItoSR: Primitive::apply_sr_ccr(src.w, status, flow_controller); break; - case Operation::EORItoSR: Primitive::apply_sr_ccr(src.w, status, flow_controller); break; - case Operation::ORItoSR: Primitive::apply_sr_ccr(src.w, status, flow_controller); break; - case Operation::ANDItoCCR: Primitive::apply_sr_ccr(src.w, status, flow_controller); break; - case Operation::EORItoCCR: Primitive::apply_sr_ccr(src.w, status, flow_controller); break; - case Operation::ORItoCCR: Primitive::apply_sr_ccr(src.w, status, flow_controller); break; + case Operation::ANDItoSR: + Primitive::apply_sr_ccr(src.w, status, flow_controller); + break; + case Operation::EORItoSR: + Primitive::apply_sr_ccr(src.w, status, flow_controller); + break; + case Operation::ORItoSR: + Primitive::apply_sr_ccr(src.w, status, flow_controller); + break; + case Operation::ANDItoCCR: + Primitive::apply_sr_ccr(src.w, status, flow_controller); + break; + case Operation::EORItoCCR: + Primitive::apply_sr_ccr(src.w, status, flow_controller); + break; + case Operation::ORItoCCR: + Primitive::apply_sr_ccr(src.w, status, flow_controller); + break; /* Multiplications. @@ -721,8 +760,12 @@ template < Divisions. */ - case Operation::DIVUw: Primitive::divide(src.w, dest.l, status, flow_controller); break; - case Operation::DIVSw: Primitive::divide(src.w, dest.l, status, flow_controller); break; + case Operation::DIVUw: + Primitive::divide(src.w, dest.l, status, flow_controller); + break; + case Operation::DIVSw: + Primitive::divide(src.w, dest.l, status, flow_controller); + break; // TRAP, which is a nicer form of ILLEGAL. case Operation::TRAP: From 8b88d1294d2800359d07dbea319f24b7055aaa84 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 1 Dec 2024 09:04:32 -0500 Subject: [PATCH 3/4] Remove errant spaces. --- Components/8272/Results.hpp | 2 +- Components/8272/Status.hpp | 10 ++++---- InstructionSets/ARM/OperationMapper.hpp | 4 ++-- InstructionSets/ARM/Registers.hpp | 2 +- .../Implementation/PerformImplementation.hpp | 4 ++-- .../x86/Implementation/Resolver.hpp | 24 +++++++++---------- InstructionSets/x86/Instruction.cpp | 2 +- Machines/Acorn/Archimedes/Archimedes.cpp | 2 +- .../Archimedes/InputOutputController.hpp | 14 +++++------ .../Acorn/Archimedes/MemoryController.hpp | 4 ++-- Machines/Acorn/Archimedes/Video.hpp | 4 ++-- Machines/MSX/MSX.cpp | 4 ++-- Machines/PCCompatible/MDA.hpp | 2 +- Machines/PCCompatible/PCCompatible.cpp | 4 ++-- Machines/Sinclair/ZX8081/ZX8081.cpp | 2 +- Numeric/Carry.hpp | 8 +++---- .../6502/Implementation/6502Storage.hpp | 2 +- Reflection/Dispatcher.hpp | 8 +++---- 18 files changed, 51 insertions(+), 51 deletions(-) diff --git a/Components/8272/Results.hpp b/Components/8272/Results.hpp index 08477cd26..df81e903c 100644 --- a/Components/8272/Results.hpp +++ b/Components/8272/Results.hpp @@ -52,7 +52,7 @@ public: } /// @returns @c true if all result bytes are exhausted; @c false otherwise. - bool empty() const { return result_.empty(); } + bool empty() const { return result_.empty(); } /// @returns The next byte of the result. uint8_t next() { diff --git a/Components/8272/Status.hpp b/Components/8272/Status.hpp index 04990092e..61bf02ab3 100644 --- a/Components/8272/Status.hpp +++ b/Components/8272/Status.hpp @@ -38,7 +38,7 @@ enum class Status0: uint8_t { enum class Status1: uint8_t { EndOfCylinder = 0x80, - DataError = 0x20, + DataError = 0x20, OverRun = 0x10, NoData = 0x04, NotWriteable = 0x02, @@ -47,7 +47,7 @@ enum class Status1: uint8_t { enum class Status2: uint8_t { DeletedControlMark = 0x40, - DataCRCError = 0x20, + DataCRCError = 0x20, WrongCyinder = 0x10, ScanEqualHit = 0x08, ScanNotSatisfied = 0x04, @@ -57,7 +57,7 @@ enum class Status2: uint8_t { enum class Status3: uint8_t { Fault = 0x80, - WriteProtected = 0x40, + WriteProtected = 0x40, Ready = 0x20, Track0 = 0x10, TwoSided = 0x08, @@ -91,9 +91,9 @@ public: void set(const MainStatus flag, const bool value) { set(uint8_t(flag), value, main_status_); } - void start_seek(const int drive) { main_status_ |= 1 << drive; } + void start_seek(const int drive) { main_status_ |= 1 << drive; } void set(const Status0 flag) { set(uint8_t(flag), true, status_[0]); } - void set(const Status1 flag) { set(uint8_t(flag), true, status_[1]); } + void set(const Status1 flag) { set(uint8_t(flag), true, status_[1]); } void set(const Status2 flag) { set(uint8_t(flag), true, status_[2]); } void set_status0(uint8_t value) { status_[0] = value; } diff --git a/InstructionSets/ARM/OperationMapper.hpp b/InstructionSets/ARM/OperationMapper.hpp index 0e19e10fe..17a98ea99 100644 --- a/InstructionSets/ARM/OperationMapper.hpp +++ b/InstructionSets/ARM/OperationMapper.hpp @@ -323,7 +323,7 @@ struct CoprocessorDataOperation { constexpr CoprocessorDataOperation(const uint32_t opcode) noexcept : opcode_(opcode) {} uint32_t operand1() const { return (opcode_ >> 16) & 0xf; } - uint32_t operand2() const { return opcode_ & 0xf; } + uint32_t operand2() const { return opcode_ & 0xf; } uint32_t destination() const { return (opcode_ >> 12) & 0xf; } uint32_t coprocessor() const { return (opcode_ >> 8) & 0xf; } uint32_t information() const { return (opcode_ >> 5) & 0x7; } @@ -356,7 +356,7 @@ struct CoprocessorRegisterTransfer { constexpr CoprocessorRegisterTransfer(const uint32_t opcode) noexcept : opcode_(opcode) {} uint32_t operand1() const { return (opcode_ >> 16) & 0xf; } - uint32_t operand2() const { return opcode_ & 0xf; } + uint32_t operand2() const { return opcode_ & 0xf; } uint32_t destination() const { return (opcode_ >> 12) & 0xf; } uint32_t coprocessor() const { return (opcode_ >> 8) & 0xf; } uint32_t information() const { return (opcode_ >> 5) & 0x7; } diff --git a/InstructionSets/ARM/Registers.hpp b/InstructionSets/ARM/Registers.hpp index 71513293d..502b81f24 100644 --- a/InstructionSets/ARM/Registers.hpp +++ b/InstructionSets/ARM/Registers.hpp @@ -194,7 +194,7 @@ struct Registers { const auto r14 = pc_status(pc_offset_during(type)); switch(type) { case Exception::IRQ: set_mode(Mode::IRQ); break; - case Exception::FIQ: set_mode(Mode::FIQ); break; + case Exception::FIQ: set_mode(Mode::FIQ); break; default: set_mode(Mode::Supervisor); break; } active_[14] = r14; diff --git a/InstructionSets/x86/Implementation/PerformImplementation.hpp b/InstructionSets/x86/Implementation/PerformImplementation.hpp index 7d9e1c9de..a2dbb4a33 100644 --- a/InstructionSets/x86/Implementation/PerformImplementation.hpp +++ b/InstructionSets/x86/Implementation/PerformImplementation.hpp @@ -119,12 +119,12 @@ template < // The two following return the high and low parts of that pair; they also work in Byte mode to return AH:AL, // i.e. AX split into high and low parts. const auto pair_high = [&]() -> IntT& { - if constexpr (data_size == DataSize::Byte) return context.registers.ah(); + if constexpr (data_size == DataSize::Byte) return context.registers.ah(); else if constexpr (data_size == DataSize::Word) return context.registers.dx(); else if constexpr (data_size == DataSize::DWord) return context.registers.edx(); }; const auto pair_low = [&]() -> IntT& { - if constexpr (data_size == DataSize::Byte) return context.registers.al(); + if constexpr (data_size == DataSize::Byte) return context.registers.al(); else if constexpr (data_size == DataSize::Word) return context.registers.ax(); else if constexpr (data_size == DataSize::DWord) return context.registers.eax(); }; diff --git a/InstructionSets/x86/Implementation/Resolver.hpp b/InstructionSets/x86/Implementation/Resolver.hpp index 4d71a881c..6cf0ac315 100644 --- a/InstructionSets/x86/Implementation/Resolver.hpp +++ b/InstructionSets/x86/Implementation/Resolver.hpp @@ -68,42 +68,42 @@ IntT *register_(ContextT &context) { // // (i) does the `constexpr` version of a `switch`; and // (i) ensures .eax() etc aren't called on @c registers for 16-bit processors, so they need not implement 32-bit storage. - if constexpr (supports_dword && std::is_same_v) { return &context.registers.eax(); } + if constexpr (supports_dword && std::is_same_v) { return &context.registers.eax(); } else if constexpr (std::is_same_v) { return &context.registers.ax(); } else if constexpr (std::is_same_v) { return &context.registers.al(); } - else { return nullptr; } + else { return nullptr; } case Source::eCX: - if constexpr (supports_dword && std::is_same_v) { return &context.registers.ecx(); } + if constexpr (supports_dword && std::is_same_v) { return &context.registers.ecx(); } else if constexpr (std::is_same_v) { return &context.registers.cx(); } else if constexpr (std::is_same_v) { return &context.registers.cl(); } - else { return nullptr; } + else { return nullptr; } case Source::eDX: - if constexpr (supports_dword && std::is_same_v) { return &context.registers.edx(); } + if constexpr (supports_dword && std::is_same_v) { return &context.registers.edx(); } else if constexpr (std::is_same_v) { return &context.registers.dx(); } else if constexpr (std::is_same_v) { return &context.registers.dl(); } else if constexpr (std::is_same_v) { return nullptr; } case Source::eBX: - if constexpr (supports_dword && std::is_same_v) { return &context.registers.ebx(); } + if constexpr (supports_dword && std::is_same_v) { return &context.registers.ebx(); } else if constexpr (std::is_same_v) { return &context.registers.bx(); } else if constexpr (std::is_same_v) { return &context.registers.bl(); } else if constexpr (std::is_same_v) { return nullptr; } case Source::eSPorAH: - if constexpr (supports_dword && std::is_same_v) { return &context.registers.esp(); } + if constexpr (supports_dword && std::is_same_v) { return &context.registers.esp(); } else if constexpr (std::is_same_v) { return &context.registers.sp(); } else if constexpr (std::is_same_v) { return &context.registers.ah(); } else { return nullptr; } case Source::eBPorCH: - if constexpr (supports_dword && std::is_same_v) { return &context.registers.ebp(); } + if constexpr (supports_dword && std::is_same_v) { return &context.registers.ebp(); } else if constexpr (std::is_same_v) { return &context.registers.bp(); } else if constexpr (std::is_same_v) { return &context.registers.ch(); } - else { return nullptr; } + else { return nullptr; } case Source::eSIorDH: - if constexpr (supports_dword && std::is_same_v) { return &context.registers.esi(); } + if constexpr (supports_dword && std::is_same_v) { return &context.registers.esi(); } else if constexpr (std::is_same_v) { return &context.registers.si(); } else if constexpr (std::is_same_v) { return &context.registers.dh(); } - else { return nullptr; } + else { return nullptr; } case Source::eDIorBH: - if constexpr (supports_dword && std::is_same_v) { return &context.registers.edi(); } + if constexpr (supports_dword && std::is_same_v) { return &context.registers.edi(); } else if constexpr (std::is_same_v) { return &context.registers.di(); } else if constexpr (std::is_same_v) { return &context.registers.bh(); } else { return nullptr; } diff --git a/InstructionSets/x86/Instruction.cpp b/InstructionSets/x86/Instruction.cpp index edcf2b738..afb7e2d77 100644 --- a/InstructionSets/x86/Instruction.cpp +++ b/InstructionSets/x86/Instruction.cpp @@ -487,7 +487,7 @@ std::string InstructionSet::x86::to_string( case Operation::OUTS: case Operation::OUTS_REP: switch(instruction.second.data_segment()) { - default: break; + default: break; case Source::ES: operation += "es "; break; case Source::CS: operation += "cs "; break; case Source::DS: operation += "ds "; break; diff --git a/Machines/Acorn/Archimedes/Archimedes.cpp b/Machines/Acorn/Archimedes/Archimedes.cpp index e87b203dd..405e5c7cb 100644 --- a/Machines/Acorn/Archimedes/Archimedes.cpp +++ b/Machines/Acorn/Archimedes/Archimedes.cpp @@ -69,7 +69,7 @@ class ConcreteMachine: // This is a 24-cycle window, so at 24Mhz macro_tick() is called at 1Mhz. // Hence, required ticks are: // - // * CPU: 24; + // * CPU: 24; // * video: 24 / video_divider; // * floppy: 8; // * timers: 2; diff --git a/Machines/Acorn/Archimedes/InputOutputController.hpp b/Machines/Acorn/Archimedes/InputOutputController.hpp index 11fd2e6f4..4480aafad 100644 --- a/Machines/Acorn/Archimedes/InputOutputController.hpp +++ b/Machines/Acorn/Archimedes/InputOutputController.hpp @@ -165,7 +165,7 @@ struct InputOutputController: public ClockingHint::Observer { // // fast/1 = FDC // sync/2 = econet - // sync/3 = serial line + // sync/3 = serial line // // bank 4 = podules // @@ -410,7 +410,7 @@ struct InputOutputController: public ClockingHint::Observer { // b0: ? // b1: double/single density; 0 = double. // b2: ? - // b3: floppy drive reset; 0 = reset. + // b3: floppy drive reset; 0 = reset. // b4: printer strobe // b5: ? // b6: ? @@ -474,12 +474,12 @@ struct InputOutputController: public ClockingHint::Observer { return true; } - auto &sound() { return sound_; } + auto &sound() { return sound_; } const auto &sound() const { return sound_; } - auto &video() { return video_; } - const auto &video() const { return video_; } - auto &keyboard() { return keyboard_; } - const auto &keyboard() const { return keyboard_; } + auto &video() { return video_; } + const auto &video() const { return video_; } + auto &keyboard() { return keyboard_; } + const auto &keyboard() const { return keyboard_; } void update_interrupts() { const auto set = [&](Interrupt &target, uint8_t flag, bool set) { diff --git a/Machines/Acorn/Archimedes/MemoryController.hpp b/Machines/Acorn/Archimedes/MemoryController.hpp index 162a95b10..e100a87db 100644 --- a/Machines/Acorn/Archimedes/MemoryController.hpp +++ b/Machines/Acorn/Archimedes/MemoryController.hpp @@ -225,8 +225,8 @@ struct MemoryController { return ioc_.sound().speaker(); } - auto &sound() { return ioc_.sound(); } - const auto &sound() const { return ioc_.sound(); } + auto &sound() { return ioc_.sound(); } + const auto &sound() const { return ioc_.sound(); } auto &video() { return ioc_.video(); } const auto &video() const { return ioc_.video(); } auto &keyboard() { return ioc_.keyboard(); } diff --git a/Machines/Acorn/Archimedes/Video.hpp b/Machines/Acorn/Archimedes/Video.hpp index 78e5bef0d..ee6a372a4 100644 --- a/Machines/Acorn/Archimedes/Video.hpp +++ b/Machines/Acorn/Archimedes/Video.hpp @@ -225,7 +225,7 @@ struct Video { return vertical_state_.phase() != Phase::Display; } - void set_frame_start(uint32_t address) { + void set_frame_start(uint32_t address) { frame_start_ = address; ++frame_start_sets_; } @@ -233,7 +233,7 @@ struct Video { void set_buffer_end(uint32_t address) { buffer_end_ = address; } void set_cursor_start(uint32_t address) { cursor_start_ = address; } - Outputs::CRT::CRT &crt() { return crt_; } + Outputs::CRT::CRT &crt() { return crt_; } const Outputs::CRT::CRT &crt() const { return crt_; } int clock_divider() const { diff --git a/Machines/MSX/MSX.cpp b/Machines/MSX/MSX.cpp index 66dae2aa4..d53a3db17 100644 --- a/Machines/MSX/MSX.cpp +++ b/Machines/MSX/MSX.cpp @@ -1039,13 +1039,13 @@ std::unique_ptr Machine::MSX(const Analyser::Static::Target *target, co const auto msx_target = dynamic_cast(target); if(msx_target->has_msx_music) { switch(msx_target->model) { - default: return nullptr; + default: return nullptr; case Target::Model::MSX1: return std::make_unique>(*msx_target, rom_fetcher); case Target::Model::MSX2: return std::make_unique>(*msx_target, rom_fetcher); } } else { switch(msx_target->model) { - default: return nullptr; + default: return nullptr; case Target::Model::MSX1: return std::make_unique>(*msx_target, rom_fetcher); case Target::Model::MSX2: return std::make_unique>(*msx_target, rom_fetcher); } diff --git a/Machines/PCCompatible/MDA.hpp b/Machines/PCCompatible/MDA.hpp index dc0a79c42..3f1c0b378 100644 --- a/Machines/PCCompatible/MDA.hpp +++ b/Machines/PCCompatible/MDA.hpp @@ -116,7 +116,7 @@ class MDA { if(count) { switch(output_state) { case OutputState::Sync: crt.output_sync(count); break; - case OutputState::Border: crt.output_blank(count); break; + case OutputState::Border: crt.output_blank(count); break; case OutputState::Pixels: crt.output_data(count); pixels = pixel_pointer = nullptr; diff --git a/Machines/PCCompatible/PCCompatible.cpp b/Machines/PCCompatible/PCCompatible.cpp index c0f17eb3f..bef5fc256 100644 --- a/Machines/PCCompatible/PCCompatible.cpp +++ b/Machines/PCCompatible/PCCompatible.cpp @@ -362,7 +362,7 @@ class KeyboardController { const auto last_mode = mode_; mode_ = Mode(mode); switch(mode_) { - case Mode::NormalOperation: break; + case Mode::NormalOperation: break; case Mode::NoIRQsIgnoreInput: pic_.apply_edge<1>(false); break; @@ -932,7 +932,7 @@ class ConcreteMachine: void run_for(const Cycles duration) override { switch(speed_) { case Target::Speed::ApproximatelyOriginal: run_for(duration); break; - case Target::Speed::Fast: run_for(duration); break; + case Target::Speed::Fast: run_for(duration); break; } } diff --git a/Machines/Sinclair/ZX8081/ZX8081.cpp b/Machines/Sinclair/ZX8081/ZX8081.cpp index 1186c20b7..7ae99729d 100644 --- a/Machines/Sinclair/ZX8081/ZX8081.cpp +++ b/Machines/Sinclair/ZX8081/ZX8081.cpp @@ -39,7 +39,7 @@ namespace { // TODO: // Quiksilva sound support: -// 7FFFh.W PSG index +// 7FFFh.W PSG index // 7FFEh.R/W PSG data namespace Sinclair { diff --git a/Numeric/Carry.hpp b/Numeric/Carry.hpp index 52453537f..0cae0061f 100644 --- a/Numeric/Carry.hpp +++ b/Numeric/Carry.hpp @@ -13,8 +13,8 @@ namespace Numeric { /// @returns @c true if from @c bit there was: -/// • carry after calculating @c lhs + @c rhs if @c is_add is true; or -/// • borrow after calculating @c lhs - @c rhs if @c is_add is false; +/// • carry after calculating @c lhs + @c rhs if @c is_add is true; or +/// • borrow after calculating @c lhs - @c rhs if @c is_add is false; /// producing @c result. template bool carried_out(IntT lhs, IntT rhs, IntT result) { // Additive: @@ -40,8 +40,8 @@ template bool carried_out(IntT lhs, IntT r } /// @returns @c true if there was carry into @c bit when computing either: -/// • @c lhs + @c rhs; or -/// • @c lhs - @c rhs; +/// • @c lhs + @c rhs; or +/// • @c lhs - @c rhs; /// producing @c result. template bool carried_in(IntT lhs, IntT rhs, IntT result) { // 0 and 0 or 1 and 1 => did if 1. diff --git a/Processors/6502/Implementation/6502Storage.hpp b/Processors/6502/Implementation/6502Storage.hpp index 6d7a163fb..9fe4f6b74 100644 --- a/Processors/6502/Implementation/6502Storage.hpp +++ b/Processors/6502/Implementation/6502Storage.hpp @@ -188,7 +188,7 @@ class ProcessorStorage { CycleAddSignedOperandToPC, // sets next_address to PC + (signed)operand. If the high byte of next_address differs from the PC, schedules a throwaway read from the half-updated PC. 65C02 specific: if the top two bytes are the same, proceeds directly to fetch-decode-execute, ignoring any pending interrupts. OperationAddSignedOperandToPC16, // adds (signed)operand into the PC, leaving old PC in next_address_ and skipping a program step if there was no carry from low to high byte - CycleFetchFromNextAddress, // performs a throwaway fetch from next_address_ + CycleFetchFromNextAddress, // performs a throwaway fetch from next_address_ OperationSetFlagsFromOperand, // sets all flags based on operand_ OperationSetOperandFromFlagsWithBRKSet, // sets operand_ to the value of all flags, with the break flag set diff --git a/Reflection/Dispatcher.hpp b/Reflection/Dispatcher.hpp index 8a59c0547..8830acef8 100644 --- a/Reflection/Dispatcher.hpp +++ b/Reflection/Dispatcher.hpp @@ -56,10 +56,10 @@ static constexpr int switch_max = 2048; /// Provides glue for a run of calls like: /// -/// SequencerT.perform<0>(...) -/// SequencerT.perform<1>(...) -/// SequencerT.perform<2>(...) -/// ...etc... +/// SequencerT.perform<0>(...) +/// SequencerT.perform<1>(...) +/// SequencerT.perform<2>(...) +/// ...etc... /// /// Allowing the caller to execute any subrange of the calls. template From 3a0f4a0bfce69a51d712e6df90340aed03997b81 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 1 Dec 2024 17:51:20 -0500 Subject: [PATCH 4/4] Improve `const`ness, formatting. --- Analyser/Static/AppleII/Target.hpp | 2 +- Components/6845/CRTC6845.hpp | 2 +- InstructionSets/M50740/Decoder.cpp | 4 +- InstructionSets/M50740/Decoder.hpp | 24 +- InstructionSets/M50740/Executor.cpp | 22 +- InstructionSets/M50740/Executor.hpp | 223 +++++----- InstructionSets/M50740/Instruction.hpp | 23 +- InstructionSets/M50740/Parser.hpp | 7 +- InstructionSets/PowerPC/Decoder.cpp | 71 +-- InstructionSets/PowerPC/Decoder.hpp | 8 +- InstructionSets/PowerPC/Instruction.hpp | 5 +- InstructionSets/x86/AccessType.hpp | 16 +- InstructionSets/x86/Decoder.cpp | 7 +- InstructionSets/x86/Decoder.hpp | 334 +++++++-------- InstructionSets/x86/Flags.hpp | 258 +++++------ .../x86/Implementation/Arithmetic.hpp | 15 +- InstructionSets/x86/Implementation/BCD.hpp | 4 +- .../x86/Implementation/FlowControl.hpp | 60 ++- InstructionSets/x86/Implementation/InOut.hpp | 4 +- .../x86/Implementation/Logical.hpp | 2 +- .../Implementation/PerformImplementation.hpp | 22 +- .../x86/Implementation/Resolver.hpp | 19 +- .../x86/Implementation/ShiftRoll.hpp | 14 +- InstructionSets/x86/Instruction.hpp | 405 +++++++++--------- InstructionSets/x86/Model.hpp | 2 +- Machines/Acorn/Electron/Keyboard.hpp | 2 +- Machines/Apple/AppleII/VideoSwitches.hpp | 4 +- Machines/Apple/AppleIIgs/Video.hpp | 4 +- Outputs/Log.hpp | 54 +-- Outputs/ScanTarget.hpp | 2 +- Processors/6502/6502.hpp | 8 +- Processors/6502Esque/6502Selector.hpp | 4 +- Processors/Z80/Implementation/Z80Storage.hpp | 2 +- Storage/Disk/Encodings/MFM/Constants.hpp | 2 +- 34 files changed, 857 insertions(+), 778 deletions(-) diff --git a/Analyser/Static/AppleII/Target.hpp b/Analyser/Static/AppleII/Target.hpp index f08bf1f68..fd3cb6892 100644 --- a/Analyser/Static/AppleII/Target.hpp +++ b/Analyser/Static/AppleII/Target.hpp @@ -50,7 +50,7 @@ struct Target: public Analyser::Static::Target, public Reflection::StructImpl= Personality::EGA; } diff --git a/InstructionSets/M50740/Decoder.cpp b/InstructionSets/M50740/Decoder.cpp index b19b53f79..5a2acdba7 100644 --- a/InstructionSets/M50740/Decoder.cpp +++ b/InstructionSets/M50740/Decoder.cpp @@ -13,7 +13,7 @@ namespace InstructionSet { namespace M50740 { -Instruction Decoder::instrucion_for_opcode(uint8_t opcode) { +Instruction Decoder::instrucion_for_opcode(const uint8_t opcode) { switch(opcode) { default: return Instruction(opcode); @@ -231,7 +231,7 @@ Instruction Decoder::instrucion_for_opcode(uint8_t opcode) { } } -std::pair Decoder::decode(const uint8_t *source, size_t length) { +std::pair Decoder::decode(const uint8_t *source, const size_t length) { const uint8_t *const end = source + length; if(phase_ == Phase::Instruction && source != end) { diff --git a/InstructionSets/M50740/Decoder.hpp b/InstructionSets/M50740/Decoder.hpp index b744cd63e..18d32baa7 100644 --- a/InstructionSets/M50740/Decoder.hpp +++ b/InstructionSets/M50740/Decoder.hpp @@ -16,19 +16,19 @@ namespace InstructionSet::M50740 { class Decoder { - public: - std::pair decode(const uint8_t *source, size_t length); - Instruction instrucion_for_opcode(uint8_t opcode); +public: + std::pair decode(const uint8_t *, size_t length); + Instruction instrucion_for_opcode(uint8_t); - private: - enum class Phase { - Instruction, - AwaitingOperand, - ReadyToPost - } phase_ = Phase::Instruction; - int operand_size_ = 0, operand_bytes_ = 0; - int consumed_ = 0; - Instruction instr_; +private: + enum class Phase { + Instruction, + AwaitingOperand, + ReadyToPost + } phase_ = Phase::Instruction; + int operand_size_ = 0, operand_bytes_ = 0; + int consumed_ = 0; + Instruction instr_; }; } diff --git a/InstructionSets/M50740/Executor.cpp b/InstructionSets/M50740/Executor.cpp index ee3bbff33..85e3ccfdb 100644 --- a/InstructionSets/M50740/Executor.cpp +++ b/InstructionSets/M50740/Executor.cpp @@ -49,7 +49,7 @@ void Executor::set_rom(const std::vector &rom) { reset(); } -void Executor::run_for(Cycles cycles) { +void Executor::run_for(const Cycles cycles) { // The incoming clock is divided by four; the local cycles_ count // ensures that fractional parts are kept track of. cycles_ += cycles; @@ -61,7 +61,7 @@ void Executor::reset() { set_program_counter(uint16_t(memory_[0x1ffe] | (memory_[0x1fff] << 8))); } -void Executor::set_interrupt_line(bool line) { +void Executor::set_interrupt_line(const bool line) { // Super hack: interrupt now, if permitted. Otherwise do nothing. // So this will fail to catch enabling of interrupts while the line // is active, amongst other things. @@ -117,12 +117,12 @@ uint8_t Executor::read(uint16_t address) { } } -void Executor::set_port_output(int port) { +void Executor::set_port_output(const int port) { // Force 'output' to a 1 anywhere that a bit is set as input. port_handler_.set_port_output(port, port_outputs_[port] | ~port_directions_[port]); } -void Executor::write(uint16_t address, uint8_t value) { +void Executor::write(uint16_t address, const uint8_t value) { address &= 0x1fff; // RAM writes are easy. @@ -182,7 +182,7 @@ void Executor::write(uint16_t address, uint8_t value) { } } -void Executor::push(uint8_t value) { +void Executor::push(const uint8_t value) { write(s_, value); --s_; } @@ -192,7 +192,7 @@ uint8_t Executor::pull() { return read(s_); } -void Executor::set_flags(uint8_t flags) { +void Executor::set_flags(const uint8_t flags) { negative_result_ = flags; overflow_result_ = uint8_t(flags << 1); index_mode_ = flags & 0x20; @@ -213,7 +213,7 @@ uint8_t Executor::flags() { carry_flag_; } -template inline void Executor::perform_interrupt(uint16_t vector) { +template inline void Executor::perform_interrupt(const uint16_t vector) { // BRK has an unused operand. ++program_counter_; push(uint8_t(program_counter_ >> 8)); @@ -222,7 +222,7 @@ template inline void Executor::perform_interrupt(uint16_t vector) { set_program_counter(uint16_t(memory_[vector] | (memory_[vector+1] << 8))); } -void Executor::set_interrupt_request(uint8_t ®, uint8_t value, uint16_t vector) { +void Executor::set_interrupt_request(uint8_t ®, const uint8_t value, const uint16_t vector) { // TODO: this allows interrupts through only if fully enabled at the time they // signal. Which isn't quite correct, albeit that it seems sufficient for the // IIgs ADB controller. @@ -797,7 +797,7 @@ template void Executor::perform(uint8_t *operand [[maybe_u } } -inline void Executor::subtract_duration(int duration) { +inline void Executor::subtract_duration(const int duration) { // Pass along. CachingExecutor::subtract_duration(duration); @@ -846,7 +846,7 @@ inline void Executor::subtract_duration(int duration) { } } -inline int Executor::update_timer(Timer &timer, int count) { +inline int Executor::update_timer(Timer &timer, const int count) { const int next_value = timer.value - count; if(next_value < 0) { // Determine how many reloads were required to get above zero. @@ -859,6 +859,6 @@ inline int Executor::update_timer(Timer &timer, int count) { return 0; } -uint8_t Executor::get_output_mask(int port) { +uint8_t Executor::get_output_mask(const int port) { return port_directions_[port]; } diff --git a/InstructionSets/M50740/Executor.hpp b/InstructionSets/M50740/Executor.hpp index 88d1edf00..e097cbbcf 100644 --- a/InstructionSets/M50740/Executor.hpp +++ b/InstructionSets/M50740/Executor.hpp @@ -35,143 +35,142 @@ struct PortHandler { * timing is correct to whole-opcode boundaries only. */ class Executor: public CachingExecutor { - public: - Executor(PortHandler &); - void set_rom(const std::vector &rom); +public: + Executor(PortHandler &); + void set_rom(const std::vector &rom); - void reset(); - void set_interrupt_line(bool); + void reset(); + void set_interrupt_line(bool); - uint8_t get_output_mask(int port); + uint8_t get_output_mask(int port); - /*! - Runs, in discrete steps, the minimum number of instructions as it takes to complete at least @c cycles. - */ - void run_for(Cycles cycles); + /*! + Runs, in discrete steps, the minimum number of instructions as it takes to complete at least @c cycles. + */ + void run_for(Cycles); - private: - // MARK: - CachingExecutor-facing interface. +private: + // MARK: - CachingExecutor-facing interface. - friend CachingExecutor; + friend CachingExecutor; - /*! - Maps instructions to performers; called by the CachingExecutor and for this instruction set, extremely trivial. - */ - inline PerformerIndex action_for(Instruction instruction) { - // This is a super-simple processor, so the opcode can be used directly to index the performers. - return instruction.opcode; - } + /*! + Maps instructions to performers; called by the CachingExecutor and for this instruction set, extremely trivial. + */ + inline PerformerIndex action_for(const Instruction instruction) { + // This is a super-simple processor, so the opcode can be used directly to index the performers. + return instruction.opcode; + } - /*! - Parses from @c start and no later than @c max_address, using the CachingExecutor as a target. - */ - inline void parse(uint16_t start, uint16_t closing_bound) { - Parser parser; - parser.parse(*this, &memory_[0], start & 0x1fff, closing_bound); - } + /*! + Parses from @c start and no later than @c max_address, using the CachingExecutor as a target. + */ + inline void parse(const uint16_t start, const uint16_t closing_bound) { + Parser parser; + parser.parse(*this, &memory_[0], start & 0x1fff, closing_bound); + } - private: - // MARK: - Internal framework for generator performers. + // MARK: - Internal framework for generator performers. - /*! - Provides dynamic lookup of @c perform(Executor*). - */ - class PerformerLookup { - public: - PerformerLookup() { - fill(performers_); + /*! + Provides dynamic lookup of @c perform(Executor*). + */ + class PerformerLookup { + public: + PerformerLookup() { + fill(performers_); + } + + Performer performer(const Operation operation, const AddressingMode addressing_mode) { + const auto index = + (int(operation) - MinOperation) * (1 + MaxAddressingMode - MinAddressingMode) + + (int(addressing_mode) - MinAddressingMode); + return performers_[index]; + } + + private: + Performer performers_[(1 + MaxAddressingMode - MinAddressingMode) * (1 + MaxOperation - MinOperation)]; + + template void fill_operation(Performer *target) { + *target = &Executor::perform; + + if constexpr (addressing_mode+1 <= MaxAddressingMode) { + fill_operation(target + 1); } + } - Performer performer(Operation operation, AddressingMode addressing_mode) { - const auto index = - (int(operation) - MinOperation) * (1 + MaxAddressingMode - MinAddressingMode) + - (int(addressing_mode) - MinAddressingMode); - return performers_[index]; + template void fill(Performer *target) { + fill_operation(target); + target += 1 + MaxAddressingMode - MinAddressingMode; + + if constexpr (operation+1 <= MaxOperation) { + fill(target); } + } + }; + inline static PerformerLookup performer_lookup_; - private: - Performer performers_[(1 + MaxAddressingMode - MinAddressingMode) * (1 + MaxOperation - MinOperation)]; + /*! + Performs @c operation using @c operand as the value fetched from memory, if any. + */ + template void perform(uint8_t *operand); - template void fill_operation(Performer *target) { - *target = &Executor::perform; + /*! + Performs @c operation in @c addressing_mode. + */ + template void perform(); - if constexpr (addressing_mode+1 <= MaxAddressingMode) { - fill_operation(target + 1); - } - } +private: + // MARK: - Instruction set state. - template void fill(Performer *target) { - fill_operation(target); - target += 1 + MaxAddressingMode - MinAddressingMode; + // Memory. + std::array memory_; - if constexpr (operation+1 <= MaxOperation) { - fill(target); - } - } - }; - inline static PerformerLookup performer_lookup_; + // Registers. + uint8_t a_ = 0, x_ = 0, y_ = 0, s_ = 0; - /*! - Performs @c operation using @c operand as the value fetched from memory, if any. - */ - template void perform(uint8_t *operand); + uint8_t negative_result_ = 0; + uint8_t zero_result_ = 0; + uint8_t interrupt_disable_ = 0x04; + uint8_t carry_flag_ = 0; + uint8_t overflow_result_ = 0; + bool index_mode_ = false; + bool decimal_mode_ = false; - /*! - Performs @c operation in @c addressing_mode. - */ - template void perform(); + // IO ports. + uint8_t port_directions_[4] = {0x00, 0x00, 0x00, 0x00}; + uint8_t port_outputs_[4] = {0xff, 0xff, 0xff, 0xff}; - private: - // MARK: - Instruction set state. + // Timers. + struct Timer { + uint8_t value = 0xff, reload_value = 0xff; + }; + int timer_divider_ = 0; + Timer timers_[3], prescalers_[2]; + inline int update_timer(Timer &timer, int count); - // Memory. - std::array memory_; + // Interrupt and timer control. + uint8_t interrupt_control_ = 0, timer_control_ = 0; + bool interrupt_line_ = false; - // Registers. - uint8_t a_ = 0, x_ = 0, y_ = 0, s_ = 0; + // Access helpers. + inline uint8_t read(uint16_t address); + inline void write(uint16_t address, uint8_t value); + inline void push(uint8_t); + inline uint8_t pull(); + inline void set_flags(uint8_t); + inline uint8_t flags(); + template inline void perform_interrupt(uint16_t vector); + inline void set_port_output(int port); - uint8_t negative_result_ = 0; - uint8_t zero_result_ = 0; - uint8_t interrupt_disable_ = 0x04; - uint8_t carry_flag_ = 0; - uint8_t overflow_result_ = 0; - bool index_mode_ = false; - bool decimal_mode_ = false; + void set_interrupt_request(uint8_t ®, uint8_t value, uint16_t vector); - // IO ports. - uint8_t port_directions_[4] = {0x00, 0x00, 0x00, 0x00}; - uint8_t port_outputs_[4] = {0xff, 0xff, 0xff, 0xff}; + // MARK: - Execution time - // Timers. - struct Timer { - uint8_t value = 0xff, reload_value = 0xff; - }; - int timer_divider_ = 0; - Timer timers_[3], prescalers_[2]; - inline int update_timer(Timer &timer, int count); - - // Interrupt and timer control. - uint8_t interrupt_control_ = 0, timer_control_ = 0; - bool interrupt_line_ = false; - - // Access helpers. - inline uint8_t read(uint16_t address); - inline void write(uint16_t address, uint8_t value); - inline void push(uint8_t value); - inline uint8_t pull(); - inline void set_flags(uint8_t); - inline uint8_t flags(); - template inline void perform_interrupt(uint16_t vector); - inline void set_port_output(int port); - - void set_interrupt_request(uint8_t ®, uint8_t value, uint16_t vector); - - // MARK: - Execution time - - Cycles cycles_; - Cycles cycles_since_port_handler_; - PortHandler &port_handler_; - inline void subtract_duration(int duration); + Cycles cycles_; + Cycles cycles_since_port_handler_; + PortHandler &port_handler_; + inline void subtract_duration(int); }; } diff --git a/InstructionSets/M50740/Instruction.hpp b/InstructionSets/M50740/Instruction.hpp index 2b7d3138e..5bfbe82e6 100644 --- a/InstructionSets/M50740/Instruction.hpp +++ b/InstructionSets/M50740/Instruction.hpp @@ -31,7 +31,7 @@ enum class AddressingMode { static constexpr auto MaxAddressingMode = int(AddressingMode::ZeroPageRelative); static constexpr auto MinAddressingMode = int(AddressingMode::Implied); -constexpr int size(AddressingMode mode) { +constexpr int size(const AddressingMode mode) { // This is coupled to the AddressingMode list above; be careful! constexpr int sizes[] = { 0, 0, 1, @@ -92,14 +92,14 @@ enum class Operation: uint8_t { static constexpr auto MaxOperation = int(Operation::STY); static constexpr auto MinOperation = int(Operation::BBC0); -constexpr AccessType access_type(Operation operation) { +constexpr AccessType access_type(const Operation operation) { if(operation < Operation::ADC) return AccessType::None; if(operation < Operation::ASL) return AccessType::Read; if(operation < Operation::LDM) return AccessType::ReadModifyWrite; return AccessType::Write; } -constexpr bool uses_index_mode(Operation operation) { +constexpr bool uses_index_mode(const Operation operation) { return operation == Operation::ADC || operation == Operation::AND || operation == Operation::CMP || operation == Operation::EOR || @@ -110,7 +110,7 @@ constexpr bool uses_index_mode(Operation operation) { /*! @returns The name of @c operation. */ -inline constexpr const char *operation_name(Operation operation) { +inline constexpr const char *operation_name(const Operation operation) { #define MAP(x) case Operation::x: return #x; switch(operation) { default: break; @@ -133,7 +133,7 @@ inline constexpr const char *operation_name(Operation operation) { return "???"; } -inline std::ostream &operator <<(std::ostream &stream, Operation operation) { +inline std::ostream &operator <<(std::ostream &stream, const Operation operation) { stream << operation_name(operation); return stream; } @@ -141,7 +141,7 @@ inline std::ostream &operator <<(std::ostream &stream, Operation operation) { /*! @returns The name of @c addressing_mode. */ -inline constexpr const char *addressing_mode_name(AddressingMode addressing_mode) { +inline constexpr const char *addressing_mode_name(const AddressingMode addressing_mode) { switch(addressing_mode) { default: break; case AddressingMode::Implied: return ""; @@ -167,7 +167,7 @@ inline constexpr const char *addressing_mode_name(AddressingMode addressing_mode return "???"; } -inline std::ostream &operator <<(std::ostream &stream, AddressingMode mode) { +inline std::ostream &operator <<(std::ostream &stream, const AddressingMode mode) { stream << addressing_mode_name(mode); return stream; } @@ -177,7 +177,11 @@ inline std::ostream &operator <<(std::ostream &stream, AddressingMode mode) { would appear in an assembler. E.g. '$5a' for that zero page address, or '$5a, x' for zero-page indexed from $5a. This function may access up to three bytes from @c operation onwards. */ -inline std::string address(AddressingMode addressing_mode, const uint8_t *operation, uint16_t program_counter) { +inline std::string address( + const AddressingMode addressing_mode, + const uint8_t *operation, + const uint16_t program_counter +) { std::stringstream output; output << std::hex; @@ -220,7 +224,8 @@ struct Instruction { AddressingMode addressing_mode = AddressingMode::Implied; uint8_t opcode = 0; - Instruction(Operation operation, AddressingMode addressing_mode, uint8_t opcode) : operation(operation), addressing_mode(addressing_mode), opcode(opcode) {} + Instruction(const Operation operation, const AddressingMode addressing_mode, const uint8_t opcode) : + operation(operation), addressing_mode(addressing_mode), opcode(opcode) {} Instruction(uint8_t opcode) : opcode(opcode) {} Instruction() = default; }; diff --git a/InstructionSets/M50740/Parser.hpp b/InstructionSets/M50740/Parser.hpp index e9350b6eb..d1955a52f 100644 --- a/InstructionSets/M50740/Parser.hpp +++ b/InstructionSets/M50740/Parser.hpp @@ -15,7 +15,7 @@ namespace InstructionSet::M50740 { template struct Parser { - void parse(Target &target, const uint8_t *storage, uint16_t start, uint16_t closing_bound) { + void parse(Target &target, const uint8_t *storage, uint16_t start, const uint16_t closing_bound) { Decoder decoder; while(start <= closing_bound) { @@ -97,7 +97,10 @@ template struct Parser { // Provide any fixed address accesses. switch(next.second.addressing_mode) { case AddressingMode::Absolute: - target.add_access(uint16_t(storage[start + 1] | (storage[start + 2] << 8)), access_type(next.second.operation)); + target.add_access( + uint16_t(storage[start + 1] | (storage[start + 2] << 8)), + access_type(next.second.operation) + ); break; case AddressingMode::ZeroPage: case AddressingMode::ZeroPageRelative: target.add_access(storage[start + 1], access_type(next.second.operation)); diff --git a/InstructionSets/PowerPC/Decoder.cpp b/InstructionSets/PowerPC/Decoder.cpp index 3c0c1796e..17a5519df 100644 --- a/InstructionSets/PowerPC/Decoder.cpp +++ b/InstructionSets/PowerPC/Decoder.cpp @@ -12,7 +12,8 @@ using namespace InstructionSet::PowerPC; namespace { -template Instruction instruction(uint32_t opcode, bool is_supervisor = false) { +template +Instruction instruction(const uint32_t opcode, const bool is_supervisor = false) { // If validation isn't required, there's nothing to do here. if constexpr (!validate_reserved_bits) { return Instruction(operation, opcode, is_supervisor); @@ -243,7 +244,7 @@ template Instruc } template -Instruction Decoder::decode(uint32_t opcode) { +Instruction Decoder::decode(const uint32_t opcode) { // Quick bluffer's guide to PowerPC instruction encoding: // // There is a six-bit field at the very top of the instruction. @@ -332,23 +333,29 @@ Instruction Decoder::decode(uint32_t opcode) { default: break; // 64-bit instructions. - BindConditional(is64bit, SixTen(0b011111, 0b0000001001), mulhdux); BindConditional(is64bit, SixTen(0b011111, 0b1000001001), mulhdux); + BindConditional(is64bit, SixTen(0b011111, 0b0000001001), mulhdux); + BindConditional(is64bit, SixTen(0b011111, 0b1000001001), mulhdux); BindConditional(is64bit, SixTen(0b011111, 0b0000010101), ldx); BindConditional(is64bit, SixTen(0b011111, 0b0000011011), sldx); BindConditional(is64bit, SixTen(0b011111, 0b0000110101), ldux); BindConditional(is64bit, SixTen(0b011111, 0b0000111010), cntlzdx); BindConditional(is64bit, SixTen(0b011111, 0b0001000100), td); - BindConditional(is64bit, SixTen(0b011111, 0b0001001001), mulhdx); BindConditional(is64bit, SixTen(0b011111, 0b1001001001), mulhdx); + BindConditional(is64bit, SixTen(0b011111, 0b0001001001), mulhdx); + BindConditional(is64bit, SixTen(0b011111, 0b1001001001), mulhdx); BindConditional(is64bit, SixTen(0b011111, 0b0001010100), ldarx); BindConditional(is64bit, SixTen(0b011111, 0b0010010101), stdx); BindConditional(is64bit, SixTen(0b011111, 0b0010110101), stdux); - BindConditional(is64bit, SixTen(0b011111, 0b0011101001), mulldx); BindConditional(is64bit, SixTen(0b011111, 0b1011101001), mulldx); + BindConditional(is64bit, SixTen(0b011111, 0b0011101001), mulldx); + BindConditional(is64bit, SixTen(0b011111, 0b1011101001), mulldx); BindConditional(is64bit, SixTen(0b011111, 0b0101010101), lwax); BindConditional(is64bit, SixTen(0b011111, 0b0101110101), lwaux); - BindConditional(is64bit, SixTen(0b011111, 0b1100111011), sradix); BindConditional(is64bit, SixTen(0b011111, 0b1100111010), sradix); + BindConditional(is64bit, SixTen(0b011111, 0b1100111011), sradix); + BindConditional(is64bit, SixTen(0b011111, 0b1100111010), sradix); BindConditional(is64bit, SixTen(0b011111, 0b0110110010), slbie); - BindConditional(is64bit, SixTen(0b011111, 0b0111001001), divdux); BindConditional(is64bit, SixTen(0b011111, 0b1111001001), divdux); - BindConditional(is64bit, SixTen(0b011111, 0b0111101001), divdx); BindConditional(is64bit, SixTen(0b011111, 0b1111101001), divdx); + BindConditional(is64bit, SixTen(0b011111, 0b0111001001), divdux); + BindConditional(is64bit, SixTen(0b011111, 0b1111001001), divdux); + BindConditional(is64bit, SixTen(0b011111, 0b0111101001), divdx); + BindConditional(is64bit, SixTen(0b011111, 0b1111101001), divdx); BindConditional(is64bit, SixTen(0b011111, 0b1000011011), srdx); BindConditional(is64bit, SixTen(0b011111, 0b1100011010), sradx); BindConditional(is64bit, SixTen(0b111111, 0b1111011010), extswx); @@ -356,16 +363,22 @@ Instruction Decoder::decode(uint32_t opcode) { // Power instructions; these are all taken from the MPC601 manual rather than // the PowerPC Programmer's Reference Guide, hence the decimal encoding of the // ten-bit field. - BindConditional(is601, SixTen(0b011111, 360), absx); BindConditional(is601, SixTen(0b011111, 512 + 360), absx); + BindConditional(is601, SixTen(0b011111, 360), absx); + BindConditional(is601, SixTen(0b011111, 512 + 360), absx); BindConditional(is601, SixTen(0b011111, 531), clcs); - BindConditional(is601, SixTen(0b011111, 331), divx); BindConditional(is601, SixTen(0b011111, 512 + 331), divx); - BindConditional(is601, SixTen(0b011111, 363), divsx); BindConditional(is601, SixTen(0b011111, 512 + 363), divsx); - BindConditional(is601, SixTen(0b011111, 264), dozx); BindConditional(is601, SixTen(0b011111, 512 + 264), dozx); + BindConditional(is601, SixTen(0b011111, 331), divx); + BindConditional(is601, SixTen(0b011111, 512 + 331), divx); + BindConditional(is601, SixTen(0b011111, 363), divsx); + BindConditional(is601, SixTen(0b011111, 512 + 363), divsx); + BindConditional(is601, SixTen(0b011111, 264), dozx); + BindConditional(is601, SixTen(0b011111, 512 + 264), dozx); BindConditional(is601, SixTen(0b011111, 277), lscbxx); BindConditional(is601, SixTen(0b011111, 29), maskgx); BindConditional(is601, SixTen(0b011111, 541), maskirx); - BindConditional(is601, SixTen(0b011111, 107), mulx); BindConditional(is601, SixTen(0b011111, 512 + 107), mulx); - BindConditional(is601, SixTen(0b011111, 488), nabsx); BindConditional(is601, SixTen(0b011111, 512 + 488), nabsx); + BindConditional(is601, SixTen(0b011111, 107), mulx); + BindConditional(is601, SixTen(0b011111, 512 + 107), mulx); + BindConditional(is601, SixTen(0b011111, 488), nabsx); + BindConditional(is601, SixTen(0b011111, 512 + 488), nabsx); BindConditional(is601, SixTen(0b011111, 537), rribx); BindConditional(is601, SixTen(0b011111, 153), slex); BindConditional(is601, SixTen(0b011111, 217), sleqx); @@ -553,17 +566,22 @@ Instruction Decoder::decode(uint32_t opcode) { if(is64bit(model)) { switch(opcode & 0b111111'00000'00000'00000'000000'111'00) { default: break; - case 0b011110'00000'00000'00000'000000'000'00: return instruction(opcode); - case 0b011110'00000'00000'00000'000000'001'00: return instruction(opcode); - case 0b011110'00000'00000'00000'000000'010'00: return instruction(opcode); - case 0b011110'00000'00000'00000'000000'011'00: return instruction(opcode); + case 0b011110'00000'00000'00000'000000'000'00: + return instruction(opcode); + case 0b011110'00000'00000'00000'000000'001'00: + return instruction(opcode); + case 0b011110'00000'00000'00000'000000'010'00: + return instruction(opcode); + case 0b011110'00000'00000'00000'000000'011'00: + return instruction(opcode); } } // stwcx. and stdcx. switch(opcode & 0b111111'0000'0000'0000'0000'111111111'1) { default: break; - case 0b011111'0000'0000'0000'0000'010010110'1: return instruction(opcode); + case 0b011111'0000'0000'0000'0000'010010110'1: + return instruction(opcode); case 0b011111'0000'0000'0000'0000'011010110'1: if(is64bit(model)) return instruction(opcode); return Instruction(opcode); @@ -573,11 +591,16 @@ Instruction Decoder::decode(uint32_t opcode) { if(is64bit(model)) { switch(opcode & 0b111111'00'00000000'00000000'000000'11) { default: break; - case 0b111010'00'00000000'00000000'000000'00: return instruction(opcode); - case 0b111010'00'00000000'00000000'000000'01: return instruction(opcode); - case 0b111010'00'00000000'00000000'000000'10: return instruction(opcode); - case 0b111110'00'00000000'00000000'000000'00: return instruction(opcode); - case 0b111110'00'00000000'00000000'000000'01: return instruction(opcode); + case 0b111010'00'00000000'00000000'000000'00: + return instruction(opcode); + case 0b111010'00'00000000'00000000'000000'01: + return instruction(opcode); + case 0b111010'00'00000000'00000000'000000'10: + return instruction(opcode); + case 0b111110'00'00000000'00000000'000000'00: + return instruction(opcode); + case 0b111110'00'00000000'00000000'000000'01: + return instruction(opcode); } } diff --git a/InstructionSets/PowerPC/Decoder.hpp b/InstructionSets/PowerPC/Decoder.hpp index 7443f8ab0..a6d161447 100644 --- a/InstructionSets/PowerPC/Decoder.hpp +++ b/InstructionSets/PowerPC/Decoder.hpp @@ -21,15 +21,15 @@ enum class Model { MPC620, }; -constexpr bool is64bit(Model model) { +constexpr bool is64bit(const Model model) { return model == Model::MPC620; } -constexpr bool is32bit(Model model) { +constexpr bool is32bit(const Model model) { return !is64bit(model); } -constexpr bool is601(Model model) { +constexpr bool is601(const Model model) { return model == Model::MPC601; } @@ -45,7 +45,7 @@ constexpr bool is601(Model model) { TODO: determine what specific models of PowerPC do re: reserved bits. */ template struct Decoder { - Instruction decode(uint32_t opcode); + Instruction decode(uint32_t); }; } diff --git a/InstructionSets/PowerPC/Instruction.hpp b/InstructionSets/PowerPC/Instruction.hpp index 73895e4e1..4e6d219e7 100644 --- a/InstructionSets/PowerPC/Instruction.hpp +++ b/InstructionSets/PowerPC/Instruction.hpp @@ -1363,8 +1363,9 @@ struct Instruction { uint32_t opcode = 0; constexpr Instruction() noexcept = default; - constexpr Instruction(uint32_t opcode) noexcept : opcode(opcode) {} - constexpr Instruction(Operation operation, uint32_t opcode, bool is_supervisor = false) noexcept : operation(operation), is_supervisor(is_supervisor), opcode(opcode) {} + constexpr Instruction(const uint32_t opcode) noexcept : opcode(opcode) {} + constexpr Instruction(const Operation operation, const uint32_t opcode, const bool is_supervisor = false) noexcept : + operation(operation), is_supervisor(is_supervisor), opcode(opcode) {} // Instruction fields are decoded below; naming is a compromise between // Motorola's documentation and IBM's. diff --git a/InstructionSets/x86/AccessType.hpp b/InstructionSets/x86/AccessType.hpp index 3142f7c4b..c66cb3f5c 100644 --- a/InstructionSets/x86/AccessType.hpp +++ b/InstructionSets/x86/AccessType.hpp @@ -30,24 +30,24 @@ enum class AccessType { PreauthorisedRead, }; -constexpr bool is_writeable(AccessType type) { +constexpr bool is_writeable(const AccessType type) { return type == AccessType::ReadModifyWrite || type == AccessType::Write; } template struct Accessor; // Reads: return a value directly. -template struct Accessor { using type = IntT; }; -template struct Accessor { using type = IntT; }; +template struct Accessor { using type = const IntT; }; +template struct Accessor { using type = const IntT; }; // Writes: return a custom type that can be written but not read. template class Writeable { - public: - Writeable(IntT &target) : target_(target) {} - IntT operator=(IntT value) { return target_ = value; } - private: - IntT &target_; +public: + Writeable(IntT &target) : target_(target) {} + IntT operator=(IntT value) { return target_ = value; } +private: + IntT &target_; }; template struct Accessor { using type = Writeable; }; diff --git a/InstructionSets/x86/Decoder.cpp b/InstructionSets/x86/Decoder.cpp index 50b5c0d6b..7f5507c51 100644 --- a/InstructionSets/x86/Decoder.cpp +++ b/InstructionSets/x86/Decoder.cpp @@ -15,7 +15,10 @@ using namespace InstructionSet::x86; template -std::pair::InstructionT> Decoder::decode(const uint8_t *source, std::size_t length) { +std::pair::InstructionT> Decoder::decode( + const uint8_t *source, + const std::size_t length +) { // Instruction length limits: // // 8086/80186: none* @@ -1124,6 +1127,6 @@ template class InstructionSet::x86::Decoder; template class InstructionSet::x86::Decoder; template class InstructionSet::x86::Decoder; -std::pair> Decoder8086::decode(const uint8_t *source, std::size_t length) { +std::pair> Decoder8086::decode(const uint8_t *const source, const std::size_t length) { return decoder.decode(source, length); } diff --git a/InstructionSets/x86/Decoder.hpp b/InstructionSets/x86/Decoder.hpp index ee3c7e736..779ef3939 100644 --- a/InstructionSets/x86/Decoder.hpp +++ b/InstructionSets/x86/Decoder.hpp @@ -22,209 +22,209 @@ namespace InstructionSet::x86 { This is an experimental implementation; it has not yet undergone significant testing. */ template class Decoder { - public: - using InstructionT = Instruction; +public: + using InstructionT = Instruction; - /*! - @returns an @c Instruction plus a size; a positive size indicates successful decoding of - an instruction that was that many bytes long in total; a negative size specifies the [negatived] - minimum number of further bytes the caller should ideally collect before calling again. The - caller is free to call with fewer, but may not get a decoded instruction in response, and the - decoder may still not be able to complete decoding even if given that number of bytes. + /*! + @returns an @c Instruction plus a size; a positive size indicates successful decoding of + an instruction that was that many bytes long in total; a negative size specifies the [negatived] + minimum number of further bytes the caller should ideally collect before calling again. The + caller is free to call with fewer, but may not get a decoded instruction in response, and the + decoder may still not be able to complete decoding even if given that number of bytes. - Successful decoding is defined to mean that all decoding steps are complete. The output - may still be an illegal instruction (indicated by Operation::Invalid), if the byte sequence - supplied cannot form a valid instruction. + Successful decoding is defined to mean that all decoding steps are complete. The output + may still be an illegal instruction (indicated by Operation::Invalid), if the byte sequence + supplied cannot form a valid instruction. - @discussion although instructions also contain an indicator of their length, on chips prior - to the 80286 there is no limit to potential instruction length. + @discussion although instructions also contain an indicator of their length, on chips prior + to the 80286 there is no limit to potential instruction length. - The 80286 and 80386 have instruction length limits of 10 and 15 bytes respectively, so - cannot overflow the field. - */ - std::pair decode(const uint8_t *source, std::size_t length); + The 80286 and 80386 have instruction length limits of 10 and 15 bytes respectively, so + cannot overflow the field. + */ + std::pair decode(const uint8_t *source, std::size_t length); - /*! - Enables or disables 32-bit protected mode. Meaningful only if the @c Model supports it. - */ - void set_32bit_protected_mode(bool); + /*! + Enables or disables 32-bit protected mode. Meaningful only if the @c Model supports it. + */ + void set_32bit_protected_mode(bool); - private: - enum class Phase { - /// Captures all prefixes and continues until an instruction byte is encountered. - Instruction, - /// Having encountered a 0x0f first instruction byte, waits for the next byte fully to determine the instruction. - InstructionPageF, - /// Receives a ModRegRM byte and either populates the source_ and dest_ fields appropriately - /// or completes decoding of the instruction, as per the instruction format. - ModRegRM, - /// Awaits n 80386+-style scale-index-base byte ('SIB'), indicating the form of indirect addressing. - ScaleIndexBase, - /// Waits for sufficiently many bytes to pass for the required displacement and operand to be captured. - /// Cf. displacement_size_ and operand_size_. - DisplacementOrOperand, - /// Forms and returns an Instruction, and resets parsing state. - ReadyToPost - } phase_ = Phase::Instruction; +private: + enum class Phase { + /// Captures all prefixes and continues until an instruction byte is encountered. + Instruction, + /// Having encountered a 0x0f first instruction byte, waits for the next byte fully to determine the instruction. + InstructionPageF, + /// Receives a ModRegRM byte and either populates the source_ and dest_ fields appropriately + /// or completes decoding of the instruction, as per the instruction format. + ModRegRM, + /// Awaits n 80386+-style scale-index-base byte ('SIB'), indicating the form of indirect addressing. + ScaleIndexBase, + /// Waits for sufficiently many bytes to pass for the required displacement and operand to be captured. + /// Cf. displacement_size_ and operand_size_. + DisplacementOrOperand, + /// Forms and returns an Instruction, and resets parsing state. + ReadyToPost + } phase_ = Phase::Instruction; - /// During the ModRegRM phase, format dictates interpretation of the ModRegRM byte. - /// - /// During the ReadyToPost phase, format determines how transiently-recorded fields - /// are packaged into an Instruction. - enum class ModRegRMFormat: uint8_t { - // Parse the ModRegRM for mode, register and register/memory fields - // and populate the source_ and destination_ fields appropriately. - MemReg_Reg, - Reg_MemReg, + /// During the ModRegRM phase, format dictates interpretation of the ModRegRM byte. + /// + /// During the ReadyToPost phase, format determines how transiently-recorded fields + /// are packaged into an Instruction. + enum class ModRegRMFormat: uint8_t { + // Parse the ModRegRM for mode, register and register/memory fields + // and populate the source_ and destination_ fields appropriately. + MemReg_Reg, + Reg_MemReg, - // Parse for mode and register/memory fields, populating both - // source_ and destination_ fields with the single register/memory result. - MemRegSingleOperand, + // Parse for mode and register/memory fields, populating both + // source_ and destination_ fields with the single register/memory result. + MemRegSingleOperand, - // Parse for mode and register/memory fields, populating both - // the destination_ field with the result and setting source_ to Immediate. - MemRegMOV, + // Parse for mode and register/memory fields, populating both + // the destination_ field with the result and setting source_ to Immediate. + MemRegMOV, - // Parse for mode and register/memory fields, populating the - // source_ field with the result. Fills destination_ with a segment - // register based on the reg field. - Seg_MemReg, - MemReg_Seg, + // Parse for mode and register/memory fields, populating the + // source_ field with the result. Fills destination_ with a segment + // register based on the reg field. + Seg_MemReg, + MemReg_Seg, - // - // 'Group 1' - // + // + // 'Group 1' + // - // Parse for mode and register/memory fields, populating the - // destination_ field with the result. Use the 'register' field - // to pick an operation from the ADD/OR/ADC/SBB/AND/SUB/XOR/CMP group and - // waits for an operand equal to the operation size. - MemRegADD_to_CMP, + // Parse for mode and register/memory fields, populating the + // destination_ field with the result. Use the 'register' field + // to pick an operation from the ADD/OR/ADC/SBB/AND/SUB/XOR/CMP group and + // waits for an operand equal to the operation size. + MemRegADD_to_CMP, - // Acts exactly as MemRegADD_to_CMP but the operand is fixed in size - // at a single byte, which is sign extended to the operation size. - MemRegADD_to_CMP_SignExtend, + // Acts exactly as MemRegADD_to_CMP but the operand is fixed in size + // at a single byte, which is sign extended to the operation size. + MemRegADD_to_CMP_SignExtend, - // - // 'Group 2' - // + // + // 'Group 2' + // - // Parse for mode and register/memory fields, populating the - // destination_ field with the result. Use the 'register' field - // to pick an operation from the ROL/ROR/RCL/RCR/SAL/SHR/SAR group. - MemRegROL_to_SAR, + // Parse for mode and register/memory fields, populating the + // destination_ field with the result. Use the 'register' field + // to pick an operation from the ROL/ROR/RCL/RCR/SAL/SHR/SAR group. + MemRegROL_to_SAR, - // - // 'Group 3' - // + // + // 'Group 3' + // - // Parse for mode and register/memory fields, populating both - // source_ and destination_ fields with the result. Use the 'register' - // field to pick an operation from the TEST/NOT/NEG/MUL/IMUL/DIV/IDIV group. - MemRegTEST_to_IDIV, + // Parse for mode and register/memory fields, populating both + // source_ and destination_ fields with the result. Use the 'register' + // field to pick an operation from the TEST/NOT/NEG/MUL/IMUL/DIV/IDIV group. + MemRegTEST_to_IDIV, - // - // 'Group 4' - // + // + // 'Group 4' + // - // Parse for mode and register/memory fields, populating the - // source_ and destination_ fields with the result. Uses the - // 'register' field to pick INC or DEC. - MemRegINC_DEC, + // Parse for mode and register/memory fields, populating the + // source_ and destination_ fields with the result. Uses the + // 'register' field to pick INC or DEC. + MemRegINC_DEC, - // - // 'Group 5' - // + // + // 'Group 5' + // - // Parse for mode and register/memory fields, populating the - // source_ and destination_ fields with the result. Uses the - // 'register' field to pick from INC/DEC/CALL/JMP/PUSH, altering - // the source to ::Immediate and setting an operand size if necessary. - MemRegINC_to_PUSH, + // Parse for mode and register/memory fields, populating the + // source_ and destination_ fields with the result. Uses the + // 'register' field to pick from INC/DEC/CALL/JMP/PUSH, altering + // the source to ::Immediate and setting an operand size if necessary. + MemRegINC_to_PUSH, - // - // 'Group 6' - // + // + // 'Group 6' + // - // Parse for mode and register/memory field, populating both source_ - // and destination_ fields with the result. Uses the 'register' field - // to pick from SLDT/STR/LLDT/LTR/VERR/VERW. - MemRegSLDT_to_VERW, + // Parse for mode and register/memory field, populating both source_ + // and destination_ fields with the result. Uses the 'register' field + // to pick from SLDT/STR/LLDT/LTR/VERR/VERW. + MemRegSLDT_to_VERW, - // - // 'Group 7' - // + // + // 'Group 7' + // - // Parse for mode and register/memory field, populating both source_ - // and destination_ fields with the result. Uses the 'register' field - // to pick from SGDT/LGDT/SMSW/LMSW. - MemRegSGDT_to_LMSW, + // Parse for mode and register/memory field, populating both source_ + // and destination_ fields with the result. Uses the 'register' field + // to pick from SGDT/LGDT/SMSW/LMSW. + MemRegSGDT_to_LMSW, - // - // 'Group 8' - // + // + // 'Group 8' + // - // Parse for mode and register/memory field, populating destination, - // and prepare to read a single byte as source. - MemRegBT_to_BTC, - } modregrm_format_ = ModRegRMFormat::MemReg_Reg; + // Parse for mode and register/memory field, populating destination, + // and prepare to read a single byte as source. + MemRegBT_to_BTC, + } modregrm_format_ = ModRegRMFormat::MemReg_Reg; - // Ephemeral decoding state. - Operation operation_ = Operation::Invalid; - int consumed_ = 0, operand_bytes_ = 0; + // Ephemeral decoding state. + Operation operation_ = Operation::Invalid; + int consumed_ = 0, operand_bytes_ = 0; - // Source and destination locations. - Source source_ = Source::None; - Source destination_ = Source::None; + // Source and destination locations. + Source source_ = Source::None; + Source destination_ = Source::None; - // Immediate fields. - int32_t displacement_ = 0; - uint32_t operand_ = 0; - uint64_t inward_data_ = 0; - int next_inward_data_shift_ = 0; + // Immediate fields. + int32_t displacement_ = 0; + uint32_t operand_ = 0; + uint64_t inward_data_ = 0; + int next_inward_data_shift_ = 0; - // Indirection style. - ScaleIndexBase sib_; + // Indirection style. + ScaleIndexBase sib_; - // Facts about the instruction. - DataSize displacement_size_ = DataSize::None; // i.e. size of in-stream displacement, if any. - DataSize operand_size_ = DataSize::None; // i.e. size of in-stream operand, if any. - DataSize operation_size_ = DataSize::None; // i.e. size of data manipulated by the operation. + // Facts about the instruction. + DataSize displacement_size_ = DataSize::None; // i.e. size of in-stream displacement, if any. + DataSize operand_size_ = DataSize::None; // i.e. size of in-stream operand, if any. + DataSize operation_size_ = DataSize::None; // i.e. size of data manipulated by the operation. - bool sign_extend_displacement_ = true; // If set then sign extend any displacement up to the address - // size; otherwise it'll be zero-padded. - bool sign_extend_operand_ = false; // If set then sign extend the operand up to the operation size; - // otherwise it'll be zero-padded. + bool sign_extend_displacement_ = true; // If set then sign extend any displacement up to the address + // size; otherwise it'll be zero-padded. + bool sign_extend_operand_ = false; // If set then sign extend the operand up to the operation size; + // otherwise it'll be zero-padded. - // Prefix capture fields. - Repetition repetition_ = Repetition::None; - bool lock_ = false; - Source segment_override_ = Source::None; + // Prefix capture fields. + Repetition repetition_ = Repetition::None; + bool lock_ = false; + Source segment_override_ = Source::None; - // 32-bit/16-bit selection. - AddressSize default_address_size_ = AddressSize::b16; - DataSize default_data_size_ = DataSize::Word; - AddressSize address_size_ = AddressSize::b16; - DataSize data_size_ = DataSize::Word; + // 32-bit/16-bit selection. + AddressSize default_address_size_ = AddressSize::b16; + DataSize default_data_size_ = DataSize::Word; + AddressSize address_size_ = AddressSize::b16; + DataSize data_size_ = DataSize::Word; - /// Resets size capture and all fields with default values. - void reset_parsing() { - consumed_ = operand_bytes_ = 0; - displacement_size_ = operand_size_ = operation_size_ = DataSize::None; - displacement_ = operand_ = 0; - lock_ = false; - address_size_ = default_address_size_; - data_size_ = default_data_size_; - segment_override_ = Source::None; - repetition_ = Repetition::None; - phase_ = Phase::Instruction; - source_ = destination_ = Source::None; - sib_ = ScaleIndexBase(); - next_inward_data_shift_ = 0; - inward_data_ = 0; - sign_extend_operand_ = false; - sign_extend_displacement_ = true; - } + /// Resets size capture and all fields with default values. + void reset_parsing() { + consumed_ = operand_bytes_ = 0; + displacement_size_ = operand_size_ = operation_size_ = DataSize::None; + displacement_ = operand_ = 0; + lock_ = false; + address_size_ = default_address_size_; + data_size_ = default_data_size_; + segment_override_ = Source::None; + repetition_ = Repetition::None; + phase_ = Phase::Instruction; + source_ = destination_ = Source::None; + sib_ = ScaleIndexBase(); + next_inward_data_shift_ = 0; + inward_data_ = 0; + sign_extend_operand_ = false; + sign_extend_displacement_ = true; + } }; // This is a temporary measure; for reasons as-yet unknown, GCC isn't picking up the diff --git a/InstructionSets/x86/Flags.hpp b/InstructionSets/x86/Flags.hpp index 8fd2f16ca..3041b0215 100644 --- a/InstructionSets/x86/Flags.hpp +++ b/InstructionSets/x86/Flags.hpp @@ -77,154 +77,154 @@ enum class Condition { }; class Flags { - public: - using FlagT = uint32_t; +public: + using FlagT = uint32_t; - // Flag getters. - template bool flag() const { - switch(flag_v) { - case Flag::Carry: return carry_; - case Flag::AuxiliaryCarry: return auxiliary_carry_; - case Flag::Sign: return sign_; - case Flag::Overflow: return overflow_; - case Flag::Trap: return trap_; - case Flag::Interrupt: return interrupt_; - case Flag::Direction: return direction_ < 0; - case Flag::Zero: return !zero_; - case Flag::ParityOdd: return not_parity_bit(); + // Flag getters. + template bool flag() const { + switch(flag_v) { + case Flag::Carry: return carry_; + case Flag::AuxiliaryCarry: return auxiliary_carry_; + case Flag::Sign: return sign_; + case Flag::Overflow: return overflow_; + case Flag::Trap: return trap_; + case Flag::Interrupt: return interrupt_; + case Flag::Direction: return direction_ < 0; + case Flag::Zero: return !zero_; + case Flag::ParityOdd: return not_parity_bit(); + } + } + + // Condition evaluation. + template bool condition() const { + switch(test) { + case Condition::Overflow: return flag(); + case Condition::Below: return flag(); + case Condition::Zero: return flag(); + case Condition::BelowOrEqual: return flag() || flag(); + case Condition::Sign: return flag(); + case Condition::ParityOdd: return flag(); + case Condition::Less: return flag() != flag(); + case Condition::LessOrEqual: return flag() || flag() != flag(); + } + } + + // Convenience setters. + + /// Sets all of @c flags as a function of @c value: + /// • Flag::Zero: sets the zero flag if @c value is zero; + /// • Flag::Sign: sets the sign flag if the top bit of @c value is one; + /// • Flag::ParityOdd: sets parity based on the low 8 bits of @c value; + /// • Flag::Carry: sets carry if @c value is non-zero; + /// • Flag::AuxiliaryCarry: sets auxiliary carry if @c value is non-zero; + /// • Flag::Overflow: sets overflow if @c value is non-zero; + /// • Flag::Interrupt: sets interrupt if @c value is non-zero; + /// • Flag::Trap: sets interrupt if @c value is non-zero; + /// • Flag::Direction: sets direction if @c value is non-zero. + template void set_from(const IntT value) { + for(const auto flag: {flags...}) { + switch(flag) { + default: break; + case Flag::Zero: zero_ = value; break; + case Flag::Sign: sign_ = value & Numeric::top_bit(); break; + case Flag::ParityOdd: parity_ = value; break; + case Flag::Carry: carry_ = value; break; + case Flag::AuxiliaryCarry: auxiliary_carry_ = value; break; + case Flag::Overflow: overflow_ = value; break; + case Flag::Interrupt: interrupt_ = value; break; + case Flag::Trap: trap_ = value; break; + case Flag::Direction: direction_ = value ? -1 : 1; break; } } + } + template void set_from(const FlagT value) { + set_from(value); + } - // Condition evaluation. - template bool condition() const { - switch(test) { - case Condition::Overflow: return flag(); - case Condition::Below: return flag(); - case Condition::Zero: return flag(); - case Condition::BelowOrEqual: return flag() || flag(); - case Condition::Sign: return flag(); - case Condition::ParityOdd: return flag(); - case Condition::Less: return flag() != flag(); - case Condition::LessOrEqual: return flag() || flag() != flag(); - } - } + template IntT carry_bit() const { return carry_ ? 1 : 0; } + bool not_parity_bit() const { + // x86 parity always considers the lowest 8-bits only. + auto result = static_cast(parity_); + result ^= result >> 4; + result ^= result >> 2; + result ^= result >> 1; + return result & 1; + } - // Convenience setters. + template IntT direction() const { return static_cast(direction_); } - /// Sets all of @c flags as a function of @c value: - /// • Flag::Zero: sets the zero flag if @c value is zero; - /// • Flag::Sign: sets the sign flag if the top bit of @c value is one; - /// • Flag::ParityOdd: sets parity based on the low 8 bits of @c value; - /// • Flag::Carry: sets carry if @c value is non-zero; - /// • Flag::AuxiliaryCarry: sets auxiliary carry if @c value is non-zero; - /// • Flag::Overflow: sets overflow if @c value is non-zero; - /// • Flag::Interrupt: sets interrupt if @c value is non-zero; - /// • Flag::Trap: sets interrupt if @c value is non-zero; - /// • Flag::Direction: sets direction if @c value is non-zero. - template void set_from(IntT value) { - for(const auto flag: {flags...}) { - switch(flag) { - default: break; - case Flag::Zero: zero_ = value; break; - case Flag::Sign: sign_ = value & Numeric::top_bit(); break; - case Flag::ParityOdd: parity_ = value; break; - case Flag::Carry: carry_ = value; break; - case Flag::AuxiliaryCarry: auxiliary_carry_ = value; break; - case Flag::Overflow: overflow_ = value; break; - case Flag::Interrupt: interrupt_ = value; break; - case Flag::Trap: trap_ = value; break; - case Flag::Direction: direction_ = value ? -1 : 1; break; - } - } - } - template void set_from(FlagT value) { - set_from(value); - } + // Complete value get and set. + void set(uint16_t value) { + set_from(value & FlagValue::Carry); + set_from(value & FlagValue::AuxiliaryCarry); + set_from(value & FlagValue::Overflow); + set_from(value & FlagValue::Trap); + set_from(value & FlagValue::Interrupt); + set_from(value & FlagValue::Direction); - template IntT carry_bit() const { return carry_ ? 1 : 0; } - bool not_parity_bit() const { - // x86 parity always considers the lowest 8-bits only. - auto result = static_cast(parity_); - result ^= result >> 4; - result ^= result >> 2; - result ^= result >> 1; - return result & 1; - } + set_from(uint8_t(value)); - template IntT direction() const { return static_cast(direction_); } + set_from((~value) & FlagValue::Zero); + set_from((~value) & FlagValue::Parity); + } - // Complete value get and set. - void set(uint16_t value) { - set_from(value & FlagValue::Carry); - set_from(value & FlagValue::AuxiliaryCarry); - set_from(value & FlagValue::Overflow); - set_from(value & FlagValue::Trap); - set_from(value & FlagValue::Interrupt); - set_from(value & FlagValue::Direction); + uint16_t get() const { + return + 0xf002 | - set_from(uint8_t(value)); + (flag() ? FlagValue::Carry : 0) | + (flag() ? FlagValue::AuxiliaryCarry : 0) | + (flag() ? FlagValue::Sign : 0) | + (flag() ? FlagValue::Overflow : 0) | + (flag() ? FlagValue::Trap : 0) | + (flag() ? FlagValue::Interrupt : 0) | + (flag() ? FlagValue::Direction : 0) | + (flag() ? FlagValue::Zero : 0) | - set_from((~value) & FlagValue::Zero); - set_from((~value) & FlagValue::Parity); - } + (flag() ? 0 : FlagValue::Parity); + } - uint16_t get() const { - return - 0xf002 | + std::string to_string() const { + std::string result; - (flag() ? FlagValue::Carry : 0) | - (flag() ? FlagValue::AuxiliaryCarry : 0) | - (flag() ? FlagValue::Sign : 0) | - (flag() ? FlagValue::Overflow : 0) | - (flag() ? FlagValue::Trap : 0) | - (flag() ? FlagValue::Interrupt : 0) | - (flag() ? FlagValue::Direction : 0) | - (flag() ? FlagValue::Zero : 0) | + if(flag()) result += "O"; else result += "-"; + if(flag()) result += "D"; else result += "-"; + if(flag()) result += "I"; else result += "-"; + if(flag()) result += "T"; else result += "-"; + if(flag()) result += "S"; else result += "-"; + if(flag()) result += "Z"; else result += "-"; + result += "-"; + if(flag()) result += "A"; else result += "-"; + result += "-"; + if(!flag()) result += "P"; else result += "-"; + result += "-"; + if(flag()) result += "C"; else result += "-"; - (flag() ? 0 : FlagValue::Parity); - } + return result; + } - std::string to_string() const { - std::string result; + bool operator ==(const Flags &rhs) const { + return get() == rhs.get(); + } - if(flag()) result += "O"; else result += "-"; - if(flag()) result += "D"; else result += "-"; - if(flag()) result += "I"; else result += "-"; - if(flag()) result += "T"; else result += "-"; - if(flag()) result += "S"; else result += "-"; - if(flag()) result += "Z"; else result += "-"; - result += "-"; - if(flag()) result += "A"; else result += "-"; - result += "-"; - if(!flag()) result += "P"; else result += "-"; - result += "-"; - if(flag()) result += "C"; else result += "-"; +private: + // Non-zero => set; zero => unset. + uint32_t carry_; + uint32_t auxiliary_carry_; + uint32_t sign_; + uint32_t overflow_; + uint32_t trap_; + uint32_t interrupt_; - return result; - } + // +1 = direction flag not set; + // -1 = direction flag set. + int32_t direction_; - bool operator ==(const Flags &rhs) const { - return get() == rhs.get(); - } + // Zero => set; non-zero => unset. + uint32_t zero_; - private: - // Non-zero => set; zero => unset. - uint32_t carry_; - uint32_t auxiliary_carry_; - uint32_t sign_; - uint32_t overflow_; - uint32_t trap_; - uint32_t interrupt_; - - // +1 = direction flag not set; - // -1 = direction flag set. - int32_t direction_; - - // Zero => set; non-zero => unset. - uint32_t zero_; - - // Odd number of bits => set; even => unset. - uint32_t parity_; + // Odd number of bits => set; even => unset. + uint32_t parity_; }; } diff --git a/InstructionSets/x86/Implementation/Arithmetic.hpp b/InstructionSets/x86/Implementation/Arithmetic.hpp index 1066de82d..4c09dc5c4 100644 --- a/InstructionSets/x86/Implementation/Arithmetic.hpp +++ b/InstructionSets/x86/Implementation/Arithmetic.hpp @@ -240,7 +240,8 @@ void idiv( IF OperandSize = 8 (* word/byte operation *) THEN temp ← AX / SRC; (* signed division *) - IF (temp > 7FH) OR (temp < 80H) (* if a positive result is greater than 7FH or a negative result is less than 80H *) + IF (temp > 7FH) OR (temp < 80H) (* if a positive result is greater than + 7FH or a negative result is less than 80H *) THEN #DE; (* divide error *) ; ELSE AL ← temp; @@ -250,7 +251,8 @@ void idiv( IF OperandSize = 16 (* doubleword/word operation *) THEN temp ← DX:AX / SRC; (* signed division *) - IF (temp > 7FFFH) OR (temp < 8000H) (* if a positive result is greater than 7FFFH or a negative result is less than 8000H *) + IF (temp > 7FFFH) OR (temp < 8000H) (* if a positive result is greater than 7FFFH or a + negative result is less than 8000H *) THEN #DE; (* divide error *) ; ELSE AX ← temp; @@ -258,7 +260,8 @@ void idiv( FI; ELSE (* quadword/doubleword operation *) temp ← EDX:EAX / SRC; (* signed division *) - IF (temp > 7FFFFFFFH) OR (temp < 80000000H) (* if a positive result is greater than 7FFFFFFFH or a negative result is less than 80000000H *) + IF (temp > 7FFFFFFFH) OR (temp < 80000000H) (* if a positive result is greater than 7FFFFFFFH + or a negative result is less than 80000000H *) THEN #DE; (* divide error *) ; ELSE EAX ← temp; @@ -350,7 +353,11 @@ void neg( The CF flag cleared to 0 if the source operand is 0; otherwise it is set to 1. The OF, SF, ZF, AF, and PF flags are set according to the result. */ - context.flags.template set_from(Numeric::carried_in<4>(IntT(0), destination, IntT(-destination))); + context.flags.template set_from(Numeric::carried_in<4>( + IntT(0), + destination, + IntT(-destination)) + ); destination = -destination; diff --git a/InstructionSets/x86/Implementation/BCD.hpp b/InstructionSets/x86/Implementation/BCD.hpp index 21212a8db..a9cdc1876 100644 --- a/InstructionSets/x86/Implementation/BCD.hpp +++ b/InstructionSets/x86/Implementation/BCD.hpp @@ -38,7 +38,7 @@ void aaas( template void aad( CPU::RegisterPair16 &ax, - uint8_t imm, + const uint8_t imm, ContextT &context ) { /* @@ -59,7 +59,7 @@ void aad( template void aam( CPU::RegisterPair16 &ax, - uint8_t imm, + const uint8_t imm, ContextT &context ) { /* diff --git a/InstructionSets/x86/Implementation/FlowControl.hpp b/InstructionSets/x86/Implementation/FlowControl.hpp index 65af8a425..2a13eaede 100644 --- a/InstructionSets/x86/Implementation/FlowControl.hpp +++ b/InstructionSets/x86/Implementation/FlowControl.hpp @@ -18,8 +18,8 @@ namespace InstructionSet::x86::Primitive { template void jump( - bool condition, - IntT displacement, + const bool condition, + const IntT displacement, ContextT &context ) { /* @@ -42,7 +42,7 @@ void jump( template void loop( modify_t counter, - OffsetT displacement, + const OffsetT displacement, ContextT &context ) { --counter; @@ -54,7 +54,7 @@ void loop( template void loope( modify_t counter, - OffsetT displacement, + const OffsetT displacement, ContextT &context ) { --counter; @@ -66,7 +66,7 @@ void loope( template void loopne( modify_t counter, - OffsetT displacement, + const OffsetT displacement, ContextT &context ) { --counter; @@ -125,20 +125,28 @@ void call_far( return; case Source::Indirect: - source_address = uint16_t(address(instruction, pointer, context)); + source_address = uint16_t( + address(instruction, pointer, context) + ); break; case Source::IndirectNoBase: - source_address = uint16_t(address(instruction, pointer, context)); + source_address = uint16_t( + address(instruction, pointer, context) + ); break; case Source::DirectAddress: - source_address = uint16_t(address(instruction, pointer, context)); + source_address = uint16_t( + address(instruction, pointer, context) + ); break; } context.memory.preauthorise_read(source_segment, source_address, sizeof(uint16_t) * 2); - const uint16_t offset = context.memory.template access(source_segment, source_address); + const auto offset = + context.memory.template access(source_segment, source_address); source_address += 2; - const uint16_t segment = context.memory.template access(source_segment, source_address); + const auto segment = + context.memory.template access(source_segment, source_address); // At least on an 8086, the stack writes occur after the target address read. push(context.registers.cs(), context); @@ -157,25 +165,35 @@ void jump_far( const auto pointer = instruction.destination(); switch(pointer.source()) { default: - case Source::Immediate: context.flow_controller.template jump(instruction.segment(), instruction.offset()); return; + case Source::Immediate: + context.flow_controller.template jump(instruction.segment(), instruction.offset()); + return; case Source::Indirect: - source_address = uint16_t(address(instruction, pointer, context)); + source_address = uint16_t( + address(instruction, pointer, context) + ); break; case Source::IndirectNoBase: - source_address = uint16_t(address(instruction, pointer, context)); + source_address = uint16_t( + address(instruction, pointer, context) + ); break; case Source::DirectAddress: - source_address = uint16_t(address(instruction, pointer, context)); + source_address = uint16_t( + address(instruction, pointer, context) + ); break; } const Source source_segment = instruction.data_segment(); context.memory.preauthorise_read(source_segment, source_address, sizeof(uint16_t) * 2); - const uint16_t offset = context.memory.template access(source_segment, source_address); + const auto offset = + context.memory.template access(source_segment, source_address); source_address += 2; - const uint16_t segment = context.memory.template access(source_segment, source_address); + const auto segment = + context.memory.template access(source_segment, source_address); context.flow_controller.template jump(segment, offset); } @@ -193,7 +211,7 @@ void iret( template void ret_near( - InstructionT instruction, + const InstructionT instruction, ContextT &context ) { const auto ip = pop(context); @@ -203,7 +221,7 @@ void ret_near( template void ret_far( - InstructionT instruction, + const InstructionT instruction, ContextT &context ) { context.memory.preauthorise_stack_read(sizeof(uint16_t) * 2); @@ -233,9 +251,11 @@ void bound( const auto source_segment = instruction.data_segment(); context.memory.preauthorise_read(source_segment, source, 2*sizeof(IntT)); - const sIntT lower_bound = sIntT(context.memory.template access(source_segment, source)); + const auto lower_bound = + sIntT(context.memory.template access(source_segment, source)); source += 2; - const sIntT upper_bound = sIntT(context.memory.template access(source_segment, source)); + const auto upper_bound = + sIntT(context.memory.template access(source_segment, source)); if(sIntT(destination) < lower_bound || sIntT(destination) > upper_bound) { interrupt(Interrupt::BoundRangeExceeded, context); diff --git a/InstructionSets/x86/Implementation/InOut.hpp b/InstructionSets/x86/Implementation/InOut.hpp index 3f1b9d98f..98486d4ec 100644 --- a/InstructionSets/x86/Implementation/InOut.hpp +++ b/InstructionSets/x86/Implementation/InOut.hpp @@ -14,7 +14,7 @@ namespace InstructionSet::x86::Primitive { template void out( - uint16_t port, + const uint16_t port, read_t value, ContextT &context ) { @@ -23,7 +23,7 @@ void out( template void in( - uint16_t port, + const uint16_t port, write_t value, ContextT &context ) { diff --git a/InstructionSets/x86/Implementation/Logical.hpp b/InstructionSets/x86/Implementation/Logical.hpp index 186b3963d..d27f63d39 100644 --- a/InstructionSets/x86/Implementation/Logical.hpp +++ b/InstructionSets/x86/Implementation/Logical.hpp @@ -99,7 +99,7 @@ void cbw( template void cwd( IntT &dx, - IntT ax + const IntT ax ) { dx = ax & Numeric::top_bit() ? IntT(~0) : IntT(0); } diff --git a/InstructionSets/x86/Implementation/PerformImplementation.hpp b/InstructionSets/x86/Implementation/PerformImplementation.hpp index a2dbb4a33..4ef6cad44 100644 --- a/InstructionSets/x86/Implementation/PerformImplementation.hpp +++ b/InstructionSets/x86/Implementation/PerformImplementation.hpp @@ -176,8 +176,12 @@ template < case Operation::ESC: case Operation::NOP: return; - case Operation::AAM: Primitive::aam(context.registers.axp(), uint8_t(instruction.operand()), context); return; - case Operation::AAD: Primitive::aad(context.registers.axp(), uint8_t(instruction.operand()), context); return; + case Operation::AAM: + Primitive::aam(context.registers.axp(), uint8_t(instruction.operand()), context); + return; + case Operation::AAD: + Primitive::aad(context.registers.axp(), uint8_t(instruction.operand()), context); + return; case Operation::AAA: Primitive::aaas(context.registers.axp(), context); return; case Operation::AAS: Primitive::aaas(context.registers.axp(), context); return; case Operation::DAA: Primitive::daas(context.registers.al(), context); return; @@ -236,8 +240,8 @@ template < case Operation::CALLrel: Primitive::call_relative(instruction.displacement(), context); return; - case Operation::CALLabs: Primitive::call_absolute(destination_r(), context); return; - case Operation::CALLfar: Primitive::call_far(instruction, context); return; + case Operation::CALLabs: Primitive::call_absolute(destination_r(), context); return; + case Operation::CALLfar: Primitive::call_far(instruction, context); return; case Operation::JMPrel: jcc(true); return; case Operation::JMPabs: Primitive::jump_absolute(destination_r(), context); return; @@ -417,10 +421,12 @@ template < break; case Operation::OUTS: - Primitive::outs(instruction, eCX(), context.registers.dx(), eSI(), context); + Primitive::outs( + instruction, eCX(), context.registers.dx(), eSI(), context); return; case Operation::OUTS_REP: - Primitive::outs(instruction, eCX(), context.registers.dx(), eSI(), context); + Primitive::outs( + instruction, eCX(), context.registers.dx(), eSI(), context); return; case Operation::INS: @@ -453,7 +459,7 @@ template < const InstructionT &instruction, ContextT &context ) { - auto size = [](DataSize operation_size, AddressSize address_size) constexpr -> int { + const auto size = [](DataSize operation_size, AddressSize address_size) constexpr -> int { return int(operation_size) + (int(address_size) << 2); }; @@ -508,7 +514,7 @@ template < template < typename ContextT > void interrupt( - int index, + const int index, ContextT &context ) { const uint32_t address = static_cast(index) << 2; diff --git a/InstructionSets/x86/Implementation/Resolver.hpp b/InstructionSets/x86/Implementation/Resolver.hpp index 6cf0ac315..28373a129 100644 --- a/InstructionSets/x86/Implementation/Resolver.hpp +++ b/InstructionSets/x86/Implementation/Resolver.hpp @@ -21,9 +21,9 @@ namespace InstructionSet::x86 { /// is copied to @c *immediate and @c immediate is returned. template typename Accessor::type resolve( - InstructionT &instruction, - Source source, - DataPointer pointer, + const InstructionT &instruction, + const Source source, + const DataPointer pointer, ContextT &context, IntT *none = nullptr, IntT *immediate = nullptr @@ -66,8 +66,9 @@ IntT *register_(ContextT &context) { case Source::eAX: // Slightly contorted if chain here and below: // - // (i) does the `constexpr` version of a `switch`; and - // (i) ensures .eax() etc aren't called on @c registers for 16-bit processors, so they need not implement 32-bit storage. + // (i) does the `constexpr` version of a `switch`; and + // (i) ensures .eax() etc aren't called on @c registers for 16-bit processors, + // so they need not implement 32-bit storage. if constexpr (supports_dword && std::is_same_v) { return &context.registers.eax(); } else if constexpr (std::is_same_v) { return &context.registers.ax(); } else if constexpr (std::is_same_v) { return &context.registers.al(); } @@ -150,12 +151,12 @@ uint32_t address( // See forward declaration, above, for details. template typename Accessor::type resolve( - InstructionT &instruction, - Source source, - DataPointer pointer, + const InstructionT &instruction, + const Source source, + const DataPointer pointer, ContextT &context, IntT *none, - IntT *immediate + IntT *const immediate ) { // Rules: // diff --git a/InstructionSets/x86/Implementation/ShiftRoll.hpp b/InstructionSets/x86/Implementation/ShiftRoll.hpp index 49ce02209..d17b572f7 100644 --- a/InstructionSets/x86/Implementation/ShiftRoll.hpp +++ b/InstructionSets/x86/Implementation/ShiftRoll.hpp @@ -15,7 +15,7 @@ namespace InstructionSet::x86::Primitive { template void rcl( modify_t destination, - uint8_t count, + const uint8_t count, ContextT &context ) { /* @@ -76,7 +76,7 @@ void rcl( template void rcr( modify_t destination, - uint8_t count, + const uint8_t count, ContextT &context ) { /* @@ -123,7 +123,7 @@ void rcr( template void rol( modify_t destination, - uint8_t count, + const uint8_t count, ContextT &context ) { /* @@ -175,7 +175,7 @@ void rol( template void ror( modify_t destination, - uint8_t count, + const uint8_t count, ContextT &context ) { /* @@ -283,7 +283,7 @@ void ror( template void sal( modify_t destination, - uint8_t count, + const uint8_t count, ContextT &context ) { switch(count) { @@ -314,7 +314,7 @@ void sal( template void sar( modify_t destination, - uint8_t count, + const uint8_t count, ContextT &context ) { if(!count) { @@ -337,7 +337,7 @@ void sar( template void shr( modify_t destination, - uint8_t count, + const uint8_t count, ContextT &context ) { if(!count) { diff --git a/InstructionSets/x86/Instruction.hpp b/InstructionSets/x86/Instruction.hpp index 10d1f18f4..2c2c4b1d4 100644 --- a/InstructionSets/x86/Instruction.hpp +++ b/InstructionSets/x86/Instruction.hpp @@ -499,10 +499,10 @@ enum class Source: uint8_t { /// getter is used). IndirectNoBase = Indirect - 1, }; -constexpr bool is_register(Source source) { +constexpr bool is_register(const Source source) { return source < Source::None; } -constexpr bool is_segment_register(Source source) { +constexpr bool is_segment_register(const Source source) { return is_register(source) && source >= Source::ES; } @@ -698,216 +698,226 @@ class DataPointer { }; template class Instruction { - public: - using DisplacementT = typename std::conditional::type; - using ImmediateT = typename std::conditional::type; - using AddressT = ImmediateT; +public: + using DisplacementT = typename std::conditional::type; + using ImmediateT = typename std::conditional::type; + using AddressT = ImmediateT; - constexpr Instruction() noexcept = default; - constexpr Instruction(Operation operation) noexcept : - Instruction(operation, Source::None, Source::None, ScaleIndexBase(), false, AddressSize::b16, Source::None, DataSize::None, 0, 0) {} - constexpr Instruction( - Operation operation, - Source source, - Source destination, - ScaleIndexBase sib, - bool lock, - AddressSize address_size, - Source segment_override, - DataSize data_size, - DisplacementT displacement, - ImmediateT operand) noexcept : - operation_(operation), - mem_exts_source_(uint8_t( - (int(address_size) << 7) | - (displacement ? 0x40 : 0x00) | - (operand ? 0x20 : 0x00) | - int(source) | - (source == Source::Indirect ? (uint8_t(sib) & 7) : 0) - )), - source_data_dest_sib_(uint16_t( - (int(data_size) << 14) | - (lock ? (1 << 13) : 0) | - ((uint8_t(sib) & 0xf8) << 2) | - int(destination) | - (destination == Source::Indirect ? (uint8_t(sib) & 7) : 0) - )) { - // Decisions on whether to include operand, displacement and/or size extension words - // have implicitly been made in the int packing above; honour them here. - int extension = 0; - if(has_operand()) { - extensions_[extension] = operand; - ++extension; - } - if(has_displacement()) { - extensions_[extension] = ImmediateT(displacement); - ++extension; - } - - // Patch in a fully-resolved segment. - Source segment = segment_override; - if(segment == Source::None) segment = this->source().default_segment(); - if(segment == Source::None) segment = this->destination().default_segment(); - if(segment == Source::None) segment = Source::DS; - source_data_dest_sib_ |= (int(segment)&7) << 10; + constexpr Instruction() noexcept = default; + constexpr Instruction(Operation operation) noexcept : + Instruction( + operation, + Source::None, + Source::None, + ScaleIndexBase(), + false, + AddressSize::b16, + Source::None, + DataSize::None, + 0, + 0 + ) {} + constexpr Instruction( + Operation operation, + Source source, + Source destination, + ScaleIndexBase sib, + bool lock, + AddressSize address_size, + Source segment_override, + DataSize data_size, + DisplacementT displacement, + ImmediateT operand) noexcept : + operation_(operation), + mem_exts_source_(uint8_t( + (int(address_size) << 7) | + (displacement ? 0x40 : 0x00) | + (operand ? 0x20 : 0x00) | + int(source) | + (source == Source::Indirect ? (uint8_t(sib) & 7) : 0) + )), + source_data_dest_sib_(uint16_t( + (int(data_size) << 14) | + (lock ? (1 << 13) : 0) | + ((uint8_t(sib) & 0xf8) << 2) | + int(destination) | + (destination == Source::Indirect ? (uint8_t(sib) & 7) : 0) + )) { + // Decisions on whether to include operand, displacement and/or size extension words + // have implicitly been made in the int packing above; honour them here. + int extension = 0; + if(has_operand()) { + extensions_[extension] = operand; + ++extension; + } + if(has_displacement()) { + extensions_[extension] = ImmediateT(displacement); + ++extension; } - /// @returns The number of bytes used for meaningful content within this class. A receiver must use at least @c sizeof(Instruction) bytes - /// to store an @c Instruction but is permitted to reuse the trailing sizeof(Instruction) - packing_size() for any purpose it likes. Teleologically, - /// this allows a denser packing of instructions into containers. - constexpr size_t packing_size() const { - return - offsetof(Instruction, extensions_) + - (has_displacement() + has_operand()) * sizeof(ImmediateT); + // Patch in a fully-resolved segment. + Source segment = segment_override; + if(segment == Source::None) segment = this->source().default_segment(); + if(segment == Source::None) segment = this->destination().default_segment(); + if(segment == Source::None) segment = Source::DS; + source_data_dest_sib_ |= (int(segment)&7) << 10; + } + + /// @returns The number of bytes used for meaningful content within this class. A receiver must use at least @c sizeof(Instruction) bytes + /// to store an @c Instruction but is permitted to reuse the trailing sizeof(Instruction) - packing_size() for any purpose it likes. Teleologically, + /// this allows a denser packing of instructions into containers. + constexpr size_t packing_size() const { + return + offsetof(Instruction, extensions_) + + (has_displacement() + has_operand()) * sizeof(ImmediateT); + } + + /// @returns The @c Operation performed by this instruction. + constexpr Operation operation() const { + return operation_; + } + + /// @returns A @c DataPointer describing the 'destination' of this instruction, conventionally the first operand in Intel-syntax assembly. + constexpr DataPointer destination() const { + return DataPointer( + Source(source_data_dest_sib_ & sib_masks[(source_data_dest_sib_ >> 3) & 3]), + ((source_data_dest_sib_ >> 2) & 0xf8) | (source_data_dest_sib_ & 0x07) + ); + } + + /// @returns A @c DataPointer describing the 'source' of this instruction, conventionally the second operand in Intel-syntax assembly. + constexpr DataPointer source() const { + return DataPointer( + Source(mem_exts_source_ & sib_masks[(mem_exts_source_ >> 3) & 3]), + ((source_data_dest_sib_ >> 2) & 0xf8) | (mem_exts_source_ & 0x07) + ); + } + + /// @returns @c true if the lock prefix was present on this instruction; @c false otherwise. + constexpr bool lock() const { + return source_data_dest_sib_ & (1 << 13); + } + + /// @returns The address size for this instruction; will always be 16-bit for instructions decoded by a 16-bit decoder but can be 16- or 32-bit for + /// instructions decoded by a 32-bit decoder, depending on the program's use of the address size prefix byte. + constexpr AddressSize address_size() const { + return AddressSize(mem_exts_source_ >> 7); + } + + /// @returns The segment that should be used for data fetches if this operation accepts segment overrides. + constexpr Source data_segment() const { + return Source( + int(Source::ES) + + ((source_data_dest_sib_ >> 10) & 7) + ); + } + + /// @returns The data size of this operation — e.g. `MOV AX, BX` has a data size of `::Word` but `MOV EAX, EBX` has a data size of + /// `::DWord`. This value is guaranteed never to be `DataSize::None` even for operations such as `CLI` that don't have operands and operate + /// on data that is not a byte, word or double word. + constexpr DataSize operation_size() const { + return DataSize(source_data_dest_sib_ >> 14); + } + + /// @returns The immediate value provided with this instruction, if any. E.g. `ADD AX, 23h` has the operand `23h`. + constexpr ImmediateT operand() const { + const ImmediateT ops[] = {0, operand_extension()}; + return ops[has_operand()]; + } + + /// @returns The nesting level argument supplied to an ENTER. + constexpr ImmediateT nesting_level() const { + return operand(); + } + + /// @returns The immediate segment value provided with this instruction, if any. Relevant for far calls and jumps; e.g. `JMP 1234h:5678h` will + /// have a segment value of `1234h`. + constexpr uint16_t segment() const { + return uint16_t(operand()); + } + + /// @returns The offset provided with this instruction, if any. E.g. `MOV AX, [es:1998h]` has an offset of `1998h`. + constexpr ImmediateT offset() const { + const ImmediateT offsets[] = {0, displacement_extension()}; + return offsets[has_displacement()]; + } + + /// @returns The displacement provided with this instruction `SUB AX, [SI+BP-23h]` has an offset of `-23h` and `JMP 19h` + /// has an offset of `19h`. + constexpr DisplacementT displacement() const { + return DisplacementT(offset()); + } + + /// @returns The dynamic storage size argument supplied to an ENTER. + constexpr ImmediateT dynamic_storage_size() const { + return displacement(); + } + + // Standard comparison operator. + constexpr bool operator ==(const Instruction &rhs) const { + if( operation_ != rhs.operation_ || + mem_exts_source_ != rhs.mem_exts_source_ || + source_data_dest_sib_ != rhs.source_data_dest_sib_) { + return false; } - /// @returns The @c Operation performed by this instruction. - constexpr Operation operation() const { - return operation_; + // Have already established above that this and RHS have the + // same extensions, if any. + const int extension_count = has_displacement() + has_operand(); + for(int c = 0; c < extension_count; c++) { + if(extensions_[c] != rhs.extensions_[c]) return false; } - /// @returns A @c DataPointer describing the 'destination' of this instruction, conventionally the first operand in Intel-syntax assembly. - constexpr DataPointer destination() const { - return DataPointer( - Source(source_data_dest_sib_ & sib_masks[(source_data_dest_sib_ >> 3) & 3]), - ((source_data_dest_sib_ >> 2) & 0xf8) | (source_data_dest_sib_ & 0x07) - ); - } + return true; + } - /// @returns A @c DataPointer describing the 'source' of this instruction, conventionally the second operand in Intel-syntax assembly. - constexpr DataPointer source() const { - return DataPointer( - Source(mem_exts_source_ & sib_masks[(mem_exts_source_ >> 3) & 3]), - ((source_data_dest_sib_ >> 2) & 0xf8) | (mem_exts_source_ & 0x07) - ); - } +private: + Operation operation_ = Operation::Invalid; - /// @returns @c true if the lock prefix was present on this instruction; @c false otherwise. - constexpr bool lock() const { - return source_data_dest_sib_ & (1 << 13); - } + // Packing and encoding of fields is admittedly somewhat convoluted; what this + // achieves is that instructions will be sized: + // + // four bytes + up to two extension words + // (extension words being two bytes for 16-bit instructions, four for 32) + // + // The extension words are used to retain an operand and displacement + // if the instruction has those. - /// @returns The address size for this instruction; will always be 16-bit for instructions decoded by a 16-bit decoder but can be 16- or 32-bit for - /// instructions decoded by a 32-bit decoder, depending on the program's use of the address size prefix byte. - constexpr AddressSize address_size() const { - return AddressSize(mem_exts_source_ >> 7); - } + // b7: address size; + // b6: has displacement; + // b5: has operand; + // [b4, b0]: source. + uint8_t mem_exts_source_ = 0; - /// @returns The segment that should be used for data fetches if this operation accepts segment overrides. - constexpr Source data_segment() const { - return Source( - int(Source::ES) + - ((source_data_dest_sib_ >> 10) & 7) - ); - } + bool has_displacement() const { + return mem_exts_source_ & (1 << 6); + } + bool has_operand() const { + return mem_exts_source_ & (1 << 5); + } - /// @returns The data size of this operation — e.g. `MOV AX, BX` has a data size of `::Word` but `MOV EAX, EBX` has a data size of - /// `::DWord`. This value is guaranteed never to be `DataSize::None` even for operations such as `CLI` that don't have operands and operate - /// on data that is not a byte, word or double word. - constexpr DataSize operation_size() const { - return DataSize(source_data_dest_sib_ >> 14); - } + // [b15, b14]: data size; + // [b13]: lock; + // [b12, b10]: segment override; + // [b9, b5]: top five of SIB; + // [b4, b0]: dest. + uint16_t source_data_dest_sib_ = 0; - /// @returns The immediate value provided with this instruction, if any. E.g. `ADD AX, 23h` has the operand `23h`. - constexpr ImmediateT operand() const { - const ImmediateT ops[] = {0, operand_extension()}; - return ops[has_operand()]; - } + // {operand}, {displacement}. + ImmediateT extensions_[2]{}; - /// @returns The nesting level argument supplied to an ENTER. - constexpr ImmediateT nesting_level() const { - return operand(); - } - - /// @returns The immediate segment value provided with this instruction, if any. Relevant for far calls and jumps; e.g. `JMP 1234h:5678h` will - /// have a segment value of `1234h`. - constexpr uint16_t segment() const { - return uint16_t(operand()); - } - - /// @returns The offset provided with this instruction, if any. E.g. `MOV AX, [es:1998h]` has an offset of `1998h`. - constexpr ImmediateT offset() const { - const ImmediateT offsets[] = {0, displacement_extension()}; - return offsets[has_displacement()]; - } - - /// @returns The displacement provided with this instruction `SUB AX, [SI+BP-23h]` has an offset of `-23h` and `JMP 19h` - /// has an offset of `19h`. - constexpr DisplacementT displacement() const { - return DisplacementT(offset()); - } - - /// @returns The dynamic storage size argument supplied to an ENTER. - constexpr ImmediateT dynamic_storage_size() const { - return displacement(); - } - - // Standard comparison operator. - constexpr bool operator ==(const Instruction &rhs) const { - if( operation_ != rhs.operation_ || - mem_exts_source_ != rhs.mem_exts_source_ || - source_data_dest_sib_ != rhs.source_data_dest_sib_) { - return false; - } - - // Have already established above that this and RHS have the - // same extensions, if any. - const int extension_count = has_displacement() + has_operand(); - for(int c = 0; c < extension_count; c++) { - if(extensions_[c] != rhs.extensions_[c]) return false; - } - - return true; - } - - private: - Operation operation_ = Operation::Invalid; - - // Packing and encoding of fields is admittedly somewhat convoluted; what this - // achieves is that instructions will be sized: - // - // four bytes + up to two extension words - // (extension words being two bytes for 16-bit instructions, four for 32) - // - // The extension words are used to retain an operand and displacement - // if the instruction has those. - - // b7: address size; - // b6: has displacement; - // b5: has operand; - // [b4, b0]: source. - uint8_t mem_exts_source_ = 0; - - bool has_displacement() const { - return mem_exts_source_ & (1 << 6); - } - bool has_operand() const { - return mem_exts_source_ & (1 << 5); - } - - // [b15, b14]: data size; - // [b13]: lock; - // [b12, b10]: segment override; - // [b9, b5]: top five of SIB; - // [b4, b0]: dest. - uint16_t source_data_dest_sib_ = 0; - - // {operand}, {displacement}. - ImmediateT extensions_[2]{}; - - ImmediateT operand_extension() const { - return extensions_[0]; - } - ImmediateT displacement_extension() const { - return extensions_[(mem_exts_source_ >> 5) & 1]; - } - - // A lookup table to help with stripping parts of the SIB that have been - // hidden within the source/destination fields. - static constexpr uint8_t sib_masks[] = { - 0x1f, 0x1f, 0x1f, 0x18 - }; + ImmediateT operand_extension() const { + return extensions_[0]; + } + ImmediateT displacement_extension() const { + return extensions_[(mem_exts_source_ >> 5) & 1]; + } + // A lookup table to help with stripping parts of the SIB that have been + // hidden within the source/destination fields. + static constexpr uint8_t sib_masks[] = { + 0x1f, 0x1f, 0x1f, 0x18 + }; }; static_assert(sizeof(Instruction) <= 16); @@ -962,5 +972,4 @@ std::string to_string( Model model, int offset_length = 0, int immediate_length = 0); - } diff --git a/InstructionSets/x86/Model.hpp b/InstructionSets/x86/Model.hpp index 8bd8ea8d8..1eb87af0c 100644 --- a/InstructionSets/x86/Model.hpp +++ b/InstructionSets/x86/Model.hpp @@ -19,7 +19,7 @@ enum class Model { i80386, }; -static constexpr bool is_32bit(Model model) { return model >= Model::i80386; } +static constexpr bool is_32bit(const Model model) { return model >= Model::i80386; } template struct AddressT { using type = uint16_t; }; template <> struct AddressT { using type = uint32_t; }; diff --git a/Machines/Acorn/Electron/Keyboard.hpp b/Machines/Acorn/Electron/Keyboard.hpp index eec2dbc86..61d425a1e 100644 --- a/Machines/Acorn/Electron/Keyboard.hpp +++ b/Machines/Acorn/Electron/Keyboard.hpp @@ -35,7 +35,7 @@ enum Key: uint16_t { KeyBreak = 0xfffd, }; -constexpr bool is_modifier(Key key) { +constexpr bool is_modifier(const Key key) { return (key == KeyShift) || (key == KeyControl) || (key == KeyFunc); } diff --git a/Machines/Apple/AppleII/VideoSwitches.hpp b/Machines/Apple/AppleII/VideoSwitches.hpp index 39a714caa..894c7df83 100644 --- a/Machines/Apple/AppleII/VideoSwitches.hpp +++ b/Machines/Apple/AppleII/VideoSwitches.hpp @@ -25,8 +25,8 @@ enum class GraphicsMode { /// Fat low res mode is regular low res mode, but clocked out at 7Mhz rather than 14, leading to improper colours. FatLowRes }; -constexpr bool is_text_mode(GraphicsMode m) { return m <= GraphicsMode::DoubleText; } -constexpr bool is_double_mode(GraphicsMode m) { return int(m) & 1; } +constexpr bool is_text_mode(const GraphicsMode m) { return m <= GraphicsMode::DoubleText; } +constexpr bool is_double_mode(const GraphicsMode m) { return int(m) & 1; } template class VideoSwitches { public: diff --git a/Machines/Apple/AppleIIgs/Video.hpp b/Machines/Apple/AppleIIgs/Video.hpp index 5219cffaa..c7d17e9bd 100644 --- a/Machines/Apple/AppleIIgs/Video.hpp +++ b/Machines/Apple/AppleIIgs/Video.hpp @@ -86,7 +86,9 @@ class Video: public Apple::II::VideoSwitches { DoubleHighResMono, SuperHighRes }; - constexpr bool is_colour_ntsc(GraphicsMode m) { return m >= GraphicsMode::HighRes && m <= GraphicsMode::FatLowRes; } + constexpr bool is_colour_ntsc(const GraphicsMode m) { + return m >= GraphicsMode::HighRes && m <= GraphicsMode::FatLowRes; + } GraphicsMode graphics_mode(int row) const { if(new_video_ & 0x80) { diff --git a/Outputs/Log.hpp b/Outputs/Log.hpp index 5832b696f..7e1e234d9 100644 --- a/Outputs/Log.hpp +++ b/Outputs/Log.hpp @@ -59,7 +59,7 @@ enum class Source { WDFDC, }; -constexpr bool is_enabled(Source source) { +constexpr bool is_enabled(const Source source) { #ifdef NDEBUG return false; #endif @@ -133,39 +133,39 @@ constexpr const char *prefix(Source source) { template class Logger { - public: - static constexpr bool enabled = is_enabled(source); +public: + static constexpr bool enabled = is_enabled(source); - struct LogLine { - public: - LogLine(FILE *stream) : stream_(stream) { - if constexpr (!enabled) return; + struct LogLine { + public: + LogLine(FILE *const stream) : stream_(stream) { + if constexpr (!enabled) return; - const auto source_prefix = prefix(source); - if(source_prefix) { - fprintf(stream_, "[%s] ", source_prefix); - } + const auto source_prefix = prefix(source); + if(source_prefix) { + fprintf(stream_, "[%s] ", source_prefix); } + } - ~LogLine() { - if constexpr (!enabled) return; - fprintf(stream_, "\n"); - } + ~LogLine() { + if constexpr (!enabled) return; + fprintf(stream_, "\n"); + } - void append(const char *format, ...) { - if constexpr (!enabled) return; - va_list args; - va_start(args, format); - vfprintf(stream_, format, args); - va_end(args); - } + void append(const char *const format, ...) { + if constexpr (!enabled) return; + va_list args; + va_start(args, format); + vfprintf(stream_, format, args); + va_end(args); + } - private: - FILE *stream_; - }; + private: + FILE *stream_; + }; - LogLine info() { return LogLine(stdout); } - LogLine error() { return LogLine(stderr); } + LogLine info() { return LogLine(stdout); } + LogLine error() { return LogLine(stderr); } }; } diff --git a/Outputs/ScanTarget.hpp b/Outputs/ScanTarget.hpp index 806ff12c7..94d81792d 100644 --- a/Outputs/ScanTarget.hpp +++ b/Outputs/ScanTarget.hpp @@ -50,7 +50,7 @@ enum class DisplayType { CompositeMonochrome }; -constexpr bool is_composite(DisplayType type) { +constexpr bool is_composite(const DisplayType type) { return type == DisplayType::CompositeColour || type == DisplayType::CompositeMonochrome; } diff --git a/Processors/6502/6502.hpp b/Processors/6502/6502.hpp index 25855272a..74983db96 100644 --- a/Processors/6502/6502.hpp +++ b/Processors/6502/6502.hpp @@ -38,10 +38,10 @@ enum Personality { PWDC65C02, // like the Rockwell, but with STP and WAI }; -constexpr bool has_decimal_mode(Personality p) { return p >= Personality::P6502; } -constexpr bool is_65c02(Personality p) { return p >= Personality::PSynertek65C02; } -constexpr bool has_bbrbbsrmbsmb(Personality p) { return p >= Personality::PRockwell65C02; } -constexpr bool has_stpwai(Personality p) { return p >= Personality::PWDC65C02; } +constexpr bool has_decimal_mode(const Personality p) { return p >= Personality::P6502; } +constexpr bool is_65c02(const Personality p) { return p >= Personality::PSynertek65C02; } +constexpr bool has_bbrbbsrmbsmb(const Personality p) { return p >= Personality::PRockwell65C02; } +constexpr bool has_stpwai(const Personality p) { return p >= Personality::PWDC65C02; } /*! An opcode that is guaranteed to cause a 6502 to jam. diff --git a/Processors/6502Esque/6502Selector.hpp b/Processors/6502Esque/6502Selector.hpp index 01cfe6049..5c4cfd8e7 100644 --- a/Processors/6502Esque/6502Selector.hpp +++ b/Processors/6502Esque/6502Selector.hpp @@ -48,7 +48,7 @@ template <> class BusHandlerT: public BusHandler {}; /* Query for implemented registers. */ -constexpr bool has(Type processor_type, Register r) { +constexpr bool has(const Type processor_type, const Register r) { switch(r) { case Register::LastOperationAddress: case Register::ProgramCounter: @@ -67,7 +67,7 @@ constexpr bool has(Type processor_type, Register r) { } } -constexpr bool has_extended_bus_output(Type processor_type) { +constexpr bool has_extended_bus_output(const Type processor_type) { return processor_type == Type::TWDC65816; } diff --git a/Processors/Z80/Implementation/Z80Storage.hpp b/Processors/Z80/Implementation/Z80Storage.hpp index aaf07e8c9..76c4ccf8d 100644 --- a/Processors/Z80/Implementation/Z80Storage.hpp +++ b/Processors/Z80/Implementation/Z80Storage.hpp @@ -115,7 +115,7 @@ class ProcessorStorage { void *destination = nullptr; PartialMachineCycle machine_cycle{}; }; - static constexpr bool is_terminal(MicroOp::Type type) { + static constexpr bool is_terminal(const MicroOp::Type type) { return type == MicroOp::MoveToNextProgram || type == MicroOp::DecodeOperation; } diff --git a/Storage/Disk/Encodings/MFM/Constants.hpp b/Storage/Disk/Encodings/MFM/Constants.hpp index ec1be8775..9e8f1c64f 100644 --- a/Storage/Disk/Encodings/MFM/Constants.hpp +++ b/Storage/Disk/Encodings/MFM/Constants.hpp @@ -16,7 +16,7 @@ enum class Density { Single, Double, High }; -constexpr bool is_mfm(Density density) { +constexpr bool is_mfm(const Density density) { return density != Density::Single; }