Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,047 changes: 767 additions & 280 deletions arch/M68K/M68KDisassembler.c

Large diffs are not rendered by default.

267 changes: 267 additions & 0 deletions arch/M68K/M68KDisassembler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,273 @@

#include "../../MCInst.h"

/* ======================================================================== */
/* ============================ GENERAL DEFINES =========================== */
/* ======================================================================== */

/* Bit Isolation Functions */
#define BIT_0(A) ((A) & 0x00000001)
#define BIT_1(A) ((A) & 0x00000002)
#define BIT_2(A) ((A) & 0x00000004)
#define BIT_3(A) ((A) & 0x00000008)
#define BIT_4(A) ((A) & 0x00000010)
#define BIT_5(A) ((A) & 0x00000020)
#define BIT_6(A) ((A) & 0x00000040)
#define BIT_7(A) ((A) & 0x00000080)
#define BIT_8(A) ((A) & 0x00000100)
#define BIT_9(A) ((A) & 0x00000200)
#define BIT_A(A) ((A) & 0x00000400)
#define BIT_B(A) ((A) & 0x00000800)
#define BIT_C(A) ((A) & 0x00001000)
#define BIT_D(A) ((A) & 0x00002000)
#define BIT_E(A) ((A) & 0x00004000)
#define BIT_F(A) ((A) & 0x00008000)
#define BIT_10(A) ((A) & 0x00010000)
#define BIT_11(A) ((A) & 0x00020000)
#define BIT_12(A) ((A) & 0x00040000)
#define BIT_13(A) ((A) & 0x00080000)
#define BIT_14(A) ((A) & 0x00100000)
#define BIT_15(A) ((A) & 0x00200000)
#define BIT_16(A) ((A) & 0x00400000)
#define BIT_17(A) ((A) & 0x00800000)
#define BIT_18(A) ((A) & 0x01000000)
#define BIT_19(A) ((A) & 0x02000000)
#define BIT_1A(A) ((A) & 0x04000000)
#define BIT_1B(A) ((A) & 0x08000000)
#define BIT_1C(A) ((A) & 0x10000000)
#define BIT_1D(A) ((A) & 0x20000000)
#define BIT_1E(A) ((A) & 0x40000000)
#define BIT_1F(A) ((A) & 0x80000000)

/* These are the CPU types understood by this disassembler */
#define TYPE_68000 1
#define TYPE_68010 2
#define TYPE_68020 4
#define TYPE_68030 8
#define TYPE_68040 16
#define TYPE_68060 32
#define TYPE_CPU32 64

#define M68000_ONLY TYPE_68000

#define M68010_ONLY TYPE_68010
#define M68010_LESS (TYPE_68000 | TYPE_68010)
#define M68010_PLUS \
(TYPE_68010 | TYPE_68020 | TYPE_68030 | TYPE_68040 | TYPE_68060)

#define M68020_ONLY TYPE_68020
#define M68020_LESS (TYPE_68010 | TYPE_68020)
#define M68020_PLUS (TYPE_68020 | TYPE_68030 | TYPE_68040 | TYPE_68060)

#define M68030_ONLY TYPE_68030
#define M68030_LESS (TYPE_68010 | TYPE_68020 | TYPE_68030)
#define M68030_PLUS (TYPE_68030 | TYPE_68040 | TYPE_68060)

#define M68040_PLUS (TYPE_68040 | TYPE_68060)

/* Extension word formats */
#define EXT_8BIT_DISPLACEMENT(A) ((A) & 0xff)
#define EXT_FULL(A) BIT_8(A)
#define EXT_EFFECTIVE_ZERO(A) (((A) & 0xe4) == 0xc4 || ((A) & 0xe2) == 0xc0)
#define EXT_BASE_REGISTER_PRESENT(A) (!BIT_7(A))
#define EXT_INDEX_REGISTER_PRESENT(A) (!BIT_6(A))
#define EXT_INDEX_REGISTER(A) (((A) >> 12) & 7)
#define EXT_INDEX_PRE_POST(A) (EXT_INDEX_REGISTER_PRESENT(A) && (A) & 3)
#define EXT_INDEX_PRE(A) \
(EXT_INDEX_REGISTER_PRESENT(A) && ((A) & 7) < 4 && ((A) & 7) != 0)
#define EXT_INDEX_POST(A) (EXT_INDEX_REGISTER_PRESENT(A) && ((A) & 7) > 4)
#define EXT_INDEX_SCALE(A) (((A) >> 9) & 3)
#define EXT_INDEX_LONG(A) BIT_B(A)
#define EXT_INDEX_AR(A) BIT_F(A)
#define EXT_BASE_DISPLACEMENT_PRESENT(A) (((A) & 0x30) > 0x10)
#define EXT_BASE_DISPLACEMENT_WORD(A) (((A) & 0x30) == 0x20)
#define EXT_BASE_DISPLACEMENT_LONG(A) (((A) & 0x30) == 0x30)
/* Outer displacement is present when I/IS[1:0] (bits 1-0) is 2 (word) or 3 (long).
* This applies regardless of the IS bit (bit 6): when index is suppressed,
* I/IS values 5-7 mirror 1-3 (just indirect instead of postindexed).
* The old check ((A) & 0x47) < 0x44 incorrectly excluded IS=1 cases
* (I/IS=6,7) which DO have outer displacements per the M68K spec.
*/
#define EXT_OUTER_DISPLACEMENT_PRESENT(A) (((A) & 3) > 1)
#define EXT_OUTER_DISPLACEMENT_WORD(A) (((A) & 3) == 2)
#define EXT_OUTER_DISPLACEMENT_LONG(A) (((A) & 3) == 3)

#define IS_BITSET(val, b) ((val) & (1 << (b)))
#define BITFIELD_MASK(sb, eb) (((1 << ((sb) + 1)) - 1) & (~((1 << (eb)) - 1)))
#define BITFIELD(val, sb, eb) ((BITFIELD_MASK(sb, eb) & (val)) >> (eb))

/* Bitfield offset/width encoding.
* Public decode macros (M68K_BF_*) live in <capstone/m68k.h>.
* Internal aliases kept for brevity within arch code. */
#define M68K_BITFIELD_REG_FLAG M68K_BF_REG_FLAG
#define M68K_BITFIELD_IS_REG(v) M68K_BF_IS_REG(v)
#define M68K_BITFIELD_REG_NUM(v) M68K_BF_REG_NUM(v)
#define M68K_BITFIELD_ENCODE_REG(regnum) (((regnum) & 7) | M68K_BF_REG_FLAG)

/* ── Coprocessor ID (CpID) ───────────────────────────────────────────
* Bits 11:9 of the F-line instruction word select the coprocessor. */
#define M68K_CPID(info) (((info)->ir >> 9) & 7)

#define M68K_CPID_MMU 0 /* PMMU (68030/68851) */
#define M68K_CPID_FPU 1 /* FPU (68881/68882/internal) */
#define M68K_CPID_CACHE 2 /* Cache ops -- cinvl/cpushl on 68040+ */

/* ── IR bit-field helpers ────────────────────────────────────────────
* Extract commonly-used fields from the first instruction word. */

/* 6-bit coprocessor condition (bits 5:0 of IR). */
#define M68K_IR_CONDITION(info) ((info)->ir & 0x3f)

/* cinv/cpush: select cpush(1) vs cinv(0) -- bit 5 of IR. */
#define M68K_IR_IS_CPUSH(info) (((info)->ir >> 5) & 1)

/* cinv/cpush: cache scope -- bits 4:3 of IR (0=invalid,1=line,2=page,3=all). */
#define M68K_IR_CACHE_SCOPE(info) (((info)->ir >> 3) & 3)

/* cinv/cpush: cache selector -- bits 7:6 of IR (DC/IC/BC). */
#define M68K_IR_CACHE_SEL(info) (((info)->ir >> 6) & 3)

/* ── FPU extension-word bit-field helpers ────────────────────────────
* The FPU command word is the 16-bit extension following the F-line. */

/* R/M bit (bit 14): 1 = source from EA, 0 = source from FP register. */
#define M68K_FEXT_RM(ext) (((ext) >> 14) & 1)

/* Type / command class (bits 15:13). */
#define M68K_FEXT_TYPE(ext) (((ext) >> 13) & 7)

/* Source specifier (bits 12:10) -- data format when R/M=1. */
#define M68K_FEXT_SRC(ext) (((ext) >> 10) & 7)

/* Destination FP register (bits 9:7). */
#define M68K_FEXT_DST(ext) (((ext) >> 7) & 7)

/* Opmode (bits 5:0) -- FPU operation selector. */
#define M68K_FEXT_OPMODE(ext) ((ext) & 0x3f)

/* Single/double precision flag (bit 6) -- 68040+ only. */
#define M68K_FEXT_SD_FLAG(ext) (((ext) >> 6) & 1)

/* FMOVECR signature: bits 15:10 == 0x17 (010111b). */
#define M68K_FEXT_IS_FMOVECR(ext) (BITFIELD((ext), 15, 10) == 0x17)

/* Register-select field for FMOVE to/from FPCR/FPSR/FPIAR (bits 12:10). */
#define M68K_FEXT_REGSEL(ext) (((ext) >> 10) & 7)

/* Direction bit for FMOVE FPCR (bit 13): 0 = ea->fpcr, 1 = fpcr->ea. */
#define M68K_FEXT_DIR(ext) (((ext) >> 13) & 1)

/* ── FPU condition-code mask ─────────────────────────────────────────
* FBcc/FDBcc/FScc/FTRAPcc encode the FP condition in bits 5,3:0
* of the extension word (or IR for FBcc). Bit 4 is always 0,
* yielding the 0x2f mask. */
#define M68K_FP_COND(x) ((x) & 0x2f)

/* Maximum valid condition codes per coprocessor. */
#define M68K_PMMU_MAX_COND 16
#define M68K_FPU_MAX_COND 32

/* ── FPU source-format constants (bits 12:10 of ext word) ───────────*/
#define M68K_FPSRC_LONG 0x00 /* .l -- 32-bit integer */
#define M68K_FPSRC_SINGLE 0x01 /* .s -- 32-bit IEEE single */
#define M68K_FPSRC_EXTENDED 0x02 /* .x -- 96-bit extended real */
#define M68K_FPSRC_PACKED 0x03 /* .p -- 96-bit packed decimal */
#define M68K_FPSRC_WORD 0x04 /* .w -- 16-bit integer */
#define M68K_FPSRC_DOUBLE 0x05 /* .d -- 64-bit IEEE double */
#define M68K_FPSRC_BYTE 0x06 /* .b -- 8-bit integer */

/* ── FPU special raw opmodes (before SD-flag masking) ───────────────
* FSSQRT/FDSQRT have raw 7-bit opmodes 0x41/0x45. After the 6-bit
* truncation (& 0x3f) they become 0x01/0x05 with the SD flag set. */
#define M68K_FPOP_FSSQRT_RAW 0x01 /* 0x41 & 0x3f */
#define M68K_FPOP_FDSQRT_RAW 0x05 /* 0x45 & 0x3f */

/* ── CPU-type guard macros ───────────────────────────────────────────
* These reference the `info` parameter available at each call site.
* They early-return from the calling function on type mismatch. */

#define LIMIT_CPU_TYPES(info, ALLOWED_CPU_TYPES) \
do { \
if (!(info->type & ALLOWED_CPU_TYPES)) { \
d68000_invalid(info); \
return; \
} \
} while (0)

/* Like LIMIT_CPU_TYPES but also reverses the instruction word consumption,
* so the invalid instruction produces size=0 (not decoded) instead of size=2.
* Use for handlers that replace d68000_invalid in the dispatch table. */
#define LIMIT_CPU_TYPES_UNDECODED(info, ALLOWED_CPU_TYPES) \
do { \
if (!(info->type & ALLOWED_CPU_TYPES)) { \
info->pc -= 2; \
d68000_invalid(info); \
return; \
} \
} while (0)

/* Like LIMIT_CPU_TYPES but also rejects CPU32. CPU32 shares TYPE_68020 but
* lacks some 68020 instructions (CAS, CAS2, CHK.L, PACK, UNPK). */
#define LIMIT_CPU_TYPES_NOT_CPU32(info, ALLOWED_CPU_TYPES) \
do { \
if (!(info->type & (ALLOWED_CPU_TYPES)) || \
(info->type & TYPE_CPU32)) { \
d68000_invalid(info); \
return; \
} \
} while (0)

/* Require CpID == FPU. Rejects all other coprocessor IDs.
* Used by cpDBcc, cpScc, cpTRAPcc handlers. */
#define REQUIRE_CPID_FPU(info) \
do { \
if (M68K_CPID(info) != M68K_CPID_FPU) { \
d68000_invalid(info); \
return; \
} \
} while (0)

Comment thread
Rot127 marked this conversation as resolved.
/* Require CpID == MMU or CpID == FPU.
* CpID MMU is rejected on CPU32 (no PMMU). Used by cpSAVE/cpRESTORE. */
#define REQUIRE_CPID_FPU_OR_PMMU(info) \
Comment thread
Rot127 marked this conversation as resolved.
do { \
int _cpid = M68K_CPID(info); \
if (_cpid == M68K_CPID_MMU && ((info)->type & TYPE_CPU32)) { \
d68000_invalid(info); \
return; \
} \
if (_cpid != M68K_CPID_MMU && _cpid != M68K_CPID_FPU) { \
d68000_invalid(info); \
return; \
} \
} while (0)

/* ── EA / immediate convenience aliases ─────────────────────────────
* Shorthand wrappers around the sized get_ea_mode_str / get_imm_str
* functions. These expand at the call site where 'info' is in scope. */

/* Fake a split interface */
#define get_ea_mode_str_8(instruction) get_ea_mode_str(instruction, 0)
#define get_ea_mode_str_16(instruction) get_ea_mode_str(instruction, 1)
#define get_ea_mode_str_32(instruction) get_ea_mode_str(instruction, 2)

#define get_imm_str_s8() get_imm_str_s(0)
#define get_imm_str_s16() get_imm_str_s(1)
#define get_imm_str_s32() get_imm_str_s(2)

#define get_imm_str_u8() get_imm_str_u(0)
#define get_imm_str_u16() get_imm_str_u(1)
#define get_imm_str_u32() get_imm_str_u(2)

/* ── Operand access shorthands ──────────────────────────────────────
* Quick access to the operand array and instruction size via `info`. */
#define IOPS(I) (&info->extension.operands[(I)])
#define ISIZE (info->extension.op_size.cpu_size)

/* ======================================================================== */
/* ============================ INTERNAL TYPES ============================ */
/* ======================================================================== */

/* Private, For internal use only */
typedef struct m68k_info {
const uint8_t *code;
Expand Down
Loading
Loading