1 /* Capstone Disassembly Engine */
2 /* M680X Backend by Wolfgang Schwotzer <wolfgang.schwotzer@gmx.net> 2017 */
3
4 /* ======================================================================== */
5 /* ================================ INCLUDES ============================== */
6 /* ======================================================================== */
7
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11
12 #include "../../cs_priv.h"
13 #include "../../utils.h"
14
15 #include "../../MCInst.h"
16 #include "../../MCInstrDesc.h"
17 #include "../../MCRegisterInfo.h"
18 #include "M680XInstPrinter.h"
19 #include "M680XDisassembler.h"
20 #include "M680XDisassemblerInternals.h"
21
22 #ifdef CAPSTONE_HAS_M680X
23
24 #ifndef DECL_SPEC
25 #ifdef _MSC_VER
26 #define DECL_SPEC __cdecl
27 #else
28 #define DECL_SPEC
29 #endif // _MSC_VER
30 #endif // DECL_SPEC
31
32 /* ======================================================================== */
33 /* ============================ GENERAL DEFINES =========================== */
34 /* ======================================================================== */
35
36 /* ======================================================================== */
37 /* =============================== PROTOTYPES ============================= */
38 /* ======================================================================== */
39
40 typedef enum insn_hdlr_id {
41 illgl_hid,
42 rel8_hid,
43 rel16_hid,
44 imm8_hid,
45 imm16_hid,
46 imm32_hid,
47 dir_hid,
48 ext_hid,
49 idxX_hid,
50 idxY_hid,
51 idx09_hid,
52 inh_hid,
53 rr09_hid,
54 rbits_hid,
55 bitmv_hid,
56 tfm_hid,
57 opidx_hid,
58 opidxdr_hid,
59 idxX0_hid,
60 idxX16_hid,
61 imm8rel_hid,
62 idxS_hid,
63 idxS16_hid,
64 idxXp_hid,
65 idxX0p_hid,
66 idx12_hid,
67 idx12s_hid,
68 rr12_hid,
69 loop_hid,
70 index_hid,
71 imm8i12x_hid,
72 imm16i12x_hid,
73 exti12x_hid,
74 HANDLER_ID_ENDING,
75 } insn_hdlr_id;
76
77 // Access modes for the first 4 operands. If there are more than
78 // four operands they use the same access mode as the 4th operand.
79 //
80 // u: unchanged
81 // r: (r)read access
82 // w: (w)write access
83 // m: (m)odify access (= read + write)
84 //
85 typedef enum e_access_mode {
86
87 uuuu,
88 rrrr,
89 wwww,
90 rwww,
91 rrrm,
92 rmmm,
93 wrrr,
94 mrrr,
95 mwww,
96 mmmm,
97 mwrr,
98 mmrr,
99 wmmm,
100 rruu,
101 muuu,
102 ACCESS_MODE_ENDING,
103 } e_access_mode;
104
105 // Access type values are compatible with enum cs_ac_type:
106 typedef enum e_access {
107 UNCHANGED = CS_AC_INVALID,
108 READ = CS_AC_READ,
109 WRITE = CS_AC_WRITE,
110 MODIFY = (CS_AC_READ | CS_AC_WRITE),
111 } e_access;
112
113 /* Properties of one instruction in PAGE1 (without prefix) */
114 typedef struct inst_page1 {
115 unsigned insn : 9; // A value of type m680x_insn
116 unsigned handler_id1 : 6; // Type insn_hdlr_id, first instr. handler id
117 unsigned handler_id2 : 6; // Type insn_hdlr_id, second instr. handler id
118 } inst_page1;
119
120 /* Properties of one instruction in any other PAGE X */
121 typedef struct inst_pageX {
122 unsigned opcode : 8; // The opcode byte
123 unsigned insn : 9; // A value of type m680x_insn
124 unsigned handler_id1 : 6; // Type insn_hdlr_id, first instr. handler id
125 unsigned handler_id2 : 6; // Type insn_hdlr_id, second instr. handler id
126 } inst_pageX;
127
128 typedef struct insn_props {
129 unsigned group : 4;
130 unsigned access_mode : 5; // A value of type e_access_mode
131 unsigned reg0 : 5; // A value of type m680x_reg
132 unsigned reg1 : 5; // A value of type m680x_reg
133 bool cc_modified : 1;
134 bool update_reg_access : 1;
135 } insn_props;
136
137 #include "m6800.inc"
138 #include "m6801.inc"
139 #include "hd6301.inc"
140 #include "m6811.inc"
141 #include "cpu12.inc"
142 #include "m6805.inc"
143 #include "m6808.inc"
144 #include "hcs08.inc"
145 #include "m6809.inc"
146 #include "hd6309.inc"
147
148 #include "insn_props.inc"
149
150 //////////////////////////////////////////////////////////////////////////////
151
152 // M680X instuctions have 1 up to 8 bytes (CPU12: MOVW IDX2,IDX2).
153 // A reader is needed to read a byte or word from a given memory address.
154 // See also X86 reader(...)
read_byte(const m680x_info * info,uint8_t * byte,uint16_t address)155 static bool read_byte(const m680x_info *info, uint8_t *byte, uint16_t address)
156 {
157 if (address < info->offset ||
158 (uint32_t)(address - info->offset) >= info->size)
159 // out of code buffer range
160 return false;
161
162 *byte = info->code[address - info->offset];
163
164 return true;
165 }
166
read_byte_sign_extended(const m680x_info * info,int16_t * word,uint16_t address)167 static bool read_byte_sign_extended(const m680x_info *info, int16_t *word,
168 uint16_t address)
169 {
170 if (address < info->offset ||
171 (uint32_t)(address - info->offset) >= info->size)
172 // out of code buffer range
173 return false;
174
175 *word = (int16_t) info->code[address - info->offset];
176
177 if (*word & 0x80)
178 *word |= 0xFF00;
179
180 return true;
181 }
182
read_word(const m680x_info * info,uint16_t * word,uint16_t address)183 static bool read_word(const m680x_info *info, uint16_t *word, uint16_t address)
184 {
185 if (address < info->offset ||
186 (uint32_t)(address + 1 - info->offset) >= info->size)
187 // out of code buffer range
188 return false;
189
190 *word = (uint16_t)info->code[address - info->offset] << 8;
191 *word |= (uint16_t)info->code[address + 1 - info->offset];
192
193 return true;
194 }
195
read_sdword(const m680x_info * info,int32_t * sdword,uint16_t address)196 static bool read_sdword(const m680x_info *info, int32_t *sdword,
197 uint16_t address)
198 {
199 if (address < info->offset ||
200 (uint32_t)(address + 3 - info->offset) >= info->size)
201 // out of code buffer range
202 return false;
203
204 *sdword = (uint32_t)info->code[address - info->offset] << 24;
205 *sdword |= (uint32_t)info->code[address + 1 - info->offset] << 16;
206 *sdword |= (uint32_t)info->code[address + 2 - info->offset] << 8;
207 *sdword |= (uint32_t)info->code[address + 3 - info->offset];
208
209 return true;
210 }
211
212 // For PAGE2 and PAGE3 opcodes when using an an array of inst_page1 most
213 // entries have M680X_INS_ILLGL. To avoid wasting memory an inst_pageX is
214 // used which contains the opcode. Using a binary search for the right opcode
215 // is much faster (= O(log n) ) in comparison to a linear search ( = O(n) ).
binary_search(const inst_pageX * const inst_pageX_table,size_t table_size,unsigned int opcode)216 static int binary_search(const inst_pageX *const inst_pageX_table,
217 size_t table_size, unsigned int opcode)
218 {
219 // As part of the algorithm last may get negative.
220 // => signed integer has to be used.
221 int first = 0;
222 int last = (int)table_size - 1;
223 int middle = (first + last) / 2;
224
225 while (first <= last) {
226 if (inst_pageX_table[middle].opcode < opcode) {
227 first = middle + 1;
228 }
229 else if (inst_pageX_table[middle].opcode == opcode) {
230 return middle; /* item found */
231 }
232 else
233 last = middle - 1;
234
235 middle = (first + last) / 2;
236 }
237
238 if (first > last)
239 return -1; /* item not found */
240
241 return -2;
242 }
243
M680X_get_insn_id(cs_struct * handle,cs_insn * insn,unsigned int id)244 void M680X_get_insn_id(cs_struct *handle, cs_insn *insn, unsigned int id)
245 {
246 const m680x_info *const info = (const m680x_info *)handle->printer_info;
247 const cpu_tables *cpu = info->cpu;
248 uint8_t insn_prefix = (id >> 8) & 0xff;
249 // opcode is the first instruction byte without the prefix.
250 uint8_t opcode = id & 0xff;
251 int index;
252 int i;
253
254 insn->id = M680X_INS_ILLGL;
255
256 for (i = 0; i < ARR_SIZE(cpu->pageX_prefix); ++i) {
257 if (cpu->pageX_table_size[i] == 0 ||
258 (cpu->inst_pageX_table[i] == NULL))
259 break;
260
261 if (cpu->pageX_prefix[i] == insn_prefix) {
262 index = binary_search(cpu->inst_pageX_table[i],
263 cpu->pageX_table_size[i], opcode);
264 insn->id = (index >= 0) ?
265 cpu->inst_pageX_table[i][index].insn :
266 M680X_INS_ILLGL;
267 return;
268 }
269 }
270
271 if (insn_prefix != 0)
272 return;
273
274 insn->id = cpu->inst_page1_table[id].insn;
275
276 if (insn->id != M680X_INS_ILLGL)
277 return;
278
279 // Check if opcode byte is present in an overlay table
280 for (i = 0; i < ARR_SIZE(cpu->overlay_table_size); ++i) {
281 if (cpu->overlay_table_size[i] == 0 ||
282 (cpu->inst_overlay_table[i] == NULL))
283 break;
284
285 if ((index = binary_search(cpu->inst_overlay_table[i],
286 cpu->overlay_table_size[i],
287 opcode)) >= 0) {
288 insn->id = cpu->inst_overlay_table[i][index].insn;
289 return;
290 }
291 }
292 }
293
add_insn_group(cs_detail * detail,m680x_group_type group)294 static void add_insn_group(cs_detail *detail, m680x_group_type group)
295 {
296 if (detail != NULL &&
297 (group != M680X_GRP_INVALID) && (group != M680X_GRP_ENDING))
298 detail->groups[detail->groups_count++] = (uint8_t)group;
299 }
300
exists_reg_list(uint16_t * regs,uint8_t count,m680x_reg reg)301 static bool exists_reg_list(uint16_t *regs, uint8_t count, m680x_reg reg)
302 {
303 uint8_t i;
304
305 for (i = 0; i < count; ++i) {
306 if (regs[i] == (uint16_t)reg)
307 return true;
308 }
309
310 return false;
311 }
312
add_reg_to_rw_list(MCInst * MI,m680x_reg reg,e_access access)313 static void add_reg_to_rw_list(MCInst *MI, m680x_reg reg, e_access access)
314 {
315 cs_detail *detail = MI->flat_insn->detail;
316
317 if (detail == NULL || (reg == M680X_REG_INVALID))
318 return;
319
320 switch (access) {
321 case MODIFY:
322 if (!exists_reg_list(detail->regs_read,
323 detail->regs_read_count, reg))
324 detail->regs_read[detail->regs_read_count++] =
325 (uint16_t)reg;
326
327 // intentionally fall through
328
329 case WRITE:
330 if (!exists_reg_list(detail->regs_write,
331 detail->regs_write_count, reg))
332 detail->regs_write[detail->regs_write_count++] =
333 (uint16_t)reg;
334
335 break;
336
337 case READ:
338 if (!exists_reg_list(detail->regs_read,
339 detail->regs_read_count, reg))
340 detail->regs_read[detail->regs_read_count++] =
341 (uint16_t)reg;
342
343 break;
344
345 case UNCHANGED:
346 default:
347 break;
348 }
349 }
350
update_am_reg_list(MCInst * MI,m680x_info * info,cs_m680x_op * op,e_access access)351 static void update_am_reg_list(MCInst *MI, m680x_info *info, cs_m680x_op *op,
352 e_access access)
353 {
354 if (MI->flat_insn->detail == NULL)
355 return;
356
357 switch (op->type) {
358 case M680X_OP_REGISTER:
359 add_reg_to_rw_list(MI, op->reg, access);
360 break;
361
362 case M680X_OP_INDEXED:
363 add_reg_to_rw_list(MI, op->idx.base_reg, READ);
364
365 if (op->idx.base_reg == M680X_REG_X &&
366 info->cpu->reg_byte_size[M680X_REG_H])
367 add_reg_to_rw_list(MI, M680X_REG_H, READ);
368
369
370 if (op->idx.offset_reg != M680X_REG_INVALID)
371 add_reg_to_rw_list(MI, op->idx.offset_reg, READ);
372
373 if (op->idx.inc_dec) {
374 add_reg_to_rw_list(MI, op->idx.base_reg, WRITE);
375
376 if (op->idx.base_reg == M680X_REG_X &&
377 info->cpu->reg_byte_size[M680X_REG_H])
378 add_reg_to_rw_list(MI, M680X_REG_H, WRITE);
379 }
380
381 break;
382
383 default:
384 break;
385 }
386 }
387
388 static const e_access g_access_mode_to_access[4][15] = {
389 {
390 UNCHANGED, READ, WRITE, READ, READ, READ, WRITE, MODIFY,
391 MODIFY, MODIFY, MODIFY, MODIFY, WRITE, READ, MODIFY,
392 },
393 {
394 UNCHANGED, READ, WRITE, WRITE, READ, MODIFY, READ, READ,
395 WRITE, MODIFY, WRITE, MODIFY, MODIFY, READ, UNCHANGED,
396 },
397 {
398 UNCHANGED, READ, WRITE, WRITE, READ, MODIFY, READ, READ,
399 WRITE, MODIFY, READ, READ, MODIFY, UNCHANGED, UNCHANGED,
400 },
401 {
402 UNCHANGED, READ, WRITE, WRITE, MODIFY, MODIFY, READ, READ,
403 WRITE, MODIFY, READ, READ, MODIFY, UNCHANGED, UNCHANGED,
404 },
405 };
406
get_access(int operator_index,e_access_mode access_mode)407 static e_access get_access(int operator_index, e_access_mode access_mode)
408 {
409 int idx = (operator_index > 3) ? 3 : operator_index;
410
411 return g_access_mode_to_access[idx][access_mode];
412 }
413
build_regs_read_write_counts(MCInst * MI,m680x_info * info,e_access_mode access_mode)414 static void build_regs_read_write_counts(MCInst *MI, m680x_info *info,
415 e_access_mode access_mode)
416 {
417 cs_m680x *m680x = &info->m680x;
418 int i;
419
420 if (MI->flat_insn->detail == NULL || (!m680x->op_count))
421 return;
422
423 for (i = 0; i < m680x->op_count; ++i) {
424
425 e_access access = get_access(i, access_mode);
426 update_am_reg_list(MI, info, &m680x->operands[i], access);
427 }
428 }
429
add_operators_access(MCInst * MI,m680x_info * info,e_access_mode access_mode)430 static void add_operators_access(MCInst *MI, m680x_info *info,
431 e_access_mode access_mode)
432 {
433 cs_m680x *m680x = &info->m680x;
434 int offset = 0;
435 int i;
436
437 if (MI->flat_insn->detail == NULL || (!m680x->op_count) ||
438 (access_mode == uuuu))
439 return;
440
441 for (i = 0; i < m680x->op_count; ++i) {
442 e_access access;
443
444 // Ugly fix: MULD has a register operand, an immediate operand
445 // AND an implicitly changed register W
446 if (info->insn == M680X_INS_MULD && (i == 1))
447 offset = 1;
448
449 access = get_access(i + offset, access_mode);
450 m680x->operands[i].access = access;
451 }
452 }
453
454 typedef struct insn_to_changed_regs {
455 m680x_insn insn;
456 e_access_mode access_mode;
457 m680x_reg regs[10];
458 } insn_to_changed_regs;
459
set_changed_regs_read_write_counts(MCInst * MI,m680x_info * info)460 static void set_changed_regs_read_write_counts(MCInst *MI, m680x_info *info)
461 {
462 //TABLE
463 #define EOL M680X_REG_INVALID
464 static const insn_to_changed_regs changed_regs[] = {
465 { M680X_INS_BSR, mmmm, { M680X_REG_S, EOL } },
466 { M680X_INS_CALL, mmmm, { M680X_REG_S, EOL } },
467 {
468 M680X_INS_CWAI, mrrr, {
469 M680X_REG_S, M680X_REG_PC, M680X_REG_U,
470 M680X_REG_Y, M680X_REG_X, M680X_REG_DP,
471 M680X_REG_D, M680X_REG_CC, EOL
472 },
473 },
474 { M680X_INS_DAA, mrrr, { M680X_REG_A, EOL } },
475 {
476 M680X_INS_DIV, mmrr, {
477 M680X_REG_A, M680X_REG_H, M680X_REG_X, EOL
478 }
479 },
480 {
481 M680X_INS_EDIV, mmrr, {
482 M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL
483 }
484 },
485 {
486 M680X_INS_EDIVS, mmrr, {
487 M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL
488 }
489 },
490 { M680X_INS_EMACS, mrrr, { M680X_REG_X, M680X_REG_Y, EOL } },
491 { M680X_INS_EMAXM, rrrr, { M680X_REG_D, EOL } },
492 { M680X_INS_EMINM, rrrr, { M680X_REG_D, EOL } },
493 { M680X_INS_EMUL, mmrr, { M680X_REG_D, M680X_REG_Y, EOL } },
494 { M680X_INS_EMULS, mmrr, { M680X_REG_D, M680X_REG_Y, EOL } },
495 { M680X_INS_ETBL, wmmm, { M680X_REG_A, M680X_REG_B, EOL } },
496 { M680X_INS_FDIV, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
497 { M680X_INS_IDIV, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
498 { M680X_INS_IDIVS, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
499 { M680X_INS_JSR, mmmm, { M680X_REG_S, EOL } },
500 { M680X_INS_LBSR, mmmm, { M680X_REG_S, EOL } },
501 { M680X_INS_MAXM, rrrr, { M680X_REG_A, EOL } },
502 { M680X_INS_MINM, rrrr, { M680X_REG_A, EOL } },
503 {
504 M680X_INS_MEM, mmrr, {
505 M680X_REG_X, M680X_REG_Y, M680X_REG_A, EOL
506 }
507 },
508 { M680X_INS_MUL, mmmm, { M680X_REG_A, M680X_REG_B, EOL } },
509 { M680X_INS_MULD, mwrr, { M680X_REG_D, M680X_REG_W, EOL } },
510 { M680X_INS_PSHA, rmmm, { M680X_REG_A, M680X_REG_S, EOL } },
511 { M680X_INS_PSHB, rmmm, { M680X_REG_B, M680X_REG_S, EOL } },
512 { M680X_INS_PSHC, rmmm, { M680X_REG_CC, M680X_REG_S, EOL } },
513 { M680X_INS_PSHD, rmmm, { M680X_REG_D, M680X_REG_S, EOL } },
514 { M680X_INS_PSHH, rmmm, { M680X_REG_H, M680X_REG_S, EOL } },
515 { M680X_INS_PSHX, rmmm, { M680X_REG_X, M680X_REG_S, EOL } },
516 { M680X_INS_PSHY, rmmm, { M680X_REG_Y, M680X_REG_S, EOL } },
517 { M680X_INS_PULA, wmmm, { M680X_REG_A, M680X_REG_S, EOL } },
518 { M680X_INS_PULB, wmmm, { M680X_REG_B, M680X_REG_S, EOL } },
519 { M680X_INS_PULC, wmmm, { M680X_REG_CC, M680X_REG_S, EOL } },
520 { M680X_INS_PULD, wmmm, { M680X_REG_D, M680X_REG_S, EOL } },
521 { M680X_INS_PULH, wmmm, { M680X_REG_H, M680X_REG_S, EOL } },
522 { M680X_INS_PULX, wmmm, { M680X_REG_X, M680X_REG_S, EOL } },
523 { M680X_INS_PULY, wmmm, { M680X_REG_Y, M680X_REG_S, EOL } },
524 {
525 M680X_INS_REV, mmrr, {
526 M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL
527 }
528 },
529 {
530 M680X_INS_REVW, mmmm, {
531 M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL
532 }
533 },
534 { M680X_INS_RTC, mwww, { M680X_REG_S, M680X_REG_PC, EOL } },
535 {
536 M680X_INS_RTI, mwww, {
537 M680X_REG_S, M680X_REG_CC, M680X_REG_B,
538 M680X_REG_A, M680X_REG_DP, M680X_REG_X,
539 M680X_REG_Y, M680X_REG_U, M680X_REG_PC,
540 EOL
541 },
542 },
543 { M680X_INS_RTS, mwww, { M680X_REG_S, M680X_REG_PC, EOL } },
544 { M680X_INS_SEX, wrrr, { M680X_REG_A, M680X_REG_B, EOL } },
545 { M680X_INS_SEXW, rwww, { M680X_REG_W, M680X_REG_D, EOL } },
546 {
547 M680X_INS_SWI, mmrr, {
548 M680X_REG_S, M680X_REG_PC, M680X_REG_U,
549 M680X_REG_Y, M680X_REG_X, M680X_REG_DP,
550 M680X_REG_A, M680X_REG_B, M680X_REG_CC,
551 EOL
552 }
553 },
554 {
555 M680X_INS_SWI2, mmrr, {
556 M680X_REG_S, M680X_REG_PC, M680X_REG_U,
557 M680X_REG_Y, M680X_REG_X, M680X_REG_DP,
558 M680X_REG_A, M680X_REG_B, M680X_REG_CC,
559 EOL
560 },
561 },
562 {
563 M680X_INS_SWI3, mmrr, {
564 M680X_REG_S, M680X_REG_PC, M680X_REG_U,
565 M680X_REG_Y, M680X_REG_X, M680X_REG_DP,
566 M680X_REG_A, M680X_REG_B, M680X_REG_CC,
567 EOL
568 },
569 },
570 { M680X_INS_TBL, wrrr, { M680X_REG_A, M680X_REG_B, EOL } },
571 {
572 M680X_INS_WAI, mrrr, {
573 M680X_REG_S, M680X_REG_PC, M680X_REG_X,
574 M680X_REG_A, M680X_REG_B, M680X_REG_CC,
575 EOL
576 }
577 },
578 {
579 M680X_INS_WAV, rmmm, {
580 M680X_REG_A, M680X_REG_B, M680X_REG_X,
581 M680X_REG_Y, EOL
582 }
583 },
584 {
585 M680X_INS_WAVR, rmmm, {
586 M680X_REG_A, M680X_REG_B, M680X_REG_X,
587 M680X_REG_Y, EOL
588 }
589 },
590 };
591
592 int i, j;
593
594 if (MI->flat_insn->detail == NULL)
595 return;
596
597 for (i = 0; i < ARR_SIZE(changed_regs); ++i) {
598 if (info->insn == changed_regs[i].insn) {
599 e_access_mode access_mode = changed_regs[i].access_mode;
600
601 for (j = 0; changed_regs[i].regs[j] != EOL; ++j) {
602 e_access access;
603
604 m680x_reg reg = changed_regs[i].regs[j];
605
606 if (!info->cpu->reg_byte_size[reg]) {
607 if (info->insn != M680X_INS_MUL)
608 continue;
609
610 // Hack for M68HC05: MUL uses reg. A,X
611 reg = M680X_REG_X;
612 }
613
614 access = get_access(j, access_mode);
615 add_reg_to_rw_list(MI, reg, access);
616 }
617 }
618 }
619
620 #undef EOL
621 }
622
623 typedef struct insn_desc {
624 uint32_t opcode;
625 m680x_insn insn;
626 insn_hdlr_id hid[2];
627 uint16_t insn_size;
628 } insn_desc;
629
630 // If successfull return the additional byte size needed for M6809
631 // indexed addressing mode (including the indexed addressing post_byte).
632 // On error return -1.
get_indexed09_post_byte_size(const m680x_info * info,uint16_t address)633 static int get_indexed09_post_byte_size(const m680x_info *info,
634 uint16_t address)
635 {
636 uint8_t ir = 0;
637 uint8_t post_byte;
638
639 // Read the indexed addressing post byte.
640 if (!read_byte(info, &post_byte, address))
641 return -1;
642
643 // Depending on the indexed addressing mode more bytes have to be read.
644 switch (post_byte & 0x9F) {
645 case 0x87:
646 case 0x8A:
647 case 0x8E:
648 case 0x8F:
649 case 0x90:
650 case 0x92:
651 case 0x97:
652 case 0x9A:
653 case 0x9E:
654 return -1; // illegal indexed post bytes
655
656 case 0x88: // n8,R
657 case 0x8C: // n8,PCR
658 case 0x98: // [n8,R]
659 case 0x9C: // [n8,PCR]
660 if (!read_byte(info, &ir, address + 1))
661 return -1;
662 return 2;
663
664 case 0x89: // n16,R
665 case 0x8D: // n16,PCR
666 case 0x99: // [n16,R]
667 case 0x9D: // [n16,PCR]
668 if (!read_byte(info, &ir, address + 2))
669 return -1;
670 return 3;
671
672 case 0x9F: // [n]
673 if ((post_byte & 0x60) != 0 ||
674 !read_byte(info, &ir, address + 2))
675 return -1;
676 return 3;
677 }
678
679 // Any other indexed post byte is valid and
680 // no additional bytes have to be read.
681 return 1;
682 }
683
684 // If successfull return the additional byte size needed for CPU12
685 // indexed addressing mode (including the indexed addressing post_byte).
686 // On error return -1.
get_indexed12_post_byte_size(const m680x_info * info,uint16_t address,bool is_subset)687 static int get_indexed12_post_byte_size(const m680x_info *info,
688 uint16_t address, bool is_subset)
689 {
690 uint8_t ir;
691 uint8_t post_byte;
692
693 // Read the indexed addressing post byte.
694 if (!read_byte(info, &post_byte, address))
695 return -1;
696
697 // Depending on the indexed addressing mode more bytes have to be read.
698 if (!(post_byte & 0x20)) // n5,R
699 return 1;
700
701 switch (post_byte & 0xe7) {
702 case 0xe0:
703 case 0xe1: // n9,R
704 if (is_subset)
705 return -1;
706
707 if (!read_byte(info, &ir, address))
708 return -1;
709 return 2;
710
711 case 0xe2: // n16,R
712 case 0xe3: // [n16,R]
713 if (is_subset)
714 return -1;
715
716 if (!read_byte(info, &ir, address + 1))
717 return -1;
718 return 3;
719
720 case 0xe4: // A,R
721 case 0xe5: // B,R
722 case 0xe6: // D,R
723 case 0xe7: // [D,R]
724 default: // n,-r n,+r n,r- n,r+
725 break;
726 }
727
728 return 1;
729 }
730
731 // Check for M6809/HD6309 TFR/EXG instruction for valid register
is_tfr09_reg_valid(const m680x_info * info,uint8_t reg_nibble)732 static bool is_tfr09_reg_valid(const m680x_info *info, uint8_t reg_nibble)
733 {
734 if (info->cpu->tfr_reg_valid != NULL)
735 return info->cpu->tfr_reg_valid[reg_nibble];
736
737 return true; // e.g. for the M6309 all registers are valid
738 }
739
740 // Check for CPU12 TFR/EXG instruction for valid register
is_exg_tfr12_post_byte_valid(const m680x_info * info,uint8_t post_byte)741 static bool is_exg_tfr12_post_byte_valid(const m680x_info *info,
742 uint8_t post_byte)
743 {
744 return !(post_byte & 0x08);
745 }
746
is_tfm_reg_valid(const m680x_info * info,uint8_t reg_nibble)747 static bool is_tfm_reg_valid(const m680x_info *info, uint8_t reg_nibble)
748 {
749 // HD6809 TFM instruction: Only register X,Y,U,S,D is allowed
750 return reg_nibble <= 4;
751 }
752
753 // If successfull return the additional byte size needed for CPU12
754 // loop instructions DBEQ/DBNE/IBEQ/IBNE/TBEQ/TBNE (including the post byte).
755 // On error return -1.
get_loop_post_byte_size(const m680x_info * info,uint16_t address)756 static int get_loop_post_byte_size(const m680x_info *info, uint16_t address)
757 {
758 uint8_t post_byte;
759 uint8_t rr;
760
761 if (!read_byte(info, &post_byte, address))
762 return -1;
763
764 // According to documentation bit 3 is don't care and not checked here.
765 if ((post_byte >= 0xc0) ||
766 ((post_byte & 0x07) == 2) || ((post_byte & 0x07) == 3))
767 return -1;
768
769 if (!read_byte(info, &rr, address + 1))
770 return -1;
771
772 return 2;
773 }
774
775 // If successfull return the additional byte size needed for HD6309
776 // bit move instructions BAND/BEOR/BIAND/BIEOR/BIOR/BOR/LDBT/STBT
777 // (including the post byte).
778 // On error return -1.
get_bitmv_post_byte_size(const m680x_info * info,uint16_t address)779 static int get_bitmv_post_byte_size(const m680x_info *info, uint16_t address)
780 {
781 uint8_t post_byte;
782 uint8_t rr;
783
784 if (!read_byte(info, &post_byte, address))
785 return -1;
786
787 if ((post_byte & 0xc0) == 0xc0)
788 return -1; // Invalid register specified
789 else {
790 if (!read_byte(info, &rr, address + 1))
791 return -1;
792 }
793
794 return 2;
795 }
796
is_sufficient_code_size(const m680x_info * info,uint16_t address,insn_desc * insn_description)797 static bool is_sufficient_code_size(const m680x_info *info, uint16_t address,
798 insn_desc *insn_description)
799 {
800 int i;
801 bool retval = true;
802 uint16_t size = 0;
803 int sz;
804
805 for (i = 0; i < 2; i++) {
806 uint8_t ir = 0;
807 bool is_subset = false;
808
809 switch (insn_description->hid[i]) {
810
811 case imm32_hid:
812 if ((retval = read_byte(info, &ir, address + size + 3)))
813 size += 4;
814 break;
815
816 case ext_hid:
817 case imm16_hid:
818 case rel16_hid:
819 case imm8rel_hid:
820 case opidxdr_hid:
821 case idxX16_hid:
822 case idxS16_hid:
823 if ((retval = read_byte(info, &ir, address + size + 1)))
824 size += 2;
825 break;
826
827 case rel8_hid:
828 case dir_hid:
829 case rbits_hid:
830 case imm8_hid:
831 case idxX_hid:
832 case idxXp_hid:
833 case idxY_hid:
834 case idxS_hid:
835 case index_hid:
836 if ((retval = read_byte(info, &ir, address + size)))
837 size++;
838 break;
839
840 case illgl_hid:
841 case inh_hid:
842 case idxX0_hid:
843 case idxX0p_hid:
844 case opidx_hid:
845 retval = true;
846 break;
847
848 case idx09_hid:
849 sz = get_indexed09_post_byte_size(info, address + size);
850 if (sz >= 0)
851 size += sz;
852 else
853 retval = false;
854 break;
855
856 case idx12s_hid:
857 is_subset = true;
858
859 // intentionally fall through
860
861 case idx12_hid:
862 sz = get_indexed12_post_byte_size(info,
863 address + size, is_subset);
864 if (sz >= 0)
865 size += sz;
866 else
867 retval = false;
868 break;
869
870 case exti12x_hid:
871 case imm16i12x_hid:
872 sz = get_indexed12_post_byte_size(info,
873 address + size, false);
874 if (sz >= 0) {
875 size += sz;
876 if ((retval = read_byte(info, &ir,
877 address + size + 1)))
878 size += 2;
879 } else
880 retval = false;
881 break;
882
883 case imm8i12x_hid:
884 sz = get_indexed12_post_byte_size(info,
885 address + size, false);
886 if (sz >= 0) {
887 size += sz;
888 if ((retval = read_byte(info, &ir,
889 address + size)))
890 size++;
891 } else
892 retval = false;
893 break;
894
895 case tfm_hid:
896 if ((retval = read_byte(info, &ir, address + size))) {
897 size++;
898 retval = is_tfm_reg_valid(info, (ir >> 4) & 0x0F) &&
899 is_tfm_reg_valid(info, ir & 0x0F);
900 }
901 break;
902
903 case rr09_hid:
904 if ((retval = read_byte(info, &ir, address + size))) {
905 size++;
906 retval = is_tfr09_reg_valid(info, (ir >> 4) & 0x0F) &&
907 is_tfr09_reg_valid(info, ir & 0x0F);
908 }
909 break;
910
911 case rr12_hid:
912 if ((retval = read_byte(info, &ir, address + size))) {
913 size++;
914 retval = is_exg_tfr12_post_byte_valid(info, ir);
915 }
916 break;
917
918 case bitmv_hid:
919 sz = get_bitmv_post_byte_size(info, address + size);
920 if (sz >= 0)
921 size += sz;
922 else
923 retval = false;
924 break;
925
926 case loop_hid:
927 sz = get_loop_post_byte_size(info, address + size);
928 if (sz >= 0)
929 size += sz;
930 else
931 retval = false;
932 break;
933
934 default:
935 CS_ASSERT(0 && "Unexpected instruction handler id");
936 retval = false;
937 break;
938 }
939
940 if (!retval)
941 return false;
942 }
943
944 insn_description->insn_size += size;
945
946 return retval;
947 }
948
949 // Check for a valid M680X instruction AND for enough bytes in the code buffer
950 // Return an instruction description in insn_desc.
decode_insn(const m680x_info * info,uint16_t address,insn_desc * insn_description)951 static bool decode_insn(const m680x_info *info, uint16_t address,
952 insn_desc *insn_description)
953 {
954 const inst_pageX *inst_table = NULL;
955 const cpu_tables *cpu = info->cpu;
956 size_t table_size = 0;
957 uint16_t base_address = address;
958 uint8_t ir; // instruction register
959 int i;
960 int index;
961
962 if (!read_byte(info, &ir, address++))
963 return false;
964
965 insn_description->insn = M680X_INS_ILLGL;
966 insn_description->opcode = ir;
967
968 // Check if a page prefix byte is present
969 for (i = 0; i < ARR_SIZE(cpu->pageX_table_size); ++i) {
970 if (cpu->pageX_table_size[i] == 0 ||
971 (cpu->inst_pageX_table[i] == NULL))
972 break;
973
974 if ((cpu->pageX_prefix[i] == ir)) {
975 // Get pageX instruction and handler id.
976 // Abort for illegal instr.
977 inst_table = cpu->inst_pageX_table[i];
978 table_size = cpu->pageX_table_size[i];
979
980 if (!read_byte(info, &ir, address++))
981 return false;
982
983 insn_description->opcode =
984 (insn_description->opcode << 8) | ir;
985
986 if ((index = binary_search(inst_table, table_size,
987 ir)) < 0)
988 return false;
989
990 insn_description->hid[0] =
991 inst_table[index].handler_id1;
992 insn_description->hid[1] =
993 inst_table[index].handler_id2;
994 insn_description->insn = inst_table[index].insn;
995 break;
996 }
997 }
998
999 if (insn_description->insn == M680X_INS_ILLGL) {
1000 // Get page1 insn description
1001 insn_description->insn = cpu->inst_page1_table[ir].insn;
1002 insn_description->hid[0] =
1003 cpu->inst_page1_table[ir].handler_id1;
1004 insn_description->hid[1] =
1005 cpu->inst_page1_table[ir].handler_id2;
1006 }
1007
1008 if (insn_description->insn == M680X_INS_ILLGL) {
1009 // Check if opcode byte is present in an overlay table
1010 for (i = 0; i < ARR_SIZE(cpu->overlay_table_size); ++i) {
1011 if (cpu->overlay_table_size[i] == 0 ||
1012 (cpu->inst_overlay_table[i] == NULL))
1013 break;
1014
1015 inst_table = cpu->inst_overlay_table[i];
1016 table_size = cpu->overlay_table_size[i];
1017
1018 if ((index = binary_search(inst_table, table_size,
1019 ir)) >= 0) {
1020 insn_description->hid[0] =
1021 inst_table[index].handler_id1;
1022 insn_description->hid[1] =
1023 inst_table[index].handler_id2;
1024 insn_description->insn = inst_table[index].insn;
1025 break;
1026 }
1027 }
1028 }
1029
1030 insn_description->insn_size = address - base_address;
1031
1032 return (insn_description->insn != M680X_INS_ILLGL) &&
1033 (insn_description->insn != M680X_INS_INVLD) &&
1034 is_sufficient_code_size(info, address, insn_description);
1035 }
1036
illegal_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1037 static void illegal_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1038 {
1039 cs_m680x_op *op0 = &info->m680x.operands[info->m680x.op_count++];
1040 uint8_t temp8 = 0;
1041
1042 info->insn = M680X_INS_ILLGL;
1043 read_byte(info, &temp8, (*address)++);
1044 op0->imm = (int32_t)temp8 & 0xff;
1045 op0->type = M680X_OP_IMMEDIATE;
1046 op0->size = 1;
1047 }
1048
inherent_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1049 static void inherent_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1050 {
1051 // There is nothing to do here :-)
1052 }
1053
add_reg_operand(m680x_info * info,m680x_reg reg)1054 static void add_reg_operand(m680x_info *info, m680x_reg reg)
1055 {
1056 cs_m680x *m680x = &info->m680x;
1057 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1058
1059 op->type = M680X_OP_REGISTER;
1060 op->reg = reg;
1061 op->size = info->cpu->reg_byte_size[reg];
1062 }
1063
set_operand_size(m680x_info * info,cs_m680x_op * op,uint8_t default_size)1064 static void set_operand_size(m680x_info *info, cs_m680x_op *op,
1065 uint8_t default_size)
1066 {
1067 cs_m680x *m680x = &info->m680x;
1068
1069 if (info->insn == M680X_INS_JMP || info->insn == M680X_INS_JSR)
1070 op->size = 0;
1071 else if (info->insn == M680X_INS_DIVD ||
1072 ((info->insn == M680X_INS_AIS || info->insn == M680X_INS_AIX) &&
1073 op->type != M680X_OP_REGISTER))
1074 op->size = 1;
1075 else if (info->insn == M680X_INS_DIVQ ||
1076 info->insn == M680X_INS_MOVW)
1077 op->size = 2;
1078 else if (info->insn == M680X_INS_EMACS)
1079 op->size = 4;
1080 else if ((m680x->op_count > 0) &&
1081 (m680x->operands[0].type == M680X_OP_REGISTER))
1082 op->size = m680x->operands[0].size;
1083 else
1084 op->size = default_size;
1085 }
1086
1087 static const m680x_reg reg_s_reg_ids[] = {
1088 M680X_REG_CC, M680X_REG_A, M680X_REG_B, M680X_REG_DP,
1089 M680X_REG_X, M680X_REG_Y, M680X_REG_U, M680X_REG_PC,
1090 };
1091
1092 static const m680x_reg reg_u_reg_ids[] = {
1093 M680X_REG_CC, M680X_REG_A, M680X_REG_B, M680X_REG_DP,
1094 M680X_REG_X, M680X_REG_Y, M680X_REG_S, M680X_REG_PC,
1095 };
1096
reg_bits_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1097 static void reg_bits_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1098 {
1099 cs_m680x_op *op0 = &info->m680x.operands[0];
1100 uint8_t reg_bits = 0;
1101 uint16_t bit_index;
1102 const m680x_reg *reg_to_reg_ids = NULL;
1103
1104 read_byte(info, ®_bits, (*address)++);
1105
1106 switch (op0->reg) {
1107 case M680X_REG_U:
1108 reg_to_reg_ids = ®_u_reg_ids[0];
1109 break;
1110
1111 case M680X_REG_S:
1112 reg_to_reg_ids = ®_s_reg_ids[0];
1113 break;
1114
1115 default:
1116 CS_ASSERT(0 && "Unexpected operand0 register");
1117 break;
1118 }
1119
1120 if ((info->insn == M680X_INS_PULU ||
1121 (info->insn == M680X_INS_PULS)) &&
1122 ((reg_bits & 0x80) != 0))
1123 // PULS xxx,PC or PULU xxx,PC which is like return from
1124 // subroutine (RTS)
1125 add_insn_group(MI->flat_insn->detail, M680X_GRP_RET);
1126
1127 for (bit_index = 0; bit_index < 8; ++bit_index) {
1128 if (reg_bits & (1 << bit_index))
1129 add_reg_operand(info, reg_to_reg_ids[bit_index]);
1130 }
1131 }
1132
1133 static const m680x_reg g_tfr_exg_reg_ids[] = {
1134 /* 16-bit registers */
1135 M680X_REG_D, M680X_REG_X, M680X_REG_Y, M680X_REG_U,
1136 M680X_REG_S, M680X_REG_PC, M680X_REG_W, M680X_REG_V,
1137 /* 8-bit registers */
1138 M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_DP,
1139 M680X_REG_0, M680X_REG_0, M680X_REG_E, M680X_REG_F,
1140 };
1141
reg_reg09_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1142 static void reg_reg09_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1143 {
1144 uint8_t regs = 0;
1145
1146 read_byte(info, ®s, (*address)++);
1147
1148 add_reg_operand(info, g_tfr_exg_reg_ids[regs >> 4]);
1149 add_reg_operand(info, g_tfr_exg_reg_ids[regs & 0x0f]);
1150
1151 if ((regs & 0x0f) == 0x05) {
1152 // EXG xxx,PC or TFR xxx,PC which is like a JMP
1153 add_insn_group(MI->flat_insn->detail, M680X_GRP_JUMP);
1154 }
1155 }
1156
1157
reg_reg12_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1158 static void reg_reg12_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1159 {
1160 static const m680x_reg g_tfr_exg12_reg0_ids[] = {
1161 M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP3,
1162 M680X_REG_D, M680X_REG_X, M680X_REG_Y, M680X_REG_S,
1163 };
1164 static const m680x_reg g_tfr_exg12_reg1_ids[] = {
1165 M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP2,
1166 M680X_REG_D, M680X_REG_X, M680X_REG_Y, M680X_REG_S,
1167 };
1168 uint8_t regs = 0;
1169
1170 read_byte(info, ®s, (*address)++);
1171
1172 // The opcode of this instruction depends on
1173 // the msb of its post byte.
1174 if (regs & 0x80)
1175 info->insn = M680X_INS_EXG;
1176 else
1177 info->insn = M680X_INS_TFR;
1178
1179 add_reg_operand(info, g_tfr_exg12_reg0_ids[(regs >> 4) & 0x07]);
1180 add_reg_operand(info, g_tfr_exg12_reg1_ids[regs & 0x07]);
1181 }
1182
add_rel_operand(m680x_info * info,int16_t offset,uint16_t address)1183 static void add_rel_operand(m680x_info *info, int16_t offset, uint16_t address)
1184 {
1185 cs_m680x *m680x = &info->m680x;
1186 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1187
1188 op->type = M680X_OP_RELATIVE;
1189 op->size = 0;
1190 op->rel.offset = offset;
1191 op->rel.address = address;
1192 }
1193
relative8_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1194 static void relative8_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1195 {
1196 int16_t offset = 0;
1197
1198 read_byte_sign_extended(info, &offset, (*address)++);
1199 add_rel_operand(info, offset, *address + offset);
1200 add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1201
1202 if ((info->insn != M680X_INS_BRA) &&
1203 (info->insn != M680X_INS_BSR) &&
1204 (info->insn != M680X_INS_BRN))
1205 add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1206 }
1207
relative16_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1208 static void relative16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1209 {
1210 uint16_t offset = 0;
1211
1212 read_word(info, &offset, *address);
1213 *address += 2;
1214 add_rel_operand(info, (int16_t)offset, *address + offset);
1215 add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1216
1217 if ((info->insn != M680X_INS_LBRA) &&
1218 (info->insn != M680X_INS_LBSR) &&
1219 (info->insn != M680X_INS_LBRN))
1220 add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1221 }
1222
1223 static const m680x_reg g_rr5_to_reg_ids[] = {
1224 M680X_REG_X, M680X_REG_Y, M680X_REG_U, M680X_REG_S,
1225 };
1226
add_indexed_operand(m680x_info * info,m680x_reg base_reg,bool post_inc_dec,uint8_t inc_dec,uint8_t offset_bits,uint16_t offset,bool no_comma)1227 static void add_indexed_operand(m680x_info *info, m680x_reg base_reg,
1228 bool post_inc_dec, uint8_t inc_dec, uint8_t offset_bits,
1229 uint16_t offset, bool no_comma)
1230 {
1231 cs_m680x *m680x = &info->m680x;
1232 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1233
1234 op->type = M680X_OP_INDEXED;
1235 set_operand_size(info, op, 1);
1236 op->idx.base_reg = base_reg;
1237 op->idx.offset_reg = M680X_REG_INVALID;
1238 op->idx.inc_dec = inc_dec;
1239
1240 if (inc_dec && post_inc_dec)
1241 op->idx.flags |= M680X_IDX_POST_INC_DEC;
1242
1243 if (offset_bits != M680X_OFFSET_NONE) {
1244 op->idx.offset = offset;
1245 op->idx.offset_addr = 0;
1246 }
1247
1248 op->idx.offset_bits = offset_bits;
1249 op->idx.flags |= (no_comma ? M680X_IDX_NO_COMMA : 0);
1250 }
1251
1252 // M6800/1/2/3 indexed mode handler
indexedX_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1253 static void indexedX_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1254 {
1255 uint8_t offset = 0;
1256
1257 read_byte(info, &offset, (*address)++);
1258
1259 add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_8,
1260 (uint16_t)offset, false);
1261 }
1262
indexedY_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1263 static void indexedY_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1264 {
1265 uint8_t offset = 0;
1266
1267 read_byte(info, &offset, (*address)++);
1268
1269 add_indexed_operand(info, M680X_REG_Y, false, 0, M680X_OFFSET_BITS_8,
1270 (uint16_t)offset, false);
1271 }
1272
1273 // M6809/M6309 indexed mode handler
indexed09_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1274 static void indexed09_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1275 {
1276 cs_m680x *m680x = &info->m680x;
1277 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1278 uint8_t post_byte = 0;
1279 uint16_t offset = 0;
1280 int16_t soffset = 0;
1281
1282 read_byte(info, &post_byte, (*address)++);
1283
1284 op->type = M680X_OP_INDEXED;
1285 set_operand_size(info, op, 1);
1286 op->idx.base_reg = g_rr5_to_reg_ids[(post_byte >> 5) & 0x03];
1287 op->idx.offset_reg = M680X_REG_INVALID;
1288
1289 if (!(post_byte & 0x80)) {
1290 // n5,R
1291 if ((post_byte & 0x10) == 0x10)
1292 op->idx.offset = post_byte | 0xfff0;
1293 else
1294 op->idx.offset = post_byte & 0x0f;
1295
1296 op->idx.offset_addr = op->idx.offset + *address;
1297 op->idx.offset_bits = M680X_OFFSET_BITS_5;
1298 }
1299 else {
1300 if ((post_byte & 0x10) == 0x10)
1301 op->idx.flags |= M680X_IDX_INDIRECT;
1302
1303 // indexed addressing
1304 switch (post_byte & 0x1f) {
1305 case 0x00: // ,R+
1306 op->idx.inc_dec = 1;
1307 op->idx.flags |= M680X_IDX_POST_INC_DEC;
1308 break;
1309
1310 case 0x11: // [,R++]
1311 case 0x01: // ,R++
1312 op->idx.inc_dec = 2;
1313 op->idx.flags |= M680X_IDX_POST_INC_DEC;
1314 break;
1315
1316 case 0x02: // ,-R
1317 op->idx.inc_dec = -1;
1318 break;
1319
1320 case 0x13: // [,--R]
1321 case 0x03: // ,--R
1322 op->idx.inc_dec = -2;
1323 break;
1324
1325 case 0x14: // [,R]
1326 case 0x04: // ,R
1327 break;
1328
1329 case 0x15: // [B,R]
1330 case 0x05: // B,R
1331 op->idx.offset_reg = M680X_REG_B;
1332 break;
1333
1334 case 0x16: // [A,R]
1335 case 0x06: // A,R
1336 op->idx.offset_reg = M680X_REG_A;
1337 break;
1338
1339 case 0x1c: // [n8,PCR]
1340 case 0x0c: // n8,PCR
1341 op->idx.base_reg = M680X_REG_PC;
1342 read_byte_sign_extended(info, &soffset, (*address)++);
1343 op->idx.offset_addr = offset + *address;
1344 op->idx.offset = soffset;
1345 op->idx.offset_bits = M680X_OFFSET_BITS_8;
1346 break;
1347
1348 case 0x18: // [n8,R]
1349 case 0x08: // n8,R
1350 read_byte_sign_extended(info, &soffset, (*address)++);
1351 op->idx.offset = soffset;
1352 op->idx.offset_bits = M680X_OFFSET_BITS_8;
1353 break;
1354
1355 case 0x1d: // [n16,PCR]
1356 case 0x0d: // n16,PCR
1357 op->idx.base_reg = M680X_REG_PC;
1358 read_word(info, &offset, *address);
1359 *address += 2;
1360 op->idx.offset_addr = offset + *address;
1361 op->idx.offset = (int16_t)offset;
1362 op->idx.offset_bits = M680X_OFFSET_BITS_16;
1363 break;
1364
1365 case 0x19: // [n16,R]
1366 case 0x09: // n16,R
1367 read_word(info, &offset, *address);
1368 *address += 2;
1369 op->idx.offset = (int16_t)offset;
1370 op->idx.offset_bits = M680X_OFFSET_BITS_16;
1371 break;
1372
1373 case 0x1b: // [D,R]
1374 case 0x0b: // D,R
1375 op->idx.offset_reg = M680X_REG_D;
1376 break;
1377
1378 case 0x1f: // [n16]
1379 op->type = M680X_OP_EXTENDED;
1380 op->ext.indirect = true;
1381 read_word(info, &op->ext.address, *address);
1382 *address += 2;
1383 break;
1384
1385 default:
1386 op->idx.base_reg = M680X_REG_INVALID;
1387 break;
1388 }
1389 }
1390
1391 if (((info->insn == M680X_INS_LEAU) ||
1392 (info->insn == M680X_INS_LEAS) ||
1393 (info->insn == M680X_INS_LEAX) ||
1394 (info->insn == M680X_INS_LEAY)) &&
1395 (m680x->operands[0].reg == M680X_REG_X ||
1396 (m680x->operands[0].reg == M680X_REG_Y)))
1397 // Only LEAX and LEAY modify CC register
1398 add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1399 }
1400
1401
1402 static const m680x_reg g_idx12_to_reg_ids[4] = {
1403 M680X_REG_X, M680X_REG_Y, M680X_REG_S, M680X_REG_PC,
1404 };
1405
1406 static const m680x_reg g_or12_to_reg_ids[3] = {
1407 M680X_REG_A, M680X_REG_B, M680X_REG_D
1408 };
1409
1410 // CPU12 indexed mode handler
indexed12_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1411 static void indexed12_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1412 {
1413 cs_m680x *m680x = &info->m680x;
1414 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1415 uint8_t post_byte = 0;
1416 uint8_t offset8 = 0;
1417
1418 read_byte(info, &post_byte, (*address)++);
1419
1420 op->type = M680X_OP_INDEXED;
1421 set_operand_size(info, op, 1);
1422 op->idx.offset_reg = M680X_REG_INVALID;
1423
1424 if (!(post_byte & 0x20)) {
1425 // n5,R n5 is a 5-bit signed offset
1426 op->idx.base_reg = g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1427
1428 if ((post_byte & 0x10) == 0x10)
1429 op->idx.offset = post_byte | 0xfff0;
1430 else
1431 op->idx.offset = post_byte & 0x0f;
1432
1433 op->idx.offset_addr = op->idx.offset + *address;
1434 op->idx.offset_bits = M680X_OFFSET_BITS_5;
1435 }
1436 else {
1437 if ((post_byte & 0xe0) == 0xe0)
1438 op->idx.base_reg =
1439 g_idx12_to_reg_ids[(post_byte >> 3) & 0x03];
1440
1441 switch (post_byte & 0xe7) {
1442 case 0xe0:
1443 case 0xe1: // n9,R
1444 read_byte(info, &offset8, (*address)++);
1445 op->idx.offset = offset8;
1446
1447 if (post_byte & 0x01) // sign extension
1448 op->idx.offset |= 0xff00;
1449
1450 op->idx.offset_bits = M680X_OFFSET_BITS_9;
1451
1452 if (op->idx.base_reg == M680X_REG_PC)
1453 op->idx.offset_addr = op->idx.offset + *address;
1454
1455 break;
1456
1457 case 0xe3: // [n16,R]
1458 op->idx.flags |= M680X_IDX_INDIRECT;
1459
1460 // intentionally fall through
1461 case 0xe2: // n16,R
1462 read_word(info, (uint16_t *)&op->idx.offset, *address);
1463 (*address) += 2;
1464 op->idx.offset_bits = M680X_OFFSET_BITS_16;
1465
1466 if (op->idx.base_reg == M680X_REG_PC)
1467 op->idx.offset_addr = op->idx.offset + *address;
1468
1469 break;
1470
1471 case 0xe4: // A,R
1472 case 0xe5: // B,R
1473 case 0xe6: // D,R
1474 op->idx.offset_reg =
1475 g_or12_to_reg_ids[post_byte & 0x03];
1476 break;
1477
1478 case 0xe7: // [D,R]
1479 op->idx.offset_reg = M680X_REG_D;
1480 op->idx.flags |= M680X_IDX_INDIRECT;
1481 break;
1482
1483 default: // n,-r n,+r n,r- n,r+
1484 // PC is not allowed in this mode
1485 op->idx.base_reg =
1486 g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1487 op->idx.inc_dec = post_byte & 0x0f;
1488
1489 if (op->idx.inc_dec & 0x08) // evtl. sign extend value
1490 op->idx.inc_dec |= 0xf0;
1491
1492 if (op->idx.inc_dec >= 0)
1493 op->idx.inc_dec++;
1494
1495 if (post_byte & 0x10)
1496 op->idx.flags |= M680X_IDX_POST_INC_DEC;
1497
1498 break;
1499
1500 }
1501 }
1502 }
1503
index_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1504 static void index_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1505 {
1506 cs_m680x *m680x = &info->m680x;
1507 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1508
1509 op->type = M680X_OP_CONSTANT;
1510 read_byte(info, &op->const_val, (*address)++);
1511 };
1512
direct_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1513 static void direct_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1514 {
1515 cs_m680x *m680x = &info->m680x;
1516 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1517
1518 op->type = M680X_OP_DIRECT;
1519 set_operand_size(info, op, 1);
1520 read_byte(info, &op->direct_addr, (*address)++);
1521 };
1522
extended_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1523 static void extended_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1524 {
1525 cs_m680x *m680x = &info->m680x;
1526 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1527
1528 op->type = M680X_OP_EXTENDED;
1529 set_operand_size(info, op, 1);
1530 read_word(info, &op->ext.address, *address);
1531 *address += 2;
1532 }
1533
immediate_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1534 static void immediate_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1535 {
1536 cs_m680x *m680x = &info->m680x;
1537 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1538 uint16_t word = 0;
1539 int16_t sword = 0;
1540
1541 op->type = M680X_OP_IMMEDIATE;
1542 set_operand_size(info, op, 1);
1543
1544 switch (op->size) {
1545 case 1:
1546 read_byte_sign_extended(info, &sword, *address);
1547 op->imm = sword;
1548 break;
1549
1550 case 2:
1551 read_word(info, &word, *address);
1552 op->imm = (int16_t)word;
1553 break;
1554
1555 case 4:
1556 read_sdword(info, &op->imm, *address);
1557 break;
1558
1559 default:
1560 op->imm = 0;
1561 CS_ASSERT(0 && "Unexpected immediate byte size");
1562 }
1563
1564 *address += op->size;
1565 }
1566
1567 // handler for bit move instructions, e.g: BAND A,5,1,$40 Used by HD6309
bit_move_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1568 static void bit_move_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1569 {
1570 static const m680x_reg m680x_reg[] = {
1571 M680X_REG_CC, M680X_REG_A, M680X_REG_B, M680X_REG_INVALID,
1572 };
1573
1574 uint8_t post_byte = 0;
1575 cs_m680x *m680x = &info->m680x;
1576 cs_m680x_op *op;
1577
1578 read_byte(info, &post_byte, *address);
1579 (*address)++;
1580
1581 // operand[0] = register
1582 add_reg_operand(info, m680x_reg[post_byte >> 6]);
1583
1584 // operand[1] = bit index in source operand
1585 op = &m680x->operands[m680x->op_count++];
1586 op->type = M680X_OP_CONSTANT;
1587 op->const_val = (post_byte >> 3) & 0x07;
1588
1589 // operand[2] = bit index in destination operand
1590 op = &m680x->operands[m680x->op_count++];
1591 op->type = M680X_OP_CONSTANT;
1592 op->const_val = post_byte & 0x07;
1593
1594 direct_hdlr(MI, info, address);
1595 }
1596
1597 // handler for TFM instruction, e.g: TFM X+,Y+ Used by HD6309
tfm_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1598 static void tfm_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1599 {
1600 static const uint8_t inc_dec_r0[] = {
1601 1, -1, 1, 0,
1602 };
1603 static const uint8_t inc_dec_r1[] = {
1604 1, -1, 0, 1,
1605 };
1606 uint8_t regs = 0;
1607 uint8_t index = (MI->Opcode & 0xff) - 0x38;
1608
1609 read_byte(info, ®s, *address);
1610
1611 add_indexed_operand(info, g_tfr_exg_reg_ids[regs >> 4], true,
1612 inc_dec_r0[index], M680X_OFFSET_NONE, 0, true);
1613 add_indexed_operand(info, g_tfr_exg_reg_ids[regs & 0x0f], true,
1614 inc_dec_r1[index], M680X_OFFSET_NONE, 0, true);
1615
1616 add_reg_to_rw_list(MI, M680X_REG_W, READ | WRITE);
1617 }
1618
opidx_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1619 static void opidx_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1620 {
1621 cs_m680x *m680x = &info->m680x;
1622 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1623
1624 // bit index is coded in Opcode
1625 op->type = M680X_OP_CONSTANT;
1626 op->const_val = (MI->Opcode & 0x0e) >> 1;
1627 }
1628
1629 // handler for bit test and branch instruction. Used by M6805.
1630 // The bit index is part of the opcode.
1631 // Example: BRSET 3,<$40,LOOP
opidx_dir_rel_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1632 static void opidx_dir_rel_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1633 {
1634 cs_m680x *m680x = &info->m680x;
1635 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1636
1637 // bit index is coded in Opcode
1638 op->type = M680X_OP_CONSTANT;
1639 op->const_val = (MI->Opcode & 0x0e) >> 1;
1640 direct_hdlr(MI, info, address);
1641 relative8_hdlr(MI, info, address);
1642
1643 add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1644 }
1645
indexedX0_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1646 static void indexedX0_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1647 {
1648 add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_NONE,
1649 0, false);
1650 }
1651
indexedX16_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1652 static void indexedX16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1653 {
1654 uint16_t offset = 0;
1655
1656 read_word(info, &offset, *address);
1657 *address += 2;
1658 add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_16,
1659 offset, false);
1660 }
1661
imm_rel_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1662 static void imm_rel_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1663 {
1664 immediate_hdlr(MI, info, address);
1665 relative8_hdlr(MI, info, address);
1666 }
1667
indexedS_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1668 static void indexedS_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1669 {
1670 uint8_t offset = 0;
1671
1672 read_byte(info, &offset, (*address)++);
1673
1674 add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_8,
1675 (uint16_t)offset, false);
1676 }
1677
indexedS16_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1678 static void indexedS16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1679 {
1680 uint16_t offset = 0;
1681
1682 read_word(info, &offset, *address);
1683 address += 2;
1684
1685 add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_16,
1686 offset, false);
1687 }
1688
indexedX0p_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1689 static void indexedX0p_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1690 {
1691 add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_NONE,
1692 0, true);
1693 }
1694
indexedXp_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1695 static void indexedXp_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1696 {
1697 uint8_t offset = 0;
1698
1699 read_byte(info, &offset, (*address)++);
1700
1701 add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_BITS_8,
1702 (uint16_t)offset, false);
1703 }
1704
imm_idx12_x_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1705 static void imm_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1706 {
1707 cs_m680x *m680x = &info->m680x;
1708 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1709
1710 indexed12_hdlr(MI, info, address);
1711 op->type = M680X_OP_IMMEDIATE;
1712
1713 if (info->insn == M680X_INS_MOVW) {
1714 uint16_t imm16 = 0;
1715
1716 read_word(info, &imm16, *address);
1717 op->imm = (int16_t)imm16;
1718 op->size = 2;
1719 }
1720 else {
1721 uint8_t imm8 = 0;
1722
1723 read_byte(info, &imm8, *address);
1724 op->imm = (int8_t)imm8;
1725 op->size = 1;
1726 }
1727
1728 set_operand_size(info, op, 1);
1729 }
1730
ext_idx12_x_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1731 static void ext_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1732 {
1733 cs_m680x *m680x = &info->m680x;
1734 cs_m680x_op *op0 = &m680x->operands[m680x->op_count++];
1735 uint16_t imm16 = 0;
1736
1737 indexed12_hdlr(MI, info, address);
1738 read_word(info, &imm16, *address);
1739 op0->type = M680X_OP_EXTENDED;
1740 op0->ext.address = (int16_t)imm16;
1741 set_operand_size(info, op0, 1);
1742 }
1743
1744 // handler for CPU12 DBEQ/DNBE/IBEQ/IBNE/TBEQ/TBNE instructions.
1745 // Example: DBNE X,$1000
loop_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1746 static void loop_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1747 {
1748 static const m680x_reg index_to_reg_id[] = {
1749 M680X_REG_A, M680X_REG_B, M680X_REG_INVALID, M680X_REG_INVALID,
1750 M680X_REG_D, M680X_REG_X, M680X_REG_Y, M680X_REG_S,
1751 };
1752 static const m680x_insn index_to_insn_id[] = {
1753 M680X_INS_DBEQ, M680X_INS_DBNE, M680X_INS_TBEQ, M680X_INS_TBNE,
1754 M680X_INS_IBEQ, M680X_INS_IBNE, M680X_INS_ILLGL, M680X_INS_ILLGL
1755 };
1756 cs_m680x *m680x = &info->m680x;
1757 uint8_t post_byte = 0;
1758 uint8_t rel = 0;
1759 cs_m680x_op *op;
1760
1761 read_byte(info, &post_byte, (*address)++);
1762
1763 info->insn = index_to_insn_id[(post_byte >> 5) & 0x07];
1764
1765 if (info->insn == M680X_INS_ILLGL) {
1766 illegal_hdlr(MI, info, address);
1767 };
1768
1769 read_byte(info, &rel, (*address)++);
1770
1771 add_reg_operand(info, index_to_reg_id[post_byte & 0x07]);
1772
1773 op = &m680x->operands[m680x->op_count++];
1774
1775 op->type = M680X_OP_RELATIVE;
1776
1777 op->rel.offset = (post_byte & 0x10) ? 0xff00 | rel : rel;
1778
1779 op->rel.address = *address + op->rel.offset;
1780
1781 add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1782 }
1783
1784 static void (*const g_insn_handler[])(MCInst *, m680x_info *, uint16_t *) = {
1785 illegal_hdlr,
1786 relative8_hdlr,
1787 relative16_hdlr,
1788 immediate_hdlr, // 8-bit
1789 immediate_hdlr, // 16-bit
1790 immediate_hdlr, // 32-bit
1791 direct_hdlr,
1792 extended_hdlr,
1793 indexedX_hdlr,
1794 indexedY_hdlr,
1795 indexed09_hdlr,
1796 inherent_hdlr,
1797 reg_reg09_hdlr,
1798 reg_bits_hdlr,
1799 bit_move_hdlr,
1800 tfm_hdlr,
1801 opidx_hdlr,
1802 opidx_dir_rel_hdlr,
1803 indexedX0_hdlr,
1804 indexedX16_hdlr,
1805 imm_rel_hdlr,
1806 indexedS_hdlr,
1807 indexedS16_hdlr,
1808 indexedXp_hdlr,
1809 indexedX0p_hdlr,
1810 indexed12_hdlr,
1811 indexed12_hdlr, // subset of indexed12
1812 reg_reg12_hdlr,
1813 loop_hdlr,
1814 index_hdlr,
1815 imm_idx12_x_hdlr,
1816 imm_idx12_x_hdlr,
1817 ext_idx12_x_hdlr,
1818 }; /* handler function pointers */
1819
1820 /* Disasemble one instruction at address and store in str_buff */
m680x_disassemble(MCInst * MI,m680x_info * info,uint16_t address)1821 static unsigned int m680x_disassemble(MCInst *MI, m680x_info *info,
1822 uint16_t address)
1823 {
1824 cs_m680x *m680x = &info->m680x;
1825 cs_detail *detail = MI->flat_insn->detail;
1826 uint16_t base_address = address;
1827 insn_desc insn_description;
1828 e_access_mode access_mode;
1829
1830 if (detail != NULL) {
1831 memset(detail, 0, offsetof(cs_detail, m680x)+sizeof(cs_m680x));
1832 }
1833
1834 memset(&insn_description, 0, sizeof(insn_description));
1835 memset(m680x, 0, sizeof(*m680x));
1836 info->insn_size = 1;
1837
1838 if (decode_insn(info, address, &insn_description)) {
1839 m680x_reg reg;
1840
1841 if (insn_description.opcode > 0xff)
1842 address += 2; // 8-bit opcode + page prefix
1843 else
1844 address++; // 8-bit opcode only
1845
1846 info->insn = insn_description.insn;
1847
1848 MCInst_setOpcode(MI, insn_description.opcode);
1849
1850 reg = g_insn_props[info->insn].reg0;
1851
1852 if (reg != M680X_REG_INVALID) {
1853 if (reg == M680X_REG_HX &&
1854 (!info->cpu->reg_byte_size[reg]))
1855 reg = M680X_REG_X;
1856
1857 add_reg_operand(info, reg);
1858 // First (or second) operand is a register which is
1859 // part of the mnemonic
1860 m680x->flags |= M680X_FIRST_OP_IN_MNEM;
1861 reg = g_insn_props[info->insn].reg1;
1862
1863 if (reg != M680X_REG_INVALID) {
1864 if (reg == M680X_REG_HX &&
1865 (!info->cpu->reg_byte_size[reg]))
1866 reg = M680X_REG_X;
1867
1868 add_reg_operand(info, reg);
1869 m680x->flags |= M680X_SECOND_OP_IN_MNEM;
1870 }
1871 }
1872
1873 // Call addressing mode specific instruction handler
1874 (g_insn_handler[insn_description.hid[0]])(MI, info,
1875 &address);
1876 (g_insn_handler[insn_description.hid[1]])(MI, info,
1877 &address);
1878
1879 add_insn_group(detail, g_insn_props[info->insn].group);
1880
1881 if (g_insn_props[info->insn].cc_modified &&
1882 (info->cpu->insn_cc_not_modified[0] != info->insn) &&
1883 (info->cpu->insn_cc_not_modified[1] != info->insn))
1884 add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1885
1886 access_mode = g_insn_props[info->insn].access_mode;
1887
1888 // Fix for M6805 BSET/BCLR. It has a differnt operand order
1889 // in comparison to the M6811
1890 if ((info->cpu->insn_cc_not_modified[0] == info->insn) ||
1891 (info->cpu->insn_cc_not_modified[1] == info->insn))
1892 access_mode = rmmm;
1893
1894 build_regs_read_write_counts(MI, info, access_mode);
1895 add_operators_access(MI, info, access_mode);
1896
1897 if (g_insn_props[info->insn].update_reg_access)
1898 set_changed_regs_read_write_counts(MI, info);
1899
1900 info->insn_size = (uint8_t)insn_description.insn_size;
1901
1902 return info->insn_size;
1903 }
1904 else
1905 MCInst_setOpcode(MI, insn_description.opcode);
1906
1907 // Illegal instruction
1908 address = base_address;
1909 illegal_hdlr(MI, info, &address);
1910 return 1;
1911 }
1912
1913 // Tables to get the byte size of a register on the CPU
1914 // based on an enum m680x_reg value.
1915 // Invalid registers return 0.
1916 static const uint8_t g_m6800_reg_byte_size[22] = {
1917 // A B E F 0 D W CC DP MD HX H X Y S U V Q PC T2 T3
1918 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 0, 0
1919 };
1920
1921 static const uint8_t g_m6805_reg_byte_size[22] = {
1922 // A B E F 0 D W CC DP MD HX H X Y S U V Q PC T2 T3
1923 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 2, 0, 0
1924 };
1925
1926 static const uint8_t g_m6808_reg_byte_size[22] = {
1927 // A B E F 0 D W CC DP MD HX H X Y S U V Q PC T2 T3
1928 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 1, 1, 0, 2, 0, 0, 0, 2, 0, 0
1929 };
1930
1931 static const uint8_t g_m6801_reg_byte_size[22] = {
1932 // A B E F 0 D W CC DP MD HX H X Y S U V Q PC T2 T3
1933 0, 1, 1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 0, 0
1934 };
1935
1936 static const uint8_t g_m6811_reg_byte_size[22] = {
1937 // A B E F 0 D W CC DP MD HX H X Y S U V Q PC T2 T3
1938 0, 1, 1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 2, 0, 0
1939 };
1940
1941 static const uint8_t g_cpu12_reg_byte_size[22] = {
1942 // A B E F 0 D W CC DP MD HX H X Y S U V Q PC T2 T3
1943 0, 1, 1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 2, 2, 2
1944 };
1945
1946 static const uint8_t g_m6809_reg_byte_size[22] = {
1947 // A B E F 0 D W CC DP MD HX H X Y S U V Q PC T2 T3
1948 0, 1, 1, 0, 0, 0, 2, 0, 1, 1, 0, 0, 0, 2, 2, 2, 2, 0, 0, 2, 0, 0
1949 };
1950
1951 static const uint8_t g_hd6309_reg_byte_size[22] = {
1952 // A B E F 0 D W CC DP MD HX H X Y S U V Q PC T2 T3
1953 0, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 0, 0, 2, 2, 2, 2, 2, 4, 2, 0, 0
1954 };
1955
1956 // Table to check for a valid register nibble on the M6809 CPU
1957 // used for TFR and EXG instruction.
1958 static const bool m6809_tfr_reg_valid[16] = {
1959 true, true, true, true, true, true, false, false,
1960 true, true, true, true, false, false, false, false,
1961 };
1962
1963 static const cpu_tables g_cpu_tables[] = {
1964 {
1965 // M680X_CPU_TYPE_INVALID
1966 NULL,
1967 { NULL, NULL },
1968 { 0, 0 },
1969 { 0x00, 0x00, 0x00 },
1970 { NULL, NULL, NULL },
1971 { 0, 0, 0 },
1972 NULL,
1973 NULL,
1974 { M680X_INS_INVLD, M680X_INS_INVLD }
1975 },
1976 {
1977 // M680X_CPU_TYPE_6301
1978 &g_m6800_inst_page1_table[0],
1979 { &g_m6801_inst_overlay_table[0], &g_hd6301_inst_overlay_table[0] },
1980 {
1981 ARR_SIZE(g_m6801_inst_overlay_table),
1982 ARR_SIZE(g_hd6301_inst_overlay_table)
1983 },
1984 { 0x00, 0x00, 0x00 },
1985 { NULL, NULL, NULL },
1986 { 0, 0, 0 },
1987 &g_m6801_reg_byte_size[0],
1988 NULL,
1989 { M680X_INS_INVLD, M680X_INS_INVLD }
1990 },
1991 {
1992 // M680X_CPU_TYPE_6309
1993 &g_m6809_inst_page1_table[0],
1994 { &g_hd6309_inst_overlay_table[0], NULL },
1995 { ARR_SIZE(g_hd6309_inst_overlay_table), 0 },
1996 { 0x10, 0x11, 0x00 },
1997 { &g_hd6309_inst_page2_table[0], &g_hd6309_inst_page3_table[0], NULL },
1998 {
1999 ARR_SIZE(g_hd6309_inst_page2_table),
2000 ARR_SIZE(g_hd6309_inst_page3_table),
2001 0
2002 },
2003 &g_hd6309_reg_byte_size[0],
2004 NULL,
2005 { M680X_INS_INVLD, M680X_INS_INVLD }
2006 },
2007 {
2008 // M680X_CPU_TYPE_6800
2009 &g_m6800_inst_page1_table[0],
2010 { NULL, NULL },
2011 { 0, 0 },
2012 { 0x00, 0x00, 0x00 },
2013 { NULL, NULL, NULL },
2014 { 0, 0, 0 },
2015 &g_m6800_reg_byte_size[0],
2016 NULL,
2017 { M680X_INS_INVLD, M680X_INS_INVLD }
2018 },
2019 {
2020 // M680X_CPU_TYPE_6801
2021 &g_m6800_inst_page1_table[0],
2022 { &g_m6801_inst_overlay_table[0], NULL },
2023 { ARR_SIZE(g_m6801_inst_overlay_table), 0 },
2024 { 0x00, 0x00, 0x00 },
2025 { NULL, NULL, NULL },
2026 { 0, 0, 0 },
2027 &g_m6801_reg_byte_size[0],
2028 NULL,
2029 { M680X_INS_INVLD, M680X_INS_INVLD }
2030 },
2031 {
2032 // M680X_CPU_TYPE_6805
2033 &g_m6805_inst_page1_table[0],
2034 { NULL, NULL },
2035 { 0, 0 },
2036 { 0x00, 0x00, 0x00 },
2037 { NULL, NULL, NULL },
2038 { 0, 0, 0 },
2039 &g_m6805_reg_byte_size[0],
2040 NULL,
2041 { M680X_INS_BCLR, M680X_INS_BSET }
2042 },
2043 {
2044 // M680X_CPU_TYPE_6808
2045 &g_m6805_inst_page1_table[0],
2046 { &g_m6808_inst_overlay_table[0], NULL },
2047 { ARR_SIZE(g_m6808_inst_overlay_table), 0 },
2048 { 0x9E, 0x00, 0x00 },
2049 { &g_m6808_inst_page2_table[0], NULL, NULL },
2050 { ARR_SIZE(g_m6808_inst_page2_table), 0, 0 },
2051 &g_m6808_reg_byte_size[0],
2052 NULL,
2053 { M680X_INS_BCLR, M680X_INS_BSET }
2054 },
2055 {
2056 // M680X_CPU_TYPE_6809
2057 &g_m6809_inst_page1_table[0],
2058 { NULL, NULL },
2059 { 0, 0 },
2060 { 0x10, 0x11, 0x00 },
2061 {
2062 &g_m6809_inst_page2_table[0],
2063 &g_m6809_inst_page3_table[0],
2064 NULL
2065 },
2066 {
2067 ARR_SIZE(g_m6809_inst_page2_table),
2068 ARR_SIZE(g_m6809_inst_page3_table),
2069 0
2070 },
2071 &g_m6809_reg_byte_size[0],
2072 &m6809_tfr_reg_valid[0],
2073 { M680X_INS_INVLD, M680X_INS_INVLD }
2074 },
2075 {
2076 // M680X_CPU_TYPE_6811
2077 &g_m6800_inst_page1_table[0],
2078 {
2079 &g_m6801_inst_overlay_table[0],
2080 &g_m6811_inst_overlay_table[0]
2081 },
2082 {
2083 ARR_SIZE(g_m6801_inst_overlay_table),
2084 ARR_SIZE(g_m6811_inst_overlay_table)
2085 },
2086 { 0x18, 0x1A, 0xCD },
2087 {
2088 &g_m6811_inst_page2_table[0],
2089 &g_m6811_inst_page3_table[0],
2090 &g_m6811_inst_page4_table[0]
2091 },
2092 {
2093 ARR_SIZE(g_m6811_inst_page2_table),
2094 ARR_SIZE(g_m6811_inst_page3_table),
2095 ARR_SIZE(g_m6811_inst_page4_table)
2096 },
2097 &g_m6811_reg_byte_size[0],
2098 NULL,
2099 { M680X_INS_INVLD, M680X_INS_INVLD }
2100 },
2101 {
2102 // M680X_CPU_TYPE_CPU12
2103 &g_cpu12_inst_page1_table[0],
2104 { NULL, NULL },
2105 { 0, 0 },
2106 { 0x18, 0x00, 0x00 },
2107 { &g_cpu12_inst_page2_table[0], NULL, NULL },
2108 { ARR_SIZE(g_cpu12_inst_page2_table), 0, 0 },
2109 &g_cpu12_reg_byte_size[0],
2110 NULL,
2111 { M680X_INS_INVLD, M680X_INS_INVLD }
2112 },
2113 {
2114 // M680X_CPU_TYPE_HCS08
2115 &g_m6805_inst_page1_table[0],
2116 {
2117 &g_m6808_inst_overlay_table[0],
2118 &g_hcs08_inst_overlay_table[0]
2119 },
2120 {
2121 ARR_SIZE(g_m6808_inst_overlay_table),
2122 ARR_SIZE(g_hcs08_inst_overlay_table)
2123 },
2124 { 0x9E, 0x00, 0x00 },
2125 { &g_hcs08_inst_page2_table[0], NULL, NULL },
2126 { ARR_SIZE(g_hcs08_inst_page2_table), 0, 0 },
2127 &g_m6808_reg_byte_size[0],
2128 NULL,
2129 { M680X_INS_BCLR, M680X_INS_BSET }
2130 },
2131 };
2132
2133 static const char * const s_cpu_type[] = {
2134 "INVALID", "6301", "6309", "6800", "6801", "6805", "6808",
2135 "6809", "6811", "CPU12", "HCS08",
2136 };
2137
m680x_setup_internals(m680x_info * info,e_cpu_type cpu_type,uint16_t address,const uint8_t * code,uint16_t code_len)2138 static bool m680x_setup_internals(m680x_info *info, e_cpu_type cpu_type,
2139 uint16_t address,
2140 const uint8_t *code, uint16_t code_len)
2141 {
2142 if (cpu_type == M680X_CPU_TYPE_INVALID) {
2143 return false;
2144 }
2145
2146 info->code = code;
2147 info->size = code_len;
2148 info->offset = address;
2149 info->cpu_type = cpu_type;
2150
2151 info->cpu = &g_cpu_tables[info->cpu_type];
2152
2153 return true;
2154 }
2155
M680X_getInstruction(csh ud,const uint8_t * code,size_t code_len,MCInst * MI,uint16_t * size,uint64_t address,void * inst_info)2156 bool M680X_getInstruction(csh ud, const uint8_t *code, size_t code_len,
2157 MCInst *MI, uint16_t *size, uint64_t address, void *inst_info)
2158 {
2159 unsigned int insn_size = 0;
2160 e_cpu_type cpu_type = M680X_CPU_TYPE_INVALID; // No default CPU type
2161 cs_struct *handle = (cs_struct *)ud;
2162 m680x_info *info = (m680x_info *)handle->printer_info;
2163
2164 MCInst_clear(MI);
2165
2166 if (handle->mode & CS_MODE_M680X_6800)
2167 cpu_type = M680X_CPU_TYPE_6800;
2168
2169 else if (handle->mode & CS_MODE_M680X_6801)
2170 cpu_type = M680X_CPU_TYPE_6801;
2171
2172 else if (handle->mode & CS_MODE_M680X_6805)
2173 cpu_type = M680X_CPU_TYPE_6805;
2174
2175 else if (handle->mode & CS_MODE_M680X_6808)
2176 cpu_type = M680X_CPU_TYPE_6808;
2177
2178 else if (handle->mode & CS_MODE_M680X_HCS08)
2179 cpu_type = M680X_CPU_TYPE_HCS08;
2180
2181 else if (handle->mode & CS_MODE_M680X_6809)
2182 cpu_type = M680X_CPU_TYPE_6809;
2183
2184 else if (handle->mode & CS_MODE_M680X_6301)
2185 cpu_type = M680X_CPU_TYPE_6301;
2186
2187 else if (handle->mode & CS_MODE_M680X_6309)
2188 cpu_type = M680X_CPU_TYPE_6309;
2189
2190 else if (handle->mode & CS_MODE_M680X_6811)
2191 cpu_type = M680X_CPU_TYPE_6811;
2192
2193 else if (handle->mode & CS_MODE_M680X_CPU12)
2194 cpu_type = M680X_CPU_TYPE_CPU12;
2195
2196 if (cpu_type != M680X_CPU_TYPE_INVALID &&
2197 m680x_setup_internals(info, cpu_type, (uint16_t)address, code,
2198 (uint16_t)code_len))
2199 insn_size = m680x_disassemble(MI, info, (uint16_t)address);
2200
2201 if (insn_size == 0) {
2202 *size = 1;
2203 return false;
2204 }
2205
2206 // Make sure we always stay within range
2207 if (insn_size > code_len) {
2208 *size = (uint16_t)code_len;
2209 return false;
2210 }
2211 else
2212 *size = (uint16_t)insn_size;
2213
2214 return true;
2215 }
2216
M680X_disassembler_init(cs_struct * ud)2217 cs_err M680X_disassembler_init(cs_struct *ud)
2218 {
2219 if (M680X_REG_ENDING != ARR_SIZE(g_m6800_reg_byte_size)) {
2220 CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6800_reg_byte_size));
2221
2222 return CS_ERR_MODE;
2223 }
2224
2225 if (M680X_REG_ENDING != ARR_SIZE(g_m6801_reg_byte_size)) {
2226 CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6801_reg_byte_size));
2227
2228 return CS_ERR_MODE;
2229 }
2230
2231 if (M680X_REG_ENDING != ARR_SIZE(g_m6805_reg_byte_size)) {
2232 CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6805_reg_byte_size));
2233
2234 return CS_ERR_MODE;
2235 }
2236
2237 if (M680X_REG_ENDING != ARR_SIZE(g_m6808_reg_byte_size)) {
2238 CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6808_reg_byte_size));
2239
2240 return CS_ERR_MODE;
2241 }
2242
2243 if (M680X_REG_ENDING != ARR_SIZE(g_m6811_reg_byte_size)) {
2244 CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6811_reg_byte_size));
2245
2246 return CS_ERR_MODE;
2247 }
2248
2249 if (M680X_REG_ENDING != ARR_SIZE(g_cpu12_reg_byte_size)) {
2250 CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_cpu12_reg_byte_size));
2251
2252 return CS_ERR_MODE;
2253 }
2254
2255 if (M680X_REG_ENDING != ARR_SIZE(g_m6809_reg_byte_size)) {
2256 CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6809_reg_byte_size));
2257
2258 return CS_ERR_MODE;
2259 }
2260
2261 if (M680X_INS_ENDING != ARR_SIZE(g_insn_props)) {
2262 CS_ASSERT(M680X_INS_ENDING == ARR_SIZE(g_insn_props));
2263
2264 return CS_ERR_MODE;
2265 }
2266
2267 if (M680X_CPU_TYPE_ENDING != ARR_SIZE(s_cpu_type)) {
2268 CS_ASSERT(M680X_CPU_TYPE_ENDING == ARR_SIZE(s_cpu_type));
2269
2270 return CS_ERR_MODE;
2271 }
2272
2273 if (M680X_CPU_TYPE_ENDING != ARR_SIZE(g_cpu_tables)) {
2274 CS_ASSERT(M680X_CPU_TYPE_ENDING == ARR_SIZE(g_cpu_tables));
2275
2276 return CS_ERR_MODE;
2277 }
2278
2279 if (HANDLER_ID_ENDING != ARR_SIZE(g_insn_handler)) {
2280 CS_ASSERT(HANDLER_ID_ENDING == ARR_SIZE(g_insn_handler));
2281
2282 return CS_ERR_MODE;
2283 }
2284
2285 if (ACCESS_MODE_ENDING != MATRIX_SIZE(g_access_mode_to_access)) {
2286 CS_ASSERT(ACCESS_MODE_ENDING ==
2287 MATRIX_SIZE(g_access_mode_to_access));
2288
2289 return CS_ERR_MODE;
2290 }
2291
2292 return CS_ERR_OK;
2293 }
2294
2295 #ifndef CAPSTONE_DIET
M680X_reg_access(const cs_insn * insn,cs_regs regs_read,uint8_t * regs_read_count,cs_regs regs_write,uint8_t * regs_write_count)2296 void M680X_reg_access(const cs_insn *insn,
2297 cs_regs regs_read, uint8_t *regs_read_count,
2298 cs_regs regs_write, uint8_t *regs_write_count)
2299 {
2300 if (insn->detail == NULL) {
2301 *regs_read_count = 0;
2302 *regs_write_count = 0;
2303 }
2304 else {
2305 *regs_read_count = insn->detail->regs_read_count;
2306 *regs_write_count = insn->detail->regs_write_count;
2307
2308 memcpy(regs_read, insn->detail->regs_read,
2309 *regs_read_count * sizeof(insn->detail->regs_read[0]));
2310 memcpy(regs_write, insn->detail->regs_write,
2311 *regs_write_count *
2312 sizeof(insn->detail->regs_write[0]));
2313 }
2314 }
2315 #endif
2316
2317 #endif
2318
2319