summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--disasm.cpp381
-rw-r--r--disasm.h356
2 files changed, 321 insertions, 416 deletions
diff --git a/disasm.cpp b/disasm.cpp
index 45b0def..317429e 100644
--- a/disasm.cpp
+++ b/disasm.cpp
@@ -32,46 +32,50 @@ enum class ShiftKind: int {
kRotate = 3,
};
-constexpr AddrModeArg FetchImmediate(const uint32_t offset, const DataBuffer &code, const OpSize s)
+constexpr Arg FetchImmediate(const uint32_t offset, const DataBuffer &code, const OpSize s)
{
if (s == OpSize::kInvalid) {
- return AddrModeArg{};
+ return Arg{};
} else if (s == OpSize::kLong) {
if (offset + kInstructionSizeStepBytes < code.occupied_size) {
const int32_t value = GetI32BE(code.buffer + offset);
- return AddrModeArg::Immediate(s, value);
+ return Arg::Immediate(value);
}
} else if (offset < code.occupied_size) {
const int16_t value = GetI16BE(code.buffer + offset);
if (s == OpSize::kByte) {
+ // Technically it is impossible to have value lower that -128 in 8
+ // bits signed integer, but the second byte being 0xff is actually
+ // a valid thing and it is how values from -255 to -129 are
+ // represented.
if (value > 255 || value < -255) {
// Invalid immediate value for instruction with .b suffix
- return AddrModeArg{};
+ return Arg{};
}
}
- return AddrModeArg::Immediate(s, value);
+ return Arg::Immediate(value);
}
- return AddrModeArg{};
+ return Arg{};
}
-constexpr AddrModeArg FetchAddrModeArg(
+constexpr Arg FetchArg(
const uint32_t offset, const DataBuffer &code, const int m, const int xn, const OpSize s)
{
switch (m) {
case 0: // Dn
- return AddrModeArg::Dn(xn);
+ return Arg::Dn(xn);
case 1: // An
- return AddrModeArg::An(xn);
+ return Arg::An(xn);
case 2: // (An)
- return AddrModeArg::AnAddr(xn);
+ return Arg::AnAddr(xn);
case 3: // (An)+
- return AddrModeArg::AnAddrIncr(xn);
+ return Arg::AnAddrIncr(xn);
case 4: // -(An)
- return AddrModeArg::AnAddrDecr(xn);
+ return Arg::AnAddrDecr(xn);
case 5: // (d16, An), Additional Word
if (offset < code.occupied_size) {
const int16_t d16 = GetI16BE(code.buffer + offset);
- return AddrModeArg::D16AnAddr(xn, d16);
+ return Arg::D16AnAddr(xn, d16);
}
break;
case 6: // (d8, An, Xi), Brief Extension Word
@@ -82,11 +86,11 @@ constexpr AddrModeArg FetchAddrModeArg(
// i.e. xxxx_x000_xxxx_xxxx
break;
}
- const char r = ((briefext >> 15) & 1) ? 'a' : 'd';
- const uint8_t xi = (briefext >> 12) & 7;
+ // Xi number (lower 3 bits, mask 0x7) with An/Dn bit (mask 0x8)
+ const uint8_t xi = (briefext >> 12) & 0xf;
const OpSize s = ((briefext >> 11) & 1) ? OpSize::kLong : OpSize::kWord;
const int8_t d8 = briefext & 0xff;
- return AddrModeArg::D8AnXiAddr(xn, r, xi, s, d8);
+ return Arg::D8AnXiAddr(xn, xi, s, d8);
}
break;
case 7:
@@ -94,19 +98,19 @@ constexpr AddrModeArg FetchAddrModeArg(
case 0: // (xxx).W, Additional Word
if (offset < code.occupied_size) {
const int32_t w = GetI16BE(code.buffer + offset);
- return AddrModeArg::Word(w);
+ return Arg::Word(w);
}
break;
case 1: // (xxx).L, Additional Long
if (offset + kInstructionSizeStepBytes < code.occupied_size) {
const int32_t l = GetI32BE(code.buffer + offset);
- return AddrModeArg::Long(l);
+ return Arg::Long(l);
}
break;
case 2: // (d16, PC), Additional Word
if (offset < code.occupied_size) {
const int16_t d16 = GetI16BE(code.buffer + offset);
- return AddrModeArg::D16PCAddr(xn, d16);
+ return Arg::D16PCAddr(d16);
}
break;
case 3: // (d8, PC, Xi), Brief Extension Word
@@ -117,11 +121,11 @@ constexpr AddrModeArg FetchAddrModeArg(
// i.e. xxxx_x000_xxxx_xxxx
break;
}
- const char r = ((briefext >> 15) & 1) ? 'a' : 'd';
- const uint8_t xi = (briefext >> 12) & 7;
+ // Xi number (lower 3 bits, mask 0x7) with An/Dn bit (mask 0x8)
+ const uint8_t xi = (briefext >> 12) & 0xf;
const OpSize s = ((briefext >> 11) & 1) ? OpSize::kLong : OpSize::kWord;
const int8_t d8 = briefext & 0xff;
- return AddrModeArg::D8PCXiAddr(xn, r, xi, s, d8);
+ return Arg::D8PCXiAddr(xn, xi, s, d8);
}
break;
case 4: // #imm
@@ -133,16 +137,16 @@ constexpr AddrModeArg FetchAddrModeArg(
}
break;
}
- return AddrModeArg{};
+ return Arg{};
}
-static inline AddrModeArg FetchAddrModeArg(
+static inline Arg FetchArg(
const uint32_t offset, const DataBuffer &code, const uint16_t instr, const OpSize s)
{
const int addrmode = instr & 0x3f;
const int m = (addrmode >> 3) & 7;
const int xn = addrmode & 7;
- return FetchAddrModeArg(offset, code, m, xn, s);
+ return FetchArg(offset, code, m, xn, s);
}
static size_t disasm_verbatim(DisasmNode &node, const uint16_t instr)
@@ -156,7 +160,8 @@ static size_t disasm_verbatim(DisasmNode &node, const uint16_t instr)
static size_t disasm_jsr_jmp(
DisasmNode &node, const uint16_t instr, const DataBuffer &code, const JKind jtype)
{
- const auto a = FetchAddrModeArg(node.offset + kInstructionSizeStepBytes, code, instr, OpSize::kWord);
+ const OpSize opsize = OpSize::kWord;
+ const auto a = FetchArg(node.offset + kInstructionSizeStepBytes, code, instr, opsize);
switch (a.mode) {
case AddrMode::kInvalid:
case AddrMode::kDn: // 4e80..4e87 / 4ec0..4ec7
@@ -180,7 +185,7 @@ static size_t disasm_jsr_jmp(
case AddrMode::kWord: // 4eb8 / 4ef8
{
// FIXME support s.abs_marks option for this instruction
- const uint32_t branch_addr = static_cast<uint32_t>(a.value);
+ const uint32_t branch_addr = static_cast<uint32_t>(a.lword);
node.branch_addr = branch_addr;
node.has_branch_addr = true;
}
@@ -188,7 +193,7 @@ static size_t disasm_jsr_jmp(
case AddrMode::kLong: // 4eb9 / 4ef9
{
// FIXME support s.abs_marks option for this instruction
- const uint32_t branch_addr = static_cast<uint32_t>(a.value);
+ const uint32_t branch_addr = static_cast<uint32_t>(a.lword);
node.branch_addr = branch_addr;
node.has_branch_addr = true;
}
@@ -196,7 +201,7 @@ static size_t disasm_jsr_jmp(
case AddrMode::kD16PCAddr: // 4eba / 4efa
{
// FIXME support s.abs_marks option for this instruction
- const uint32_t branch_addr = static_cast<uint32_t>(a.value) + kInstructionSizeStepBytes;
+ const uint32_t branch_addr = static_cast<uint32_t>(a.lword) + kInstructionSizeStepBytes;
node.branch_addr = branch_addr;
node.has_branch_addr = true;
}
@@ -211,20 +216,20 @@ static size_t disasm_jsr_jmp(
node.is_call = (jtype == JKind::kJsr);
node.opcode = (jtype == JKind::kJsr) ? OpCode::kJSR : OpCode::kJMP;
node.size_spec = OpSize::kNone;
- node.arg1 = Arg::FromAddrModeArg(a);
- return node.size = kInstructionSizeStepBytes + a.Size();
+ node.arg1 = a;
+ return node.size = kInstructionSizeStepBytes + a.Size(opsize);
}
static inline size_t disasm_ext(
DisasmNode &node,
const OpSize opsize,
- const AddrModeArg arg)
+ const Arg arg)
{
assert(arg.mode == AddrMode::kDn);
node.opcode = OpCode::kEXT;
node.size_spec = opsize;
- node.arg1 = Arg::FromAddrModeArg(arg);
- return node.size = kInstructionSizeStepBytes + arg.Size();
+ node.arg1 = arg;
+ return node.size = kInstructionSizeStepBytes + arg.Size(opsize);
}
static size_t disasm_ext_movem(
@@ -235,7 +240,7 @@ static size_t disasm_ext_movem(
const unsigned xn = instr & 7;
const auto opsize = static_cast<OpSize>(((instr >> 6) & 1) + 1);
if (m == 0 && dir == MoveDirection::kRegisterToMemory) {
- return disasm_ext(node, opsize, AddrModeArg::Dn(xn));
+ return disasm_ext(node, opsize, Arg::Dn(xn));
}
if (node.offset + kInstructionSizeStepBytes >= code.occupied_size) {
// Not enough space for regmask, but maybe it is just EXT?
@@ -246,7 +251,7 @@ static size_t disasm_ext_movem(
// This is just not representable: at least one register must be specified
return disasm_verbatim(node, instr);
}
- const auto a = FetchAddrModeArg(
+ const auto a = FetchArg(
node.offset + kInstructionSizeStepBytes * 2, code, m, xn, opsize);
switch (a.mode) {
case AddrMode::kInvalid:
@@ -282,20 +287,21 @@ static size_t disasm_ext_movem(
node.opcode = OpCode::kMOVEM;
node.size_spec = opsize;
if (dir == MoveDirection::kMemoryToRegister) {
- node.arg1 = Arg::FromAddrModeArg(a);
+ node.arg1 = a;
node.arg2 = (a.mode == AddrMode::kAnAddrDecr) ? Arg::RegMaskPredecrement(regmask) : Arg::RegMask(regmask);
} else {
node.arg1 = (a.mode == AddrMode::kAnAddrDecr) ? Arg::RegMaskPredecrement(regmask) : Arg::RegMask(regmask);
- node.arg2 = Arg::FromAddrModeArg(a);
+ node.arg2 = a;
}
- return node.size = kInstructionSizeStepBytes * 2 + a.Size();
+ return node.size = kInstructionSizeStepBytes * 2 + a.Size(opsize);
}
static size_t disasm_lea(
DisasmNode &node, const uint16_t instr, const DataBuffer &code)
{
- const auto addr = FetchAddrModeArg(
- node.offset + kInstructionSizeStepBytes, code, instr, OpSize::kLong);
+ const OpSize opsize = OpSize::kLong;
+ const auto addr = FetchArg(
+ node.offset + kInstructionSizeStepBytes, code, instr, opsize);
switch (addr.mode) {
case AddrMode::kInvalid:
case AddrMode::kDn:
@@ -317,19 +323,20 @@ static size_t disasm_lea(
return disasm_verbatim(node, instr);
}
const unsigned an = ((instr >> 9) & 7);
- const auto reg = AddrModeArg::An(an);
+ const auto reg = Arg::An(an);
node.opcode = OpCode::kLEA;
node.size_spec = OpSize::kLong;
- node.arg1 = Arg::FromAddrModeArg(addr);
- node.arg2 = Arg::FromAddrModeArg(reg);
- return node.size = kInstructionSizeStepBytes + addr.Size() + reg.Size();
+ node.arg1 = addr;
+ node.arg2 = reg;
+ return node.size = kInstructionSizeStepBytes + addr.Size(opsize) + reg.Size(opsize);
}
static size_t disasm_chk(
DisasmNode &node, const uint16_t instr, const DataBuffer &code)
{
- const auto src = FetchAddrModeArg(
- node.offset + kInstructionSizeStepBytes, code, instr, OpSize::kWord);
+ const OpSize opsize = OpSize::kWord;
+ const auto src = FetchArg(
+ node.offset + kInstructionSizeStepBytes, code, instr, opsize);
switch (src.mode) {
case AddrMode::kInvalid:
return disasm_verbatim(node, instr);
@@ -351,12 +358,12 @@ static size_t disasm_chk(
return disasm_verbatim(node, instr);
}
const unsigned dn = ((instr >> 9) & 7);
- const auto dst = AddrModeArg::Dn(dn);
+ const auto dst = Arg::Dn(dn);
node.opcode = OpCode::kCHK;
node.size_spec = OpSize::kWord;
- node.arg1 = Arg::FromAddrModeArg(src);
- node.arg2 = Arg::FromAddrModeArg(dst);
- return node.size = kInstructionSizeStepBytes + src.Size() + dst.Size();
+ node.arg1 = src;
+ node.arg2 = dst;
+ return node.size = kInstructionSizeStepBytes + src.Size(opsize) + dst.Size(opsize);
}
static size_t disasm_bra_bsr_bcc(
@@ -413,24 +420,24 @@ static inline size_t disasm_movep(
const unsigned an = instr & 7;
const OpSize opsize = ((instr >> 6) & 1) ? OpSize::kLong : OpSize::kWord;
const auto dir = static_cast<MoveDirection>(!((instr >> 7) & 1));
- const auto addr = FetchAddrModeArg(
+ const auto addr = FetchArg(
node.offset + kInstructionSizeStepBytes, code, 5, an, opsize);
if (addr.mode == AddrMode::kInvalid) {
// Boundary check failed, most likely
return disasm_verbatim(node, instr);
}
assert(addr.mode == AddrMode::kD16AnAddr);
- const auto reg = AddrModeArg::Dn(dn);
+ const auto reg = Arg::Dn(dn);
node.opcode = OpCode::kMOVEP;
node.size_spec = opsize;
if (dir == MoveDirection::kRegisterToMemory) {
- node.arg1 = Arg::FromAddrModeArg(reg);
- node.arg2 = Arg::FromAddrModeArg(addr);
+ node.arg1 = reg;
+ node.arg2 = addr;
} else {
- node.arg1 = Arg::FromAddrModeArg(addr);
- node.arg2 = Arg::FromAddrModeArg(reg);
+ node.arg1 = addr;
+ node.arg2 = reg;
}
- return node.size = kInstructionSizeStepBytes + addr.Size() + reg.Size();
+ return node.size = kInstructionSizeStepBytes + addr.Size(opsize) + reg.Size(opsize);
}
static size_t disasm_src_arg_bitops_movep(
@@ -447,7 +454,7 @@ static size_t disasm_src_arg_bitops_movep(
const unsigned xn = instr & 7;
// Fetch AddrMode::kDn if has_dn_src, otherwise fetch AddrMode::kImmediate
// byte
- const auto src = FetchAddrModeArg(
+ const auto src = FetchArg(
node.offset + kInstructionSizeStepBytes,
code,
(has_dn_src) ? 0 : 7,
@@ -462,8 +469,9 @@ static size_t disasm_src_arg_bitops_movep(
assert(dn == 4);
assert(src.mode == AddrMode::kImmediate);
}
- const auto dst = FetchAddrModeArg(
- node.offset + kInstructionSizeStepBytes + src.Size(), code, m, xn, OpSize::kWord);
+ const OpSize opsize = OpSize::kWord;
+ const auto dst = FetchArg(
+ node.offset + kInstructionSizeStepBytes + src.Size(opsize), code, m, xn, opsize);
const unsigned opcode = (instr >> 6) & 3;
switch (dst.mode) {
case AddrMode::kInvalid:
@@ -492,9 +500,9 @@ static size_t disasm_src_arg_bitops_movep(
}
node.opcode = OpCodeForBitOps(opcode);
node.size_spec = dst.mode == AddrMode::kDn ? OpSize::kLong : OpSize::kByte;
- node.arg1 = Arg::FromAddrModeArg(src);
- node.arg2 = Arg::FromAddrModeArg(dst);
- return node.size = kInstructionSizeStepBytes + src.Size() + dst.Size();
+ node.arg1 = src;
+ node.arg2 = dst;
+ return node.size = kInstructionSizeStepBytes + src.Size(opsize) + dst.Size(opsize);
}
static size_t disasm_bitops(DisasmNode &n, const uint16_t i, const DataBuffer &c)
@@ -503,11 +511,11 @@ static size_t disasm_bitops(DisasmNode &n, const uint16_t i, const DataBuffer &c
}
static size_t disasm_logical_immediate_to(
- DisasmNode &node, OpCode opcode, OpSize opsize, AddrModeArg imm)
+ DisasmNode &node, OpCode opcode, OpSize opsize, Arg imm)
{
node.opcode = opcode;
node.size_spec = opsize;
- node.arg1 = Arg::FromAddrModeArg(imm);
+ node.arg1 = imm;
node.arg2 = (opsize == OpSize::kByte) ? Arg::CCR() : Arg::SR();
return node.size = kInstructionSizeStepBytes * 2;
}
@@ -571,8 +579,8 @@ static size_t disasm_bitops_movep(
if (m == 7 && xn == 4) {
return disasm_logical_immediate_to(node, mnemonic, opsize, src);
}
- const auto dst = FetchAddrModeArg(
- node.offset + kInstructionSizeStepBytes + src.Size(), code, m, xn, opsize);
+ const auto dst = FetchArg(
+ node.offset + kInstructionSizeStepBytes + src.Size(opsize), code, m, xn, opsize);
switch (dst.mode) {
case AddrMode::kInvalid:
return disasm_verbatim(node, instr);
@@ -600,9 +608,9 @@ static size_t disasm_bitops_movep(
}
node.opcode = mnemonic;
node.size_spec = opsize;
- node.arg1 = Arg::FromAddrModeArg(src);
- node.arg2 = Arg::FromAddrModeArg(dst);
- return node.size = kInstructionSizeStepBytes + src.Size() + dst.Size();
+ node.arg1 = src;
+ node.arg2 = dst;
+ return node.size = kInstructionSizeStepBytes + src.Size(opsize) + dst.Size(opsize);
}
static size_t disasm_move_movea(
@@ -611,7 +619,7 @@ static size_t disasm_move_movea(
const int opsize_raw = (instr >> 12) & 3;
const OpSize opsize = (opsize_raw == 1)
? OpSize::kByte : (opsize_raw == 3 ? OpSize::kWord : OpSize::kLong);
- const auto src = FetchAddrModeArg(
+ const auto src = FetchArg(
node.offset + kInstructionSizeStepBytes, code, instr, opsize);
if (src.mode == AddrMode::kInvalid) {
return disasm_verbatim(node, instr);
@@ -622,8 +630,8 @@ static size_t disasm_move_movea(
}
const int m = (instr >> 6) & 7;
const int xn = (instr >> 9) & 7;
- const auto dst = FetchAddrModeArg(
- node.offset + kInstructionSizeStepBytes + src.Size(), code, m, xn, opsize);
+ const auto dst = FetchArg(
+ node.offset + kInstructionSizeStepBytes + src.Size(opsize), code, m, xn, opsize);
switch (dst.mode) {
case AddrMode::kInvalid:
return disasm_verbatim(node, instr);
@@ -649,16 +657,16 @@ static size_t disasm_move_movea(
}
node.opcode = (dst.mode == AddrMode::kAn) ? OpCode::kMOVEA : OpCode::kMOVE;
node.size_spec = opsize;
- node.arg1 = Arg::FromAddrModeArg(src);
- node.arg2 = Arg::FromAddrModeArg(dst);
- return node.size = kInstructionSizeStepBytes + src.Size() + dst.Size();
+ node.arg1 = src;
+ node.arg2 = dst;
+ return node.size = kInstructionSizeStepBytes + src.Size(opsize) + dst.Size(opsize);
}
static size_t disasm_move_from_sr(
DisasmNode &node, const uint16_t instr, const DataBuffer &code)
{
const auto opsize = OpSize::kWord;
- const auto dst = FetchAddrModeArg(
+ const auto dst = FetchArg(
node.offset + kInstructionSizeStepBytes, code, instr, opsize);
switch (dst.mode) {
case AddrMode::kInvalid:
@@ -683,15 +691,15 @@ static size_t disasm_move_from_sr(
node.opcode = OpCode::kMOVE;
node.size_spec = opsize;
node.arg1 = Arg::SR();
- node.arg2 = Arg::FromAddrModeArg(dst);
- return node.size = kInstructionSizeStepBytes + dst.Size();
+ node.arg2 = dst;
+ return node.size = kInstructionSizeStepBytes + dst.Size(opsize);
}
static size_t disasm_move_to(
DisasmNode &node, const uint16_t instr, const DataBuffer &code, const ArgType reg)
{
const auto opsize = OpSize::kWord;
- const auto src = FetchAddrModeArg(
+ const auto src = FetchArg(
node.offset + kInstructionSizeStepBytes, code, instr, opsize);
switch (src.mode) {
case AddrMode::kInvalid:
@@ -714,9 +722,9 @@ static size_t disasm_move_to(
}
node.opcode = OpCode::kMOVE;
node.size_spec = opsize;
- node.arg1 = Arg::FromAddrModeArg(src);
+ node.arg1 = src;
node.arg2 = Arg{reg, 0};
- return node.size = kInstructionSizeStepBytes + src.Size();
+ return node.size = kInstructionSizeStepBytes + src.Size(opsize);
}
static OpCode opcode_for_negx_clr_neg_not(const unsigned opcode)
@@ -750,7 +758,7 @@ static size_t disasm_move_negx_clr_neg_not(
assert(false);
return disasm_verbatim(node, instr);
}
- const auto a = FetchAddrModeArg(
+ const auto a = FetchArg(
node.offset + kInstructionSizeStepBytes, code, instr, opsize);
switch (a.mode) {
case AddrMode::kInvalid:
@@ -774,8 +782,8 @@ static size_t disasm_move_negx_clr_neg_not(
}
node.opcode = opcode_for_negx_clr_neg_not(opcode);
node.size_spec = opsize;
- node.arg1 = Arg::FromAddrModeArg(a);
- return node.size = kInstructionSizeStepBytes + a.Size();
+ node.arg1 = a;
+ return node.size = kInstructionSizeStepBytes + a.Size(opsize);
}
static inline size_t disasm_trivial(
@@ -790,7 +798,7 @@ static inline size_t disasm_tas(
DisasmNode &node, const uint16_t instr, const DataBuffer &code)
{
const auto opsize = OpSize::kByte;
- const auto a = FetchAddrModeArg(
+ const auto a = FetchArg(
node.offset + kInstructionSizeStepBytes, code, instr, opsize);
switch (a.mode) {
case AddrMode::kInvalid:
@@ -814,8 +822,8 @@ static inline size_t disasm_tas(
}
node.opcode = OpCode::kTAS;
node.size_spec = opsize;
- node.arg1 = Arg::FromAddrModeArg(a);
- return node.size = kInstructionSizeStepBytes + a.Size();
+ node.arg1 = a;
+ return node.size = kInstructionSizeStepBytes + a.Size(opsize);
}
static size_t disasm_tst_tas_illegal(
@@ -830,7 +838,7 @@ static size_t disasm_tst_tas_illegal(
}
return disasm_tas(node, instr, code);
}
- const auto a = FetchAddrModeArg(node.offset + kInstructionSizeStepBytes, code, m, xn, opsize);
+ const auto a = FetchArg(node.offset + kInstructionSizeStepBytes, code, m, xn, opsize);
switch (a.mode) {
case AddrMode::kInvalid:
return disasm_verbatim(node, instr);
@@ -853,8 +861,8 @@ static size_t disasm_tst_tas_illegal(
}
node.opcode = OpCode::kTST;
node.size_spec = opsize;
- node.arg1 = Arg::FromAddrModeArg(a);
- return node.size = kInstructionSizeStepBytes + a.Size();
+ node.arg1 = a;
+ return node.size = kInstructionSizeStepBytes + a.Size(opsize);
}
static size_t disasm_trap(DisasmNode &node, const uint16_t instr)
@@ -884,8 +892,8 @@ static size_t disasm_link_unlink(DisasmNode &node, const uint16_t instr, const D
node.opcode = OpCode::kLINK;
node.size_spec = opsize;
node.arg1 = Arg::AddrModeXn(ArgType::kAn, xn);
- node.arg2 = Arg::FromAddrModeArg(src);
- return node.size = kInstructionSizeStepBytes + src.Size();
+ node.arg2 = src;
+ return node.size = kInstructionSizeStepBytes + src.Size(opsize);
}
static size_t disasm_move_usp(DisasmNode &node, const uint16_t instr)
@@ -907,8 +915,9 @@ static size_t disasm_move_usp(DisasmNode &node, const uint16_t instr)
static size_t disasm_nbcd_swap_pea(DisasmNode &node, const uint16_t instr, const DataBuffer &code)
{
const bool is_nbcd = !((instr >> 6) & 1);
- const auto arg = FetchAddrModeArg(
- node.offset + kInstructionSizeStepBytes, code, instr, OpSize::kWord);
+ const OpSize opsize = OpSize::kWord;
+ const auto arg = FetchArg(
+ node.offset + kInstructionSizeStepBytes, code, instr, opsize);
bool is_swap{};
switch (arg.mode) {
case AddrMode::kInvalid:
@@ -944,8 +953,8 @@ static size_t disasm_nbcd_swap_pea(DisasmNode &node, const uint16_t instr, const
}
node.opcode = is_nbcd ? OpCode::kNBCD : is_swap ? OpCode::kSWAP : OpCode::kPEA;
node.size_spec = is_nbcd ? OpSize::kByte : is_swap ? OpSize::kWord : OpSize::kLong;
- node.arg1 = Arg::FromAddrModeArg(arg);
- return node.size = kInstructionSizeStepBytes + arg.Size();
+ node.arg1 = arg;
+ return node.size = kInstructionSizeStepBytes + arg.Size(opsize);
}
static size_t disasm_stop(DisasmNode &node, const uint16_t instr, const DataBuffer &code)
@@ -956,7 +965,7 @@ static size_t disasm_stop(DisasmNode &node, const uint16_t instr, const DataBuff
}
node.opcode = OpCode::kSTOP;
node.size_spec = OpSize::kNone;
- node.arg1 = Arg::FromAddrModeArg(a);
+ node.arg1 = a;
return node.size = kInstructionSizeStepBytes * 2;
}
@@ -1006,7 +1015,7 @@ static size_t disasm_chunk_4(DisasmNode &node, const uint16_t instr, const DataB
static size_t disasm_addq_subq(
DisasmNode &node, const uint16_t instr, const DataBuffer &code, const OpSize opsize)
{
- const auto a = FetchAddrModeArg(node.offset + kInstructionSizeStepBytes, code, instr, opsize);
+ const auto a = FetchArg(node.offset + kInstructionSizeStepBytes, code, instr, opsize);
switch (a.mode) {
case AddrMode::kInvalid:
return disasm_verbatim(node, instr);
@@ -1037,8 +1046,8 @@ static size_t disasm_addq_subq(
node.opcode = ((instr >> 8) & 1) ? OpCode::kSUBQ : OpCode::kADDQ;
node.size_spec = opsize;
node.arg1 = Arg::Immediate(imm);
- node.arg2 = Arg::FromAddrModeArg(a);
- return node.size = kInstructionSizeStepBytes + a.Size();
+ node.arg2 = a;
+ return node.size = kInstructionSizeStepBytes + a.Size(opsize);
}
static size_t disasm_dbcc(DisasmNode &node, const uint16_t instr, const DataBuffer &code)
@@ -1064,8 +1073,9 @@ static size_t disasm_dbcc(DisasmNode &node, const uint16_t instr, const DataBuff
static size_t disasm_scc_dbcc(DisasmNode &node, const uint16_t instr, const DataBuffer &code)
{
- const auto a = FetchAddrModeArg(
- node.offset + kInstructionSizeStepBytes, code, instr, OpSize::kWord);
+ const OpSize opsize = OpSize::kWord;
+ const auto a = FetchArg(
+ node.offset + kInstructionSizeStepBytes, code, instr, opsize);
switch (a.mode) {
case AddrMode::kInvalid:
return disasm_verbatim(node, instr);
@@ -1090,8 +1100,8 @@ static size_t disasm_scc_dbcc(DisasmNode &node, const uint16_t instr, const Data
node.opcode = OpCode::kScc;
node.condition = static_cast<Condition>((instr >> 8) & 0xf);
node.size_spec = OpSize::kNone;
- node.arg1 = Arg::FromAddrModeArg(a);
- return node.size = kInstructionSizeStepBytes + a.Size();
+ node.arg1 = a;
+ return node.size = kInstructionSizeStepBytes + a.Size(opsize);
}
static size_t disasm_addq_subq_scc_dbcc(DisasmNode &n, const uint16_t instr, const DataBuffer &c)
@@ -1110,13 +1120,14 @@ static size_t disasm_moveq(DisasmNode &node, const uint16_t instr)
return disasm_verbatim(node, instr);
}
const int xn = (instr >> 9) & 7;
- const auto dst = AddrModeArg::Dn(xn);
+ const auto dst = Arg::Dn(xn);
const int8_t data = instr & 0xff;
+ const OpSize opsize = OpSize::kLong;
node.opcode = OpCode::kMOVEQ;
- node.size_spec = OpSize::kLong;
+ node.size_spec = opsize;
node.arg1 = Arg::Immediate(data);
- node.arg2 = Arg::FromAddrModeArg(dst);
- return node.size = kInstructionSizeStepBytes + dst.Size();
+ node.arg2 = dst;
+ return node.size = kInstructionSizeStepBytes + dst.Size(opsize);
}
@@ -1127,7 +1138,7 @@ static size_t disasm_divu_divs_mulu_muls(
const OpCode opcode)
{
const auto opsize = OpSize::kWord;
- const auto src = FetchAddrModeArg(
+ const auto src = FetchArg(
node.offset + kInstructionSizeStepBytes, code, instr, opsize);
switch (src.mode) {
case AddrMode::kInvalid:
@@ -1150,12 +1161,12 @@ static size_t disasm_divu_divs_mulu_muls(
break;
}
const unsigned dn = (instr >> 9) & 7;
- const auto dst = AddrModeArg::Dn(dn);
+ const auto dst = Arg::Dn(dn);
node.opcode = opcode;
node.size_spec = opsize;
- node.arg1 = Arg::FromAddrModeArg(src);
- node.arg2 = Arg::FromAddrModeArg(dst);
- return node.size = kInstructionSizeStepBytes + dst.Size() + src.Size();
+ node.arg1 = src;
+ node.arg2 = dst;
+ return node.size = kInstructionSizeStepBytes + dst.Size(opsize) + src.Size(opsize);
}
static size_t disasm_addx_subx_abcd_sbcd(
@@ -1167,16 +1178,16 @@ static size_t disasm_addx_subx_abcd_sbcd(
const int m = (instr >> 3) & 1;
const int xn = instr & 7;
const int xi = (instr >> 9) & 7;
- const auto src = m ? AddrModeArg::AnAddrDecr(xn) : AddrModeArg::Dn(xn);
- const auto dst = m ? AddrModeArg::AnAddrDecr(xi) : AddrModeArg::Dn(xi);
+ const auto src = m ? Arg::AnAddrDecr(xn) : Arg::Dn(xn);
+ const auto dst = m ? Arg::AnAddrDecr(xi) : Arg::Dn(xi);
node.opcode = opcode;
// XXX GNU AS does not know ABCD.B, it only knows ABCD, but happily consumes
// SBCD.B and others. That's why `skip_suffix` flag is needed, specifically
// for ABCD mnemonic. It is probably a bug in GNU AS.
node.size_spec = (opcode == OpCode::kABCD) ? OpSize::kNone : opsize;
- node.arg1 = Arg::FromAddrModeArg(src);
- node.arg2 = Arg::FromAddrModeArg(dst);
- return node.size = kInstructionSizeStepBytes + src.Size() + dst.Size();
+ node.arg1 = src;
+ node.arg2 = dst;
+ return node.size = kInstructionSizeStepBytes + src.Size(opsize) + dst.Size(opsize);
}
static size_t disasm_or_and(
@@ -1187,7 +1198,7 @@ static size_t disasm_or_and(
const OpCode opcode)
{
const bool dir_to_addr = (instr >> 8) & 1;
- const auto addr = FetchAddrModeArg(
+ const auto addr = FetchArg(
node.offset + kInstructionSizeStepBytes, code, instr, opsize);
switch (addr.mode) {
case AddrMode::kInvalid:
@@ -1222,17 +1233,17 @@ static size_t disasm_or_and(
}
break;
}
- const auto reg = AddrModeArg::Dn((instr >> 9) & 7);
+ const auto reg = Arg::Dn((instr >> 9) & 7);
node.opcode = opcode;
node.size_spec = opsize;
if (dir_to_addr) {
- node.arg1 = Arg::FromAddrModeArg(reg);
- node.arg2 = Arg::FromAddrModeArg(addr);
+ node.arg1 = reg;
+ node.arg2 = addr;
} else {
- node.arg1 = Arg::FromAddrModeArg(addr);
- node.arg2 = Arg::FromAddrModeArg(reg);
+ node.arg1 = addr;
+ node.arg2 = reg;
}
- return node.size = kInstructionSizeStepBytes + addr.Size() + reg.Size();
+ return node.size = kInstructionSizeStepBytes + addr.Size(opsize) + reg.Size(opsize);
}
static size_t disasm_divu_divs_sbcd_or(
@@ -1255,7 +1266,7 @@ static inline size_t disasm_adda_suba_cmpa(
DisasmNode &node, const uint16_t instr, const DataBuffer &code, const OpCode opcode)
{
const OpSize opsize = static_cast<OpSize>(((instr >> 8) & 1) + 1);
- const auto src = FetchAddrModeArg(
+ const auto src = FetchArg(
node.offset + kInstructionSizeStepBytes, code, instr, opsize);
switch (src.mode) {
case AddrMode::kInvalid:
@@ -1275,12 +1286,12 @@ static inline size_t disasm_adda_suba_cmpa(
break;
}
const unsigned an = (instr >> 9) & 7;
- const auto dst = AddrModeArg::An(an);
+ const auto dst = Arg::An(an);
node.opcode = opcode;
node.size_spec = opsize;
- node.arg1 = Arg::FromAddrModeArg(src);
- node.arg2 = Arg::FromAddrModeArg(dst);
- return node.size = kInstructionSizeStepBytes + src.Size() + dst.Size();
+ node.arg1 = src;
+ node.arg2 = dst;
+ return node.size = kInstructionSizeStepBytes + src.Size(opsize) + dst.Size(opsize);
}
static size_t disasm_add_sub_cmp(
@@ -1291,7 +1302,7 @@ static size_t disasm_add_sub_cmp(
const OpSize opsize,
const bool dir_to_addr)
{
- const auto addr = FetchAddrModeArg(
+ const auto addr = FetchArg(
node.offset + kInstructionSizeStepBytes, code, instr, opsize);
switch (addr.mode) {
case AddrMode::kInvalid:
@@ -1327,17 +1338,17 @@ static size_t disasm_add_sub_cmp(
break;
}
const unsigned dn = (instr >> 9) & 7;
- const auto reg = AddrModeArg::Dn(dn);
+ const auto reg = Arg::Dn(dn);
node.opcode = opcode;
node.size_spec = opsize;
if (dir_to_addr) {
- node.arg1 = Arg::FromAddrModeArg(reg);
- node.arg2 = Arg::FromAddrModeArg(addr);
+ node.arg1 = reg;
+ node.arg2 = addr;
} else {
- node.arg1 = Arg::FromAddrModeArg(addr);
- node.arg2 = Arg::FromAddrModeArg(reg);
+ node.arg1 = addr;
+ node.arg2 = reg;
}
- return node.size = kInstructionSizeStepBytes + addr.Size() + reg.Size();
+ return node.size = kInstructionSizeStepBytes + addr.Size(opsize) + reg.Size(opsize);
}
static size_t disasm_cmpm(DisasmNode &node, const uint16_t instr)
@@ -1350,19 +1361,19 @@ static size_t disasm_cmpm(DisasmNode &node, const uint16_t instr)
(void) m;
const int xn = instr & 7;
const int xi = (instr >> 9) & 7;
- const auto src = AddrModeArg::AnAddrIncr(xn);
- const auto dst = AddrModeArg::AnAddrIncr(xi);
+ const auto src = Arg::AnAddrIncr(xn);
+ const auto dst = Arg::AnAddrIncr(xi);
node.opcode = OpCode::kCMPM;
node.size_spec = opsize;
- node.arg1 = Arg::FromAddrModeArg(src);
- node.arg2 = Arg::FromAddrModeArg(dst);
- return node.size = kInstructionSizeStepBytes + src.Size() + dst.Size();
+ node.arg1 = src;
+ node.arg2 = dst;
+ return node.size = kInstructionSizeStepBytes + src.Size(opsize) + dst.Size(opsize);
}
static size_t disasm_eor(DisasmNode &node, const uint16_t instr, const DataBuffer &code)
{
const OpSize opsize = static_cast<OpSize>((instr >> 6) & 3);
- const auto addr = FetchAddrModeArg(
+ const auto addr = FetchArg(
node.offset + kInstructionSizeStepBytes, code, instr, opsize);
switch (addr.mode) {
case AddrMode::kInvalid:
@@ -1385,12 +1396,12 @@ static size_t disasm_eor(DisasmNode &node, const uint16_t instr, const DataBuffe
// PC relative and immediate cannot be destination
return disasm_verbatim(node, instr);
}
- const auto reg = AddrModeArg::Dn((instr >> 9) & 7);
+ const auto reg = Arg::Dn((instr >> 9) & 7);
node.opcode = OpCode::kEOR;
node.size_spec = opsize;
- node.arg1 = Arg::FromAddrModeArg(reg);
- node.arg2 = Arg::FromAddrModeArg(addr);
- return node.size = kInstructionSizeStepBytes + addr.Size() + reg.Size();
+ node.arg1 = reg;
+ node.arg2 = addr;
+ return node.size = kInstructionSizeStepBytes + addr.Size(opsize) + reg.Size(opsize);
}
static size_t disasm_eor_cmpm_cmp_cmpa(
@@ -1422,13 +1433,14 @@ static inline size_t disasm_exg(DisasmNode &node, const uint16_t instr)
assert(m != 4); // Only m == 2, m == 3 and m == 5 values are allowed
const int xn = instr & 7;
const int xi = (instr >> 9) & 7;
- const auto src = (m == 3) ? AddrModeArg::An(xi) : AddrModeArg::Dn(xi);
- const auto dst = (m == 2) ? AddrModeArg::Dn(xn) : AddrModeArg::An(xn);
+ const auto src = (m == 3) ? Arg::An(xi) : Arg::Dn(xi);
+ const auto dst = (m == 2) ? Arg::Dn(xn) : Arg::An(xn);
+ const auto opsize = OpSize::kNone;
node.opcode = OpCode::kEXG;
- node.size_spec = OpSize::kNone;
- node.arg1 = Arg::FromAddrModeArg(src);
- node.arg2 = Arg::FromAddrModeArg(dst);
- return node.size = kInstructionSizeStepBytes + src.Size() + dst.Size();
+ node.size_spec = opsize;
+ node.arg1 = src;
+ node.arg2 = dst;
+ return node.size = kInstructionSizeStepBytes + src.Size(opsize) + dst.Size(opsize);
}
static size_t disasm_chunk_c(DisasmNode &node, const uint16_t instr, const DataBuffer &code)
@@ -1497,8 +1509,8 @@ static size_t disasm_shift_rotate(DisasmNode &node, const uint16_t instr, const
return disasm_verbatim(node, instr);
}
const auto dst = (opsize == OpSize::kInvalid)
- ? FetchAddrModeArg(node.offset + kInstructionSizeStepBytes, code, instr, opsize)
- : AddrModeArg::Dn(xn);
+ ? FetchArg(node.offset + kInstructionSizeStepBytes, code, instr, opsize)
+ : Arg::Dn(xn);
if (opsize == OpSize::kInvalid) {
switch (dst.mode) {
case AddrMode::kInvalid:
@@ -1530,13 +1542,13 @@ static size_t disasm_shift_rotate(DisasmNode &node, const uint16_t instr, const
node.opcode = ShiftKindToOpcode(kind, dir);
node.size_spec = opsize;
if (opsize == OpSize::kInvalid) {
- node.arg1 = Arg::FromAddrModeArg(dst);
+ node.arg1 = dst;
} else {
const unsigned m = (instr >> 5) & 1;
node.arg1 = m ? Arg::AddrModeXn(ArgType::kDn, src) : Arg::Immediate(imm);
- node.arg2 = Arg::FromAddrModeArg(dst);
+ node.arg2 = dst;
}
- return node.size = kInstructionSizeStepBytes + dst.Size();
+ return node.size = kInstructionSizeStepBytes + dst.Size(opsize);
}
static size_t m68k_disasm(DisasmNode &n, uint16_t i, const DataBuffer &c)
@@ -1759,34 +1771,19 @@ static int OpcodeSNPrintf(
return snprintf(buf, bufsz, "%s%s", ToString(opcode, condition), ToString(size_spec));
}
-static char RegChar(RegKind k)
+static char RegChar(const uint8_t xi)
{
- switch (k) {
- case RegKind::kDnWord:
- case RegKind::kDnLong:
- return 'd';
- case RegKind::kAnWord:
- case RegKind::kAnLong:
- return 'a';
- }
- assert(false);
- return 'd';
+ return (xi & 0x08) ? 'a' : 'd';
}
-static char SizeSpecChar(RegKind k)
+static char SizeSpecChar(const uint8_t xi)
{
- switch (k) {
- case RegKind::kDnWord:
- return 'w';
- case RegKind::kDnLong:
- return 'l';
- case RegKind::kAnWord:
- return 'w';
- case RegKind::kAnLong:
- return 'l';
- }
- assert(false);
- return 'w';
+ return (xi & 0x10) ? 'l' : 'w';
+}
+
+static unsigned RegNum(const uint8_t xi)
+{
+ return xi & 0x7;
}
static inline size_t snprint_reg_mask(
@@ -1843,12 +1840,12 @@ int Arg::SNPrint(char *const buf, const size_t bufsz, const Settings &) const
return snprintf(buf, bufsz, "%%a%u@(%d:w)", d16_an.an, d16_an.d16);
case ArgType::kD8AnXiAddr:
return snprintf(
- buf, bufsz, "%%a%u@(%d,%%%c%d:%c)",
+ buf, bufsz, "%%a%u@(%d,%%%c%u:%c)",
d8_an_xi.an,
d8_an_xi.d8,
- RegChar(d8_an_xi.kind),
- d8_an_xi.xi,
- SizeSpecChar(d8_an_xi.kind));
+ RegChar(d8_an_xi.xi),
+ RegNum(d8_an_xi.xi),
+ SizeSpecChar(d8_an_xi.xi));
case ArgType::kWord:
return snprintf(buf, bufsz, "0x%x:w", lword);
case ArgType::kLong:
@@ -1857,11 +1854,11 @@ int Arg::SNPrint(char *const buf, const size_t bufsz, const Settings &) const
return snprintf(buf, bufsz, "%%pc@(%d:w)", d16_pc.d16);
case ArgType::kD8PCXiAddr:
return snprintf(
- buf, bufsz, "%%pc@(%d,%%%c%d:%c)",
+ buf, bufsz, "%%pc@(%d,%%%c%u:%c)",
d8_pc_xi.d8,
- RegChar(d8_pc_xi.kind),
- d8_pc_xi.xi,
- SizeSpecChar(d8_pc_xi.kind));
+ RegChar(d8_pc_xi.xi),
+ RegNum(d8_pc_xi.xi),
+ SizeSpecChar(d8_pc_xi.xi));
case ArgType::kImmediate:
return snprintf(buf, bufsz, "#%d", lword);
case ArgType::kRegMask:
diff --git a/disasm.h b/disasm.h
index 7c40438..cac0bea 100644
--- a/disasm.h
+++ b/disasm.h
@@ -10,22 +10,6 @@
#include <cstdint>
#include <cstdio>
-enum class AddrMode: uint8_t {
- kInvalid = 0,
- kDn,
- kAn,
- kAnAddr,
- kAnAddrIncr,
- kAnAddrDecr,
- kD16AnAddr,
- kD8AnXiAddr,
- kWord,
- kLong,
- kD16PCAddr,
- kD8PCXiAddr,
- kImmediate,
-};
-
enum class OpSize: int {
kByte = 0,
kWord = 1,
@@ -35,90 +19,6 @@ enum class OpSize: int {
kShort, ///< Semantically is the same as kByte, pseudosize, used for Bcc
};
-struct AddrModeArg {
- AddrMode mode{};
- uint8_t xn{}; /// Xn register number: 0..7
- char r{}; /// Xi register type specifier letter: either 'd' or 'a'
- uint8_t xi{}; /// Xi register number: 0..7
- OpSize s{}; /// Size specifier of Xi or imm
- int32_t value{}; /// Word, Long or Immediate
- /// Size of the extension: 0, 2 or 4 bytes
- constexpr size_t Size() const
- {
- switch (mode) {
- case AddrMode::kInvalid:
- case AddrMode::kDn:
- case AddrMode::kAn:
- case AddrMode::kAnAddr:
- case AddrMode::kAnAddrIncr:
- case AddrMode::kAnAddrDecr:
- return 0;
- case AddrMode::kD16AnAddr:
- case AddrMode::kD8AnXiAddr:
- case AddrMode::kWord:
- return 2;
- case AddrMode::kLong:
- return 4;
- case AddrMode::kD16PCAddr:
- case AddrMode::kD8PCXiAddr:
- return 2;
- case AddrMode::kImmediate:
- return s == OpSize::kLong ? 4 : 2;
- }
- return 0;
- }
- static constexpr AddrModeArg Dn(uint8_t xn)
- {
- return AddrModeArg{AddrMode::kDn, xn};
- }
- static constexpr AddrModeArg An(uint8_t xn)
- {
- return AddrModeArg{AddrMode::kAn, xn};
- }
- static constexpr AddrModeArg AnAddr(uint8_t xn)
- {
- return AddrModeArg{AddrMode::kAnAddr, xn};
- }
- static constexpr AddrModeArg AnAddrIncr(uint8_t xn)
- {
- return AddrModeArg{AddrMode::kAnAddrIncr, xn};
- }
- static constexpr AddrModeArg AnAddrDecr(uint8_t xn)
- {
- return AddrModeArg{AddrMode::kAnAddrDecr, xn};
- }
- static constexpr AddrModeArg D16AnAddr(uint8_t xn, int16_t d16)
- {
- return AddrModeArg{AddrMode::kD16AnAddr, xn, 0, 0, OpSize::kWord, d16};
- }
- static constexpr AddrModeArg D8AnXiAddr(
- uint8_t xn, char r, uint8_t xi, OpSize s, int8_t d8)
- {
- return AddrModeArg{AddrMode::kD8AnXiAddr, xn, r, xi, s, d8};
- }
- static constexpr AddrModeArg Word(int16_t w)
- {
- return AddrModeArg{AddrMode::kWord, 0, 0, 0, OpSize::kWord, w};
- }
- static constexpr AddrModeArg Long(int32_t l)
- {
- return AddrModeArg{AddrMode::kLong, 1, 0, 0, OpSize::kWord, l};
- }
- static constexpr AddrModeArg D16PCAddr(uint8_t xn, int16_t d16)
- {
- return AddrModeArg{AddrMode::kD16PCAddr, xn, 0, 0, OpSize::kWord, d16};
- }
- static constexpr AddrModeArg D8PCXiAddr(
- uint8_t xn, char r, uint8_t xi, OpSize s, int8_t d8)
- {
- return AddrModeArg{AddrMode::kD8PCXiAddr, xn, r, xi, s, d8};
- }
- static constexpr AddrModeArg Immediate(OpSize s, int32_t value)
- {
- return AddrModeArg{AddrMode::kImmediate, 4, 0, 0, s, value};
- }
-};
-
enum class OpCode: uint8_t {
kNone,
kRaw, ///< Emits ".short"
@@ -215,40 +115,52 @@ enum class Condition: uint8_t {
kLE = 15,
};
+enum class AddrMode: uint8_t {
+ kInvalid = 0,
+ kDn = 1,
+ kAn = 2,
+ kAnAddr = 3,
+ kAnAddrIncr = 4,
+ kAnAddrDecr = 5,
+ kD16AnAddr = 6,
+ kD8AnXiAddr = 7,
+ kWord = 8,
+ kLong = 9,
+ kD16PCAddr = 10,
+ kD8PCXiAddr = 11,
+ kImmediate = 12,
+};
+
enum class ArgType: uint8_t {
- kNone,
- kRaw, ///< Emits "0xXXXX" for ".short"
- kDn, ///< Dn
- kAn, ///< An
- kAnAddr, ///< (An)
- kAnAddrIncr, ///< (An)+
- kAnAddrDecr, ///< -(An)
- kD16AnAddr, ///< (d16,An)
- kD8AnXiAddr, ///< (d8,An,Xi)
- kWord, ///< (xxx).W
- kLong, ///< (xxx).L
- kD16PCAddr, ///< (d16,PC)
- kD8PCXiAddr, ///< (d8,PC,Xn)
- kImmediate, ///< #imm
+ kNone = 0,
+ kDn = 1, ///< Dn
+ kAn = 2, ///< An
+ kAnAddr = 3, ///< (An)
+ kAnAddrIncr = 4, ///< (An)+
+ kAnAddrDecr = 5, ///< -(An)
+ kD16AnAddr = 6, ///< (d16,An)
+ kD8AnXiAddr = 7, ///< (d8,An,Xi)
+ kWord = 8, ///< (xxx).W
+ kLong = 9, ///< (xxx).L
+ kD16PCAddr = 10, ///< (d16,PC)
+ kD8PCXiAddr = 11, ///< (d8,PC,Xn)
+ kImmediate = 12, ///< #imm
kRegMask,
kRegMaskPredecrement,
kDisplacement, ///< For BRA, BSR, Bcc and DBcc
kCCR,
kSR,
kUSP,
-};
-
-enum class RegKind: uint8_t {
- kDnWord,
- kDnLong,
- kAnWord,
- kAnLong,
+ kRaw, ///< Emits "0xXXXX" for ".short"
};
struct D8AnPCXiAddr {
- RegKind kind; ///< Kind of Xi reg, for kD8AnXiAddr and kD8PCXiAddr
uint8_t an; ///< ID number of An reg, for kD8AnXiAddr only
- uint8_t xi; ///< ID number of Xi reg, for kD8AnXiAddr and kD8PCXiAddr
+ /*! ID number of Xi reg (3 lower bits), for kD8AnXiAddr and kD8PCXiAddr.
+ * Bit 3 (mask 0x8) means 0 == Dn, 1 == An.
+ * Bit 4 (mask 0x10) means 0 == Word, 1 == Long.
+ */
+ uint8_t xi;
int8_t d8; ///< Displacement, for kD8AnXiAddr and kD8PCXiAddr
};
@@ -257,12 +169,14 @@ struct D16AnPCAddr {
int16_t d16; ///< Displacement, for D16AnAddr and kD16PCAddr
};
-static_assert(sizeof(D8AnPCXiAddr) == sizeof(uint32_t), "");
-static_assert(sizeof(D16AnPCAddr) == sizeof(uint32_t), "");
+static_assert(sizeof(D8AnPCXiAddr) <= sizeof(uint32_t), "");
+static_assert(sizeof(D16AnPCAddr) <= sizeof(uint32_t), "");
struct Arg {
- using Self = Arg;
- ArgType type{ArgType::kNone};
+ union {
+ ArgType type{ArgType::kNone};
+ AddrMode mode;
+ };
union {
int32_t lword{}; ///< kLong, kWord, kDisplacement, kImmediate
uint16_t uword; ///< kRegMask, kRaw
@@ -272,129 +186,113 @@ struct Arg {
D8AnPCXiAddr d8_an_xi; ///< kD8AnXiAddr
D8AnPCXiAddr d8_pc_xi; ///< kD8PCXiAddr
};
- static constexpr Self Raw(const uint16_t instr) {
- Arg a{ArgType::kRaw, 0};
- a.uword = instr;
- return a;
- }
- static constexpr Self RegMask(const uint16_t regmask) {
- Arg a{ArgType::kRegMask, 0};
- a.uword = regmask;
- return a;
- }
- static constexpr Self RegMaskPredecrement(const uint16_t regmask) {
- Arg a{ArgType::kRegMaskPredecrement, 0};
- a.uword = regmask;
- return a;
- }
- static constexpr Self Displacement(const int32_t displacement) {
- Arg a{ArgType::kDisplacement, 0};
- a.lword = displacement;
- return a;
- }
- static constexpr Self Immediate(int32_t value) {
- Arg a{ArgType::kImmediate, 0};
- a.lword = value;
- return a;
+ /// Size of the instruction extension: 0, 2 or 4 bytes
+ constexpr size_t Size(const OpSize s) const
+ {
+ switch (mode) {
+ case AddrMode::kInvalid:
+ case AddrMode::kDn:
+ case AddrMode::kAn:
+ case AddrMode::kAnAddr:
+ case AddrMode::kAnAddrIncr:
+ case AddrMode::kAnAddrDecr:
+ return 0;
+ case AddrMode::kD16AnAddr:
+ case AddrMode::kD8AnXiAddr:
+ case AddrMode::kWord:
+ return 2;
+ case AddrMode::kLong:
+ return 4;
+ case AddrMode::kD16PCAddr:
+ case AddrMode::kD8PCXiAddr:
+ return 2;
+ case AddrMode::kImmediate:
+ // Byte and Word immediate are of 2 bytes length
+ return s == OpSize::kLong ? 4 : 2;
+ }
+ return 0;
}
- static constexpr Self CCR() { return Arg{ArgType::kCCR, 0}; }
- static constexpr Self SR() { return Arg{ArgType::kSR, 0}; }
- static constexpr Self USP() { return Arg{ArgType::kUSP, 0}; }
- static constexpr Self AddrModeXn(const ArgType type, const uint8_t xn) {
+ static constexpr auto AddrModeXn(const ArgType type, const uint8_t xn) {
Arg a{type, 0};
a.xn = xn;
return a;
}
-private:
- static constexpr Self addrModeD16AnAddr(const D16AnPCAddr d16_an) {
+ static constexpr auto Dn(const uint8_t xn) { return AddrModeXn(ArgType::kDn, xn); }
+ static constexpr auto An(const uint8_t xn) { return AddrModeXn(ArgType::kAn, xn); }
+ static constexpr auto AnAddr(const uint8_t xn) { return AddrModeXn(ArgType::kAnAddr, xn); }
+ static constexpr auto AnAddrIncr(const uint8_t xn)
+ {
+ return AddrModeXn(ArgType::kAnAddrIncr, xn);
+ }
+ static constexpr auto AnAddrDecr(const uint8_t xn)
+ {
+ return AddrModeXn(ArgType::kAnAddrDecr, xn);
+ }
+ static constexpr auto D16AnAddr(const uint8_t xn, const int16_t d16)
+ {
Arg a{ArgType::kD16AnAddr, 0};
- a.d16_an = d16_an;
+ a.d16_an = D16AnPCAddr{xn, d16};
return a;
}
- static constexpr Self addrModeD16PCAddr(const D16AnPCAddr d16_pc) {
+ static constexpr auto D16PCAddr(const int16_t d16)
+ {
Arg a{ArgType::kD16PCAddr, 0};
- a.d16_pc = d16_pc;
+ a.d16_pc = D16AnPCAddr{0, d16};
return a;
}
- static constexpr Self addrModeWord(const int16_t value) {
+ static constexpr auto Word(const int16_t w)
+ {
Arg a{ArgType::kWord, 0};
- a.lword = value;
+ a.lword = w;
return a;
}
- static constexpr Self addrModeLong(const int32_t value) {
+ static constexpr auto Long(const int32_t l)
+ {
Arg a{ArgType::kLong, 0};
- a.lword = value;
+ a.lword = l;
return a;
}
- static constexpr Self addrModeD8AnAddr(const D8AnPCXiAddr d8_an_xi) {
+ static constexpr auto D8AnXiAddr(
+ const uint8_t xn, const uint8_t xi, const OpSize s, const int8_t d8)
+ {
Arg a{ArgType::kD8AnXiAddr, 0};
- a.d8_an_xi = d8_an_xi;
+ a.d8_an_xi = D8AnPCXiAddr{xn, uint8_t(xi | (s == OpSize::kLong ? 0x10u : 0u)), d8};
return a;
}
- static constexpr Self addrModeD8PCAddr(const D8AnPCXiAddr d8_pc_xi) {
+ static constexpr auto D8PCXiAddr(
+ const uint8_t xn, const uint8_t xi, const OpSize s, const int8_t d8)
+ {
Arg a{ArgType::kD8PCXiAddr, 0};
- a.d8_pc_xi = d8_pc_xi;
+ a.d8_pc_xi = D8AnPCXiAddr{xn, uint8_t(xi | (s == OpSize::kLong ? 0x10u : 0u)), d8};
return a;
}
- static constexpr Self addrModeImmediate(const int32_t value) {
+ static constexpr auto Immediate(const int32_t value) {
Arg a{ArgType::kImmediate, 0};
a.lword = value;
return a;
}
- static constexpr RegKind regKindFromRegCharSizeChar(char r, OpSize s)
- {
- if (r == 'd' && s == OpSize::kWord) {
- return RegKind::kDnWord;
- } else if (r == 'd' && s == OpSize::kLong) {
- return RegKind::kDnLong;
- } else if (r == 'a' && s == OpSize::kWord) {
- return RegKind::kAnWord;
- } else if (r == 'a' && s == OpSize::kLong) {
- return RegKind::kAnLong;
- }
- return RegKind::kDnWord;
+ static constexpr auto RegMask(const uint16_t regmask) {
+ Arg a{ArgType::kRegMask, 0};
+ a.uword = regmask;
+ return a;
}
-public:
- static constexpr Self FromAddrModeArg(AddrModeArg arg) {
- switch (arg.mode) {
- case AddrMode::kInvalid:
- return Arg{};
- case AddrMode::kDn:
- return AddrModeXn(ArgType::kDn, arg.xn);
- case AddrMode::kAn:
- return AddrModeXn(ArgType::kAn, arg.xn);
- case AddrMode::kAnAddr:
- return AddrModeXn(ArgType::kAnAddr, arg.xn);
- case AddrMode::kAnAddrIncr:
- return AddrModeXn(ArgType::kAnAddrIncr, arg.xn);
- case AddrMode::kAnAddrDecr:
- return AddrModeXn(ArgType::kAnAddrDecr, arg.xn);
- case AddrMode::kD16AnAddr:
- return addrModeD16AnAddr(D16AnPCAddr{arg.xn, static_cast<int16_t>(arg.value)});
- case AddrMode::kD8AnXiAddr:
- return addrModeD8AnAddr(D8AnPCXiAddr{
- regKindFromRegCharSizeChar(arg.r, arg.s),
- arg.xn,
- arg.xi,
- static_cast<int8_t>(arg.value),
- });
- case AddrMode::kWord:
- return addrModeWord(arg.value);
- case AddrMode::kLong:
- return addrModeLong(arg.value);
- case AddrMode::kD16PCAddr:
- return addrModeD16PCAddr(D16AnPCAddr{0, static_cast<int16_t>(arg.value)});
- case AddrMode::kD8PCXiAddr:
- return addrModeD8PCAddr(D8AnPCXiAddr{
- regKindFromRegCharSizeChar(arg.r, arg.s),
- 0,
- arg.xi,
- static_cast<int8_t>(arg.value),
- });
- case AddrMode::kImmediate:
- return addrModeImmediate(arg.value);
- }
- return Arg{};
+ static constexpr auto RegMaskPredecrement(const uint16_t regmask) {
+ Arg a{ArgType::kRegMaskPredecrement, 0};
+ a.uword = regmask;
+ return a;
+ }
+ static constexpr auto Displacement(const int32_t displacement) {
+ Arg a{ArgType::kDisplacement, 0};
+ a.lword = displacement;
+ return a;
+ }
+ static constexpr auto CCR() { return Arg{ArgType::kCCR, 0}; }
+ static constexpr auto SR() { return Arg{ArgType::kSR, 0}; }
+ static constexpr auto USP() { return Arg{ArgType::kUSP, 0}; }
+ static constexpr auto Raw(const uint16_t instr) {
+ Arg a{ArgType::kRaw, 0};
+ a.uword = instr;
+ return a;
}
int SNPrint(char *buf, size_t bufsz, const Settings&) const;
};
@@ -426,6 +324,15 @@ struct ReferenceNode {
uint32_t refs_count{};
};
+struct Op {
+ OpCode opcode{OpCode::kNone}; ///< Identifies instruction (mnemonic)
+ /// Size specifier, the suffix `b`, `w` or `l`
+ OpSize size_spec{OpSize::kNone};
+ Condition condition{Condition::kT}; ///< For Scc, Bcc and Dbcc
+ Arg arg1{}; ///< First argument, optional
+ Arg arg2{}; ///< Second argument, optional, cannot be set if arg1 is not set
+};
+
struct DisasmNode {
const TracedNodeType type{};
/// Absolute offset of the instruction (PC value basically)
@@ -441,11 +348,12 @@ struct DisasmNode {
bool is_call{};
ReferenceNode *ref_by{};
ReferenceNode *last_ref_by{};
- OpCode opcode{OpCode::kNone}; ///< Should replace `mnemonic` field
+ OpCode opcode{OpCode::kNone}; ///< Identifies instruction (mnemonic)
/// Size specifier, the suffix `b`, `w` or `l`
OpSize size_spec{OpSize::kNone};
Condition condition{Condition::kT}; ///< For Scc, Bcc and Dbcc
- Arg arg1{}, arg2{}; ///< Should replace `arguments` field
+ Arg arg1{}, arg2{}; ///< Argument specifiers (in order as in asm listing)
+ Op op{};
/*! Disassembles instruction with arguments
* returns size of whole instruction with arguments in bytes