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:
parent
fed79a116f
commit
607ddd2f78
@ -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
|
||||
// b0–b2 and b3–b5: 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);
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
||||
//
|
||||
|
@ -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"]];
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user