1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-08-06 16:25:35 +00:00

Preserve MOVEM order in Operation.

This commit is contained in:
Thomas Harte
2022-05-06 09:45:06 -04:00
parent fed79a116f
commit 607ddd2f78
8 changed files with 104 additions and 93 deletions

View File

@@ -76,8 +76,6 @@ constexpr Operation Predecoder<model>::operation(OpT op) {
} }
switch(op) { switch(op) {
case MOVEMtoRl: case MOVEMtoMl: return Operation::MOVEMl;
case MOVEMtoRw: case MOVEMtoMw: return Operation::MOVEMw;
case MOVEPtoRl: case MOVEPtoMl: return Operation::MOVEPl; case MOVEPtoRl: case MOVEPtoMl: return Operation::MOVEPl;
case MOVEPtoRw: case MOVEPtoMw: return Operation::MOVEPw; case MOVEPtoRw: case MOVEPtoMw: return Operation::MOVEPw;
@@ -456,16 +454,16 @@ template <uint8_t op> uint32_t Predecoder<model>::invalid_operands() {
An An
>::value; >::value;
case MOVEMtoMw: case MOVEMtoMl: case OpT(Operation::MOVEMtoMw): case OpT(Operation::MOVEMtoMl):
return ~TwoOperandMask< return ~TwoOperandMask<
Imm, Imm,
Ind | PreDec | d16An | d8AnXn | XXXw | XXXl Ind | PreDec | d16An | d8AnXn | XXXw | XXXl
>::value; >::value;
case MOVEMtoRw: case MOVEMtoRl: case OpT(Operation::MOVEMtoRw): case OpT(Operation::MOVEMtoRl):
return ~TwoOperandMask< return ~TwoOperandMask<
Ind | PostInc | d16An | d8AnXn | XXXw | XXXl | d16PC | d8PCXn, Imm,
Imm Ind | PostInc | d16An | d8AnXn | XXXw | XXXl | d16PC | d8PCXn
>::value; >::value;
case MOVEPtoRl: case MOVEPtoRw: case MOVEPtoRl: case MOVEPtoRw:
@@ -796,16 +794,12 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
// b0b2 and b3b5: effective address. // b0b2 and b3b5: effective address.
// [already decoded: b10: direction] // [already decoded: b10: direction]
// //
case MOVEMtoMl: case MOVEMtoMw: case OpT(Operation::MOVEMtoMl): case OpT(Operation::MOVEMtoMw):
case OpT(Operation::MOVEMtoRl): case OpT(Operation::MOVEMtoRw):
return validated<op, validate>( return validated<op, validate>(
AddressingMode::ImmediateData, 0, AddressingMode::ImmediateData, 0,
combined_mode(ea_mode, ea_register), ea_register); combined_mode(ea_mode, ea_register), ea_register);
case MOVEMtoRl: case MOVEMtoRw:
return validated<op, validate>(
combined_mode(ea_mode, ea_register), ea_register,
AddressingMode::ImmediateData, 0);
// //
// MARK: TRAP, BCCb, BSRb // MARK: TRAP, BCCb, BSRb
// //
@@ -1087,10 +1081,10 @@ Preinstruction Predecoder<model>::decode4(uint16_t instruction) {
case 0x840: Decode(Op::PEA); case 0x840: Decode(Op::PEA);
// 4-128 (p232) // 4-128 (p232)
case 0x880: Decode(MOVEMtoMw); case 0x880: Decode(Op::MOVEMtoMw);
case 0x8c0: Decode(MOVEMtoMl); case 0x8c0: Decode(Op::MOVEMtoMl);
case 0xc80: Decode(MOVEMtoRw); case 0xc80: Decode(Op::MOVEMtoRw);
case 0xcc0: Decode(MOVEMtoRl); case 0xcc0: Decode(Op::MOVEMtoRl);
// 4-192 (p296) // 4-192 (p296)
case 0xa00: Decode(Op::TSTb); case 0xa00: Decode(Op::TSTb);

View File

@@ -66,10 +66,7 @@ template <Model model> class Predecoder {
// time that's knowable from the Operation alone, hence the rather awkward // time that's knowable from the Operation alone, hence the rather awkward
// extension of @c Operation. // extension of @c Operation.
enum ExtendedOperation: OpT { enum ExtendedOperation: OpT {
MOVEMtoRl = uint8_t(Operation::Max) + 1, MOVEMtoRw, MOVEPtoRl = uint8_t(Operation::Max) + 1, MOVEPtoRw,
MOVEMtoMl, MOVEMtoMw,
MOVEPtoRl, MOVEPtoRw,
MOVEPtoMl, MOVEPtoMw, MOVEPtoMl, MOVEPtoMw,
MOVEQ, MOVEQ,

View File

@@ -51,7 +51,8 @@ template <Model model, typename BusHandler> class Executor {
void link(uint32_t &address, uint32_t offset); void link(uint32_t &address, uint32_t offset);
void unlink(uint32_t &address); void unlink(uint32_t &address);
template <typename IntT> void movep(Preinstruction instruction, uint32_t source, uint32_t dest); template <typename IntT> void movep(Preinstruction instruction, uint32_t source, uint32_t dest);
template <typename IntT> void movem(Preinstruction instruction, uint32_t source, uint32_t dest); template <typename IntT> void movem_toM(Preinstruction instruction, uint32_t source, uint32_t dest);
template <typename IntT> void movem_toR(Preinstruction instruction, uint32_t source, uint32_t dest);
// TODO: ownership of this shouldn't be here. // TODO: ownership of this shouldn't be here.
struct Registers { struct Registers {

View File

@@ -439,79 +439,81 @@ void Executor<model, BusHandler>::movep(Preinstruction instruction, uint32_t sou
template <Model model, typename BusHandler> template <Model model, typename BusHandler>
template <typename IntT> template <typename IntT>
void Executor<model, BusHandler>::movem(Preinstruction instruction, uint32_t source, uint32_t dest) { void Executor<model, BusHandler>::movem_toM(Preinstruction instruction, uint32_t source, uint32_t dest) {
if(instruction.mode<0>() == AddressingMode::ImmediateData) { // Move registers to memory. This is the only permitted use of the predecrement mode,
// Move registers to memory. This is the only permitted use of the predecrement mode, // which reverses output order.
// which reverses output order.
if(instruction.mode<1>() == AddressingMode::AddressRegisterIndirectWithPredecrement) {
// 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:
//
// "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)."
registers_[8 + instruction.reg<1>()].l += 2;
uint32_t reg = registers_[8 + instruction.reg<1>()].l; if(instruction.mode<1>() == AddressingMode::AddressRegisterIndirectWithPredecrement) {
int index = 15; // 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:
//
// "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)."
registers_[8 + instruction.reg<1>()].l += 2;
while(source) { uint32_t reg = registers_[8 + instruction.reg<1>()].l;
if(source & 1) { int index = 15;
reg -= sizeof(IntT);
bus_handler_.template write<IntT>(reg, IntT(registers_[index].l));
}
--index;
source >>= 1;
}
registers_[8 + instruction.reg<1>()].l = reg;
return;
}
int index = 0;
while(source) { while(source) {
if(source & 1) { if(source & 1) {
bus_handler_.template write<IntT>(dest, IntT(registers_[index].l)); reg -= sizeof(IntT);
dest += sizeof(IntT); bus_handler_.template write<IntT>(reg, IntT(registers_[index].l));
} }
++index; --index;
source >>= 1; source >>= 1;
} }
} else { registers_[8 + instruction.reg<1>()].l = reg;
// Move memory to registers. return;
// }
// Another 68000 convention has been broken here; the instruction form is:
// MOVEM <ea>, # int index = 0;
// ... but the instruction is encoded as [MOVEM] [#] [ea]. while(source) {
// if(source & 1) {
// TODO: solve this. bus_handler_.template write<IntT>(dest, IntT(registers_[index].l));
int index = 0; dest += sizeof(IntT);
while(dest) { }
if(dest & 1) { ++index;
if constexpr (sizeof(IntT) == 2) { source >>= 1;
registers_[index].l = int16_t(bus_handler_.template read<uint16_t>(source)); }
} else { }
registers_[index].l = bus_handler_.template read<uint32_t>(source);
} template <Model model, typename BusHandler>
source += sizeof(IntT); template <typename IntT>
void Executor<model, BusHandler>::movem_toR(Preinstruction instruction, uint32_t source, uint32_t dest) {
// Move memory to registers.
//
// A 68000 convention has been broken here; the instruction form is:
// MOVEM <ea>, #
// ... but the instruction is encoded as [MOVEM] [#] [ea].
//
// This project's decoder decodes as #, <ea>.
int index = 0;
while(source) {
if(source & 1) {
if constexpr (sizeof(IntT) == 2) {
registers_[index].l = int16_t(bus_handler_.template read<uint16_t>(dest));
} else {
registers_[index].l = bus_handler_.template read<uint32_t>(dest);
} }
++index; dest += sizeof(IntT);
dest >>= 1;
} }
++index;
source >>= 1;
}
if(instruction.mode<0>() == AddressingMode::AddressRegisterIndirectWithPostincrement) { if(instruction.mode<1>() == AddressingMode::AddressRegisterIndirectWithPostincrement) {
// If the effective address is specified by the postincrement mode ... // "If the effective address is specified by the postincrement mode ...
// [i]f the addressing register is also loaded from memory, the memory value is // [i]f the addressing register is also loaded from memory, the memory value is
// ignored and the register is written with the postincremented effective address. // ignored and the register is written with the postincremented effective address."
registers_[8 + instruction.reg<0>()].l = source; registers_[8 + instruction.reg<1>()].l = source;
}
} }
} }

View File

@@ -1184,12 +1184,20 @@ template <
flow_controller.template movep<uint16_t>(instruction, src.l, dest.l); flow_controller.template movep<uint16_t>(instruction, src.l, dest.l);
break; break;
case Operation::MOVEMl: case Operation::MOVEMtoRl:
flow_controller.template movem<uint32_t>(instruction, src.l, dest.l); flow_controller.template movem_toR<uint32_t>(instruction, src.l, dest.l);
break; break;
case Operation::MOVEMw: case Operation::MOVEMtoMl:
flow_controller.template movem<uint16_t>(instruction, src.l, dest.l); flow_controller.template movem_toM<uint32_t>(instruction, src.l, dest.l);
break;
case Operation::MOVEMtoRw:
flow_controller.template movem_toR<uint16_t>(instruction, src.l, dest.l);
break;
case Operation::MOVEMtoMw:
flow_controller.template movem_toM<uint16_t>(instruction, src.l, dest.l);
break; break;
/* /*

View File

@@ -72,7 +72,9 @@ enum class Operation: uint8_t {
ROXLb, ROXLw, ROXLl, ROXLm, ROXLb, ROXLw, ROXLl, ROXLm,
ROXRb, ROXRw, ROXRl, ROXRm, ROXRb, ROXRw, ROXRl, ROXRm,
MOVEMl, MOVEMw, MOVEMtoRl, MOVEMtoRw,
MOVEMtoMl, MOVEMtoMw,
MOVEPl, MOVEPw, MOVEPl, MOVEPw,
ANDb, ANDw, ANDl, ANDb, ANDw, ANDl,
@@ -192,7 +194,10 @@ constexpr DataSize operand_size(Operation operation) {
case Operation::RORw: case Operation::RORm: case Operation::RORw: case Operation::RORm:
case Operation::ROXLw: case Operation::ROXLm: case Operation::ROXLw: case Operation::ROXLm:
case Operation::ROXRw: case Operation::ROXRm: case Operation::ROXRw: case Operation::ROXRm:
case Operation::MOVEMw: case Operation::MOVEMl: case Operation::MOVEMtoRw:
case Operation::MOVEMtoRl:
case Operation::MOVEMtoMw:
case Operation::MOVEMtoMl:
case Operation::MOVEPw: case Operation::MOVEPw:
case Operation::ANDw: case Operation::EORw: case Operation::ANDw: case Operation::EORw:
case Operation::NOTw: case Operation::ORw: case Operation::NOTw: case Operation::ORw:
@@ -266,9 +271,10 @@ template <Model model, Operation t_operation = Operation::Undefined> uint8_t ope
// (which means that source and destination will appear as their effective addresses) // (which means that source and destination will appear as their effective addresses)
// //
case Operation::PEA: case Operation::PEA:
case Operation::JMP: case Operation::JSR: case Operation::JMP: case Operation::JSR:
case Operation::MOVEPw: case Operation::MOVEPl: case Operation::MOVEPw: case Operation::MOVEPl:
case Operation::MOVEMw: case Operation::MOVEMl: case Operation::MOVEMtoMw: case Operation::MOVEMtoMl:
case Operation::MOVEMtoRw: case Operation::MOVEMtoRl:
return 0; return 0;
// //

View File

@@ -73,7 +73,7 @@
- (void)setUp { - (void)setUp {
// To limit tests run to a subset of files and/or of tests, uncomment and fill in below. // To limit tests run to a subset of files and/or of tests, uncomment and fill in below.
_fileSet = [NSSet setWithArray:@[@"movem.json"]]; _fileSet = [NSSet setWithArray:@[@"movem.json"]];
_testSet = [NSSet setWithArray:@[@"MOVEM 00a8 (0)"]]; // _testSet = [NSSet setWithArray:@[@"MOVEM 00a8 (0)"]];
// _fileSet = [NSSet setWithArray:@[@"jmp_jsr.json"]]; // _fileSet = [NSSet setWithArray:@[@"jmp_jsr.json"]];
// _testSet = [NSSet setWithArray:@[@"CHK 41a8"]]; // _testSet = [NSSet setWithArray:@[@"CHK 41a8"]];
} }

View File

@@ -246,8 +246,11 @@ template <int index> NSString *operand(Preinstruction instruction, uint16_t opco
case Operation::ROXRl: instruction = @"ROXR.l"; break; case Operation::ROXRl: instruction = @"ROXR.l"; break;
case Operation::ROXRm: instruction = @"ROXR.w"; break; case Operation::ROXRm: instruction = @"ROXR.w"; break;
case Operation::MOVEMl: instruction = @"MOVEM.l"; break; // TODO: switch operand order for toR.
case Operation::MOVEMw: instruction = @"MOVEM.w"; break; case Operation::MOVEMtoMl: instruction = @"MOVEM.l"; break;
case Operation::MOVEMtoMw: instruction = @"MOVEM.w"; break;
case Operation::MOVEMtoRl: instruction = @"MOVEM.l"; break;
case Operation::MOVEMtoRw: instruction = @"MOVEM.w"; break;
case Operation::MOVEPl: instruction = @"MOVEP.l"; break; case Operation::MOVEPl: instruction = @"MOVEP.l"; break;
case Operation::MOVEPw: instruction = @"MOVEP.w"; break; case Operation::MOVEPw: instruction = @"MOVEP.w"; break;