mirror of
https://github.com/TomHarte/CLK.git
synced 2025-03-29 17:30:23 +00:00
Start experimenting with a simple AND for operand validation.
This commit is contained in:
parent
959db77b88
commit
b965f2053a
InstructionSets/68k
@ -37,6 +37,32 @@ constexpr AddressingMode combined_mode(int mode, int reg) {
|
|||||||
return modes[use_reg];
|
return modes[use_reg];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <AddressingMode... T> struct Mask {
|
||||||
|
static constexpr uint32_t value = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <AddressingMode F, AddressingMode... T> struct Mask<F, T...> {
|
||||||
|
static constexpr uint32_t value = uint32_t(1 << int(F)) | Mask<T...>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
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.
|
// MARK: - Instruction decoders.
|
||||||
@ -115,6 +141,145 @@ constexpr Operation Predecoder<model>::operation(OpT op) {
|
|||||||
return Operation::Undefined;
|
return Operation::Undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <Model model>
|
||||||
|
template <uint8_t op> uint32_t Predecoder<model>::invalid_operands() {
|
||||||
|
// A few recurring combinations; terminology is directly from
|
||||||
|
// the Programmers' Reference Manual.
|
||||||
|
|
||||||
|
//
|
||||||
|
// All modes: the complete set.
|
||||||
|
//
|
||||||
|
// (and the complete set without AddressRegisterDirect, for byte operations).
|
||||||
|
static constexpr uint32_t AllModes = Mask<
|
||||||
|
AddressingMode::DataRegisterDirect,
|
||||||
|
AddressingMode::AddressRegisterDirect,
|
||||||
|
AddressingMode::AddressRegisterIndirect,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithPostincrement,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithPredecrement,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithDisplacement,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithIndex8bitDisplacement,
|
||||||
|
AddressingMode::AbsoluteShort,
|
||||||
|
AddressingMode::AbsoluteLong,
|
||||||
|
AddressingMode::ImmediateData,
|
||||||
|
AddressingMode::ProgramCounterIndirectWithDisplacement,
|
||||||
|
AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement
|
||||||
|
>::value;
|
||||||
|
static constexpr uint32_t AllModes_b = Mask<
|
||||||
|
AddressingMode::DataRegisterDirect,
|
||||||
|
AddressingMode::AddressRegisterIndirect,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithPostincrement,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithPredecrement,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithDisplacement,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithIndex8bitDisplacement,
|
||||||
|
AddressingMode::AbsoluteShort,
|
||||||
|
AddressingMode::AbsoluteLong,
|
||||||
|
AddressingMode::ImmediateData,
|
||||||
|
AddressingMode::ProgramCounterIndirectWithDisplacement,
|
||||||
|
AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement
|
||||||
|
>::value;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Alterable addressing modes (with and without AddressRegisterDirect).
|
||||||
|
//
|
||||||
|
// Dn, An, (An), (An)+, -(An), (d16, An), (d8, An, Xn), (xxx).W, (xxx).L
|
||||||
|
// (and sans An for _b)
|
||||||
|
static constexpr uint32_t AlterableAddressingModes = Mask<
|
||||||
|
AddressingMode::DataRegisterDirect,
|
||||||
|
AddressingMode::AddressRegisterDirect,
|
||||||
|
AddressingMode::AddressRegisterIndirect,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithPostincrement,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithPredecrement,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithDisplacement,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithIndex8bitDisplacement,
|
||||||
|
AddressingMode::AbsoluteShort,
|
||||||
|
AddressingMode::AbsoluteLong
|
||||||
|
>::value;
|
||||||
|
static constexpr uint32_t AlterableAddressingModes_b = Mask<
|
||||||
|
AddressingMode::DataRegisterDirect,
|
||||||
|
AddressingMode::AddressRegisterIndirect,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithPostincrement,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithPredecrement,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithDisplacement,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithIndex8bitDisplacement,
|
||||||
|
AddressingMode::AbsoluteShort,
|
||||||
|
AddressingMode::AbsoluteLong
|
||||||
|
>::value;
|
||||||
|
|
||||||
|
switch(op) {
|
||||||
|
default: return NoOperandMask::value;
|
||||||
|
|
||||||
|
case OpT(Operation::ABCD):
|
||||||
|
case OpT(Operation::ADDXb): case OpT(Operation::ADDXw): case OpT(Operation::ADDXl):
|
||||||
|
return ~TwoOperandMask<Mask<
|
||||||
|
AddressingMode::DataRegisterDirect,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithPredecrement
|
||||||
|
>::value, Mask<
|
||||||
|
AddressingMode::DataRegisterDirect,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithPredecrement
|
||||||
|
>::value>::value;
|
||||||
|
|
||||||
|
case ADDtoRb:
|
||||||
|
return ~TwoOperandMask<
|
||||||
|
AllModes_b
|
||||||
|
, Mask<
|
||||||
|
AddressingMode::DataRegisterDirect
|
||||||
|
>::value>::value;
|
||||||
|
|
||||||
|
case ADDtoRw: case ADDtoRl:
|
||||||
|
return ~TwoOperandMask<
|
||||||
|
AllModes
|
||||||
|
, Mask<
|
||||||
|
AddressingMode::DataRegisterDirect
|
||||||
|
>::value>::value;
|
||||||
|
|
||||||
|
case ADDtoMb: case ADDtoMw: case ADDtoMl:
|
||||||
|
return ~TwoOperandMask<Mask<
|
||||||
|
AddressingMode::DataRegisterDirect
|
||||||
|
>::value, Mask<
|
||||||
|
// TODO: I strongly suspect this should be AlterableAddressingModes regardless
|
||||||
|
// of the documentation. Verify.
|
||||||
|
AddressingMode::AddressRegisterIndirect,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithPostincrement,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithPredecrement,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithDisplacement,
|
||||||
|
AddressingMode::AddressRegisterIndirectWithIndex8bitDisplacement,
|
||||||
|
AddressingMode::AbsoluteShort,
|
||||||
|
AddressingMode::AbsoluteLong
|
||||||
|
>::value>::value;
|
||||||
|
|
||||||
|
case OpT(Operation::ADDAw): case OpT(Operation::ADDAl):
|
||||||
|
return ~TwoOperandMask<
|
||||||
|
AllModes
|
||||||
|
, Mask<
|
||||||
|
AddressingMode::AddressRegisterDirect
|
||||||
|
>::value>::value;
|
||||||
|
|
||||||
|
case ADDIb: case ADDIl: case ADDIw:
|
||||||
|
return ~TwoOperandMask<Mask<
|
||||||
|
AddressingMode::ImmediateData
|
||||||
|
>::value,
|
||||||
|
AlterableAddressingModes_b
|
||||||
|
>::value;
|
||||||
|
|
||||||
|
case ADDQb:
|
||||||
|
return ~TwoOperandMask<Mask<
|
||||||
|
AddressingMode::Quick
|
||||||
|
>::value,
|
||||||
|
AlterableAddressingModes_b
|
||||||
|
>::value;
|
||||||
|
|
||||||
|
case ADDQw: case ADDQl:
|
||||||
|
return ~TwoOperandMask<Mask<
|
||||||
|
AddressingMode::Quick
|
||||||
|
>::value,
|
||||||
|
AlterableAddressingModes
|
||||||
|
>::value;
|
||||||
|
|
||||||
|
case OpT(Operation::NBCD):
|
||||||
|
return ~OneOperandMask<AlterableAddressingModes_b>::value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Provides a post-decoding validation step — primarily ensures that the prima facie addressing modes are supported by the operation.
|
/// 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
|
// TODO: once complete and working, see how ugly it would be to incorpoate these tests into the main
|
||||||
// decoding switches.
|
// decoding switches.
|
||||||
@ -128,7 +293,19 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::validated
|
|||||||
default: return original;
|
default: return original;
|
||||||
|
|
||||||
// NBCD.
|
// NBCD.
|
||||||
case OpT(Operation::NBCD):
|
case OpT(Operation::ABCD):
|
||||||
|
case OpT(Operation::ADDXb): case OpT(Operation::ADDXw): case OpT(Operation::ADDXl):
|
||||||
|
case ADDtoRb: case ADDtoRw: case ADDtoRl:
|
||||||
|
case ADDIb: case ADDIl: case ADDIw:
|
||||||
|
case ADDtoMb: case ADDtoMw: case ADDtoMl:
|
||||||
|
case OpT(Operation::ADDAw): case OpT(Operation::ADDAl):
|
||||||
|
case ADDQb: case ADDQw: case ADDQl:
|
||||||
|
case OpT(Operation::NBCD): {
|
||||||
|
const auto invalid = invalid_operands<op>();
|
||||||
|
const auto observed = operand_mask(original);
|
||||||
|
return (observed & invalid) ? Preinstruction() : original;
|
||||||
|
}
|
||||||
|
|
||||||
case OpT(Operation::MOVEfromSR):
|
case OpT(Operation::MOVEfromSR):
|
||||||
case OpT(Operation::TAS):
|
case OpT(Operation::TAS):
|
||||||
switch(original.mode<0>()) {
|
switch(original.mode<0>()) {
|
||||||
@ -157,7 +334,6 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::validated
|
|||||||
case ORIb: case ORIl: case ORIw:
|
case ORIb: case ORIl: case ORIw:
|
||||||
case ANDIb: case ANDIl: case ANDIw:
|
case ANDIb: case ANDIl: case ANDIw:
|
||||||
case SUBIb: case SUBIl: case SUBIw:
|
case SUBIb: case SUBIl: case SUBIw:
|
||||||
case ADDIb: case ADDIl: case ADDIw:
|
|
||||||
switch(original.mode<1>()) {
|
switch(original.mode<1>()) {
|
||||||
default: return original;
|
default: return original;
|
||||||
|
|
||||||
@ -187,7 +363,7 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::validated
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ADD, SUB, MOVE, MOVEA
|
// ADD, SUB, MOVE, MOVEA
|
||||||
case ADDQb: case ADDQw: case ADDQl:
|
// case ADDQb: case ADDQw: case ADDQl:
|
||||||
case SUBQb: case SUBQw: case SUBQl:
|
case SUBQb: case SUBQw: case SUBQl:
|
||||||
case OpT(Operation::MOVEb): case OpT(Operation::MOVEw): case OpT(Operation::MOVEl):
|
case OpT(Operation::MOVEb): case OpT(Operation::MOVEw): case OpT(Operation::MOVEl):
|
||||||
case OpT(Operation::MOVEAw): case OpT(Operation::MOVEAl):
|
case OpT(Operation::MOVEAw): case OpT(Operation::MOVEAl):
|
||||||
@ -226,7 +402,7 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::validated
|
|||||||
}
|
}
|
||||||
|
|
||||||
case SUBtoRb: case SUBtoRw: case SUBtoRl:
|
case SUBtoRb: case SUBtoRw: case SUBtoRl:
|
||||||
case ADDtoRb: case ADDtoRw: case ADDtoRl: {
|
/*case ADDtoRb: case ADDtoRw: case ADDtoRl: */{
|
||||||
constexpr bool is_byte = op == ADDtoRb || op == SUBtoRb || op == SUBtoRb || op == ADDtoRb;
|
constexpr bool is_byte = op == ADDtoRb || op == SUBtoRb || op == SUBtoRb || op == ADDtoRb;
|
||||||
|
|
||||||
switch(original.mode<0>()) {
|
switch(original.mode<0>()) {
|
||||||
@ -263,7 +439,7 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::validated
|
|||||||
return Preinstruction();
|
return Preinstruction();
|
||||||
}
|
}
|
||||||
|
|
||||||
case ADDtoMb: case ADDtoMw: case ADDtoMl:
|
/*case ADDtoMb: case ADDtoMw: case ADDtoMl:*/
|
||||||
case SUBtoMb: case SUBtoMw: case SUBtoMl: {
|
case SUBtoMb: case SUBtoMw: case SUBtoMl: {
|
||||||
// TODO: I'm going to need get-size-by-operation elsewhere; use that here when implemented.
|
// TODO: I'm going to need get-size-by-operation elsewhere; use that here when implemented.
|
||||||
constexpr bool is_byte = op == ADDtoMb || op == SUBtoMb;
|
constexpr bool is_byte = op == ADDtoMb || op == SUBtoMb;
|
||||||
@ -313,7 +489,7 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::validated
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ADDA, SUBA.
|
// ADDA, SUBA.
|
||||||
case OpT(Operation::ADDAw): case OpT(Operation::ADDAl):
|
// case OpT(Operation::ADDAw): case OpT(Operation::ADDAl):
|
||||||
case OpT(Operation::SUBAw): case OpT(Operation::SUBAl):
|
case OpT(Operation::SUBAw): case OpT(Operation::SUBAl):
|
||||||
switch(original.mode<0>()) {
|
switch(original.mode<0>()) {
|
||||||
default: break;
|
default: break;
|
||||||
|
@ -49,6 +49,7 @@ template <Model model> class Predecoder {
|
|||||||
// Specific instruction decoders.
|
// Specific instruction decoders.
|
||||||
template <OpT operation, bool validate = true> Preinstruction decode(uint16_t instruction);
|
template <OpT operation, bool validate = true> Preinstruction decode(uint16_t instruction);
|
||||||
template <OpT operation, bool validate> Preinstruction validated(Preinstruction original);
|
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
|
// 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
|
// know both the type of operation and how to decode the operands. Most of the
|
||||||
|
@ -187,7 +187,7 @@ constexpr int8_t quick(Operation op, uint16_t instruction) {
|
|||||||
/// as ProgramCounterIndirectWithIndex8bitDisplacement.
|
/// as ProgramCounterIndirectWithIndex8bitDisplacement.
|
||||||
enum class AddressingMode: uint8_t {
|
enum class AddressingMode: uint8_t {
|
||||||
/// No adddressing mode; this operand doesn't exist.
|
/// No adddressing mode; this operand doesn't exist.
|
||||||
None = 0b11'111,
|
None = 0b01'101,
|
||||||
|
|
||||||
/// Dn
|
/// Dn
|
||||||
DataRegisterDirect = 0b00'000,
|
DataRegisterDirect = 0b00'000,
|
||||||
@ -232,7 +232,7 @@ enum class AddressingMode: uint8_t {
|
|||||||
ImmediateData = 0b01'100,
|
ImmediateData = 0b01'100,
|
||||||
|
|
||||||
/// .q; value is embedded in the opcode.
|
/// .q; value is embedded in the opcode.
|
||||||
Quick = 0b11'110,
|
Quick = 0b01'110,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
Loading…
x
Reference in New Issue
Block a user