2022-04-11 19:00:55 +00:00
|
|
|
|
//
|
|
|
|
|
// Instruction.hpp
|
|
|
|
|
// Clock Signal
|
|
|
|
|
//
|
|
|
|
|
// Created by Thomas Harte on 10/04/2022.
|
|
|
|
|
// Copyright © 2022 Thomas Harte. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#ifndef InstructionSets_68k_Instruction_hpp
|
|
|
|
|
#define InstructionSets_68k_Instruction_hpp
|
|
|
|
|
|
2022-04-15 13:40:37 +00:00
|
|
|
|
#include "Model.hpp"
|
2022-04-11 19:00:55 +00:00
|
|
|
|
|
2022-05-03 15:09:57 +00:00
|
|
|
|
#include <cassert>
|
|
|
|
|
#include <cstdint>
|
2022-05-12 23:46:08 +00:00
|
|
|
|
#include <string>
|
2022-05-03 15:09:57 +00:00
|
|
|
|
|
2022-04-11 19:00:55 +00:00
|
|
|
|
namespace InstructionSet {
|
|
|
|
|
namespace M68k {
|
|
|
|
|
|
|
|
|
|
enum class Operation: uint8_t {
|
|
|
|
|
Undefined,
|
|
|
|
|
|
2022-10-21 19:28:29 +00:00
|
|
|
|
//
|
|
|
|
|
// 68000 operations.
|
|
|
|
|
//
|
|
|
|
|
|
2022-04-12 11:49:08 +00:00
|
|
|
|
NOP,
|
|
|
|
|
|
2022-04-11 19:00:55 +00:00
|
|
|
|
ABCD, SBCD, NBCD,
|
|
|
|
|
|
|
|
|
|
ADDb, ADDw, ADDl,
|
|
|
|
|
ADDAw, ADDAl,
|
|
|
|
|
ADDXb, ADDXw, ADDXl,
|
|
|
|
|
|
|
|
|
|
SUBb, SUBw, SUBl,
|
|
|
|
|
SUBAw, SUBAl,
|
|
|
|
|
SUBXb, SUBXw, SUBXl,
|
|
|
|
|
|
2022-04-13 13:29:12 +00:00
|
|
|
|
MOVEb, MOVEw, MOVEl,
|
2022-04-11 19:00:55 +00:00
|
|
|
|
MOVEAw, MOVEAl,
|
2022-04-19 23:36:21 +00:00
|
|
|
|
LEA, PEA,
|
2022-04-11 19:00:55 +00:00
|
|
|
|
|
|
|
|
|
MOVEtoSR, MOVEfromSR,
|
|
|
|
|
MOVEtoCCR,
|
2022-04-12 11:49:08 +00:00
|
|
|
|
MOVEtoUSP, MOVEfromUSP,
|
2022-04-11 19:00:55 +00:00
|
|
|
|
|
|
|
|
|
ORItoSR, ORItoCCR,
|
|
|
|
|
ANDItoSR, ANDItoCCR,
|
|
|
|
|
EORItoSR, EORItoCCR,
|
|
|
|
|
|
2022-04-15 19:33:54 +00:00
|
|
|
|
BTST, BCLR,
|
|
|
|
|
BCHG, BSET,
|
|
|
|
|
|
2022-04-11 19:00:55 +00:00
|
|
|
|
CMPb, CMPw, CMPl,
|
2022-04-12 11:49:08 +00:00
|
|
|
|
CMPAw, CMPAl,
|
2022-04-11 19:00:55 +00:00
|
|
|
|
TSTb, TSTw, TSTl,
|
|
|
|
|
|
2022-04-18 12:55:46 +00:00
|
|
|
|
JMP,
|
|
|
|
|
JSR, RTS,
|
2022-04-11 19:00:55 +00:00
|
|
|
|
DBcc,
|
|
|
|
|
Scc,
|
|
|
|
|
|
2022-10-22 19:20:30 +00:00
|
|
|
|
Bccb, Bccw,
|
|
|
|
|
BSRb, BSRw,
|
2022-04-18 12:55:46 +00:00
|
|
|
|
|
2022-04-11 19:00:55 +00:00
|
|
|
|
CLRb, CLRw, CLRl,
|
|
|
|
|
NEGXb, NEGXw, NEGXl,
|
|
|
|
|
NEGb, NEGw, NEGl,
|
|
|
|
|
|
|
|
|
|
ASLb, ASLw, ASLl, ASLm,
|
|
|
|
|
ASRb, ASRw, ASRl, ASRm,
|
|
|
|
|
LSLb, LSLw, LSLl, LSLm,
|
|
|
|
|
LSRb, LSRw, LSRl, LSRm,
|
|
|
|
|
ROLb, ROLw, ROLl, ROLm,
|
|
|
|
|
RORb, RORw, RORl, RORm,
|
|
|
|
|
ROXLb, ROXLw, ROXLl, ROXLm,
|
|
|
|
|
ROXRb, ROXRw, ROXRl, ROXRm,
|
|
|
|
|
|
2022-05-06 13:45:06 +00:00
|
|
|
|
MOVEMtoRl, MOVEMtoRw,
|
|
|
|
|
MOVEMtoMl, MOVEMtoMw,
|
|
|
|
|
|
2022-04-12 20:17:30 +00:00
|
|
|
|
MOVEPl, MOVEPw,
|
2022-04-11 19:00:55 +00:00
|
|
|
|
|
|
|
|
|
ANDb, ANDw, ANDl,
|
|
|
|
|
EORb, EORw, EORl,
|
|
|
|
|
NOTb, NOTw, NOTl,
|
|
|
|
|
ORb, ORw, ORl,
|
|
|
|
|
|
2022-10-22 19:20:30 +00:00
|
|
|
|
MULUw, MULSw,
|
|
|
|
|
DIVUw, DIVSw,
|
2022-04-11 19:00:55 +00:00
|
|
|
|
|
2022-04-12 11:49:08 +00:00
|
|
|
|
RTE, RTR,
|
2022-04-11 19:00:55 +00:00
|
|
|
|
|
|
|
|
|
TRAP, TRAPV,
|
2022-10-22 19:20:30 +00:00
|
|
|
|
CHKw,
|
2022-04-11 19:00:55 +00:00
|
|
|
|
|
|
|
|
|
EXG, SWAP,
|
|
|
|
|
|
|
|
|
|
TAS,
|
|
|
|
|
|
|
|
|
|
EXTbtow, EXTwtol,
|
|
|
|
|
|
2022-04-15 13:40:37 +00:00
|
|
|
|
LINKw, UNLINK,
|
2022-04-11 19:00:55 +00:00
|
|
|
|
|
2022-04-12 11:49:08 +00:00
|
|
|
|
STOP, RESET,
|
2022-04-12 20:17:30 +00:00
|
|
|
|
|
2022-10-25 13:50:19 +00:00
|
|
|
|
//
|
|
|
|
|
// 68010 additions.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
BKPT, RTD,
|
|
|
|
|
|
2022-10-21 19:28:29 +00:00
|
|
|
|
//
|
|
|
|
|
// 68020 additions.
|
|
|
|
|
//
|
2022-10-22 19:20:30 +00:00
|
|
|
|
|
2022-10-25 13:50:19 +00:00
|
|
|
|
TRAPcc,
|
|
|
|
|
|
|
|
|
|
CALLM, RTM,
|
2022-10-21 19:28:29 +00:00
|
|
|
|
|
|
|
|
|
BFCHG, BFCLR,
|
|
|
|
|
BFEXTS, BFEXTU,
|
|
|
|
|
BFFFO, BFINS,
|
|
|
|
|
BFSET, BFTST,
|
|
|
|
|
|
2022-10-22 19:20:30 +00:00
|
|
|
|
PACK, UNPK,
|
2022-10-21 19:28:29 +00:00
|
|
|
|
|
2022-10-22 19:20:30 +00:00
|
|
|
|
CASb, CASw, CASl,
|
|
|
|
|
CAS2w, CAS2l,
|
2022-10-21 19:28:29 +00:00
|
|
|
|
|
2022-10-22 19:20:30 +00:00
|
|
|
|
CHK2b, CHK2w, CHK2l,
|
|
|
|
|
CMP2b, CMP2w, CMP2l,
|
2022-10-21 19:28:29 +00:00
|
|
|
|
|
2022-10-22 19:20:30 +00:00
|
|
|
|
DIVSl, DIVUl,
|
|
|
|
|
MULSl, MULUl,
|
|
|
|
|
|
|
|
|
|
Bccl, BSRl,
|
|
|
|
|
LINKl, CHKl,
|
|
|
|
|
|
|
|
|
|
EXTbtol,
|
2022-10-21 19:28:29 +00:00
|
|
|
|
|
|
|
|
|
cpBcc, cpDBcc, cpGEN,
|
|
|
|
|
cpScc, cpTRAPcc, cpRESTORE,
|
|
|
|
|
cpSAVE,
|
|
|
|
|
|
|
|
|
|
MOVEfromCCR,
|
|
|
|
|
MOVEC, MOVES,
|
|
|
|
|
|
2022-10-25 13:50:19 +00:00
|
|
|
|
//
|
|
|
|
|
// 68030 additions.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
PFLUSH, PFLUSHA,
|
|
|
|
|
PLOADR, PLOADW,
|
|
|
|
|
PMOVE, PMOVEFD,
|
|
|
|
|
PTESTR, PTESTW,
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// 68040 additions.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
// TODO: the big addition of the 68040 is incorporation of the FPU; should I make decoding of those instructions
|
|
|
|
|
// dependent upon a 68040 being selected, or should I offer a separate decoder in order to support systems with
|
|
|
|
|
// a coprocessor?
|
|
|
|
|
|
2022-10-21 19:28:29 +00:00
|
|
|
|
//
|
|
|
|
|
// Introspection.
|
|
|
|
|
//
|
2022-10-25 13:50:19 +00:00
|
|
|
|
Max68000 = RESET,
|
|
|
|
|
Max68010 = RTD,
|
|
|
|
|
Max68020 = MOVES,
|
|
|
|
|
Max68030 = PTESTW,
|
|
|
|
|
Max68040 = PTESTW,
|
2022-04-11 19:00:55 +00:00
|
|
|
|
};
|
|
|
|
|
|
2022-09-06 01:52:20 +00:00
|
|
|
|
const char *to_string(Operation op);
|
|
|
|
|
|
2022-06-01 12:20:06 +00:00
|
|
|
|
template <Model model>
|
|
|
|
|
constexpr bool requires_supervisor(Operation op) {
|
|
|
|
|
switch(op) {
|
2022-04-26 00:05:45 +00:00
|
|
|
|
case Operation::MOVEfromSR:
|
|
|
|
|
if constexpr (model == Model::M68000) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
[[fallthrough]];
|
|
|
|
|
case Operation::ORItoSR: case Operation::ANDItoSR:
|
|
|
|
|
case Operation::EORItoSR: case Operation::RTE:
|
|
|
|
|
case Operation::RESET: case Operation::STOP:
|
|
|
|
|
case Operation::MOVEtoUSP: case Operation::MOVEfromUSP:
|
2022-05-13 13:01:03 +00:00
|
|
|
|
case Operation::MOVEtoSR:
|
2022-04-15 13:40:37 +00:00
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-23 15:46:47 +00:00
|
|
|
|
inline constexpr bool requires_extension_word(Operation op) {
|
|
|
|
|
switch(op) {
|
|
|
|
|
case Operation::PACK:
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-26 16:30:14 +00:00
|
|
|
|
enum class DataSize {
|
|
|
|
|
Byte = 0,
|
|
|
|
|
Word = 1,
|
|
|
|
|
LongWord = 2,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// Classifies operations by the size of their memory accesses, if any.
|
2022-05-05 22:51:29 +00:00
|
|
|
|
///
|
|
|
|
|
/// For any operations that don't fit the neat model of reading one or two operands,
|
|
|
|
|
/// then writing zero or one, the size determines the data size of the operands only,
|
|
|
|
|
/// not any other accesses.
|
2022-05-19 14:27:51 +00:00
|
|
|
|
template <Operation t_operation = Operation::Undefined>
|
|
|
|
|
constexpr DataSize operand_size(Operation operation = Operation::Undefined);
|
2022-04-13 13:29:12 +00:00
|
|
|
|
|
2022-05-03 15:09:57 +00:00
|
|
|
|
template <Operation t_op = Operation::Undefined>
|
|
|
|
|
constexpr uint32_t quick(uint16_t instruction, Operation r_op = Operation::Undefined) {
|
|
|
|
|
switch((t_op != Operation::Undefined) ? t_op : r_op) {
|
2022-04-21 20:05:00 +00:00
|
|
|
|
case Operation::Bccb:
|
2022-04-21 20:13:06 +00:00
|
|
|
|
case Operation::BSRb:
|
2022-04-26 16:30:14 +00:00
|
|
|
|
case Operation::MOVEl: return uint32_t(int8_t(instruction));
|
|
|
|
|
case Operation::TRAP: return uint32_t(instruction & 15);
|
2022-10-21 19:28:29 +00:00
|
|
|
|
case Operation::BKPT: return uint32_t(instruction & 7);
|
2022-04-21 20:05:00 +00:00
|
|
|
|
default: {
|
2022-04-26 16:30:14 +00:00
|
|
|
|
uint32_t value = (instruction >> 9) & 7;
|
2022-04-21 20:05:00 +00:00
|
|
|
|
value |= (value - 1)&8;
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-03 15:09:57 +00:00
|
|
|
|
static constexpr uint8_t FetchOp1 = (1 << 0);
|
|
|
|
|
static constexpr uint8_t FetchOp2 = (1 << 1);
|
|
|
|
|
static constexpr uint8_t StoreOp1 = (1 << 2);
|
|
|
|
|
static constexpr uint8_t StoreOp2 = (1 << 3);
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Provides a bitfield with a value in the range 0–15 indicating which of the provided operation's
|
2022-05-10 00:32:02 +00:00
|
|
|
|
operands are accessed via standard fetch and store cycles; the bitfield is composted of
|
|
|
|
|
[Fetch/Store]Op[1/2] as defined above.
|
2022-04-22 14:06:39 +00:00
|
|
|
|
|
2022-05-03 15:09:57 +00:00
|
|
|
|
Unusual bus sequences, such as TAS or MOVEM, are not described here.
|
|
|
|
|
*/
|
2022-05-09 13:24:35 +00:00
|
|
|
|
template <Model model, Operation t_operation = Operation::Undefined>
|
2022-05-19 19:49:42 +00:00
|
|
|
|
constexpr uint8_t operand_flags(Operation r_operation = Operation::Undefined);
|
2022-04-21 20:05:00 +00:00
|
|
|
|
|
2022-05-09 13:24:35 +00:00
|
|
|
|
/// Lists the various condition codes used by the 680x0.
|
2022-04-30 13:00:47 +00:00
|
|
|
|
enum class Condition {
|
|
|
|
|
True = 0x00, False = 0x01,
|
|
|
|
|
High = 0x02, LowOrSame = 0x03,
|
|
|
|
|
CarryClear = 0x04, CarrySet = 0x05,
|
|
|
|
|
NotEqual = 0x06, Equal = 0x07,
|
|
|
|
|
OverflowClear = 0x08, OverflowSet = 0x09,
|
|
|
|
|
Positive = 0x0a, Negative = 0x0b,
|
|
|
|
|
GreaterThanOrEqual = 0x0c, LessThan = 0x0d,
|
|
|
|
|
GreaterThan = 0x0e, LessThanOrEqual = 0x0f,
|
|
|
|
|
};
|
|
|
|
|
|
2022-04-11 19:00:55 +00:00
|
|
|
|
/// Indicates the addressing mode applicable to an operand.
|
|
|
|
|
///
|
|
|
|
|
/// Implementation notes:
|
|
|
|
|
///
|
|
|
|
|
/// Those entries starting 0b00 or 0b01 are mapped as per the 68000's native encoding;
|
|
|
|
|
/// those starting 0b00 are those which are indicated directly by a mode field and those starting
|
|
|
|
|
/// 0b01 are those which are indicated by a register field given a mode of 0b111. The only minor
|
|
|
|
|
/// exception is AddressRegisterDirect, which exists on a 68000 but isn't specifiable by a
|
|
|
|
|
/// mode and register, it's contextual based on the instruction.
|
|
|
|
|
///
|
|
|
|
|
/// Those modes starting in 0b10 are the various extended addressing modes introduced as
|
|
|
|
|
/// of the 68020, which can be detected only after interpreting an extension word. At the
|
|
|
|
|
/// Preinstruction stage:
|
|
|
|
|
///
|
|
|
|
|
/// * AddressRegisterIndirectWithIndexBaseDisplacement, MemoryIndirectPostindexed
|
|
|
|
|
/// and MemoryIndirectPreindexed will have been partially decoded as
|
|
|
|
|
/// AddressRegisterIndirectWithIndex8bitDisplacement; and
|
|
|
|
|
/// * ProgramCounterIndirectWithIndexBaseDisplacement,
|
|
|
|
|
/// ProgramCounterMemoryIndirectPostindexed and
|
|
|
|
|
/// ProgramCounterMemoryIndirectPreindexed will have been partially decoded
|
|
|
|
|
/// as ProgramCounterIndirectWithIndex8bitDisplacement.
|
|
|
|
|
enum class AddressingMode: uint8_t {
|
|
|
|
|
/// No adddressing mode; this operand doesn't exist.
|
2022-04-24 14:43:06 +00:00
|
|
|
|
None = 0b01'101,
|
2022-04-11 19:00:55 +00:00
|
|
|
|
|
|
|
|
|
/// Dn
|
|
|
|
|
DataRegisterDirect = 0b00'000,
|
|
|
|
|
|
|
|
|
|
/// An
|
2022-04-12 18:54:11 +00:00
|
|
|
|
AddressRegisterDirect = 0b00'001,
|
2022-04-11 19:00:55 +00:00
|
|
|
|
/// (An)
|
|
|
|
|
AddressRegisterIndirect = 0b00'010,
|
|
|
|
|
/// (An)+
|
|
|
|
|
AddressRegisterIndirectWithPostincrement = 0b00'011,
|
|
|
|
|
/// -(An)
|
|
|
|
|
AddressRegisterIndirectWithPredecrement = 0b00'100,
|
|
|
|
|
/// (d16, An)
|
|
|
|
|
AddressRegisterIndirectWithDisplacement = 0b00'101,
|
|
|
|
|
/// (d8, An, Xn)
|
|
|
|
|
AddressRegisterIndirectWithIndex8bitDisplacement = 0b00'110,
|
2022-05-01 19:10:54 +00:00
|
|
|
|
/// (bd, An, Xn) [68020+]
|
2022-04-11 19:00:55 +00:00
|
|
|
|
AddressRegisterIndirectWithIndexBaseDisplacement = 0b10'000,
|
|
|
|
|
|
2022-05-01 19:10:54 +00:00
|
|
|
|
/// ([bd, An, Xn], od) [68020+]
|
2022-04-11 19:00:55 +00:00
|
|
|
|
MemoryIndirectPostindexed = 0b10'001,
|
2022-05-01 19:10:54 +00:00
|
|
|
|
/// ([bd, An], Xn, od) [68020+]
|
2022-04-11 19:00:55 +00:00
|
|
|
|
MemoryIndirectPreindexed = 0b10'010,
|
|
|
|
|
|
|
|
|
|
/// (d16, PC)
|
|
|
|
|
ProgramCounterIndirectWithDisplacement = 0b01'010,
|
|
|
|
|
/// (d8, PC, Xn)
|
|
|
|
|
ProgramCounterIndirectWithIndex8bitDisplacement = 0b01'011,
|
2022-05-01 19:10:54 +00:00
|
|
|
|
/// (bd, PC, Xn) [68020+]
|
2022-04-11 19:00:55 +00:00
|
|
|
|
ProgramCounterIndirectWithIndexBaseDisplacement = 0b10'011,
|
2022-05-01 19:10:54 +00:00
|
|
|
|
/// ([bd, PC, Xn], od) [68020+]
|
2022-04-11 19:00:55 +00:00
|
|
|
|
ProgramCounterMemoryIndirectPostindexed = 0b10'100,
|
2022-05-01 19:10:54 +00:00
|
|
|
|
/// ([bc, PC], Xn, od) [68020+]
|
2022-04-11 19:00:55 +00:00
|
|
|
|
ProgramCounterMemoryIndirectPreindexed = 0b10'101,
|
|
|
|
|
|
|
|
|
|
/// (xxx).W
|
|
|
|
|
AbsoluteShort = 0b01'000,
|
|
|
|
|
/// (xxx).L
|
|
|
|
|
AbsoluteLong = 0b01'001,
|
|
|
|
|
|
|
|
|
|
/// #
|
|
|
|
|
ImmediateData = 0b01'100,
|
2022-04-13 13:29:12 +00:00
|
|
|
|
|
2022-10-22 19:20:30 +00:00
|
|
|
|
/// An additional word of data. Differs from ImmediateData by being
|
|
|
|
|
/// a fixed size, rather than the @c operand_size of the operation.
|
|
|
|
|
ExtensionWord = 0b01'111,
|
|
|
|
|
|
2022-04-19 12:37:35 +00:00
|
|
|
|
/// .q; value is embedded in the opcode.
|
2022-04-24 14:43:06 +00:00
|
|
|
|
Quick = 0b01'110,
|
2022-04-11 19:00:55 +00:00
|
|
|
|
};
|
2022-06-13 12:57:49 +00:00
|
|
|
|
/// Guaranteed to be 1+[largest value used by AddressingMode].
|
|
|
|
|
static constexpr int AddressingModeCount = 0b10'110;
|
2022-04-11 19:00:55 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
A preinstruction is as much of an instruction as can be decoded with
|
|
|
|
|
only the first instruction word — i.e. an operation, and:
|
|
|
|
|
|
|
|
|
|
* on the 68000 and 68010, the complete addressing modes;
|
|
|
|
|
* on subsequent, a decent proportion of the addressing mode. See
|
|
|
|
|
the notes on @c AddressingMode for potential aliasing.
|
|
|
|
|
*/
|
|
|
|
|
class Preinstruction {
|
|
|
|
|
public:
|
|
|
|
|
Operation operation = Operation::Undefined;
|
|
|
|
|
|
2022-04-12 13:14:46 +00:00
|
|
|
|
// Instructions come with 0, 1 or 2 operands;
|
|
|
|
|
// the getters below act to provide a list of operands
|
|
|
|
|
// that is terminated by an AddressingMode::None.
|
|
|
|
|
//
|
|
|
|
|
// For two-operand instructions, argument 0 is a source
|
|
|
|
|
// and argument 1 is a destination.
|
|
|
|
|
//
|
|
|
|
|
// For one-operand instructions, only argument 0 will
|
|
|
|
|
// be provided, and will be a source and/or destination as
|
|
|
|
|
// per the semantics of the operation.
|
2022-05-01 17:00:20 +00:00
|
|
|
|
//
|
|
|
|
|
// The versions templated on index do a range check;
|
|
|
|
|
// if using the runtime versions then results for indices
|
|
|
|
|
// other than 0 and 1 are undefined.
|
2022-04-12 13:14:46 +00:00
|
|
|
|
|
2022-05-01 17:00:20 +00:00
|
|
|
|
AddressingMode mode(int index) const {
|
2022-05-13 15:17:57 +00:00
|
|
|
|
return AddressingMode(operands_[index] >> 3);
|
2022-05-01 17:00:20 +00:00
|
|
|
|
}
|
2022-04-19 18:35:40 +00:00
|
|
|
|
template <int index> AddressingMode mode() const {
|
2022-04-12 13:14:46 +00:00
|
|
|
|
if constexpr (index > 1) {
|
|
|
|
|
return AddressingMode::None;
|
|
|
|
|
}
|
2022-05-01 17:00:20 +00:00
|
|
|
|
return mode(index);
|
|
|
|
|
}
|
|
|
|
|
int reg(int index) const {
|
2022-05-13 15:17:57 +00:00
|
|
|
|
return operands_[index] & 7;
|
2022-04-11 19:00:55 +00:00
|
|
|
|
}
|
2022-04-19 18:35:40 +00:00
|
|
|
|
template <int index> int reg() const {
|
2022-04-12 13:14:46 +00:00
|
|
|
|
if constexpr (index > 1) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-01 17:00:20 +00:00
|
|
|
|
return reg(index);
|
2022-04-11 19:00:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-13 15:17:57 +00:00
|
|
|
|
/// @returns 0–7 to indicate data registers 0 to 7, or 8–15 to indicate address registers 0 to 7 respectively.
|
|
|
|
|
/// Provides undefined results if the addressing mode is not either @c DataRegisterDirect or
|
|
|
|
|
/// @c AddressRegisterDirect.
|
|
|
|
|
int lreg(int index) const {
|
|
|
|
|
return operands_[index] & 0xf;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 13:50:19 +00:00
|
|
|
|
/// @returns @c true if this instruction requires supervisor privileges; @c false otherwise.
|
2022-05-01 17:00:20 +00:00
|
|
|
|
bool requires_supervisor() const {
|
2022-10-23 15:46:47 +00:00
|
|
|
|
return flags_ & Flags::IsSupervisor;
|
|
|
|
|
}
|
2022-10-25 13:50:19 +00:00
|
|
|
|
/// @returns @c true if this instruction will require further fetching than can be encoded in a
|
|
|
|
|
/// @c Preinstruction. In practice this means it is one of a very small quantity of 68020+
|
|
|
|
|
/// instructions; those that can rationalise extension words into one of the two operands will
|
|
|
|
|
/// do so. Use the free function @c extension_words(instruction.operation) to
|
|
|
|
|
/// look up the number of additional words required.
|
|
|
|
|
///
|
|
|
|
|
/// (specifically affected, at least: PACK, UNPK, CAS, CAS2)
|
|
|
|
|
bool requires_further_extension() const {
|
|
|
|
|
return flags_ & Flags::RequiresFurtherExtension;
|
2022-04-26 23:44:02 +00:00
|
|
|
|
}
|
2022-10-25 13:50:19 +00:00
|
|
|
|
/// @returns The @c DataSize used for operands of this instruction, i.e. byte, word or longword.
|
2022-05-06 13:22:38 +00:00
|
|
|
|
DataSize operand_size() const {
|
2022-10-23 15:46:47 +00:00
|
|
|
|
return DataSize((flags_ & Flags::SizeMask) >> Flags::SizeShift);
|
2022-04-30 13:00:47 +00:00
|
|
|
|
}
|
2022-10-25 13:50:19 +00:00
|
|
|
|
/// @returns The condition code evaluated by this instruction if applicable. If this instruction is not
|
|
|
|
|
/// conditional, the result is undefined.
|
2022-05-01 17:00:20 +00:00
|
|
|
|
Condition condition() const {
|
2022-10-23 15:46:47 +00:00
|
|
|
|
return Condition((flags_ & Flags::ConditionMask) >> Flags::ConditionShift);
|
2022-04-26 23:44:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 19:00:55 +00:00
|
|
|
|
private:
|
2022-04-12 13:14:46 +00:00
|
|
|
|
uint8_t operands_[2] = { uint8_t(AddressingMode::None), uint8_t(AddressingMode::None)};
|
2022-04-26 23:44:02 +00:00
|
|
|
|
uint8_t flags_ = 0;
|
2022-04-11 19:00:55 +00:00
|
|
|
|
|
2022-05-12 23:46:08 +00:00
|
|
|
|
std::string operand_description(int index, int opcode) const;
|
|
|
|
|
|
2022-04-11 19:00:55 +00:00
|
|
|
|
public:
|
|
|
|
|
Preinstruction(
|
|
|
|
|
Operation operation,
|
2022-04-12 13:14:46 +00:00
|
|
|
|
AddressingMode op1_mode, int op1_reg,
|
2022-04-12 18:54:11 +00:00
|
|
|
|
AddressingMode op2_mode, int op2_reg,
|
2022-04-26 23:44:02 +00:00
|
|
|
|
bool is_supervisor,
|
2022-10-25 13:50:19 +00:00
|
|
|
|
bool requires_further_extension,
|
2022-04-30 13:00:47 +00:00
|
|
|
|
DataSize size,
|
|
|
|
|
Condition condition) : operation(operation)
|
2022-04-12 13:14:46 +00:00
|
|
|
|
{
|
2022-05-13 15:17:57 +00:00
|
|
|
|
operands_[0] = uint8_t((uint8_t(op1_mode) << 3) | op1_reg);
|
|
|
|
|
operands_[1] = uint8_t((uint8_t(op2_mode) << 3) | op2_reg);
|
2022-04-30 13:00:47 +00:00
|
|
|
|
flags_ = uint8_t(
|
2022-10-23 15:46:47 +00:00
|
|
|
|
(is_supervisor ? Flags::IsSupervisor : 0x00) |
|
2022-10-25 13:50:19 +00:00
|
|
|
|
(requires_further_extension ? Flags::RequiresFurtherExtension : 0x00) |
|
2022-10-23 15:46:47 +00:00
|
|
|
|
(int(condition) << Flags::ConditionShift) |
|
|
|
|
|
(int(size) << Flags::SizeShift)
|
2022-04-30 13:00:47 +00:00
|
|
|
|
);
|
2022-04-11 19:00:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-23 15:46:47 +00:00
|
|
|
|
struct Flags {
|
2022-10-25 13:50:19 +00:00
|
|
|
|
static constexpr uint8_t IsSupervisor = 0b1000'0000;
|
|
|
|
|
static constexpr uint8_t RequiresFurtherExtension = 0b0100'0000;
|
|
|
|
|
static constexpr uint8_t ConditionMask = 0b0011'1100;
|
|
|
|
|
static constexpr uint8_t SizeMask = 0b0000'0011;
|
2022-10-23 15:46:47 +00:00
|
|
|
|
|
|
|
|
|
static constexpr int ConditionShift = 2;
|
|
|
|
|
static constexpr int SizeShift = 0;
|
|
|
|
|
};
|
|
|
|
|
|
2022-04-11 19:00:55 +00:00
|
|
|
|
Preinstruction() {}
|
2022-05-12 23:46:08 +00:00
|
|
|
|
|
|
|
|
|
/// Produces a string description of this instruction; if @c opcode
|
|
|
|
|
/// is supplied then any quick fields in this instruction will be decoded;
|
|
|
|
|
/// otherwise they'll be printed as just 'Q'.
|
|
|
|
|
std::string to_string(int opcode = -1) const;
|
2022-09-06 15:26:16 +00:00
|
|
|
|
|
|
|
|
|
/// Produces a slightly-more-idiomatic version of the operation name than
|
|
|
|
|
/// a direct to_string(instruction.operation) would, given that this decoder
|
|
|
|
|
/// sometimes aliases operations, disambiguating based on addressing mode
|
|
|
|
|
/// (e.g. MOVEQ is MOVE.l with the Q addressing mode).
|
|
|
|
|
const char *operation_string() const;
|
2022-04-11 19:00:55 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-09 13:24:35 +00:00
|
|
|
|
#include "Implementation/InstructionOperandSize.hpp"
|
|
|
|
|
#include "Implementation/InstructionOperandFlags.hpp"
|
|
|
|
|
|
2022-04-11 19:00:55 +00:00
|
|
|
|
#endif /* InstructionSets_68k_Instruction_hpp */
|