1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-20 01:29:01 +00:00

Merge pull request #1025 from TomHarte/AndValidate

Switch to validation via a simple AND mask.
This commit is contained in:
Thomas Harte 2022-04-25 16:29:23 -04:00 committed by GitHub
commit 4e5a6c89b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 364 additions and 417 deletions

View File

@ -37,6 +37,28 @@ constexpr AddressingMode combined_mode(int mode, int reg) {
return modes[use_reg];
}
template <AddressingMode F> struct Mask {
static constexpr uint32_t value = uint32_t(1 << int(F));
};
static constexpr uint32_t NoOperand = Mask<AddressingMode::None>::value;
template <uint32_t first, uint32_t second> struct TwoOperandMask {
static constexpr uint32_t value = ((first << 16) & 0xffff0000) | (second & 0x0000ffff);
};
template <uint32_t first> struct OneOperandMask {
static constexpr uint32_t value = TwoOperandMask<first, NoOperand>::value;
};
struct NoOperandMask {
static constexpr uint32_t value = OneOperandMask<NoOperand>::value;
};
uint32_t operand_mask(Preinstruction instr) {
return uint32_t((0x1'0000 << int(instr.mode<0>())) | (0x0'0001 << int(instr.mode<1>())));
}
}
// MARK: - Instruction decoders.
@ -109,382 +131,337 @@ constexpr Operation Predecoder<model>::operation(OpT op) {
case ORtoRw: case ORtoMw: return Operation::ORw;
case ORtoRl: case ORtoMl: return Operation::ORl;
case EXGRtoR: case EXGAtoA: case EXGRtoA:
return Operation::EXG;
default: break;
}
return Operation::Undefined;
}
template <Model model>
template <uint8_t op> uint32_t Predecoder<model>::invalid_operands() {
constexpr auto Dn = Mask< AddressingMode::DataRegisterDirect >::value;
constexpr auto An = Mask< AddressingMode::AddressRegisterDirect >::value;
constexpr auto Ind = Mask< AddressingMode::AddressRegisterIndirect >::value;
constexpr auto PostInc = Mask< AddressingMode::AddressRegisterIndirectWithPostincrement >::value;
constexpr auto PreDec = Mask< AddressingMode::AddressRegisterIndirectWithPredecrement >::value;
constexpr auto d16An = Mask< AddressingMode::AddressRegisterIndirectWithDisplacement >::value;
constexpr auto d8AnXn = Mask< AddressingMode::AddressRegisterIndirectWithIndex8bitDisplacement >::value;
constexpr auto XXXw = Mask< AddressingMode::AbsoluteShort >::value;
constexpr auto XXXl = Mask< AddressingMode::AbsoluteLong >::value;
constexpr auto d16PC = Mask< AddressingMode::ProgramCounterIndirectWithDisplacement >::value;
constexpr auto d8PCXn = Mask< AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement >::value;
constexpr auto Imm = Mask< AddressingMode::ImmediateData >::value;
constexpr auto Quick = Mask< AddressingMode::Quick >::value;
// A few recurring combinations; terminology is directly from
// the Programmers' Reference Manual.
//
// All modes: the complete set (other than Quick).
//
static constexpr auto AllModes = Dn | An | Ind | PostInc | PreDec | d16An | d8AnXn | XXXw | XXXl | d16PC | d8PCXn | Imm;
static constexpr auto AllModesNoAn = AllModes & ~An;
//
// Alterable addressing modes (with and without AddressRegisterDirect).
//
static constexpr auto AlterableAddressingModes = Dn | An | Ind | PostInc | PreDec | d16An | d8AnXn | XXXw | XXXl;
static constexpr auto AlterableAddressingModesNoAn = AlterableAddressingModes & ~An;
//
// Control [flow] addressing modes.
//
static constexpr auto ControlAddressingModes = Ind | d16An | d8AnXn | XXXw | XXXl | d16PC | d8PCXn;
switch(op) {
default: return NoOperandMask::value;
case OpT(Operation::ABCD):
case OpT(Operation::ADDXb): case OpT(Operation::ADDXw): case OpT(Operation::ADDXl):
return ~TwoOperandMask<
Dn | PreDec,
Dn | PreDec
>::value;
case ADDtoRb:
case ANDtoRb: case ANDtoRw: case ANDtoRl:
case OpT(Operation::CHK):
case OpT(Operation::CMPb):
case OpT(Operation::DIVU): case OpT(Operation::DIVS):
case ORtoRb: case ORtoRw: case ORtoRl:
case OpT(Operation::MULU): case OpT(Operation::MULS):
case SUBtoRb:
return ~TwoOperandMask<
AllModesNoAn,
Dn
>::value;
case ADDtoRw: case ADDtoRl:
case OpT(Operation::CMPw): case OpT(Operation::CMPl):
case SUBtoRw: case SUBtoRl:
return ~TwoOperandMask<
AllModes,
Dn
>::value;
case ADDtoMb: case ADDtoMw: case ADDtoMl:
case ANDtoMb: case ANDtoMw: case ANDtoMl:
case ORtoMb: case ORtoMw: case ORtoMl:
case SUBtoMb: case SUBtoMw: case SUBtoMl:
return ~TwoOperandMask<
Dn,
Ind | PostInc | PreDec | d16An | d8AnXn | XXXw | XXXl
>::value;
case OpT(Operation::ADDAw): case OpT(Operation::ADDAl):
case OpT(Operation::CMPAw): case OpT(Operation::CMPAl):
case OpT(Operation::SUBAw): case OpT(Operation::SUBAl):
case OpT(Operation::MOVEAw): case OpT(Operation::MOVEAl):
return ~TwoOperandMask<
AllModes,
An
>::value;
case ADDIb: case ADDIl: case ADDIw:
case ANDIb: case ANDIl: case ANDIw:
case BCHGI: case BCLRI: case BSETI:
case EORIb: case EORIw: case EORIl:
case ORIb: case ORIw: case ORIl:
case SUBIb: case SUBIl: case SUBIw:
return ~TwoOperandMask<
Imm,
AlterableAddressingModesNoAn
>::value;
case ADDQb:
case SUBQb:
return ~TwoOperandMask<
Quick,
AlterableAddressingModesNoAn
>::value;
case ADDQw: case ADDQl:
case SUBQw: case SUBQl:
return ~TwoOperandMask<
Quick,
AlterableAddressingModes
>::value;
case OpT(Operation::MOVEb):
return ~TwoOperandMask<
AllModesNoAn,
AlterableAddressingModesNoAn
>::value;
case OpT(Operation::MOVEw): case OpT(Operation::MOVEl):
return ~TwoOperandMask<
AllModes,
AlterableAddressingModesNoAn
>::value;
case OpT(Operation::ANDItoCCR): case OpT(Operation::ANDItoSR):
case OpT(Operation::Bccw): case OpT(Operation::Bccl):
case OpT(Operation::BSRl): case OpT(Operation::BSRw):
case OpT(Operation::EORItoCCR): case OpT(Operation::EORItoSR):
case OpT(Operation::ORItoCCR): case OpT(Operation::ORItoSR):
case OpT(Operation::STOP):
return ~OneOperandMask<
Imm
>::value;
case OpT(Operation::ASLb): case OpT(Operation::ASLw): case OpT(Operation::ASLl):
case OpT(Operation::ASRb): case OpT(Operation::ASRw): case OpT(Operation::ASRl):
case OpT(Operation::LSLb): case OpT(Operation::LSLw): case OpT(Operation::LSLl):
case OpT(Operation::LSRb): case OpT(Operation::LSRw): case OpT(Operation::LSRl):
case OpT(Operation::ROLb): case OpT(Operation::ROLw): case OpT(Operation::ROLl):
case OpT(Operation::RORb): case OpT(Operation::RORw): case OpT(Operation::RORl):
case OpT(Operation::ROXLb): case OpT(Operation::ROXLw): case OpT(Operation::ROXLl):
case OpT(Operation::ROXRb): case OpT(Operation::ROXRw): case OpT(Operation::ROXRl):
return ~TwoOperandMask<
Quick | Dn,
Dn
>::value;
case OpT(Operation::ASLm):
case OpT(Operation::ASRm):
case OpT(Operation::LSLm):
case OpT(Operation::LSRm):
case OpT(Operation::ROLm):
case OpT(Operation::RORm):
case OpT(Operation::ROXLm):
case OpT(Operation::ROXRm):
return ~OneOperandMask<
Ind | PostInc | PreDec | d16An | d8AnXn | XXXw | XXXl
>::value;
case OpT(Operation::Bccb):
case OpT(Operation::BSRb):
case OpT(Operation::TRAP):
return ~OneOperandMask<
Quick
>::value;
case OpT(Operation::BCHG):
case OpT(Operation::BCLR):
case OpT(Operation::BSET):
case OpT(Operation::EORb): case OpT(Operation::EORw): case OpT(Operation::EORl):
return ~TwoOperandMask<
Dn,
AlterableAddressingModesNoAn
>::value;
case OpT(Operation::BTST):
return ~TwoOperandMask<
Dn,
AllModesNoAn
>::value;
case CMPIb: case CMPIl: case CMPIw:
if constexpr (model == Model::M68000) {
return ~TwoOperandMask<
Imm,
Dn | Ind | PostInc | PreDec | d16An | d8AnXn | XXXw | XXXl
>::value;
}
[[fallthrough]];
case BTSTI:
return ~TwoOperandMask<
Imm,
Dn | Ind | PostInc | PreDec | d16An | d8AnXn | XXXw | XXXl | d16PC | d8PCXn
>::value;
case OpT(Operation::CLRb): case OpT(Operation::CLRw): case OpT(Operation::CLRl):
case OpT(Operation::NBCD):
case OpT(Operation::MOVEfromSR):
case OpT(Operation::NEGXb): case OpT(Operation::NEGXw): case OpT(Operation::NEGXl):
case OpT(Operation::NEGb): case OpT(Operation::NEGw): case OpT(Operation::NEGl):
case OpT(Operation::NOTb): case OpT(Operation::NOTw): case OpT(Operation::NOTl):
case OpT(Operation::Scc):
case OpT(Operation::TAS):
return ~OneOperandMask<
AlterableAddressingModesNoAn
>::value;
case OpT(Operation::TSTb):
if constexpr (model == Model::M68000) {
return ~OneOperandMask<
AlterableAddressingModesNoAn
>::value;
}
[[fallthrough]];
case OpT(Operation::MOVEtoCCR):
case OpT(Operation::MOVEtoSR):
return ~OneOperandMask<
AllModesNoAn
>::value;
case OpT(Operation::TSTw): case OpT(Operation::TSTl):
if constexpr (model == Model::M68000) {
return ~OneOperandMask<
AlterableAddressingModesNoAn
>::value;
} else {
return ~OneOperandMask<
AllModes
>::value;
}
case CMPMb: case CMPMw: case CMPMl:
return ~TwoOperandMask<
PostInc,
PostInc
>::value;
case OpT(Operation::DBcc):
return ~TwoOperandMask<
Dn,
Imm
>::value;
case EXGRtoR:
return ~TwoOperandMask<
Dn,
Dn
>::value;
case EXGAtoA:
return ~TwoOperandMask<
An,
An
>::value;
case EXGRtoA:
return ~TwoOperandMask<
Dn,
An
>::value;
case OpT(Operation::EXTbtow): case OpT(Operation::EXTwtol):
case OpT(Operation::SWAP):
return ~OneOperandMask<
Dn
>::value;
case OpT(Operation::JMP):
case OpT(Operation::JSR):
case OpT(Operation::PEA):
return ~OneOperandMask<
ControlAddressingModes
>::value;
case OpT(Operation::LEA):
return ~TwoOperandMask<
ControlAddressingModes,
An
>::value;
case OpT(Operation::LINKw):
return ~TwoOperandMask<
An,
Imm
>::value;
case OpT(Operation::NOP):
case OpT(Operation::RTE):
case OpT(Operation::RTS):
case OpT(Operation::TRAPV):
case OpT(Operation::RTR):
return ~NoOperandMask::value;
case OpT(Operation::UNLINK):
case OpT(Operation::MOVEtoUSP):
case OpT(Operation::MOVEfromUSP):
return ~OneOperandMask<
An
>::value;
case MOVEMtoMw: case MOVEMtoMl:
return ~TwoOperandMask<
Imm,
Ind | PreDec | d16An | d8AnXn | XXXw | XXXl
>::value;
case MOVEMtoRw: case MOVEMtoRl:
return ~TwoOperandMask<
Ind | PostInc | d16An | d8AnXn | XXXw | XXXl | d16PC | d8PCXn,
Imm
>::value;
}
}
/// Provides a post-decoding validation step — primarily ensures that the prima facie addressing modes are supported by the operation.
// TODO: once complete and working, see how ugly it would be to incorpoate these tests into the main
// decoding switches.
template <Model model>
template <uint8_t op, bool validate> Preinstruction Predecoder<model>::validated(Preinstruction original) {
if constexpr (!validate) {
return original;
}
switch(op) {
default: return original;
// NBCD.
case OpT(Operation::NBCD):
case OpT(Operation::MOVEfromSR):
case OpT(Operation::TAS):
switch(original.mode<0>()) {
default: return original;
case AddressingMode::AddressRegisterDirect:
case AddressingMode::ProgramCounterIndirectWithDisplacement:
case AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement:
case AddressingMode::ImmediateData:
case AddressingMode::None:
return Preinstruction();
}
case OpT(Operation::MOVEtoCCR):
case OpT(Operation::MOVEtoSR):
switch(original.mode<0>()) {
default: return original;
case AddressingMode::AddressRegisterDirect:
case AddressingMode::None:
return Preinstruction();
}
// The various immediates.
case EORIb: case EORIl: case EORIw:
case ORIb: case ORIl: case ORIw:
case ANDIb: case ANDIl: case ANDIw:
case SUBIb: case SUBIl: case SUBIw:
case ADDIb: case ADDIl: case ADDIw:
switch(original.mode<1>()) {
default: return original;
case AddressingMode::AddressRegisterDirect:
case AddressingMode::ImmediateData:
case AddressingMode::ProgramCounterIndirectWithDisplacement:
case AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement:
case AddressingMode::None:
return Preinstruction();
}
case CMPIb: case CMPIl: case CMPIw:
switch(original.mode<1>()) {
default: return original;
case AddressingMode::ProgramCounterIndirectWithDisplacement:
case AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement:
if constexpr (model >= Model::M68010) {
return original;
}
[[fallthrough]];
case AddressingMode::AddressRegisterDirect:
case AddressingMode::ImmediateData:
case AddressingMode::None:
return Preinstruction();
}
// ADD, SUB, MOVE, MOVEA
case ADDQb: case ADDQw: case ADDQl:
case SUBQb: case SUBQw: case SUBQl:
case OpT(Operation::MOVEb): case OpT(Operation::MOVEw): case OpT(Operation::MOVEl):
case OpT(Operation::MOVEAw): case OpT(Operation::MOVEAl):
case OpT(Operation::ANDb): case OpT(Operation::ANDw): case OpT(Operation::ANDl):
case OpT(Operation::EORb): case OpT(Operation::EORw): case OpT(Operation::EORl):
case OpT(Operation::ORb): case OpT(Operation::ORw): case OpT(Operation::ORl): {
// TODO: I'm going to need get-size-by-operation elsewhere; use that here when implemented.
constexpr bool is_byte =
op == OpT(Operation::MOVEb) || op == ADDQb || op == SUBQb || op == OpT(Operation::EORb);
switch(original.mode<0>()) {
default: break;
case AddressingMode::AddressRegisterDirect:
if constexpr (!is_byte) {
break;
}
[[fallthrough]];
case AddressingMode::None:
return Preinstruction();
}
switch(original.mode<1>()) {
default: return original;
case AddressingMode::AddressRegisterDirect:
if constexpr (!is_byte) {
return original;
}
[[fallthrough]];
case AddressingMode::ImmediateData:
case AddressingMode::ProgramCounterIndirectWithDisplacement:
case AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement:
case AddressingMode::None:
return Preinstruction();
}
}
case ANDtoRb: case ANDtoRw: case ANDtoRl:
case ORtoRb: case ORtoRw: case ORtoRl:
case SUBtoRb: case SUBtoRw: case SUBtoRl:
case ADDtoRb: case ADDtoRw: case ADDtoRl: {
constexpr bool is_byte = op == ADDtoRb || op == SUBtoRb || op == SUBtoRb || op == ADDtoRb;
switch(original.mode<0>()) {
default: return original;
case AddressingMode::AddressRegisterDirect:
if constexpr (!is_byte) {
return original;
}
[[fallthrough]];
case AddressingMode::None:
return Preinstruction();
}
}
case ADDtoMb: case ADDtoMw: case ADDtoMl:
case SUBtoMb: case SUBtoMw: case SUBtoMl:
case ANDtoMb: case ANDtoMw: case ANDtoMl:
case ORtoMb: case ORtoMw: case ORtoMl: {
// TODO: I'm going to need get-size-by-operation elsewhere; use that here when implemented.
constexpr bool is_byte = op == ADDtoMb || op == SUBtoMb || op == ANDtoMb || op == ORtoMb;
switch(original.mode<0>()) {
default: break;
case AddressingMode::AddressRegisterDirect:
if constexpr (!is_byte) {
break;
}
[[fallthrough]];
case AddressingMode::None:
return Preinstruction();
}
switch(original.mode<1>()) {
default: return original;
case AddressingMode::DataRegisterDirect:
// TODO: this is per the documentation, but is it true?
if constexpr (op == ANDtoMb || op == ANDtoMw || op == ANDtoMl || op == ORtoMb || op == ORtoMw || op == ORtoMl) {
return Preinstruction();
}
case AddressingMode::AddressRegisterDirect:
if constexpr (!is_byte) {
return original;
}
[[fallthrough]];
case AddressingMode::ImmediateData:
case AddressingMode::ProgramCounterIndirectWithDisplacement:
case AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement:
case AddressingMode::None:
return Preinstruction();
}
}
case OpT(Operation::NOTb): case OpT(Operation::NOTw): case OpT(Operation::NOTl):
switch(original.mode<0>()) {
default: return original;
case AddressingMode::AddressRegisterDirect:
case AddressingMode::ImmediateData:
case AddressingMode::ProgramCounterIndirectWithDisplacement:
case AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement:
case AddressingMode::None:
return Preinstruction();
}
// ADDA, SUBA.
case OpT(Operation::ADDAw): case OpT(Operation::ADDAl):
case OpT(Operation::SUBAw): case OpT(Operation::SUBAl):
switch(original.mode<0>()) {
default: break;
case AddressingMode::None:
return Preinstruction();
}
switch(original.mode<1>()) {
default: return original;
case AddressingMode::ImmediateData:
case AddressingMode::ProgramCounterIndirectWithDisplacement:
case AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement:
case AddressingMode::None:
return Preinstruction();
}
// LEA, PEA
case OpT(Operation::LEA): case OpT(Operation::PEA):
switch(original.mode<0>()) {
default: return original;
case AddressingMode::None:
case AddressingMode::DataRegisterDirect:
case AddressingMode::AddressRegisterDirect:
case AddressingMode::AddressRegisterIndirectWithPostincrement:
case AddressingMode::AddressRegisterIndirectWithPredecrement:
case AddressingMode::ImmediateData:
return Preinstruction();
}
case OpT(Operation::BTST):
switch(original.mode<1>()) {
default: return original;
case AddressingMode::None:
case AddressingMode::AddressRegisterDirect:
return Preinstruction();
}
case OpT(Operation::BCHG):
case OpT(Operation::BSET): case OpT(Operation::BCLR):
case BCHGI: case BSETI: case BCLRI:
switch(original.mode<1>()) {
default: return original;
case AddressingMode::None:
case AddressingMode::AddressRegisterDirect:
case AddressingMode::ProgramCounterIndirectWithDisplacement:
case AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement:
case AddressingMode::ImmediateData:
return Preinstruction();
}
case BTSTI:
switch(original.mode<1>()) {
default: return original;
case AddressingMode::None:
case AddressingMode::AddressRegisterDirect:
case AddressingMode::ImmediateData:
return Preinstruction();
}
case OpT(Operation::TSTb): case OpT(Operation::TSTw): case OpT(Operation::TSTl):
switch(original.mode<0>()) {
default: return original;
case AddressingMode::AddressRegisterDirect:
if constexpr (op == OpT(Operation::TSTb)) {
return Preinstruction();
}
[[fallthrough]];
case AddressingMode::ImmediateData:
if constexpr (model < Model::M68020) {
return Preinstruction();
}
return original;
case AddressingMode::ProgramCounterIndirectWithDisplacement:
case AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement:
if constexpr (model >= Model::M68010) {
return original;
}
[[fallthrough]];
case AddressingMode::None:
return Preinstruction();
}
case OpT(Operation::CMPAw): case OpT(Operation::CMPAl):
case OpT(Operation::CMPw): case OpT(Operation::CMPl):
switch(original.mode<0>()) {
default: return original;
case AddressingMode::None:
return Preinstruction();
}
case OpT(Operation::CMPb):
switch(original.mode<0>()) {
default: return original;
case AddressingMode::None:
case AddressingMode::AddressRegisterDirect:
return Preinstruction();
}
case OpT(Operation::JSR): case OpT(Operation::JMP):
switch(original.mode<0>()) {
default: return original;
case AddressingMode::DataRegisterDirect:
case AddressingMode::AddressRegisterDirect:
case AddressingMode::AddressRegisterIndirectWithPostincrement:
case AddressingMode::AddressRegisterIndirectWithPredecrement:
case AddressingMode::ImmediateData:
case AddressingMode::None:
return Preinstruction();
}
case OpT(Operation::Scc):
case OpT(Operation::NEGXb): case OpT(Operation::NEGXw): case OpT(Operation::NEGXl):
case OpT(Operation::CLRb): case OpT(Operation::CLRw): case OpT(Operation::CLRl):
case OpT(Operation::NEGb): case OpT(Operation::NEGw): case OpT(Operation::NEGl):
switch(original.mode<0>()) {
default: return original;
case AddressingMode::AddressRegisterDirect:
case AddressingMode::ImmediateData:
case AddressingMode::ProgramCounterIndirectWithDisplacement:
case AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement:
case AddressingMode::None:
return Preinstruction();
}
case OpT(Operation::ASLm): case OpT(Operation::ASRm):
case OpT(Operation::LSLm): case OpT(Operation::LSRm):
case OpT(Operation::ROLm): case OpT(Operation::RORm):
case OpT(Operation::ROXLm): case OpT(Operation::ROXRm):
switch(original.mode<0>()) {
default: return original;
case AddressingMode::DataRegisterDirect:
case AddressingMode::AddressRegisterDirect:
case AddressingMode::ImmediateData:
case AddressingMode::ProgramCounterIndirectWithDisplacement:
case AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement:
case AddressingMode::None:
return Preinstruction();
}
case MOVEMtoMw: case MOVEMtoMl:
switch(original.mode<1>()) {
default: return original;
case AddressingMode::DataRegisterDirect:
case AddressingMode::AddressRegisterDirect:
case AddressingMode::AddressRegisterIndirectWithPostincrement:
case AddressingMode::ImmediateData:
case AddressingMode::ProgramCounterIndirectWithDisplacement:
case AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement:
case AddressingMode::None:
return Preinstruction();
}
case MOVEMtoRw: case MOVEMtoRl:
switch(original.mode<0>()) {
default: return original;
case AddressingMode::DataRegisterDirect:
case AddressingMode::AddressRegisterDirect:
case AddressingMode::AddressRegisterIndirectWithPredecrement:
case AddressingMode::ImmediateData:
case AddressingMode::None:
return Preinstruction();
}
case OpT(Operation::DIVU): case OpT(Operation::DIVS):
case OpT(Operation::MULU): case OpT(Operation::MULS):
case OpT(Operation::CHK):
switch(original.mode<0>()) {
default: return original;
case AddressingMode::AddressRegisterDirect:
case AddressingMode::None:
return Preinstruction();
}
}
const auto invalid = invalid_operands<op>();
const auto observed = operand_mask(original);
return (observed & invalid) ? Preinstruction() : original;
}
/// Decodes the fields within an instruction and constructs a `Preinstruction`, given that the operation has already been
@ -530,33 +507,6 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
// b0b2 and b3b5: an effective address;
// b6b8: an opmode, i.e. source + direction.
//
case OpT(Operation::SUBb): case OpT(Operation::SUBw): case OpT(Operation::SUBl):
case OpT(Operation::ANDb): case OpT(Operation::ANDw): case OpT(Operation::ANDl):
case OpT(Operation::ORb): case OpT(Operation::ORw): case OpT(Operation::ORl): {
const auto ea_combined_mode = combined_mode(ea_mode, ea_register);
// TODO: make this decision outside of this function.
if(opmode & 4) {
// Dn, <ea>
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::DataRegisterDirect, data_register,
ea_combined_mode, ea_register));
} else {
// <ea>, Dn
return validated<op, validate>(
Preinstruction(operation,
ea_combined_mode, ea_register,
AddressingMode::DataRegisterDirect, data_register));
}
return Preinstruction();
}
case ADDtoRb: case ADDtoRw: case ADDtoRl:
case SUBtoRb: case SUBtoRw: case SUBtoRl:
case ANDtoRb: case ANDtoRw: case ANDtoRl:
@ -653,26 +603,23 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
// b9b11: register Rx (data or address, data if exchange is address <-> data);
// b3b7: an opmode, indicating address/data registers.
//
case OpT(Operation::EXG):
switch((instruction >> 3)&31) {
default: return Preinstruction();
case EXGRtoR:
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::DataRegisterDirect, data_register,
AddressingMode::DataRegisterDirect, ea_register));
case 0x08: return validated<op, validate>(
Preinstruction(operation,
AddressingMode::DataRegisterDirect, data_register,
AddressingMode::DataRegisterDirect, ea_register));
case EXGAtoA:
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::AddressRegisterDirect, data_register,
AddressingMode::AddressRegisterDirect, ea_register));
case 0x09: return validated<op, validate>(
Preinstruction(operation,
AddressingMode::AddressRegisterDirect, data_register,
AddressingMode::AddressRegisterDirect, ea_register));
case 0x11: return validated<op, validate>(
Preinstruction(operation,
AddressingMode::DataRegisterDirect, data_register,
AddressingMode::AddressRegisterDirect, ea_register));
}
// TODO: remove conditional from in here.
case EXGRtoA:
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::DataRegisterDirect, data_register,
AddressingMode::AddressRegisterDirect, ea_register));
//
// MARK: MULU, MULS, DIVU, DIVS.
@ -1308,9 +1255,9 @@ Preinstruction Predecoder<model>::decodeC(uint16_t instruction) {
// 4-105 (p209)
switch(instruction & 0x1f8) {
case 0x140:
case 0x148:
case 0x188: Decode(Op::EXG);
case 0x140: Decode(EXGRtoR);
case 0x148: Decode(EXGAtoA);
case 0x188: Decode(EXGRtoA);
default: break;
}

View File

@ -49,6 +49,7 @@ template <Model model> class Predecoder {
// Specific instruction decoders.
template <OpT operation, bool validate = true> Preinstruction decode(uint16_t instruction);
template <OpT operation, bool validate> Preinstruction validated(Preinstruction original);
template <uint8_t op> uint32_t invalid_operands();
// Extended operation list; collapses into a single byte enough information to
// know both the type of operation and how to decode the operands. Most of the
@ -90,6 +91,8 @@ template <Model model> class Predecoder {
ORtoMb, ORtoMw, ORtoMl,
ORtoRb, ORtoRw, ORtoRl,
EXGRtoR, EXGAtoA, EXGRtoA,
};
static constexpr Operation operation(OpT op);

View File

@ -187,7 +187,7 @@ constexpr int8_t quick(Operation op, uint16_t instruction) {
/// as ProgramCounterIndirectWithIndex8bitDisplacement.
enum class AddressingMode: uint8_t {
/// No adddressing mode; this operand doesn't exist.
None = 0b11'111,
None = 0b01'101,
/// Dn
DataRegisterDirect = 0b00'000,
@ -232,7 +232,7 @@ enum class AddressingMode: uint8_t {
ImmediateData = 0b01'100,
/// .q; value is embedded in the opcode.
Quick = 0b11'110,
Quick = 0b01'110,
};
/*!

View File

@ -74,7 +74,6 @@ template <int index> NSString *operand(Preinstruction instruction, uint16_t opco
XCTAssertNotNil(decodings);
Predecoder<Model::M68000> decoder;
int skipped = 0;
for(int instr = 0; instr < 65536; instr++) {
NSString *const instrName = [NSString stringWithFormat:@"%04x", instr];
NSString *const expected = decodings[instrName];
@ -269,7 +268,7 @@ template <int index> NSString *operand(Preinstruction instruction, uint16_t opco
// For now, skip any unmapped operations.
default:
++skipped;
XCTAssert(false, @"Operation %d unhandled by test case", int(found.operation));
continue;
}
@ -282,8 +281,6 @@ template <int index> NSString *operand(Preinstruction instruction, uint16_t opco
XCTAssertFalse(found.mode<0>() == AddressingMode::None && found.mode<1>() != AddressingMode::None, @"Decoding of %@ provided a second operand but not a first", instrName);
XCTAssertEqualObjects(instruction, expected, "%@ should decode as %@; got %@", instrName, expected, instruction);
}
NSLog(@"Skipped %d opcodes", skipped);
}
@end