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:
@@ -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
|
|||||||
// b0–b2 and b3–b5: effective address.
|
// b0–b2 and b3–b5: 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);
|
||||||
|
@@ -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,
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@@ -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"]];
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
|
Reference in New Issue
Block a user