1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-18 08:31:04 +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) {
case MOVEMtoRl: case MOVEMtoMl: return Operation::MOVEMl;
case MOVEMtoRw: case MOVEMtoMw: return Operation::MOVEMw;
case MOVEPtoRl: case MOVEPtoMl: return Operation::MOVEPl;
case MOVEPtoRw: case MOVEPtoMw: return Operation::MOVEPw;
@ -456,16 +454,16 @@ template <uint8_t op> uint32_t Predecoder<model>::invalid_operands() {
An
>::value;
case MOVEMtoMw: case MOVEMtoMl:
case OpT(Operation::MOVEMtoMw): case OpT(Operation::MOVEMtoMl):
return ~TwoOperandMask<
Imm,
Ind | PreDec | d16An | d8AnXn | XXXw | XXXl
>::value;
case MOVEMtoRw: case MOVEMtoRl:
case OpT(Operation::MOVEMtoRw): case OpT(Operation::MOVEMtoRl):
return ~TwoOperandMask<
Ind | PostInc | d16An | d8AnXn | XXXw | XXXl | d16PC | d8PCXn,
Imm
Imm,
Ind | PostInc | d16An | d8AnXn | XXXw | XXXl | d16PC | d8PCXn
>::value;
case MOVEPtoRl: case MOVEPtoRw:
@ -796,16 +794,12 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
// b0b2 and b3b5: effective address.
// [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>(
AddressingMode::ImmediateData, 0,
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
//
@ -1087,10 +1081,10 @@ Preinstruction Predecoder<model>::decode4(uint16_t instruction) {
case 0x840: Decode(Op::PEA);
// 4-128 (p232)
case 0x880: Decode(MOVEMtoMw);
case 0x8c0: Decode(MOVEMtoMl);
case 0xc80: Decode(MOVEMtoRw);
case 0xcc0: Decode(MOVEMtoRl);
case 0x880: Decode(Op::MOVEMtoMw);
case 0x8c0: Decode(Op::MOVEMtoMl);
case 0xc80: Decode(Op::MOVEMtoRw);
case 0xcc0: Decode(Op::MOVEMtoRl);
// 4-192 (p296)
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
// extension of @c Operation.
enum ExtendedOperation: OpT {
MOVEMtoRl = uint8_t(Operation::Max) + 1, MOVEMtoRw,
MOVEMtoMl, MOVEMtoMw,
MOVEPtoRl, MOVEPtoRw,
MOVEPtoRl = uint8_t(Operation::Max) + 1, MOVEPtoRw,
MOVEPtoMl, MOVEPtoMw,
MOVEQ,

View File

@ -51,7 +51,8 @@ template <Model model, typename BusHandler> class Executor {
void link(uint32_t &address, uint32_t offset);
void unlink(uint32_t &address);
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.
struct Registers {

View File

@ -439,79 +439,81 @@ void Executor<model, BusHandler>::movep(Preinstruction instruction, uint32_t sou
template <Model model, typename BusHandler>
template <typename IntT>
void Executor<model, BusHandler>::movem(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,
// 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;
void Executor<model, BusHandler>::movem_toM(Preinstruction instruction, uint32_t source, uint32_t dest) {
// Move registers to memory. This is the only permitted use of the predecrement mode,
// which reverses output order.
uint32_t reg = registers_[8 + instruction.reg<1>()].l;
int index = 15;
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;
while(source) {
if(source & 1) {
reg -= sizeof(IntT);
bus_handler_.template write<IntT>(reg, IntT(registers_[index].l));
}
--index;
source >>= 1;
}
uint32_t reg = registers_[8 + instruction.reg<1>()].l;
int index = 15;
registers_[8 + instruction.reg<1>()].l = reg;
return;
}
int index = 0;
while(source) {
if(source & 1) {
bus_handler_.template write<IntT>(dest, IntT(registers_[index].l));
dest += sizeof(IntT);
reg -= sizeof(IntT);
bus_handler_.template write<IntT>(reg, IntT(registers_[index].l));
}
++index;
--index;
source >>= 1;
}
} else {
// Move memory to registers.
//
// Another 68000 convention has been broken here; the instruction form is:
// MOVEM <ea>, #
// ... but the instruction is encoded as [MOVEM] [#] [ea].
//
// TODO: solve this.
int index = 0;
while(dest) {
if(dest & 1) {
if constexpr (sizeof(IntT) == 2) {
registers_[index].l = int16_t(bus_handler_.template read<uint16_t>(source));
} else {
registers_[index].l = bus_handler_.template read<uint32_t>(source);
}
source += sizeof(IntT);
registers_[8 + instruction.reg<1>()].l = reg;
return;
}
int index = 0;
while(source) {
if(source & 1) {
bus_handler_.template write<IntT>(dest, IntT(registers_[index].l));
dest += sizeof(IntT);
}
++index;
source >>= 1;
}
}
template <Model model, typename BusHandler>
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 >>= 1;
dest += sizeof(IntT);
}
++index;
source >>= 1;
}
if(instruction.mode<0>() == AddressingMode::AddressRegisterIndirectWithPostincrement) {
// If the effective address is specified by the postincrement mode ...
// [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.
if(instruction.mode<1>() == AddressingMode::AddressRegisterIndirectWithPostincrement) {
// "If the effective address is specified by the postincrement mode ...
// [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."
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);
break;
case Operation::MOVEMl:
flow_controller.template movem<uint32_t>(instruction, src.l, dest.l);
case Operation::MOVEMtoRl:
flow_controller.template movem_toR<uint32_t>(instruction, src.l, dest.l);
break;
case Operation::MOVEMw:
flow_controller.template movem<uint16_t>(instruction, src.l, dest.l);
case Operation::MOVEMtoMl:
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;
/*

View File

@ -72,7 +72,9 @@ enum class Operation: uint8_t {
ROXLb, ROXLw, ROXLl, ROXLm,
ROXRb, ROXRw, ROXRl, ROXRm,
MOVEMl, MOVEMw,
MOVEMtoRl, MOVEMtoRw,
MOVEMtoMl, MOVEMtoMw,
MOVEPl, MOVEPw,
ANDb, ANDw, ANDl,
@ -192,7 +194,10 @@ constexpr DataSize operand_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::MOVEMl:
case Operation::MOVEMtoRw:
case Operation::MOVEMtoRl:
case Operation::MOVEMtoMw:
case Operation::MOVEMtoMl:
case Operation::MOVEPw:
case Operation::ANDw: case Operation::EORw:
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)
//
case Operation::PEA:
case Operation::JMP: case Operation::JSR:
case Operation::MOVEPw: case Operation::MOVEPl:
case Operation::MOVEMw: case Operation::MOVEMl:
case Operation::JMP: case Operation::JSR:
case Operation::MOVEPw: case Operation::MOVEPl:
case Operation::MOVEMtoMw: case Operation::MOVEMtoMl:
case Operation::MOVEMtoRw: case Operation::MOVEMtoRl:
return 0;
//

View File

@ -73,7 +73,7 @@
- (void)setUp {
// To limit tests run to a subset of files and/or of tests, uncomment and fill in below.
_fileSet = [NSSet setWithArray:@[@"movem.json"]];
_testSet = [NSSet setWithArray:@[@"MOVEM 00a8 (0)"]];
// _testSet = [NSSet setWithArray:@[@"MOVEM 00a8 (0)"]];
// _fileSet = [NSSet setWithArray:@[@"jmp_jsr.json"]];
// _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::ROXRm: instruction = @"ROXR.w"; break;
case Operation::MOVEMl: instruction = @"MOVEM.l"; break;
case Operation::MOVEMw: instruction = @"MOVEM.w"; break;
// TODO: switch operand order for toR.
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::MOVEPw: instruction = @"MOVEP.w"; break;