diff --git a/Components/9918/Implementation/Storage.hpp b/Components/9918/Implementation/Storage.hpp index 1d3389781..c1260eb99 100644 --- a/Components/9918/Implementation/Storage.hpp +++ b/Components/9918/Implementation/Storage.hpp @@ -59,7 +59,7 @@ struct YamahaFetcher { type(type), id(id) {} - constexpr Event() noexcept {} + constexpr Event() noexcept = default; }; // State that tracks fetching position within a line. diff --git a/InstructionSets/ARM/OperationMapper.hpp b/InstructionSets/ARM/OperationMapper.hpp new file mode 100644 index 000000000..83c04a12a --- /dev/null +++ b/InstructionSets/ARM/OperationMapper.hpp @@ -0,0 +1,469 @@ +// +// OperationMapper.hpp +// Clock Signal +// +// Created by Thomas Harte on 16/02/2024. +// Copyright © 2024 Thomas Harte. All rights reserved. +// + +#pragma once + +#include "../../Reflection/Dispatcher.hpp" + +namespace InstructionSet::ARM { + +enum class Model { + ARM2, +}; + +enum class Operation { + AND, /// Rd = Op1 AND Op2. + EOR, /// Rd = Op1 EOR Op2. + SUB, /// Rd = Op1 - Op2. + RSB, /// Rd = Op2 - Op1. + ADD, /// Rd = Op1 + Op2. + ADC, /// Rd = Op1 + Ord2 + C. + SBC, /// Rd = Op1 - Op2 + C. + RSC, /// Rd = Op2 - Op1 + C. + TST, /// Set condition codes on Op1 AND Op2. + TEQ, /// Set condition codes on Op1 EOR Op2. + CMP, /// Set condition codes on Op1 - Op2. + CMN, /// Set condition codes on Op1 + Op2. + ORR, /// Rd = Op1 OR Op2. + MOV, /// Rd = Op2 + BIC, /// Rd = Op1 AND NOT Op2. + MVN, /// Rd = NOT Op2. + + MUL, /// Rd = Rm * Rs + MLA, /// Rd = Rm * Rs + Rn + B, /// Add offset to PC; programmer allows for PC being two words ahead. + BL, /// Copy PC and PSR to R14, then branch. Copied PC points to next instruction. + + LDR, /// Read single byte or word from [base + offset], possibly mutating the base. + STR, /// Write a single byte or word to [base + offset], possibly mutating the base. + LDM, /// Read 1–16 words from [base], possibly mutating it. + STM, /// Write 1-16 words to [base], possibly mutating it. + SWI, /// Perform a software interrupt. + + CDP, /// Coprocessor data operation. + MRC, /// Move from coprocessor register to ARM register. + MCR, /// Move from ARM register to coprocessor register. + LDC, /// Coprocessor data transfer load. + STC, /// Coprocessor data transfer store. + + Undefined, +}; + +enum class Condition { + EQ, NE, CS, CC, + MI, PL, VS, VC, + HI, LS, GE, LT, + GT, LE, AL, NV, +}; + +enum class ShiftType { + LogicalLeft = 0b00, + LogicalRight = 0b01, + ArithmeticRight = 0b10, + RotateRight = 0b11, +}; + +// +// Implementation details. +// +static constexpr int FlagsStartBit = 20; +using Flags = uint8_t; + +template +constexpr bool flag_bit(uint8_t flags) { + static_assert(position >= 20 && position < 28); + return flags & (1 << (position - FlagsStartBit)); +} + +// +// Methods common to data processing and data transfer. +// +struct WithShiftControlBits { + constexpr WithShiftControlBits(uint32_t opcode) noexcept : opcode_(opcode) {} + + /// The operand 2 register index if @c operand2_is_immediate() is @c false; meaningless otherwise. + int operand2() const { return opcode_ & 0xf; } + /// The type of shift to apply to operand 2 if @c operand2_is_immediate() is @c false; meaningless otherwise. + ShiftType shift_type() const { return ShiftType((opcode_ >> 5) & 3); } + /// @returns @c true if the amount to shift by should be taken from a register; @c false if it is an immediate value. + bool shift_count_is_register() const { return opcode_ & (1 << 4); } + /// The shift amount register index if @c shift_count_is_register() is @c true; meaningless otherwise. + int shift_register() const { return (opcode_ >> 8) & 0xf; } + /// The amount to shift by if @c shift_count_is_register() is @c false; meaningless otherwise. + int shift_amount() const { return (opcode_ >> 7) & 0x1f; } + +protected: + uint32_t opcode_; +}; + +// +// Branch (i.e. B and BL). +// +struct Branch { + constexpr Branch(uint32_t opcode) noexcept : opcode_(opcode) {} + + /// The 26-bit offset to add to the PC. + int offset() const { return (opcode_ & 0xff'ffff) << 2; } + +private: + uint32_t opcode_; +}; + +// +// Data processing (i.e. AND to MVN). +// +struct DataProcessingFlags { + constexpr DataProcessingFlags(uint8_t flags) noexcept : flags_(flags) {} + + /// @returns @c true if operand 2 is defined by the @c rotate() and @c immediate() fields; + /// @c false if it is defined by the @c shift_*() and @c operand2() fields. + constexpr bool operand2_is_immediate() { return flag_bit<25>(flags_); } + + /// @c true if the status register should be updated; @c false otherwise. + constexpr bool set_condition_codes() { return flag_bit<20>(flags_); } + +private: + uint8_t flags_; +}; + +struct DataProcessing: public WithShiftControlBits { + using WithShiftControlBits::WithShiftControlBits; + + /// The destination register index. i.e. Rd. + int destination() const { return (opcode_ >> 12) & 0xf; } + + /// The operand 1 register index. i.e. Rn. + int operand1() const { return (opcode_ >> 16) & 0xf; } + + // + // Immediate values for operand 2. + // + + /// An 8-bit value to rotate right @c rotate() places if @c operand2_is_immediate() is @c true; meaningless otherwise. + int immediate() const { return opcode_ & 0xff; } + /// The number of bits to rotate @c immediate() by to the right if @c operand2_is_immediate() is @c true; meaningless otherwise. + int rotate() const { return (opcode_ >> 7) & 0x1e; } +}; + +// +// MUL and MLA. +// +struct MultiplyFlags { + constexpr MultiplyFlags(uint8_t flags) noexcept : flags_(flags) {} + + /// @c true if the status register should be updated; @c false otherwise. + constexpr bool set_condition_codes() { return flag_bit<20>(flags_); } + +private: + uint8_t flags_; +}; + +struct Multiply { + constexpr Multiply(uint32_t opcode) noexcept : opcode_(opcode) {} + + /// The destination register index. i.e. 'Rd'. + int destination() const { return (opcode_ >> 16) & 0xf; } + + /// The accumulator register index for multiply-add. i.e. 'Rn'. + int accumulator() const { return (opcode_ >> 12) & 0xf; } + + /// The multiplicand register index. i.e. 'Rs'. + int multiplicand() const { return (opcode_ >> 8) & 0xf; } + + /// The multiplier register index. i.e. 'Rm'. + int multiplier() const { return opcode_ & 0xf; } + +private: + uint32_t opcode_; +}; + +// +// Single data transfer (LDR, STR). +// +struct SingleDataTransferFlags { + constexpr SingleDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {} + + constexpr bool offset_is_immediate() { return flag_bit<25>(flags_); } + constexpr bool pre_index() { return flag_bit<24>(flags_); } + constexpr bool add_offset() { return flag_bit<23>(flags_); } + constexpr bool transfer_byte() { return flag_bit<22>(flags_); } + constexpr bool write_back_address() { return flag_bit<21>(flags_); } + +private: + uint8_t flags_; +}; + +struct SingleDataTransfer: public WithShiftControlBits { + using WithShiftControlBits::WithShiftControlBits; + + /// The destination register index. i.e. 'Rd' for LDR. + int destination() const { return (opcode_ >> 12) & 0xf; } + + /// The destination register index. i.e. 'Rd' for STR. + int source() const { return (opcode_ >> 12) & 0xf; } + + /// The base register index. i.e. 'Rn'. + int base() const { return (opcode_ >> 16) & 0xf; } + + /// The immediate offset, if @c offset_is_immediate() was @c true; meaningless otherwise. + int immediate() const { return opcode_ & 0xfff; } +}; + +// +// Block data transfer (LDR, STR). +// +struct BlockDataTransferFlags { + constexpr BlockDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {} + + constexpr bool pre_index() { return flag_bit<24>(flags_); } + constexpr bool add_offset() { return flag_bit<23>(flags_); } + constexpr bool load_psr() { return flag_bit<22>(flags_); } + constexpr bool write_back_address() { return flag_bit<21>(flags_); } + +private: + uint8_t flags_; +}; + +struct BlockDataTransfer: public WithShiftControlBits { + using WithShiftControlBits::WithShiftControlBits; + + /// The base register index. i.e. 'Rn'. + int base() const { return (opcode_ >> 16) & 0xf; } + + /// A bitfield indicating which registers to load or store. + int register_list() const { return opcode_ & 0xffff; } +}; + +// +// Coprocessor data operation. +// +struct CoprocessorDataOperationFlags { + constexpr CoprocessorDataOperationFlags(uint8_t flags) noexcept : flags_(flags) {} + + constexpr int operation() const { return (flags_ >> (FlagsStartBit - 20)) & 0xf; } + +private: + uint8_t flags_; +}; + +struct CoprocessorDataOperation { + constexpr CoprocessorDataOperation(uint32_t opcode) noexcept : opcode_(opcode) {} + + int operand1() { return (opcode_ >> 16) & 0xf; } + int operand2() { return opcode_ & 0xf; } + int destination() { return (opcode_ >> 12) & 0xf; } + int coprocessor() { return (opcode_ >> 8) & 0xf; } + int information() { return (opcode_ >> 5) & 0x7; } + +private: + uint32_t opcode_; +}; + +// +// Coprocessor register transfer. +// +struct CoprocessorRegisterTransferFlags { + constexpr CoprocessorRegisterTransferFlags(uint8_t flags) noexcept : flags_(flags) {} + + constexpr int operation() const { return (flags_ >> (FlagsStartBit - 20)) & 0x7; } + +private: + uint8_t flags_; +}; + +struct CoprocessorRegisterTransfer { + constexpr CoprocessorRegisterTransfer(uint32_t opcode) noexcept : opcode_(opcode) {} + + int operand1() { return (opcode_ >> 16) & 0xf; } + int operand2() { return opcode_ & 0xf; } + int destination() { return (opcode_ >> 12) & 0xf; } + int coprocessor() { return (opcode_ >> 8) & 0xf; } + int information() { return (opcode_ >> 5) & 0x7; } + +private: + uint32_t opcode_; +}; + +// +// Coprocessor data transfer. +// +struct CoprocessorDataTransferFlags { + constexpr CoprocessorDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {} + + constexpr bool pre_index() { return flag_bit<24>(flags_); } + constexpr bool add_offset() { return flag_bit<23>(flags_); } + constexpr bool transfer_length() { return flag_bit<22>(flags_); } + constexpr bool write_back_address() { return flag_bit<21>(flags_); } + +private: + uint8_t flags_; +}; + +struct CoprocessorDataTransfer { + constexpr CoprocessorDataTransfer(uint32_t opcode) noexcept : opcode_(opcode) {} + + int base() { return (opcode_ >> 16) & 0xf; } + + int source() { return (opcode_ >> 12) & 0xf; } + int destination() { return (opcode_ >> 12) & 0xf; } + + int coprocessor() { return (opcode_ >> 8) & 0xf; } + int offset() { return opcode_ & 0xff; } + +private: + uint32_t opcode_; +}; + +/// Operation mapper; use the free function @c dispatch as defined below. +struct OperationMapper { + template void dispatch(uint32_t instruction, SchedulerT &scheduler) { + constexpr auto partial = uint32_t(i << 20); + const auto condition = Condition(instruction >> 28); + + // Cf. the ARM2 datasheet, p.45. Tests below match its ordering + // other than that 'undefined' is the fallthrough case. More specific + // page references are provided were more detailed versions of the + // decoding are depicted. + + // Data processing; cf. p.17. + if constexpr (((partial >> 26) & 0b11) == 0b00) { + constexpr auto operation = Operation(int(Operation::AND) + ((partial >> 21) & 0xf)); + scheduler.template perform( + condition, + DataProcessing(instruction) + ); + return; + } + + // Multiply and multiply-accumulate (MUL, MLA); cf. p.23. + if constexpr (((partial >> 22) & 0b111'111) == 0b000'000) { + // This implementation provides only eight bits baked into the template parameters so + // an additional dynamic test is required to check whether this is really, really MUL or MLA. + if(((instruction >> 4) & 0b1111) == 0b1001) { + constexpr bool is_mla = partial & (1 << 21); + scheduler.template perform( + condition, + Multiply(instruction) + ); + return; + } + } + + // Single data transfer (LDR, STR); cf. p.25. + if constexpr (((partial >> 26) & 0b11) == 0b01) { + constexpr bool is_ldr = partial & (1 << 20); + scheduler.template perform( + condition, + SingleDataTransfer(instruction) + ); + return; + } + + // Block data transfer (LDM, STM); cf. p.29. + if constexpr (((partial >> 25) & 0b111) == 0b100) { + constexpr bool is_ldm = partial & (1 << 20); + scheduler.template perform( + condition, + BlockDataTransfer(instruction) + ); + return; + } + + // Branch and branch with link (B, BL); cf. p.15. + if constexpr (((partial >> 25) & 0b111) == 0b101) { + constexpr bool is_bl = partial & (1 << 24); + scheduler.template perform( + condition, + Branch(instruction) + ); + return; + } + + // Software interreupt; cf. p.35. + if constexpr (((partial >> 24) & 0b1111) == 0b1111) { + scheduler.software_interrupt(condition); + return; + } + + // Both: + // Coprocessor data operation; cf. p. 37; and + // Coprocessor register transfers; cf. p. 42. + if constexpr (((partial >> 24) & 0b1111) == 0b1110) { + if(instruction & (1 << 4)) { + // Register transfer. + const auto parameters = CoprocessorRegisterTransfer(instruction); + constexpr bool is_mrc = partial & (1 << 20); + scheduler.template perform( + condition, + parameters + ); + } else { + // Data operation. + const auto parameters = CoprocessorDataOperation(instruction); + scheduler.template perform( + condition, + parameters + ); + } + return; + } + + // Coprocessor data transfers; cf. p.39. + if constexpr (((partial >> 25) & 0b111) == 0b110) { + constexpr bool is_ldc = partial & (1 << 20); + scheduler.template perform( + condition, + CoprocessorDataTransfer(instruction) + ); + return; + } + + // Fallback position. + scheduler.unknown(instruction); + } +}; + +/// A brief documentation of the interface expected by @c dispatch below; will be a concept if/when this project adopts C++20. +struct SampleScheduler { + // General template arguments: + // + // (1) Operation, telling the function which operation to perform. Will always be from the subset + // implied by the operation category; and + // (2) Flags, an opaque type which can be converted into a DataProcessingFlags, MultiplyFlags, etc, + // by simply construction, to provide all flags that can be baked into the template parameters. + // + // Arguments are ommitted if not relevant. + // + // Function arguments: + // + // (1) Condition, indicating the condition code associated with this operation; and + // (2) An operation-specific encapsulation of the operation code for decoding of fields that didn't + // fit into the template parameters. + template void perform(Condition, DataProcessing); + template void perform(Condition, Multiply); + template void perform(Condition, SingleDataTransfer); + template void perform(Condition, BlockDataTransfer); + template void perform(Condition, Branch); + template void perform(Condition, CoprocessorRegisterTransfer); + template void perform(Condition, CoprocessorDataOperation); + template void perform(Condition, CoprocessorDataTransfer); + + // Irregular operations. + void software_interrupt(Condition); + void unknown(uint32_t opcode); +}; + +/// Decodes @c instruction, making an appropriate call into @c scheduler. +/// +/// In lieue of C++20, see the sample definition of SampleScheduler above for the expected interface. +template void dispatch(uint32_t instruction, SchedulerT &scheduler) { + OperationMapper mapper; + Reflection::dispatch(mapper, (instruction >> FlagsStartBit) & 0xff, instruction, scheduler); +} + +} diff --git a/InstructionSets/PowerPC/Instruction.hpp b/InstructionSets/PowerPC/Instruction.hpp index 7116d3a0b..73895e4e1 100644 --- a/InstructionSets/PowerPC/Instruction.hpp +++ b/InstructionSets/PowerPC/Instruction.hpp @@ -1362,9 +1362,9 @@ struct Instruction { bool is_supervisor = false; uint32_t opcode = 0; - Instruction() noexcept {} - Instruction(uint32_t opcode) noexcept : opcode(opcode) {} - Instruction(Operation operation, uint32_t opcode, bool is_supervisor = false) noexcept : operation(operation), is_supervisor(is_supervisor), opcode(opcode) {} + 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) {} // Instruction fields are decoded below; naming is a compromise between // Motorola's documentation and IBM's. diff --git a/InstructionSets/x86/Instruction.hpp b/InstructionSets/x86/Instruction.hpp index a1e475152..10d1f18f4 100644 --- a/InstructionSets/x86/Instruction.hpp +++ b/InstructionSets/x86/Instruction.hpp @@ -564,7 +564,7 @@ constexpr Operation rep_operation(Operation operation, Repetition repetition) { /// It cannot natively describe a base of ::None. class ScaleIndexBase { public: - constexpr ScaleIndexBase() noexcept {} + constexpr ScaleIndexBase() noexcept = default; constexpr ScaleIndexBase(uint8_t sib) noexcept : sib_(sib) {} constexpr ScaleIndexBase(int scale, Source index, Source base) noexcept : sib_(uint8_t( @@ -703,7 +703,7 @@ template class Instruction { using ImmediateT = typename std::conditional::type; using AddressT = ImmediateT; - constexpr Instruction() noexcept {} + 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( diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 069031998..5534d4fbe 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -213,6 +213,7 @@ 4B1EC716255398B000A1F44B /* Sound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1EC714255398B000A1F44B /* Sound.cpp */; }; 4B1EC717255398B000A1F44B /* Sound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1EC714255398B000A1F44B /* Sound.cpp */; }; 4B1EDB451E39A0AC009D6819 /* chip.png in Resources */ = {isa = PBXBuildFile; fileRef = 4B1EDB431E39A0AC009D6819 /* chip.png */; }; + 4B2005432B804D6400420C5C /* ARMDecoderTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2005422B804D6400420C5C /* ARMDecoderTests.mm */; }; 4B2130E2273A7A0A008A77B4 /* Audio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2130E0273A7A0A008A77B4 /* Audio.cpp */; }; 4B2130E3273A7A0A008A77B4 /* Audio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2130E0273A7A0A008A77B4 /* Audio.cpp */; }; 4B228CD524D773B40077EF25 /* CSScanTarget.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B228CD424D773B30077EF25 /* CSScanTarget.mm */; }; @@ -1332,6 +1333,8 @@ 4B1EC714255398B000A1F44B /* Sound.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Sound.cpp; sourceTree = ""; }; 4B1EC715255398B000A1F44B /* Sound.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Sound.hpp; sourceTree = ""; }; 4B1EDB431E39A0AC009D6819 /* chip.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = chip.png; sourceTree = ""; }; + 4B2005402B804AA300420C5C /* OperationMapper.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = OperationMapper.hpp; sourceTree = ""; }; + 4B2005422B804D6400420C5C /* ARMDecoderTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ARMDecoderTests.mm; sourceTree = ""; }; 4B2130E0273A7A0A008A77B4 /* Audio.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Audio.cpp; sourceTree = ""; }; 4B2130E1273A7A0A008A77B4 /* Audio.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Audio.hpp; sourceTree = ""; }; 4B228CD424D773B30077EF25 /* CSScanTarget.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSScanTarget.mm; sourceTree = ""; }; @@ -2752,6 +2755,14 @@ path = Icons; sourceTree = ""; }; + 4B20053D2B804A4F00420C5C /* ARM */ = { + isa = PBXGroup; + children = ( + 4B2005402B804AA300420C5C /* OperationMapper.hpp */, + ); + path = ARM; + sourceTree = ""; + }; 4B228CD324D773B30077EF25 /* ScanTarget */ = { isa = PBXGroup; children = ( @@ -4471,6 +4482,7 @@ 4B9D0C4E22C7E0CF00DE1AD3 /* 68000RollShiftTests.mm */, 4BD388872239E198002D14B5 /* 68000Tests.mm */, 4BF7019F26FFD32300996424 /* AmigaBlitterTests.mm */, + 4B2005422B804D6400420C5C /* ARMDecoderTests.mm */, 4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */, 4BE34437238389E10058E78F /* AtariSTVideoTests.mm */, 4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */, @@ -5082,6 +5094,7 @@ 4BE8EB5425C0E9D40040BC40 /* Disassembler.hpp */, 4BEDA3B625B25563000C2DBD /* README.md */, 4BDA7F7F29C4C179007A10A5 /* 6809 */, + 4B20053D2B804A4F00420C5C /* ARM */, 4B79629B2819681F008130F9 /* M68k */, 4BEDA40925B2844B000C2DBD /* M50740 */, 4BEDA3B325B25563000C2DBD /* PowerPC */, @@ -6334,6 +6347,7 @@ 4B778F2823A5EEF80000D260 /* Cartridge.cpp in Sources */, 4B7752B528217ED30073E2C5 /* SNA.cpp in Sources */, 4BEDA3C025B25563000C2DBD /* Decoder.cpp in Sources */, + 4B2005432B804D6400420C5C /* ARMDecoderTests.mm in Sources */, 4B778F4C23A5F2090000D260 /* StaticAnalyser.cpp in Sources */, 4B778F2623A5EE350000D260 /* Acorn.cpp in Sources */, 4B7752C128217F490073E2C5 /* FAT.cpp in Sources */, diff --git a/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm new file mode 100644 index 000000000..3cfeffbce --- /dev/null +++ b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm @@ -0,0 +1,49 @@ +// +// ARMDecoderTests.m +// Clock Signal +// +// Created by Thomas Harte on 16/02/2024. +// Copyright 2024 Thomas Harte. All rights reserved. +// + +#import + +#include "../../../InstructionSets/ARM/OperationMapper.hpp" + +using namespace InstructionSet::ARM; + +namespace { + +struct Scheduler { + template void perform(Condition, DataProcessing) {} + template void perform(Condition, Multiply) {} + template void perform(Condition, SingleDataTransfer) {} + template void perform(Condition, BlockDataTransfer) {} + + template void perform(Condition condition, Branch branch) { + printf("Branch %sif %d; add %08x\n", op == Operation::BL ? "with link " : "", int(condition), branch.offset()); + } + template void perform(Condition, CoprocessorRegisterTransfer) {} + template void perform(Condition, CoprocessorDataOperation) {} + template void perform(Condition, CoprocessorDataTransfer) {} + + void software_interrupt(Condition) {} + void unknown(uint32_t) {} +}; + +} + +@interface ARMDecoderTests : XCTestCase +@end + +@implementation ARMDecoderTests + +- (void)testXYX { + Scheduler scheduler; + + InstructionSet::ARM::dispatch(0xEAE06900, scheduler); +// const auto intr = Instruction(1); +// NSLog(@"%d", intr.operation()); +} + +@end diff --git a/Outputs/ScanTargets/BufferingScanTarget.hpp b/Outputs/ScanTargets/BufferingScanTarget.hpp index 896aa8286..9d43c22c7 100644 --- a/Outputs/ScanTargets/BufferingScanTarget.hpp +++ b/Outputs/ScanTargets/BufferingScanTarget.hpp @@ -203,7 +203,7 @@ class BufferingScanTarget: public Outputs::Display::ScanTarget { struct PointerSet { // This constructor is here to appease GCC's interpretation of // an ambiguity in the C++ standard; cf. https://stackoverflow.com/questions/17430377 - PointerSet() noexcept {} + PointerSet() noexcept = default; // Squeezing this struct into 64 bits makes the std::atomics more likely // to be lock free; they are under LLVM x86-64. diff --git a/Processors/68000/68000.hpp b/Processors/68000/68000.hpp index 0b271292b..013d36145 100644 --- a/Processors/68000/68000.hpp +++ b/Processors/68000/68000.hpp @@ -145,7 +145,7 @@ struct Microcycle: public MicrocycleOperationStorage { */ SlicedInt16 *value = nullptr; - constexpr Microcycle() noexcept {} + constexpr Microcycle() noexcept = default; constexpr Microcycle(OperationT dynamic_operation) noexcept { if constexpr (op == Operation::DecodeDynamically) { MicrocycleOperationStorage::operation = dynamic_operation; diff --git a/Storage/Disk/Encodings/MFM/Sector.hpp b/Storage/Disk/Encodings/MFM/Sector.hpp index 646b7d3ea..d07d05777 100644 --- a/Storage/Disk/Encodings/MFM/Sector.hpp +++ b/Storage/Disk/Encodings/MFM/Sector.hpp @@ -40,7 +40,7 @@ struct Sector { bool has_header_crc_error = false; bool is_deleted = false; - Sector() noexcept {} + Sector() noexcept = default; Sector(const Sector &&rhs) noexcept : address(rhs.address),