/src/capstonenext/arch/M68K/M68KDisassembler.h
Line | Count | Source |
1 | | /* Capstone Disassembly Engine */ |
2 | | /* M68K Backend by Daniel Collin <daniel@collin.com> 2015-2016 */ |
3 | | |
4 | | #ifndef CS_M68KDISASSEMBLER_H |
5 | | #define CS_M68KDISASSEMBLER_H |
6 | | |
7 | | #include "../../MCInst.h" |
8 | | |
9 | | /* ======================================================================== */ |
10 | | /* ============================ GENERAL DEFINES =========================== */ |
11 | | /* ======================================================================== */ |
12 | | |
13 | | /* Bit Isolation Functions */ |
14 | 2.26k | #define BIT_0(A) ((A) & 0x00000001) |
15 | | #define BIT_1(A) ((A) & 0x00000002) |
16 | | #define BIT_2(A) ((A) & 0x00000004) |
17 | 0 | #define BIT_3(A) ((A) & 0x00000008) |
18 | | #define BIT_4(A) ((A) & 0x00000010) |
19 | 1.16k | #define BIT_5(A) ((A) & 0x00000020) |
20 | 6.23k | #define BIT_6(A) ((A) & 0x00000040) |
21 | 6.23k | #define BIT_7(A) ((A) & 0x00000080) |
22 | 12.9k | #define BIT_8(A) ((A) & 0x00000100) |
23 | | #define BIT_9(A) ((A) & 0x00000200) |
24 | 616 | #define BIT_A(A) ((A) & 0x00000400) |
25 | 12.9k | #define BIT_B(A) ((A) & 0x00000800) |
26 | | #define BIT_C(A) ((A) & 0x00001000) |
27 | | #define BIT_D(A) ((A) & 0x00002000) |
28 | | #define BIT_E(A) ((A) & 0x00004000) |
29 | 13.5k | #define BIT_F(A) ((A) & 0x00008000) |
30 | | #define BIT_10(A) ((A) & 0x00010000) |
31 | | #define BIT_11(A) ((A) & 0x00020000) |
32 | | #define BIT_12(A) ((A) & 0x00040000) |
33 | | #define BIT_13(A) ((A) & 0x00080000) |
34 | | #define BIT_14(A) ((A) & 0x00100000) |
35 | | #define BIT_15(A) ((A) & 0x00200000) |
36 | | #define BIT_16(A) ((A) & 0x00400000) |
37 | | #define BIT_17(A) ((A) & 0x00800000) |
38 | | #define BIT_18(A) ((A) & 0x01000000) |
39 | | #define BIT_19(A) ((A) & 0x02000000) |
40 | | #define BIT_1A(A) ((A) & 0x04000000) |
41 | | #define BIT_1B(A) ((A) & 0x08000000) |
42 | | #define BIT_1C(A) ((A) & 0x10000000) |
43 | | #define BIT_1D(A) ((A) & 0x20000000) |
44 | | #define BIT_1E(A) ((A) & 0x40000000) |
45 | 88 | #define BIT_1F(A) ((A) & 0x80000000) |
46 | | |
47 | | /* These are the M68K feature masks understood by this disassembler. */ |
48 | | #define M68000_ONLY CS_MODE_M68K_000 |
49 | | |
50 | | #define M68010_ONLY CS_MODE_M68K_010 |
51 | 192k | #define M68010_LESS (CS_MODE_M68K_000 | CS_MODE_M68K_010) |
52 | | #define M68010_PLUS \ |
53 | | (CS_MODE_M68K_010 | CS_MODE_M68K_020 | CS_MODE_M68K_030 | \ |
54 | | CS_MODE_M68K_040 | CS_MODE_M68K_060) |
55 | | |
56 | | #define M68020_ONLY CS_MODE_M68K_020 |
57 | | #define M68020_LESS (CS_MODE_M68K_010 | CS_MODE_M68K_020) |
58 | | #define M68020_PLUS \ |
59 | | (CS_MODE_M68K_020 | CS_MODE_M68K_030 | CS_MODE_M68K_040 | \ |
60 | | CS_MODE_M68K_060) |
61 | | |
62 | | #define M68030_ONLY CS_MODE_M68K_030 |
63 | | #define M68030_LESS (CS_MODE_M68K_010 | CS_MODE_M68K_020 | CS_MODE_M68K_030) |
64 | | #define M68030_PLUS (CS_MODE_M68K_030 | CS_MODE_M68K_040 | CS_MODE_M68K_060) |
65 | | |
66 | 162 | #define M68040_PLUS (CS_MODE_M68K_040 | CS_MODE_M68K_060) |
67 | | |
68 | | typedef uint32_t m68k_feature_mask; |
69 | | |
70 | | /* Extension word formats */ |
71 | | #define EXT_8BIT_DISPLACEMENT(A) ((A) & 0xff) |
72 | 12.9k | #define EXT_FULL(A) BIT_8(A) |
73 | | #define EXT_EFFECTIVE_ZERO(A) (((A) & 0xe4) == 0xc4 || ((A) & 0xe2) == 0xc0) |
74 | 6.23k | #define EXT_BASE_REGISTER_PRESENT(A) (!BIT_7(A)) |
75 | 6.23k | #define EXT_INDEX_REGISTER_PRESENT(A) (!BIT_6(A)) |
76 | 10.7k | #define EXT_INDEX_REGISTER(A) (((A) >> 12) & 7) |
77 | | #define EXT_INDEX_PRE_POST(A) (EXT_INDEX_REGISTER_PRESENT(A) && (A) & 3) |
78 | | #define EXT_INDEX_PRE(A) \ |
79 | | (EXT_INDEX_REGISTER_PRESENT(A) && ((A) & 7) < 4 && ((A) & 7) != 0) |
80 | | #define EXT_INDEX_POST(A) (EXT_INDEX_REGISTER_PRESENT(A) && ((A) & 7) > 4) |
81 | 17.0k | #define EXT_INDEX_SCALE(A) (((A) >> 9) & 3) |
82 | 10.7k | #define EXT_INDEX_LONG(A) BIT_B(A) |
83 | 10.7k | #define EXT_INDEX_AR(A) BIT_F(A) |
84 | 18.7k | #define EXT_BASE_DISPLACEMENT_PRESENT(A) (((A) & 0x30) > 0x10) |
85 | | #define EXT_BASE_DISPLACEMENT_WORD(A) (((A) & 0x30) == 0x20) |
86 | 7.18k | #define EXT_BASE_DISPLACEMENT_LONG(A) (((A) & 0x30) == 0x30) |
87 | | /* Outer displacement is present when I/IS[1:0] (bits 1-0) is 2 (word) or 3 (long). |
88 | | * This applies regardless of the IS bit (bit 6): when index is suppressed, |
89 | | * I/IS values 5-7 mirror 1-3 (just indirect instead of postindexed). |
90 | | * The old check ((A) & 0x47) < 0x44 incorrectly excluded IS=1 cases |
91 | | * (I/IS=6,7) which DO have outer displacements per the M68K spec. |
92 | | */ |
93 | 18.7k | #define EXT_OUTER_DISPLACEMENT_PRESENT(A) (((A) & 3) > 1) |
94 | | #define EXT_OUTER_DISPLACEMENT_WORD(A) (((A) & 3) == 2) |
95 | 4.17k | #define EXT_OUTER_DISPLACEMENT_LONG(A) (((A) & 3) == 3) |
96 | | |
97 | | #define IS_BITSET(val, b) ((val) & (1 << (b))) |
98 | 4.84k | #define BITFIELD_MASK(sb, eb) (((1 << ((sb) + 1)) - 1) & (~((1 << (eb)) - 1))) |
99 | 4.84k | #define BITFIELD(val, sb, eb) ((BITFIELD_MASK(sb, eb) & (val)) >> (eb)) |
100 | | |
101 | | /* Bitfield offset/width encoding. |
102 | | * Public decode macros (M68K_BF_*) live in <capstone/m68k.h>. |
103 | | * Internal aliases kept for brevity within arch code. */ |
104 | | #define M68K_BITFIELD_REG_FLAG M68K_BF_REG_FLAG |
105 | | #define M68K_BITFIELD_IS_REG(v) M68K_BF_IS_REG(v) |
106 | | #define M68K_BITFIELD_REG_NUM(v) M68K_BF_REG_NUM(v) |
107 | 1.15k | #define M68K_BITFIELD_ENCODE_REG(regnum) (((regnum) & 7) | M68K_BF_REG_FLAG) |
108 | | |
109 | | /* ── Coprocessor ID (CpID) ─────────────────────────────────────────── |
110 | | * Bits 11:9 of the F-line instruction word select the coprocessor. */ |
111 | 18.1k | #define M68K_CPID(info) (((info)->ir >> 9) & 7) |
112 | | |
113 | 16.0k | #define M68K_CPID_MMU 0 /* PMMU (68030/68851) */ |
114 | 10.9k | #define M68K_CPID_FPU 1 /* FPU (68881/68882/internal) */ |
115 | 834 | #define M68K_CPID_CACHE 2 /* Cache ops -- cinvl/cpushl on 68040+ */ |
116 | | |
117 | | /* ── IR bit-field helpers ──────────────────────────────────────────── |
118 | | * Extract commonly-used fields from the first instruction word. */ |
119 | | |
120 | | /* 6-bit coprocessor condition (bits 5:0 of IR). */ |
121 | 3.60k | #define M68K_IR_CONDITION(info) ((info)->ir & 0x3f) |
122 | | |
123 | | /* 4-bit condition selector used by Bcc/DBcc/Scc/TRAPcc. */ |
124 | 9.06k | #define M68K_IR_CONDITION_NIBBLE(info) (((info)->ir >> 8) & 0xf) |
125 | 0 | #define M68K_CONDITION_FALSE 1 |
126 | | |
127 | | /* cinv/cpush: select cpush(1) vs cinv(0) -- bit 5 of IR. */ |
128 | 59 | #define M68K_IR_IS_CPUSH(info) (((info)->ir >> 5) & 1) |
129 | | |
130 | | /* cinv/cpush: cache scope -- bits 4:3 of IR (0=invalid,1=line,2=page,3=all). */ |
131 | 603 | #define M68K_IR_CACHE_SCOPE(info) (((info)->ir >> 3) & 3) |
132 | | |
133 | | /* cinv/cpush: cache selector -- bits 7:6 of IR (DC/IC/BC). */ |
134 | 524 | #define M68K_IR_CACHE_SEL(info) (((info)->ir >> 6) & 3) |
135 | | |
136 | | /* ── FPU extension-word bit-field helpers ──────────────────────────── |
137 | | * The FPU command word is the 16-bit extension following the F-line. */ |
138 | | |
139 | | /* R/M bit (bit 14): 1 = source from EA, 0 = source from FP register. */ |
140 | 4.38k | #define M68K_FEXT_RM(ext) (((ext) >> 14) & 1) |
141 | | |
142 | | /* Type / command class (bits 15:13). */ |
143 | 8.67k | #define M68K_FEXT_TYPE(ext) (((ext) >> 13) & 7) |
144 | | |
145 | | /* Source specifier (bits 12:10) -- data format when R/M=1. */ |
146 | 4.38k | #define M68K_FEXT_SRC(ext) (((ext) >> 10) & 7) |
147 | | |
148 | | /* Destination FP register (bits 9:7). */ |
149 | 4.46k | #define M68K_FEXT_DST(ext) (((ext) >> 7) & 7) |
150 | | |
151 | | /* Opmode (bits 5:0) -- FPU operation selector. */ |
152 | 4.46k | #define M68K_FEXT_OPMODE(ext) ((ext) & 0x3f) |
153 | | |
154 | | /* Single/double precision flag (bit 6) -- 68040+ only. */ |
155 | 7.16k | #define M68K_FEXT_SD_FLAG(ext) (((ext) >> 6) & 1) |
156 | | |
157 | | /* FMOVECR signature: bits 15:10 == 0x17 (010111b). */ |
158 | 460 | #define M68K_FEXT_IS_FMOVECR(ext) (BITFIELD((ext), 15, 10) == 0x17) |
159 | | |
160 | | /* Register-select field for FMOVE to/from FPCR/FPSR/FPIAR (bits 12:10). */ |
161 | 515 | #define M68K_FEXT_REGSEL(ext) (((ext) >> 10) & 7) |
162 | | |
163 | | /* Direction bit for FMOVE FPCR (bit 13): 0 = ea->fpcr, 1 = fpcr->ea. */ |
164 | 1.73k | #define M68K_FEXT_DIR(ext) (((ext) >> 13) & 1) |
165 | | |
166 | | /* ── FPU condition-code mask ───────────────────────────────────────── |
167 | | * FBcc/FDBcc/FScc/FTRAPcc encode the FP condition in bits 5,3:0 |
168 | | * of the extension word (or IR for FBcc). Bit 4 is always 0, |
169 | | * yielding the 0x2f mask. */ |
170 | 1.28k | #define M68K_FP_COND(x) ((x) & 0x2f) |
171 | | |
172 | | /* Maximum valid condition codes per coprocessor. */ |
173 | 1.03k | #define M68K_PMMU_MAX_COND 16 |
174 | 1.47k | #define M68K_FPU_MAX_COND 32 |
175 | | |
176 | | /* ── FPU source-format constants (bits 12:10 of ext word) ───────────*/ |
177 | 103 | #define M68K_FPSRC_LONG 0x00 /* .l -- 32-bit integer */ |
178 | 306 | #define M68K_FPSRC_SINGLE 0x01 /* .s -- 32-bit IEEE single */ |
179 | 132 | #define M68K_FPSRC_EXTENDED 0x02 /* .x -- 96-bit extended real */ |
180 | 172 | #define M68K_FPSRC_PACKED 0x03 /* .p -- 96-bit packed decimal */ |
181 | 52 | #define M68K_FPSRC_WORD 0x04 /* .w -- 16-bit integer */ |
182 | 74 | #define M68K_FPSRC_DOUBLE 0x05 /* .d -- 64-bit IEEE double */ |
183 | 102 | #define M68K_FPSRC_BYTE 0x06 /* .b -- 8-bit integer */ |
184 | | |
185 | | /* ── FPU special raw opmodes (before SD-flag masking) ─────────────── |
186 | | * FSSQRT/FDSQRT have raw 7-bit opmodes 0x41/0x45. After the 6-bit |
187 | | * truncation (& 0x3f) they become 0x01/0x05 with the SD flag set. */ |
188 | 860 | #define M68K_FPOP_FSSQRT_RAW 0x01 /* 0x41 & 0x3f */ |
189 | 845 | #define M68K_FPOP_FDSQRT_RAW 0x05 /* 0x45 & 0x3f */ |
190 | | |
191 | | /* ── Feature guard macros ──────────────────────────────────────────── |
192 | | * These reference the `info` parameter available at each call site. |
193 | | * They early-return from the calling function on guard mismatch. */ |
194 | | |
195 | | #define LIMIT_FEATURE(info, FEATURES) \ |
196 | 41.9k | do { \ |
197 | 41.9k | if (!m68k_has_feature(info, FEATURES)) { \ |
198 | 19.1k | d68000_invalid(info); \ |
199 | 19.1k | return; \ |
200 | 19.1k | } \ |
201 | 41.9k | } while (0) |
202 | | |
203 | | /* Like LIMIT_FEATURE but also reverses the instruction word consumption, |
204 | | * so the invalid instruction produces size=0 (not decoded) instead of size=2. |
205 | | * Use for handlers that replace d68000_invalid in the dispatch table. */ |
206 | | #define LIMIT_FEATURE_UNDECODED(info, FEATURES) \ |
207 | 2 | do { \ |
208 | 2 | if (!m68k_has_feature(info, FEATURES)) { \ |
209 | 2 | info->pc -= 2; \ |
210 | 2 | d68000_invalid(info); \ |
211 | 2 | return; \ |
212 | 2 | } \ |
213 | 2 | } while (0) |
214 | | |
215 | | /* Like LIMIT_FEATURE but also rejects a feature subset. CPU32 implies 68020 |
216 | | * but lacks some 68020 instructions (CAS, CAS2, CHK.L, PACK, UNPK). */ |
217 | | #define LIMIT_FEATURE_EXCLUDING(info, FEATURES, EXCLUDED_FEATURES) \ |
218 | 7.95k | do { \ |
219 | 7.95k | if (!m68k_has_feature(info, FEATURES) || \ |
220 | 7.95k | m68k_has_feature(info, EXCLUDED_FEATURES)) { \ |
221 | 2.40k | d68000_invalid(info); \ |
222 | 2.40k | return; \ |
223 | 2.40k | } \ |
224 | 7.95k | } while (0) |
225 | | |
226 | | /* Require CpID == FPU. Rejects all other coprocessor IDs. |
227 | | * Used by cpDBcc, cpScc, cpTRAPcc handlers. */ |
228 | | #define REQUIRE_CPID_FPU(info) \ |
229 | 1.65k | do { \ |
230 | 1.65k | if (M68K_CPID(info) != M68K_CPID_FPU) { \ |
231 | 998 | d68000_invalid(info); \ |
232 | 998 | return; \ |
233 | 998 | } \ |
234 | 1.65k | } while (0) |
235 | | |
236 | | /* ── EA / immediate convenience aliases ───────────────────────────── |
237 | | * Shorthand wrappers around the sized get_ea_mode_str / get_imm_str |
238 | | * functions. These expand at the call site where 'info' is in scope. */ |
239 | | |
240 | | /* Fake a split interface */ |
241 | | #define get_ea_mode_str_8(instruction) get_ea_mode_str(instruction, 0) |
242 | | #define get_ea_mode_str_16(instruction) get_ea_mode_str(instruction, 1) |
243 | | #define get_ea_mode_str_32(instruction) get_ea_mode_str(instruction, 2) |
244 | | |
245 | | #define get_imm_str_s8() get_imm_str_s(0) |
246 | | #define get_imm_str_s16() get_imm_str_s(1) |
247 | | #define get_imm_str_s32() get_imm_str_s(2) |
248 | | |
249 | | #define get_imm_str_u8() get_imm_str_u(0) |
250 | | #define get_imm_str_u16() get_imm_str_u(1) |
251 | | #define get_imm_str_u32() get_imm_str_u(2) |
252 | | |
253 | | /* ── Operand access shorthands ────────────────────────────────────── |
254 | | * Quick access to the operand array and instruction size via `info`. */ |
255 | | #define IOPS(I) (&info->extension.operands[(I)]) |
256 | 3.21k | #define ISIZE (info->extension.op_size.cpu_size) |
257 | | |
258 | | /* ======================================================================== */ |
259 | | /* ============================ INTERNAL TYPES ============================ */ |
260 | | /* ======================================================================== */ |
261 | | |
262 | | /* Private, For internal use only */ |
263 | | typedef struct m68k_info { |
264 | | const uint8_t *code; |
265 | | size_t code_len; |
266 | | uint64_t baseAddress; |
267 | | MCInst *inst; |
268 | | unsigned int pc; /* program counter */ |
269 | | unsigned int ir; /* instruction register */ |
270 | | m68k_feature_mask features; |
271 | | unsigned int address_mask; /* Address mask to simulate address lines */ |
272 | | cs_m68k extension; |
273 | | uint16_t regs_read |
274 | | [MAX_IMPL_R_REGS]; // list of implicit registers read by this insn |
275 | | uint8_t regs_read_count; // number of implicit registers read by this insn |
276 | | uint16_t regs_write |
277 | | [MAX_IMPL_W_REGS]; // list of implicit registers modified by this insn |
278 | | uint8_t regs_write_count; // number of implicit registers modified by this insn |
279 | | uint8_t groups[MAX_NUM_GROUPS]; |
280 | | uint8_t groups_count; |
281 | | } m68k_info; |
282 | | |
283 | | static inline bool m68k_has_feature(const m68k_info *info, |
284 | | m68k_feature_mask features) |
285 | 252k | { |
286 | 252k | m68k_feature_mask available = info->features; |
287 | | |
288 | 252k | if (available & CS_MODE_M68K_CPU32) |
289 | 0 | available |= CS_MODE_M68K_020; |
290 | 252k | if (available & CS_MODE_M68K_CF_ISA_A_PLUS) |
291 | 0 | available |= CS_MODE_M68K_CF_ISA_A; |
292 | 252k | if (available & CS_MODE_M68K_CF_ISA_B) |
293 | 0 | available |= CS_MODE_M68K_CF_ISA_A | CS_MODE_M68K_CF_ISA_A_PLUS; |
294 | 252k | if (available & CS_MODE_M68K_CF_ISA_C) |
295 | 0 | available |= CS_MODE_M68K_CF_ISA_A; |
296 | 252k | if (available & CS_MODE_M68K_CF_EMAC) |
297 | 0 | available |= CS_MODE_M68K_CF_MAC; |
298 | 252k | if (available & CS_MODE_M68K_CF_EMAC_B) |
299 | 0 | available |= CS_MODE_M68K_CF_EMAC | CS_MODE_M68K_CF_MAC; |
300 | | |
301 | 252k | return (available & features) != 0; |
302 | 252k | } Unexecuted instantiation: M68KModule.c:m68k_has_feature M68KDisassembler.c:m68k_has_feature Line | Count | Source | 285 | 252k | { | 286 | 252k | m68k_feature_mask available = info->features; | 287 | | | 288 | 252k | if (available & CS_MODE_M68K_CPU32) | 289 | 0 | available |= CS_MODE_M68K_020; | 290 | 252k | if (available & CS_MODE_M68K_CF_ISA_A_PLUS) | 291 | 0 | available |= CS_MODE_M68K_CF_ISA_A; | 292 | 252k | if (available & CS_MODE_M68K_CF_ISA_B) | 293 | 0 | available |= CS_MODE_M68K_CF_ISA_A | CS_MODE_M68K_CF_ISA_A_PLUS; | 294 | 252k | if (available & CS_MODE_M68K_CF_ISA_C) | 295 | 0 | available |= CS_MODE_M68K_CF_ISA_A; | 296 | 252k | if (available & CS_MODE_M68K_CF_EMAC) | 297 | 0 | available |= CS_MODE_M68K_CF_MAC; | 298 | 252k | if (available & CS_MODE_M68K_CF_EMAC_B) | 299 | 0 | available |= CS_MODE_M68K_CF_EMAC | CS_MODE_M68K_CF_MAC; | 300 | | | 301 | 252k | return (available & features) != 0; | 302 | 252k | } |
Unexecuted instantiation: M68KInstPrinter.c:m68k_has_feature |
303 | | |
304 | | bool M68K_getInstruction(csh ud, const uint8_t *code, size_t code_len, |
305 | | MCInst *instr, uint16_t *size, uint64_t address, |
306 | | void *info); |
307 | | |
308 | | #endif |