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