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 >= 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
read_byte_sign_extended(const m680x_info * info,int16_t * word,uint16_t address)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
read_word(const m680x_info * info,uint16_t * word,uint16_t address)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
read_sdword(const m680x_info * info,int32_t * sdword,uint16_t address)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) ).
binary_search(const inst_pageX * const inst_pageX_table,int table_size,uint8_t opcode)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
M680X_get_insn_id(cs_struct * handle,cs_insn * insn,unsigned int id)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 :
258 M680X_INS_ILLGL;
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
add_insn_group(cs_detail * detail,m680x_group_type group)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
exists_reg_list(uint16_t * regs,uint8_t count,m680x_reg reg)293 static bool exists_reg_list(uint16_t *regs, uint8_t count, m680x_reg reg)
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
add_reg_to_rw_list(MCInst * MI,m680x_reg reg,e_access access)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
update_am_reg_list(MCInst * MI,m680x_info * info,cs_m680x_op * op,e_access access)343 static void update_am_reg_list(MCInst *MI, m680x_info *info, cs_m680x_op *op,
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])
359 add_reg_to_rw_list(MI, M680X_REG_H, READ);
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
get_access(int operator_index,e_access_mode access_mode)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
build_regs_read_write_counts(MCInst * MI,m680x_info * info,e_access_mode access_mode)406 static void build_regs_read_write_counts(MCInst *MI, m680x_info *info,
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
add_operators_access(MCInst * MI,m680x_info * info,e_access_mode access_mode)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
set_changed_regs_read_write_counts(MCInst * MI,m680x_info * info)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, {
461 M680X_REG_S, M680X_REG_PC, M680X_REG_U,
462 M680X_REG_Y, M680X_REG_X, M680X_REG_DP,
463 M680X_REG_D, M680X_REG_CC, EOL
464 },
465 },
466 { M680X_INS_DAA, mrrr, { M680X_REG_A, EOL } },
467 {
468 M680X_INS_DIV, mmrr, {
469 M680X_REG_A, M680X_REG_H, M680X_REG_X, EOL
470 }
471 },
472 {
473 M680X_INS_EDIV, mmrr, {
474 M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL
475 }
476 },
477 {
478 M680X_INS_EDIVS, mmrr, {
479 M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL
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, {
497 M680X_REG_X, M680X_REG_Y, M680X_REG_A, EOL
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, {
518 M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL
519 }
520 },
521 {
522 M680X_INS_REVW, mmmm, {
523 M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL
524 }
525 },
526 { M680X_INS_RTC, mwww, { M680X_REG_S, M680X_REG_PC, EOL } },
527 {
528 M680X_INS_RTI, mwww, {
529 M680X_REG_S, M680X_REG_CC, M680X_REG_B,
530 M680X_REG_A, M680X_REG_DP, M680X_REG_X,
531 M680X_REG_Y, M680X_REG_U, M680X_REG_PC,
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, {
540 M680X_REG_S, M680X_REG_PC, M680X_REG_U,
541 M680X_REG_Y, M680X_REG_X, M680X_REG_DP,
542 M680X_REG_A, M680X_REG_B, M680X_REG_CC,
543 EOL
544 }
545 },
546 {
547 M680X_INS_SWI2, 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_SWI3, 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 { M680X_INS_TBL, wrrr, { M680X_REG_A, M680X_REG_B, EOL } },
563 {
564 M680X_INS_WAI, mrrr, {
565 M680X_REG_S, M680X_REG_PC, M680X_REG_X,
566 M680X_REG_A, M680X_REG_B, M680X_REG_CC,
567 EOL
568 }
569 },
570 {
571 M680X_INS_WAV, rmmm, {
572 M680X_REG_A, M680X_REG_B, M680X_REG_X,
573 M680X_REG_Y, EOL
574 }
575 },
576 {
577 M680X_INS_WAVR, rmmm, {
578 M680X_REG_A, M680X_REG_B, M680X_REG_X,
579 M680X_REG_Y, EOL
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);
607 add_reg_to_rw_list(MI, reg, access);
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.
get_indexed09_post_byte_size(const m680x_info * info,uint16_t address)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.
get_indexed12_post_byte_size(const m680x_info * info,uint16_t address,bool is_subset)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
is_tfr09_reg_valid(const m680x_info * info,uint8_t reg_nibble)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
is_exg_tfr12_post_byte_valid(const m680x_info * info,uint8_t post_byte)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
is_tfm_reg_valid(const m680x_info * info,uint8_t reg_nibble)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.
get_loop_post_byte_size(const m680x_info * info,uint16_t address)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.
get_bitmv_post_byte_size(const m680x_info * info,uint16_t address)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
is_sufficient_code_size(const m680x_info * info,uint16_t address,insn_desc * insn_description)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.
decode_insn(const m680x_info * info,uint16_t address,insn_desc * insn_description)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
illegal_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
inherent_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1040 static void inherent_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1041 {
1042 // There is nothing to do here :-)
1043 }
1044
add_reg_operand(m680x_info * info,m680x_reg reg)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
set_operand_size(m680x_info * info,cs_m680x_op * op,uint8_t default_size)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[] = {
1079 M680X_REG_CC, M680X_REG_A, M680X_REG_B, M680X_REG_DP,
1080 M680X_REG_X, M680X_REG_Y, M680X_REG_U, M680X_REG_PC,
1081 };
1082
1083 static const m680x_reg reg_u_reg_ids[] = {
1084 M680X_REG_CC, M680X_REG_A, M680X_REG_B, M680X_REG_DP,
1085 M680X_REG_X, M680X_REG_Y, M680X_REG_S, M680X_REG_PC,
1086 };
1087
reg_bits_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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, ®_bits, (*address)++);
1096
1097 switch (op0->reg) {
1098 case M680X_REG_U:
1099 reg_to_reg_ids = ®_u_reg_ids[0];
1100 break;
1101
1102 case M680X_REG_S:
1103 reg_to_reg_ids = ®_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 */
1126 M680X_REG_D, M680X_REG_X, M680X_REG_Y, M680X_REG_U,
1127 M680X_REG_S, M680X_REG_PC, M680X_REG_W, M680X_REG_V,
1128 /* 8-bit registers */
1129 M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_DP,
1130 M680X_REG_0, M680X_REG_0, M680X_REG_E, M680X_REG_F,
1131 };
1132
reg_reg09_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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, ®s, (*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
reg_reg12_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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[] = {
1152 M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP3,
1153 M680X_REG_D, M680X_REG_X, M680X_REG_Y, M680X_REG_S,
1154 };
1155 static const m680x_reg g_tfr_exg12_reg1_ids[] = {
1156 M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP2,
1157 M680X_REG_D, M680X_REG_X, M680X_REG_Y, M680X_REG_S,
1158 };
1159 uint8_t regs = 0;
1160
1161 read_byte(info, ®s, (*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
add_rel_operand(m680x_info * info,int16_t offset,uint16_t address)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
relative8_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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))
1196 add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1197 }
1198
relative16_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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))
1211 add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1212 }
1213
1214 static const m680x_reg g_rr5_to_reg_ids[] = {
1215 M680X_REG_X, M680X_REG_Y, M680X_REG_U, M680X_REG_S,
1216 };
1217
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)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
indexedX_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
indexedY_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
indexed09_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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] = {
1394 M680X_REG_X, M680X_REG_Y, M680X_REG_S, M680X_REG_PC,
1395 };
1396
1397 m680x_reg g_or12_to_reg_ids[3] = {
1398 M680X_REG_A, M680X_REG_B, M680X_REG_D
1399 };
1400
1401 // CPU12 indexed mode handler
indexed12_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
index_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
direct_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
extended_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
immediate_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
bit_move_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1559 static void bit_move_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1560 {
1561 static const m680x_reg m680x_reg[] = {
1562 M680X_REG_CC, M680X_REG_A, M680X_REG_B, M680X_REG_INVALID,
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
tfm_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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, ®s, *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
opidx_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
opidx_dir_rel_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
indexedX0_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
indexedX16_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
imm_rel_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
indexedS_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
indexedS16_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
indexedX0p_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
indexedXp_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
imm_idx12_x_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
ext_idx12_x_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)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
loop_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1737 static void loop_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1738 {
1739 static const m680x_reg index_to_reg_id[] = {
1740 M680X_REG_A, M680X_REG_B, M680X_REG_INVALID, M680X_REG_INVALID,
1741 M680X_REG_D, M680X_REG_X, M680X_REG_Y, M680X_REG_S,
1742 };
1743 static const m680x_insn index_to_insn_id[] = {
1744 M680X_INS_DBEQ, M680X_INS_DBNE, M680X_INS_TBEQ, M680X_INS_TBNE,
1745 M680X_INS_IBEQ, M680X_INS_IBNE, M680X_INS_ILLGL, M680X_INS_ILLGL
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 */
m680x_disassemble(MCInst * MI,m680x_info * info,uint16_t address)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,
1965 { M680X_INS_INVLD, M680X_INS_INVLD }
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,
1980 { M680X_INS_INVLD, M680X_INS_INVLD }
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,
1996 { M680X_INS_INVLD, M680X_INS_INVLD }
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,
2008 { M680X_INS_INVLD, M680X_INS_INVLD }
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,
2020 { M680X_INS_INVLD, M680X_INS_INVLD }
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,
2032 { M680X_INS_BCLR, M680X_INS_BSET }
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,
2044 { M680X_INS_BCLR, M680X_INS_BSET }
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],
2064 { M680X_INS_INVLD, M680X_INS_INVLD }
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,
2090 { M680X_INS_INVLD, M680X_INS_INVLD }
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,
2102 { M680X_INS_INVLD, M680X_INS_INVLD }
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,
2120 { M680X_INS_BCLR, M680X_INS_BSET }
2121 },
2122 };
2123
2124 static const char *s_cpu_type[] = {
2125 "INVALID", "6301", "6309", "6800", "6801", "6805", "6808",
2126 "6809", "6811", "CPU12", "HCS08",
2127 };
2128
m680x_setup_internals(m680x_info * info,e_cpu_type cpu_type,uint16_t address,const uint8_t * code,uint16_t code_len)2129 static bool m680x_setup_internals(m680x_info *info, e_cpu_type cpu_type,
2130 uint16_t address,
2131 const uint8_t *code, uint16_t code_len)
2132 {
2133 if (cpu_type == M680X_CPU_TYPE_INVALID) {
2134 return false;
2135 }
2136
2137 info->code = code;
2138 info->size = code_len;
2139 info->offset = address;
2140 info->cpu_type = cpu_type;
2141
2142 info->cpu = &g_cpu_tables[info->cpu_type];
2143
2144 return true;
2145 }
2146
M680X_getInstruction(csh ud,const uint8_t * code,size_t code_len,MCInst * MI,uint16_t * size,uint64_t address,void * inst_info)2147 bool M680X_getInstruction(csh ud, const uint8_t *code, size_t code_len,
2148 MCInst *MI, uint16_t *size, uint64_t address, void *inst_info)
2149 {
2150 unsigned int insn_size = 0;
2151 e_cpu_type cpu_type = M680X_CPU_TYPE_INVALID; // No default CPU type
2152 cs_struct *handle = (cs_struct *)ud;
2153 m680x_info *info = (m680x_info *)handle->printer_info;
2154
2155 MCInst_clear(MI);
2156
2157 if (handle->mode & CS_MODE_M680X_6800)
2158 cpu_type = M680X_CPU_TYPE_6800;
2159
2160 else if (handle->mode & CS_MODE_M680X_6801)
2161 cpu_type = M680X_CPU_TYPE_6801;
2162
2163 else if (handle->mode & CS_MODE_M680X_6805)
2164 cpu_type = M680X_CPU_TYPE_6805;
2165
2166 else if (handle->mode & CS_MODE_M680X_6808)
2167 cpu_type = M680X_CPU_TYPE_6808;
2168
2169 else if (handle->mode & CS_MODE_M680X_HCS08)
2170 cpu_type = M680X_CPU_TYPE_HCS08;
2171
2172 else if (handle->mode & CS_MODE_M680X_6809)
2173 cpu_type = M680X_CPU_TYPE_6809;
2174
2175 else if (handle->mode & CS_MODE_M680X_6301)
2176 cpu_type = M680X_CPU_TYPE_6301;
2177
2178 else if (handle->mode & CS_MODE_M680X_6309)
2179 cpu_type = M680X_CPU_TYPE_6309;
2180
2181 else if (handle->mode & CS_MODE_M680X_6811)
2182 cpu_type = M680X_CPU_TYPE_6811;
2183
2184 else if (handle->mode & CS_MODE_M680X_CPU12)
2185 cpu_type = M680X_CPU_TYPE_CPU12;
2186
2187 if (cpu_type != M680X_CPU_TYPE_INVALID &&
2188 m680x_setup_internals(info, cpu_type, (uint16_t)address, code,
2189 code_len))
2190 insn_size = m680x_disassemble(MI, info, (uint16_t)address);
2191
2192 if (insn_size == 0) {
2193 *size = 1;
2194 return false;
2195 }
2196
2197 // Make sure we always stay within range
2198 if (insn_size > code_len) {
2199 *size = (uint16_t)code_len;
2200 return false;
2201 }
2202 else
2203 *size = (uint16_t)insn_size;
2204
2205 return true;
2206 }
2207
M680X_disassembler_init(cs_struct * ud)2208 cs_err M680X_disassembler_init(cs_struct *ud)
2209 {
2210 if (M680X_REG_ENDING != ARR_SIZE(g_m6800_reg_byte_size)) {
2211 CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6800_reg_byte_size));
2212
2213 return CS_ERR_MODE;
2214 }
2215
2216 if (M680X_REG_ENDING != ARR_SIZE(g_m6801_reg_byte_size)) {
2217 CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6801_reg_byte_size));
2218
2219 return CS_ERR_MODE;
2220 }
2221
2222 if (M680X_REG_ENDING != ARR_SIZE(g_m6805_reg_byte_size)) {
2223 CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6805_reg_byte_size));
2224
2225 return CS_ERR_MODE;
2226 }
2227
2228 if (M680X_REG_ENDING != ARR_SIZE(g_m6808_reg_byte_size)) {
2229 CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6808_reg_byte_size));
2230
2231 return CS_ERR_MODE;
2232 }
2233
2234 if (M680X_REG_ENDING != ARR_SIZE(g_m6811_reg_byte_size)) {
2235 CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6811_reg_byte_size));
2236
2237 return CS_ERR_MODE;
2238 }
2239
2240 if (M680X_REG_ENDING != ARR_SIZE(g_cpu12_reg_byte_size)) {
2241 CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_cpu12_reg_byte_size));
2242
2243 return CS_ERR_MODE;
2244 }
2245
2246 if (M680X_REG_ENDING != ARR_SIZE(g_m6809_reg_byte_size)) {
2247 CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6809_reg_byte_size));
2248
2249 return CS_ERR_MODE;
2250 }
2251
2252 if (M680X_INS_ENDING != ARR_SIZE(g_insn_props)) {
2253 CS_ASSERT(M680X_INS_ENDING == ARR_SIZE(g_insn_props));
2254
2255 return CS_ERR_MODE;
2256 }
2257
2258 if (M680X_CPU_TYPE_ENDING != ARR_SIZE(s_cpu_type)) {
2259 CS_ASSERT(M680X_CPU_TYPE_ENDING == ARR_SIZE(s_cpu_type));
2260
2261 return CS_ERR_MODE;
2262 }
2263
2264 if (M680X_CPU_TYPE_ENDING != ARR_SIZE(g_cpu_tables)) {
2265 CS_ASSERT(M680X_CPU_TYPE_ENDING == ARR_SIZE(g_cpu_tables));
2266
2267 return CS_ERR_MODE;
2268 }
2269
2270 if (HANDLER_ID_ENDING != ARR_SIZE(g_insn_handler)) {
2271 CS_ASSERT(HANDLER_ID_ENDING == ARR_SIZE(g_insn_handler));
2272
2273 return CS_ERR_MODE;
2274 }
2275
2276 if (ACCESS_MODE_ENDING != MATRIX_SIZE(g_access_mode_to_access)) {
2277 CS_ASSERT(ACCESS_MODE_ENDING ==
2278 MATRIX_SIZE(g_access_mode_to_access));
2279
2280 return CS_ERR_MODE;
2281 }
2282
2283 return CS_ERR_OK;
2284 }
2285
2286 #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)2287 void M680X_reg_access(const cs_insn *insn,
2288 cs_regs regs_read, uint8_t *regs_read_count,
2289 cs_regs regs_write, uint8_t *regs_write_count)
2290 {
2291 if (insn->detail == NULL) {
2292 *regs_read_count = 0;
2293 *regs_write_count = 0;
2294 }
2295 else {
2296 *regs_read_count = insn->detail->regs_read_count;
2297 *regs_write_count = insn->detail->regs_write_count;
2298
2299 memcpy(regs_read, insn->detail->regs_read,
2300 *regs_read_count * sizeof(insn->detail->regs_read[0]));
2301 memcpy(regs_write, insn->detail->regs_write,
2302 *regs_write_count *
2303 sizeof(insn->detail->regs_write[0]));
2304 }
2305 }
2306 #endif
2307
2308 #endif
2309
2310