From d7d0a5c15e0741e9d440d9abd8d3886e260ae00b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 5 May 2022 18:51:29 -0400 Subject: [PATCH] Implement MOVEM to memory. --- .../Implementation/ExecutorImplementation.hpp | 46 +++++++++++++++++-- InstructionSets/M68k/Instruction.hpp | 7 ++- .../68000ComparativeTests.mm | 4 +- 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/InstructionSets/M68k/Implementation/ExecutorImplementation.hpp b/InstructionSets/M68k/Implementation/ExecutorImplementation.hpp index ff79df7d7..30a80b4fb 100644 --- a/InstructionSets/M68k/Implementation/ExecutorImplementation.hpp +++ b/InstructionSets/M68k/Implementation/ExecutorImplementation.hpp @@ -440,11 +440,51 @@ void Executor::movep(Preinstruction instruction, uint32_t sou template template void Executor::movem(Preinstruction instruction, uint32_t source, uint32_t dest) { - if(instruction.mode<0>() == AddressingMode::DataRegisterDirect) { - // Move registers to memory. + // NB: + // + // "For the MC68020, MC68030, MC68040, and CPU32, if the addressing register is also + // moved to memory, the value written is the initial register value decremented by the + // size of the operation. The MC68000 and MC68010 write the initial register value + // (not decremented)." + + if(instruction.mode<0>() == AddressingMode::ImmediateData) { + // Move registers to memory. This is the only permitted use of the predecrement mode, + // which reverses output order. if(instruction.mode<1>() == AddressingMode::AddressRegisterIndirectWithPredecrement) { - } else { + // The structure of the code in the mainline part of the executor is such + // that the address register will already have been predecremented before + // reaching here, and it'll have been by two bytes per the operand size + // rather than according to the instruction size. That's not wanted, so undo it. + // + // (TODO: with the caveat that the 68020+ have different behaviour.). + registers_[8 + instruction.reg<1>()].l += 2; + + uint32_t reg = registers_[8 + instruction.reg<1>()].l; + int index = 15; + + while(source) { + if(source & 1) { + reg -= sizeof(IntT); + bus_handler_.template write(reg, IntT(registers_[index].l)); + } + --index; + source >>= 1; + } + + registers_[8 + instruction.reg<1>()].l = reg; + return; } + + int index = 0; + while(source) { + if(source & 1) { + bus_handler_.template write(dest, IntT(registers_[index].l)); + dest += sizeof(IntT); + } + ++index; + source >>= 1; + } + } else { // Move memory to registers. } diff --git a/InstructionSets/M68k/Instruction.hpp b/InstructionSets/M68k/Instruction.hpp index 5d9b3a074..cf20b91a2 100644 --- a/InstructionSets/M68k/Instruction.hpp +++ b/InstructionSets/M68k/Instruction.hpp @@ -127,6 +127,10 @@ enum class DataSize { }; /// Classifies operations by the size of their memory accesses, if any. +/// +/// For any operations that don't fit the neat model of reading one or two operands, +/// then writing zero or one, the size determines the data size of the operands only, +/// not any other accesses. constexpr DataSize size(Operation operation) { switch(operation) { // These are given a value arbitrarily, to @@ -188,7 +192,7 @@ constexpr DataSize size(Operation operation) { case Operation::RORw: case Operation::RORm: case Operation::ROXLw: case Operation::ROXLm: case Operation::ROXRw: case Operation::ROXRm: - case Operation::MOVEMw: + case Operation::MOVEMw: case Operation::MOVEMl: case Operation::MOVEPw: case Operation::ANDw: case Operation::EORw: case Operation::NOTw: case Operation::ORw: @@ -217,7 +221,6 @@ constexpr DataSize size(Operation operation) { case Operation::LSLl: case Operation::LSRl: case Operation::ROLl: case Operation::RORl: case Operation::ROXLl: case Operation::ROXRl: - case Operation::MOVEMl: case Operation::MOVEPl: case Operation::ANDl: case Operation::EORl: case Operation::NOTl: case Operation::ORl: diff --git a/OSBindings/Mac/Clock SignalTests/68000ComparativeTests.mm b/OSBindings/Mac/Clock SignalTests/68000ComparativeTests.mm index c96d92934..06df19fe0 100644 --- a/OSBindings/Mac/Clock SignalTests/68000ComparativeTests.mm +++ b/OSBindings/Mac/Clock SignalTests/68000ComparativeTests.mm @@ -72,8 +72,8 @@ - (void)setUp { // To limit tests run to a subset of files and/or of tests, uncomment and fill in below. - _fileSet = [NSSet setWithArray:@[@"move.json"]]; -// _testSet = [NSSet setWithArray:@[@"MOVE[A] 0148"]]; + _fileSet = [NSSet setWithArray:@[@"movem.json"]]; +// _testSet = [NSSet setWithArray:@[@"MOVEM 0060 (0)"]]; // _fileSet = [NSSet setWithArray:@[@"jmp_jsr.json"]]; // _testSet = [NSSet setWithArray:@[@"CHK 41a8"]]; }