1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-11 08:30:55 +00:00

Avoid packing/unpacking of operands.

This commit is contained in:
Thomas Harte 2022-04-26 19:37:07 -04:00
parent 539c2985aa
commit baf1bd354d
2 changed files with 86 additions and 98 deletions

View File

@ -55,8 +55,8 @@ 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>())));
uint32_t operand_mask(AddressingMode mode1, AddressingMode mode2) {
return uint32_t((0x1'0000 << int(mode1)) | (0x0'0001 << int(mode2)));
}
}
@ -178,7 +178,9 @@ template <uint8_t op> uint32_t Predecoder<model>::invalid_operands() {
static constexpr auto ControlAddressingModes = Ind | d16An | d8AnXn | XXXw | XXXl | d16PC | d8PCXn;
switch(op) {
default: return ~NoOperandMask::value;
// By default, disallow all operands (including 'None'). This should catch any
// opcodes that are unmapped below.
default: return uint32_t(~0);
case OpT(Operation::ABCD):
case OpT(Operation::ADDXb): case OpT(Operation::ADDXw): case OpT(Operation::ADDXl):
@ -475,14 +477,29 @@ template <uint8_t op> uint32_t Predecoder<model>::invalid_operands() {
/// Provides a post-decoding validation step — primarily ensures that the prima facie addressing modes are supported by the operation.
template <Model model>
template <uint8_t op, bool validate> Preinstruction Predecoder<model>::validated(Preinstruction original) {
template <uint8_t op, bool validate> Preinstruction Predecoder<model>::validated(
AddressingMode op1_mode, int op1_reg,
AddressingMode op2_mode, int op2_reg
) {
constexpr auto operation = Predecoder<model>::operation(op);
if constexpr (!validate) {
return original;
return Preinstruction(
operation,
op1_mode, op1_reg,
op2_mode, op2_reg,
requires_supervisor<model>(operation));
}
const auto invalid = invalid_operands<op>();
const auto observed = operand_mask(original);
return (observed & invalid) ? Preinstruction() : original;
const auto observed = operand_mask(op1_mode, op2_mode);
return (observed & invalid) ?
Preinstruction() :
Preinstruction(
operation,
op1_mode, op1_reg,
op2_mode, op2_reg,
requires_supervisor<model>(operation));
}
/// Decodes the fields within an instruction and constructs a `Preinstruction`, given that the operation has already been
@ -498,8 +515,6 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
const auto opmode = (instruction >> 6) & 7;
const auto data_register = (instruction >> 9) & 7;
constexpr auto operation = Predecoder<model>::operation(op);
switch(op) {
//
@ -516,9 +531,8 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
AddressingMode::AddressRegisterIndirectWithPredecrement : AddressingMode::DataRegisterDirect;
return validated<op, validate>(
Preinstruction(operation,
addressing_mode, ea_register,
addressing_mode, data_register));
addressing_mode, ea_register,
addressing_mode, data_register);
}
//
@ -534,9 +548,8 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
case ORtoRb: case ORtoRw: case ORtoRl:
case OpT(Operation::CMPb): case OpT(Operation::CMPw): case OpT(Operation::CMPl):
return validated<op, validate>(
Preinstruction(operation,
combined_mode(ea_mode, ea_register), ea_register,
AddressingMode::DataRegisterDirect, data_register));
combined_mode(ea_mode, ea_register), ea_register,
AddressingMode::DataRegisterDirect, data_register);
case ADDtoMb: case ADDtoMw: case ADDtoMl:
case SUBtoMb: case SUBtoMw: case SUBtoMl:
@ -544,17 +557,15 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
case ORtoMb: case ORtoMw: case ORtoMl:
case OpT(Operation::EORb): case OpT(Operation::EORw): case OpT(Operation::EORl):
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::DataRegisterDirect, data_register,
combined_mode(ea_mode, ea_register), ea_register));
AddressingMode::DataRegisterDirect, data_register,
combined_mode(ea_mode, ea_register), ea_register);
case OpT(Operation::ADDAw): case OpT(Operation::ADDAl):
case OpT(Operation::SUBAw): case OpT(Operation::SUBAl):
case OpT(Operation::CMPAw): case OpT(Operation::CMPAl):
return validated<op, validate>(
Preinstruction(operation,
combined_mode(ea_mode, ea_register), ea_register,
AddressingMode::AddressRegisterDirect, data_register));
combined_mode(ea_mode, ea_register), ea_register,
AddressingMode::AddressRegisterDirect, data_register);
//
// MARK: EORI, ORI, ANDI, SUBI, ADDI, CMPI, B[TST/CHG/CLR/SET]I
@ -571,9 +582,8 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
case BTSTI: case BCHGI:
case BCLRI: case BSETI:
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::ImmediateData, 0,
combined_mode(ea_mode, ea_register), ea_register));
AddressingMode::ImmediateData, 0,
combined_mode(ea_mode, ea_register), ea_register);
//
@ -585,9 +595,8 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
case OpT(Operation::BTST): case OpT(Operation::BCLR):
case OpT(Operation::BCHG): case OpT(Operation::BSET):
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::DataRegisterDirect, data_register,
combined_mode(ea_mode, ea_register), ea_register));
AddressingMode::DataRegisterDirect, data_register,
combined_mode(ea_mode, ea_register), ea_register);
//
// MARK: STOP, ANDItoCCR, ANDItoSR, EORItoCCR, EORItoSR, ORItoCCR, ORItoSR, Bccl, Bccw, BSRl, BSRw
@ -600,10 +609,7 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
case OpT(Operation::ORItoSR): case OpT(Operation::ORItoCCR):
case OpT(Operation::ANDItoSR): case OpT(Operation::ANDItoCCR):
case OpT(Operation::EORItoSR): case OpT(Operation::EORItoCCR):
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::ImmediateData, 0,
operation == Operation::ORItoSR || operation == Operation::ANDItoSR || operation == Operation::EORItoSR));
return validated<op, validate>(AddressingMode::ImmediateData);
//
// MARK: CHK
@ -613,9 +619,8 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
//
case OpT(Operation::CHK):
return validated<op, validate>(
Preinstruction(operation,
combined_mode(ea_mode, ea_register), ea_register,
AddressingMode::DataRegisterDirect, data_register));
combined_mode(ea_mode, ea_register), ea_register,
AddressingMode::DataRegisterDirect, data_register);
//
// MARK: EXG.
@ -626,21 +631,18 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
//
case EXGRtoR:
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::DataRegisterDirect, data_register,
AddressingMode::DataRegisterDirect, ea_register));
AddressingMode::DataRegisterDirect, data_register,
AddressingMode::DataRegisterDirect, ea_register);
case EXGAtoA:
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::AddressRegisterDirect, data_register,
AddressingMode::AddressRegisterDirect, ea_register));
AddressingMode::AddressRegisterDirect, data_register,
AddressingMode::AddressRegisterDirect, ea_register);
case EXGRtoA:
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::DataRegisterDirect, data_register,
AddressingMode::AddressRegisterDirect, ea_register));
AddressingMode::DataRegisterDirect, data_register,
AddressingMode::AddressRegisterDirect, ea_register);
//
// MARK: MULU, MULS, DIVU, DIVS.
@ -651,9 +653,8 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
case OpT(Operation::DIVU): case OpT(Operation::DIVS):
case OpT(Operation::MULU): case OpT(Operation::MULS):
return validated<op, validate>(
Preinstruction(operation,
combined_mode(ea_mode, ea_register), ea_register,
AddressingMode::DataRegisterDirect, data_register));
combined_mode(ea_mode, ea_register), ea_register,
AddressingMode::DataRegisterDirect, data_register);
//
// MARK: LEA
@ -663,9 +664,8 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
//
case OpT(Operation::LEA):
return validated<op, validate>(
Preinstruction(operation,
combined_mode(ea_mode, ea_register), ea_register,
AddressingMode::AddressRegisterDirect, data_register));
combined_mode(ea_mode, ea_register), ea_register,
AddressingMode::AddressRegisterDirect, data_register);
//
// MARK: MOVEPtoRw, MOVEPtoRl
@ -676,15 +676,13 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
//
case OpT(MOVEPtoRw): case OpT(MOVEPtoRl):
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::AddressRegisterIndirectWithDisplacement, ea_register,
AddressingMode::DataRegisterDirect, data_register));
AddressingMode::AddressRegisterIndirectWithDisplacement, ea_register,
AddressingMode::DataRegisterDirect, data_register);
case OpT(MOVEPtoMw): case OpT(MOVEPtoMl):
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::DataRegisterDirect, data_register,
AddressingMode::AddressRegisterIndirectWithDisplacement, ea_register));
AddressingMode::DataRegisterDirect, data_register,
AddressingMode::AddressRegisterIndirectWithDisplacement, ea_register);
//
// MARK: MOVE
@ -696,9 +694,8 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
case OpT(Operation::MOVEb): case OpT(Operation::MOVEl): case OpT(Operation::MOVEw):
case OpT(Operation::MOVEAl): case OpT(Operation::MOVEAw):
return validated<op, validate>(
Preinstruction(operation,
combined_mode(ea_mode, ea_register), ea_register,
combined_mode(opmode, data_register), data_register));
combined_mode(ea_mode, ea_register), ea_register,
combined_mode(opmode, data_register), data_register);
//
// MARK: RESET, NOP RTE, RTS, TRAPV, RTR
@ -708,7 +705,7 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
case OpT(Operation::RESET): case OpT(Operation::NOP):
case OpT(Operation::RTE): case OpT(Operation::RTS): case OpT(Operation::TRAPV):
case OpT(Operation::RTR):
return validated<op, validate>(Preinstruction(operation));
return validated<op, validate>();
//
// MARK: NEGX, CLR, NEG, MOVEtoCCR, MOVEtoSR, NOT, NBCD, PEA, TST
@ -726,9 +723,7 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
case OpT(Operation::TAS):
case OpT(Operation::TSTb): case OpT(Operation::TSTw): case OpT(Operation::TSTl):
case OpT(Operation::Scc):
return validated<op, validate>(
Preinstruction(operation,
combined_mode(ea_mode, ea_register), ea_register));
return validated<op, validate>(combined_mode(ea_mode, ea_register), ea_register);
//
// MARK: UNLINK, MOVEtoUSP, MOVEfromUSP
@ -737,9 +732,7 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
//
case OpT(Operation::UNLINK):
case OpT(Operation::MOVEfromUSP): case OpT(Operation::MOVEtoUSP):
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::AddressRegisterDirect, ea_register));
return validated<op, validate>(AddressingMode::AddressRegisterDirect, ea_register);
//
// MARK: DBcc
@ -749,9 +742,8 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
//
case OpT(Operation::DBcc):
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::DataRegisterDirect, ea_register,
AddressingMode::ImmediateData, 0));
AddressingMode::DataRegisterDirect, ea_register,
AddressingMode::ImmediateData, 0);
//
// MARK: SWAP, EXTbtow, EXTwtol
@ -760,9 +752,7 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
//
case OpT(Operation::SWAP):
case OpT(Operation::EXTbtow): case OpT(Operation::EXTwtol):
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::DataRegisterDirect, ea_register));
return validated<op, validate>(AddressingMode::DataRegisterDirect, ea_register);
//
// MARK: MOVEMtoMw, MOVEMtoMl, MOVEMtoRw, MOVEMtoRl
@ -772,15 +762,13 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
//
case MOVEMtoMl: case MOVEMtoMw:
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::ImmediateData, 0,
combined_mode(ea_mode, ea_register), ea_register));
AddressingMode::ImmediateData, 0,
combined_mode(ea_mode, ea_register), ea_register);
case MOVEMtoRl: case MOVEMtoRw:
return validated<op, validate>(
Preinstruction(operation,
combined_mode(ea_mode, ea_register), ea_register,
AddressingMode::ImmediateData, 0));
combined_mode(ea_mode, ea_register), ea_register,
AddressingMode::ImmediateData, 0);
//
// MARK: TRAP, BCCb, BSRb
@ -790,9 +778,7 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
case OpT(Operation::TRAP):
case OpT(Operation::Bccb):
case OpT(Operation::BSRb):
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::Quick, 0));
return validated<op, validate>(AddressingMode::Quick);
//
// MARK: LINKw
@ -802,9 +788,8 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
//
case OpT(Operation::LINKw):
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::AddressRegisterDirect, ea_register,
AddressingMode::ImmediateData, 0));
AddressingMode::AddressRegisterDirect, ea_register,
AddressingMode::ImmediateData, 0);
//
// MARK: ADDQ, SUBQ
@ -815,9 +800,8 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
case ADDQb: case ADDQw: case ADDQl:
case SUBQb: case SUBQw: case SUBQl:
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::Quick, 0,
combined_mode(ea_mode, ea_register), ea_register));
AddressingMode::Quick, 0,
combined_mode(ea_mode, ea_register), ea_register);
//
// MARK: MOVEq
@ -827,9 +811,8 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
//
case MOVEQ:
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::Quick, 0,
AddressingMode::DataRegisterDirect, data_register));
AddressingMode::Quick, 0,
AddressingMode::DataRegisterDirect, data_register);
//
// MARK: ASR, LSR, ROXR, ROR, ASL, LSL, ROXL, ROL
@ -846,9 +829,8 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
case OpT(Operation::ROXLb): case OpT(Operation::ROXLw): case OpT(Operation::ROXLl):
case OpT(Operation::ROLb): case OpT(Operation::ROLw): case OpT(Operation::ROLl):
return validated<op, validate>(
Preinstruction(operation,
(instruction & 0x20) ? AddressingMode::DataRegisterDirect : AddressingMode::Quick, data_register,
AddressingMode::DataRegisterDirect, ea_register));
(instruction & 0x20) ? AddressingMode::DataRegisterDirect : AddressingMode::Quick, data_register,
AddressingMode::DataRegisterDirect, ea_register);
//
// MARK: ASRm, LSRm, ROXRm, RORm, ASLm, LSLm, ROXLm, ROLm
@ -859,15 +841,12 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
case OpT(Operation::LSRm): case OpT(Operation::LSLm):
case OpT(Operation::ROXRm): case OpT(Operation::ROXLm):
case OpT(Operation::RORm): case OpT(Operation::ROLm):
return validated<op, validate>(
Preinstruction(operation,
combined_mode(ea_mode, ea_register), ea_register));
return validated<op, validate>(combined_mode(ea_mode, ea_register), ea_register);
case CMPMb: case CMPMw: case CMPMl:
return validated<op, validate>(
Preinstruction(operation,
AddressingMode::AddressRegisterIndirectWithPostincrement, ea_register,
AddressingMode::AddressRegisterIndirectWithPostincrement, data_register));
AddressingMode::AddressRegisterIndirectWithPostincrement, data_register);
//
// MARK: Impossible error case.

View File

@ -19,6 +19,12 @@ namespace M68k {
A stateless decoder that can map from instruction words to preinstructions
(i.e. enough to know the operation and size, and either know the addressing mode
and registers or else know how many further extension words are needed).
WARNING: at present this handles the original 68000 instruction set only. It
requires a model only for the sake of not baking in assumptions about MOVE SR, etc,
and supporting extended addressing modes in some cases.
But it does not yet decode any operations which were not present on the 68000.
*/
template <Model model> class Predecoder {
public:
@ -48,7 +54,10 @@ 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 <OpT operation, bool validate> Preinstruction validated(
AddressingMode op1_mode = AddressingMode::None, int op1_reg = 0,
AddressingMode op2_mode = AddressingMode::None, int op2_reg = 0
);
template <uint8_t op> uint32_t invalid_operands();
// Extended operation list; collapses into a single byte enough information to