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 m680x_insn insn : 9;
116 insn_hdlr_id handler_id1 : 6; /* first instruction handler id */
117 insn_hdlr_id handler_id2 : 6; /* second instruction 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;
123 m680x_insn insn : 9;
124 insn_hdlr_id handler_id1 : 6; /* first instruction handler id */
125 insn_hdlr_id handler_id2 : 6; /* second instruction handler id */
126 } inst_pageX;
127
128 typedef struct insn_props {
129 unsigned group : 4;
130 e_access_mode access_mode : 5;
131 m680x_reg reg0 : 5;
132 m680x_reg reg1 : 5;
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
is_indexed09_post_byte_valid(const m680x_info * info,uint16_t * address,uint8_t post_byte,insn_desc * insn_description)622 static bool is_indexed09_post_byte_valid(const m680x_info *info,
623 uint16_t *address, uint8_t post_byte, insn_desc *insn_description)
624 {
625 uint8_t ir = 0;
626 bool retval;
627
628 switch (post_byte & 0x9F) {
629 case 0x87:
630 case 0x8A:
631 case 0x8E:
632 case 0x8F:
633 case 0x90:
634 case 0x92:
635 case 0x97:
636 case 0x9A:
637 case 0x9E:
638 return false; // illegal indexed post bytes
639
640 case 0x88: // n8,R
641 case 0x8C: // n8,PCR
642 case 0x98: // [n8,R]
643 case 0x9C: // [n8,PCR]
644 insn_description->insn_size++;
645 return read_byte(info, &ir, (*address)++);
646
647 case 0x89: // n16,R
648 case 0x8D: // n16,PCR
649 case 0x99: // [n16,R]
650 case 0x9D: // [n16,PCR]
651 insn_description->insn_size += 2;
652 retval = read_byte(info, &ir, *address + 1);
653 *address += 2;
654 return retval;
655
656 case 0x9F: // [n]
657 insn_description->insn_size += 2;
658 retval = (post_byte & 0x60) == 0 &&
659 read_byte(info, &ir, *address + 1);
660 *address += 2;
661 return retval;
662 }
663
664 return true; // Any other indexed post byte is valid and
665 // no additional bytes have to be read.
666 }
667
is_indexed12_post_byte_valid(const m680x_info * info,uint16_t * address,uint8_t post_byte,insn_desc * insn_description,bool is_subset)668 static bool is_indexed12_post_byte_valid(const m680x_info *info,
669 uint16_t *address, uint8_t post_byte, insn_desc *insn_description,
670 bool is_subset)
671 {
672 uint8_t ir;
673 bool result;
674
675 if (!(post_byte & 0x20)) // n5,R
676 return true;
677
678 switch (post_byte & 0xe7) {
679 case 0xe0:
680 case 0xe1: // n9,R
681 if (is_subset)
682 return false;
683
684 insn_description->insn_size++;
685 return read_byte(info, &ir, (*address)++);
686
687 case 0xe2: // n16,R
688 case 0xe3: // [n16,R]
689 if (is_subset)
690 return false;
691
692 insn_description->insn_size += 2;
693 result = read_byte(info, &ir, *address + 1);
694 *address += 2;
695 return result;
696
697 case 0xe4: // A,R
698 case 0xe5: // B,R
699 case 0xe6: // D,R
700 case 0xe7: // [D,R]
701 default: // n,-r n,+r n,r- n,r+
702 break;
703 }
704
705 return true;
706 }
707
708 // Check for M6809/HD6309 TFR/EXG instruction for valid register
is_tfr09_reg_valid(const m680x_info * info,uint8_t reg_nibble)709 static bool is_tfr09_reg_valid(const m680x_info *info, uint8_t reg_nibble)
710 {
711 if (info->cpu->tfr_reg_valid != NULL)
712 return info->cpu->tfr_reg_valid[reg_nibble];
713
714 return true; // e.g. for the M6309 all registers are valid
715 }
716
717 // Check for CPU12 TFR/EXG instruction for valid register
is_exg_tfr12_post_byte_valid(const m680x_info * info,uint8_t post_byte)718 static bool is_exg_tfr12_post_byte_valid(const m680x_info *info,
719 uint8_t post_byte)
720 {
721 return !(post_byte & 0x08);
722 }
723
is_tfm_reg_valid(const m680x_info * info,uint8_t reg_nibble)724 static bool is_tfm_reg_valid(const m680x_info *info, uint8_t reg_nibble)
725 {
726 // HD6809 TFM instruction: Only register X,Y,U,S,D is allowed
727 return reg_nibble <= 4;
728 }
729
is_loop_post_byte_valid(const m680x_info * info,uint8_t post_byte)730 static bool is_loop_post_byte_valid(const m680x_info *info, uint8_t post_byte)
731 {
732 // According to documentation bit 3 is don't care and not checked here.
733 if (post_byte >= 0xc0)
734 return false;
735
736 return ((post_byte & 0x07) != 2 && ((post_byte & 0x07) != 3));
737 }
738
is_sufficient_code_size(const m680x_info * info,uint16_t address,insn_desc * insn_description)739 static bool is_sufficient_code_size(const m680x_info *info, uint16_t address,
740 insn_desc *insn_description)
741 {
742 int i;
743 bool retval;
744
745 for (i = 0; i < 2; i++) {
746 uint8_t ir = 0;
747 bool is_subset = false;
748
749 switch (insn_description->hid[i]) {
750
751 case imm32_hid:
752 insn_description->insn_size += 4;
753 retval = read_byte(info, &ir, address + 3);
754 address += 4;
755 break;
756
757 case ext_hid:
758 case imm16_hid:
759 case rel16_hid:
760 case imm8rel_hid:
761 case opidxdr_hid:
762 case idxX16_hid:
763 case idxS16_hid:
764 insn_description->insn_size += 2;
765 retval = read_byte(info, &ir, address + 1);
766 address += 2;
767 break;
768
769 case rel8_hid:
770 case dir_hid:
771 case rbits_hid:
772 case imm8_hid:
773 case idxX_hid:
774 case idxXp_hid:
775 case idxY_hid:
776 case idxS_hid:
777 case index_hid:
778 insn_description->insn_size += 1;
779 retval = read_byte(info, &ir, address++);
780 break;
781
782 case illgl_hid:
783 case inh_hid:
784 case idxX0_hid:
785 case idxX0p_hid:
786 case opidx_hid:
787 retval = true;
788 break;
789
790 case idx09_hid:
791 insn_description->insn_size += 1;
792
793 if (!read_byte(info, &ir, address++))
794 retval = false;
795 else
796 retval = is_indexed09_post_byte_valid(info,
797 &address, ir, insn_description);
798
799 break;
800
801 case idx12s_hid:
802 is_subset = true;
803
804 // intentionally fall through
805
806 case idx12_hid:
807 insn_description->insn_size += 1;
808
809 if (!read_byte(info, &ir, address++))
810 retval = false;
811 else
812 retval = is_indexed12_post_byte_valid(info,
813 &address, ir, insn_description,
814 is_subset);
815
816 break;
817
818 case exti12x_hid:
819 case imm16i12x_hid:
820 insn_description->insn_size += 1;
821
822 if (!read_byte(info, &ir, address++))
823 retval = false;
824 else if (!is_indexed12_post_byte_valid(info, &address,
825 ir, insn_description, false))
826 retval = false;
827 else {
828 insn_description->insn_size += 2;
829 retval = read_byte(info, &ir, address + 1);
830 address += 2;
831 }
832
833 break;
834
835 case imm8i12x_hid:
836 insn_description->insn_size += 1;
837
838 if (!read_byte(info, &ir, address++))
839 retval = false;
840 else if (!is_indexed12_post_byte_valid(info, &address,
841 ir, insn_description, false))
842 retval = false;
843 else {
844 insn_description->insn_size += 1;
845 retval = read_byte(info, &ir, address++);
846 }
847
848 break;
849
850 case tfm_hid:
851 insn_description->insn_size += 1;
852
853 if (!read_byte(info, &ir, address++))
854 retval = false;
855 else
856 retval = is_tfm_reg_valid(info, (ir >> 4) & 0x0F) &&
857 is_tfm_reg_valid(info, ir & 0x0F);
858
859 break;
860
861 case rr09_hid:
862 insn_description->insn_size += 1;
863
864 if (!read_byte(info, &ir, address++))
865 retval = false;
866 else
867 retval = is_tfr09_reg_valid(info, (ir >> 4) & 0x0F) &&
868 is_tfr09_reg_valid(info, ir & 0x0F);
869
870 break;
871
872 case rr12_hid:
873 insn_description->insn_size += 1;
874
875 if (!read_byte(info, &ir, address++))
876 retval = false;
877 else
878 retval = is_exg_tfr12_post_byte_valid(info, ir);
879
880 break;
881
882 case bitmv_hid:
883 insn_description->insn_size += 2;
884
885 if (!read_byte(info, &ir, address++))
886 retval = false;
887 else if ((ir & 0xc0) == 0xc0)
888 retval = false; // Invalid register specified
889 else
890 retval = read_byte(info, &ir, address++);
891
892 break;
893
894 case loop_hid:
895 insn_description->insn_size += 2;
896
897 if (!read_byte(info, &ir, address++))
898 retval = false;
899 else if (!is_loop_post_byte_valid(info, ir))
900 retval = false;
901 else
902 retval = read_byte(info, &ir, address++);
903
904 break;
905
906 default:
907 fprintf(stderr, "Internal error: Unexpected instruction "
908 "handler id %d\n", insn_description->hid[i]);
909 retval = false;
910 break;
911 }
912
913 if (!retval)
914 return false;
915 }
916
917 return retval;
918 }
919
920 // Check for a valid M680X instruction AND for enough bytes in the code buffer
921 // Return an instruction description in insn_desc.
decode_insn(const m680x_info * info,uint16_t address,insn_desc * insn_description)922 static bool decode_insn(const m680x_info *info, uint16_t address,
923 insn_desc *insn_description)
924 {
925 const inst_pageX *inst_table = NULL;
926 const cpu_tables *cpu = info->cpu;
927 int table_size = 0;
928 uint16_t base_address = address;
929 uint8_t ir; // instruction register
930 int i;
931 int index;
932
933 if (!read_byte(info, &ir, address++))
934 return false;
935
936 insn_description->insn = M680X_INS_ILLGL;
937 insn_description->opcode = ir;
938
939 // Check if a page prefix byte is present
940 for (i = 0; i < ARR_SIZE(cpu->pageX_table_size); ++i) {
941 if (cpu->pageX_table_size[i] == 0 ||
942 (cpu->inst_pageX_table[i] == NULL))
943 break;
944
945 if ((cpu->pageX_prefix[i] == ir)) {
946 // Get pageX instruction and handler id.
947 // Abort for illegal instr.
948 inst_table = cpu->inst_pageX_table[i];
949 table_size = cpu->pageX_table_size[i];
950
951 if (!read_byte(info, &ir, address++))
952 return false;
953
954 insn_description->opcode =
955 (insn_description->opcode << 8) | ir;
956
957 if ((index = binary_search(inst_table, table_size, ir)) < 0)
958 return false;
959
960 insn_description->hid[0] =
961 inst_table[index].handler_id1;
962 insn_description->hid[1] =
963 inst_table[index].handler_id2;
964 insn_description->insn = inst_table[index].insn;
965 break;
966 }
967 }
968
969 if (insn_description->insn == M680X_INS_ILLGL) {
970 // Get page1 insn description
971 insn_description->insn = cpu->inst_page1_table[ir].insn;
972 insn_description->hid[0] =
973 cpu->inst_page1_table[ir].handler_id1;
974 insn_description->hid[1] =
975 cpu->inst_page1_table[ir].handler_id2;
976 }
977
978 if (insn_description->insn == M680X_INS_ILLGL) {
979 // Check if opcode byte is present in an overlay table
980 for (i = 0; i < ARR_SIZE(cpu->overlay_table_size); ++i) {
981 if (cpu->overlay_table_size[i] == 0 ||
982 (cpu->inst_overlay_table[i] == NULL))
983 break;
984
985 inst_table = cpu->inst_overlay_table[i];
986 table_size = cpu->overlay_table_size[i];
987
988 if ((index = binary_search(inst_table, table_size,
989 ir)) >= 0) {
990 insn_description->hid[0] =
991 inst_table[index].handler_id1;
992 insn_description->hid[1] =
993 inst_table[index].handler_id2;
994 insn_description->insn = inst_table[index].insn;
995 break;
996 }
997 }
998 }
999
1000 insn_description->insn_size = address - base_address;
1001
1002 return (insn_description->insn != M680X_INS_ILLGL) &&
1003 (insn_description->insn != M680X_INS_INVLD) &&
1004 is_sufficient_code_size(info, address, insn_description);
1005 }
1006
illegal_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1007 static void illegal_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1008 {
1009 cs_m680x_op *op0 = &info->m680x.operands[info->m680x.op_count++];
1010 uint8_t temp8 = 0;
1011
1012 info->insn = M680X_INS_ILLGL;
1013 read_byte(info, &temp8, (*address)++);
1014 op0->imm = (int32_t)temp8 & 0xff;
1015 op0->type = M680X_OP_IMMEDIATE;
1016 op0->size = 1;
1017 }
1018
inherent_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1019 static void inherent_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1020 {
1021 // There is nothing to do here :-)
1022 }
1023
add_reg_operand(m680x_info * info,m680x_reg reg)1024 static void add_reg_operand(m680x_info *info, m680x_reg reg)
1025 {
1026 cs_m680x *m680x = &info->m680x;
1027 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1028
1029 op->type = M680X_OP_REGISTER;
1030 op->reg = reg;
1031 op->size = info->cpu->reg_byte_size[reg];
1032 }
1033
set_operand_size(m680x_info * info,cs_m680x_op * op,uint8_t default_size)1034 static void set_operand_size(m680x_info *info, cs_m680x_op *op,
1035 uint8_t default_size)
1036 {
1037 cs_m680x *m680x = &info->m680x;
1038
1039 if (info->insn == M680X_INS_JMP || info->insn == M680X_INS_JSR)
1040 op->size = 0;
1041 else if (info->insn == M680X_INS_DIVD ||
1042 ((info->insn == M680X_INS_AIS || info->insn == M680X_INS_AIX) &&
1043 op->type != M680X_OP_REGISTER))
1044 op->size = 1;
1045 else if (info->insn == M680X_INS_DIVQ ||
1046 info->insn == M680X_INS_MOVW)
1047 op->size = 2;
1048 else if (info->insn == M680X_INS_EMACS)
1049 op->size = 4;
1050 else if ((m680x->op_count > 0) &&
1051 (m680x->operands[0].type == M680X_OP_REGISTER))
1052 op->size = m680x->operands[0].size;
1053 else
1054 op->size = default_size;
1055 }
1056
1057 static const m680x_reg reg_s_reg_ids[] = {
1058 M680X_REG_CC, M680X_REG_A, M680X_REG_B, M680X_REG_DP,
1059 M680X_REG_X, M680X_REG_Y, M680X_REG_U, M680X_REG_PC,
1060 };
1061
1062 static const m680x_reg reg_u_reg_ids[] = {
1063 M680X_REG_CC, M680X_REG_A, M680X_REG_B, M680X_REG_DP,
1064 M680X_REG_X, M680X_REG_Y, M680X_REG_S, M680X_REG_PC,
1065 };
1066
reg_bits_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1067 static void reg_bits_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1068 {
1069 cs_m680x_op *op0 = &info->m680x.operands[0];
1070 uint8_t reg_bits = 0;
1071 uint16_t bit_index;
1072 const m680x_reg *reg_to_reg_ids;
1073
1074 read_byte(info, ®_bits, (*address)++);
1075
1076 switch (op0->reg) {
1077 case M680X_REG_U:
1078 reg_to_reg_ids = ®_u_reg_ids[0];
1079 break;
1080
1081 case M680X_REG_S:
1082 reg_to_reg_ids = ®_s_reg_ids[0];
1083 break;
1084
1085 default:
1086 fprintf(stderr, "Internal error: Unexpected operand0 register "
1087 "%d\n", op0->reg);
1088 abort();
1089 }
1090
1091 if ((info->insn == M680X_INS_PULU ||
1092 (info->insn == M680X_INS_PULS)) &&
1093 ((reg_bits & 0x80) != 0))
1094 // PULS xxx,PC or PULU xxx,PC which is like return from
1095 // subroutine (RTS)
1096 add_insn_group(MI->flat_insn->detail, M680X_GRP_RET);
1097
1098 for (bit_index = 0; bit_index < 8; ++bit_index) {
1099 if (reg_bits & (1 << bit_index))
1100 add_reg_operand(info, reg_to_reg_ids[bit_index]);
1101 }
1102 }
1103
1104 static const m680x_reg g_tfr_exg_reg_ids[] = {
1105 /* 16-bit registers */
1106 M680X_REG_D, M680X_REG_X, M680X_REG_Y, M680X_REG_U,
1107 M680X_REG_S, M680X_REG_PC, M680X_REG_W, M680X_REG_V,
1108 /* 8-bit registers */
1109 M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_DP,
1110 M680X_REG_0, M680X_REG_0, M680X_REG_E, M680X_REG_F,
1111 };
1112
reg_reg09_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1113 static void reg_reg09_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1114 {
1115 uint8_t regs = 0;
1116
1117 read_byte(info, ®s, (*address)++);
1118
1119 add_reg_operand(info, g_tfr_exg_reg_ids[regs >> 4]);
1120 add_reg_operand(info, g_tfr_exg_reg_ids[regs & 0x0f]);
1121
1122 if ((regs & 0x0f) == 0x05) {
1123 // EXG xxx,PC or TFR xxx,PC which is like a JMP
1124 add_insn_group(MI->flat_insn->detail, M680X_GRP_JUMP);
1125 }
1126 }
1127
1128
reg_reg12_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1129 static void reg_reg12_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1130 {
1131 static const m680x_reg g_tfr_exg12_reg0_ids[] = {
1132 M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP3,
1133 M680X_REG_D, M680X_REG_X, M680X_REG_Y, M680X_REG_S,
1134 };
1135 static const m680x_reg g_tfr_exg12_reg1_ids[] = {
1136 M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP2,
1137 M680X_REG_D, M680X_REG_X, M680X_REG_Y, M680X_REG_S,
1138 };
1139 uint8_t regs = 0;
1140
1141 read_byte(info, ®s, (*address)++);
1142
1143 // The opcode of this instruction depends on
1144 // the msb of its post byte.
1145 if (regs & 0x80)
1146 info->insn = M680X_INS_EXG;
1147 else
1148 info->insn = M680X_INS_TFR;
1149
1150 add_reg_operand(info, g_tfr_exg12_reg0_ids[(regs >> 4) & 0x07]);
1151 add_reg_operand(info, g_tfr_exg12_reg1_ids[regs & 0x07]);
1152 }
1153
add_rel_operand(m680x_info * info,int16_t offset,uint16_t address)1154 static void add_rel_operand(m680x_info *info, int16_t offset, uint16_t address)
1155 {
1156 cs_m680x *m680x = &info->m680x;
1157 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1158
1159 op->type = M680X_OP_RELATIVE;
1160 op->size = 0;
1161 op->rel.offset = offset;
1162 op->rel.address = address;
1163 }
1164
relative8_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1165 static void relative8_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1166 {
1167 int16_t offset = 0;
1168
1169 read_byte_sign_extended(info, &offset, (*address)++);
1170 add_rel_operand(info, offset, *address + offset);
1171 add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1172
1173 if ((info->insn != M680X_INS_BRA) &&
1174 (info->insn != M680X_INS_BSR) &&
1175 (info->insn != M680X_INS_BRN))
1176 add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1177 }
1178
relative16_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1179 static void relative16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1180 {
1181 uint16_t offset = 0;
1182
1183 read_word(info, &offset, *address);
1184 *address += 2;
1185 add_rel_operand(info, (int16_t)offset, *address + offset);
1186 add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1187
1188 if ((info->insn != M680X_INS_LBRA) &&
1189 (info->insn != M680X_INS_LBSR) &&
1190 (info->insn != M680X_INS_LBRN))
1191 add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1192 }
1193
1194 static const m680x_reg g_rr5_to_reg_ids[] = {
1195 M680X_REG_X, M680X_REG_Y, M680X_REG_U, M680X_REG_S,
1196 };
1197
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)1198 static void add_indexed_operand(m680x_info *info, m680x_reg base_reg,
1199 bool post_inc_dec, uint8_t inc_dec, uint8_t offset_bits,
1200 uint16_t offset, bool no_comma)
1201 {
1202 cs_m680x *m680x = &info->m680x;
1203 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1204
1205 op->type = M680X_OP_INDEXED;
1206 set_operand_size(info, op, 1);
1207 op->idx.base_reg = base_reg;
1208 op->idx.offset_reg = M680X_REG_INVALID;
1209 op->idx.inc_dec = inc_dec;
1210
1211 if (inc_dec && post_inc_dec)
1212 op->idx.flags |= M680X_IDX_POST_INC_DEC;
1213
1214 if (offset_bits != M680X_OFFSET_NONE) {
1215 op->idx.offset = offset;
1216 op->idx.offset_addr = 0;
1217 }
1218
1219 op->idx.offset_bits = offset_bits;
1220 op->idx.flags |= (no_comma ? M680X_IDX_NO_COMMA : 0);
1221 }
1222
1223 // M6800/1/2/3 indexed mode handler
indexedX_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1224 static void indexedX_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1225 {
1226 uint8_t offset = 0;
1227
1228 read_byte(info, &offset, (*address)++);
1229
1230 add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_8,
1231 (uint16_t)offset, false);
1232 }
1233
indexedY_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1234 static void indexedY_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1235 {
1236 uint8_t offset = 0;
1237
1238 read_byte(info, &offset, (*address)++);
1239
1240 add_indexed_operand(info, M680X_REG_Y, false, 0, M680X_OFFSET_BITS_8,
1241 (uint16_t)offset, false);
1242 }
1243
1244 // M6809/M6309 indexed mode handler
indexed09_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1245 static void indexed09_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1246 {
1247 cs_m680x *m680x = &info->m680x;
1248 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1249 uint8_t post_byte = 0;
1250 uint16_t offset = 0;
1251 int16_t soffset = 0;
1252
1253 read_byte(info, &post_byte, (*address)++);
1254
1255 op->type = M680X_OP_INDEXED;
1256 set_operand_size(info, op, 1);
1257 op->idx.base_reg = g_rr5_to_reg_ids[(post_byte >> 5) & 0x03];
1258 op->idx.offset_reg = M680X_REG_INVALID;
1259
1260 if (!(post_byte & 0x80)) {
1261 // n5,R
1262 if ((post_byte & 0x10) == 0x10)
1263 op->idx.offset = post_byte | 0xfff0;
1264 else
1265 op->idx.offset = post_byte & 0x0f;
1266
1267 op->idx.offset_addr = op->idx.offset + *address;
1268 op->idx.offset_bits = M680X_OFFSET_BITS_5;
1269 }
1270 else {
1271 if ((post_byte & 0x10) == 0x10)
1272 op->idx.flags |= M680X_IDX_INDIRECT;
1273
1274 // indexed addressing
1275 switch (post_byte & 0x1f) {
1276 case 0x00: // ,R+
1277 op->idx.inc_dec = 1;
1278 op->idx.flags |= M680X_IDX_POST_INC_DEC;
1279 break;
1280
1281 case 0x11: // [,R++]
1282 case 0x01: // ,R++
1283 op->idx.inc_dec = 2;
1284 op->idx.flags |= M680X_IDX_POST_INC_DEC;
1285 break;
1286
1287 case 0x02: // ,-R
1288 op->idx.inc_dec = -1;
1289 break;
1290
1291 case 0x13: // [,--R]
1292 case 0x03: // ,--R
1293 op->idx.inc_dec = -2;
1294 break;
1295
1296 case 0x14: // [,R]
1297 case 0x04: // ,R
1298 break;
1299
1300 case 0x15: // [B,R]
1301 case 0x05: // B,R
1302 op->idx.offset_reg = M680X_REG_B;
1303 break;
1304
1305 case 0x16: // [A,R]
1306 case 0x06: // A,R
1307 op->idx.offset_reg = M680X_REG_A;
1308 break;
1309
1310 case 0x1c: // [n8,PCR]
1311 case 0x0c: // n8,PCR
1312 op->idx.base_reg = M680X_REG_PC;
1313 read_byte_sign_extended(info, &soffset, (*address)++);
1314 op->idx.offset_addr = offset + *address;
1315 op->idx.offset = soffset;
1316 op->idx.offset_bits = M680X_OFFSET_BITS_8;
1317 break;
1318
1319 case 0x18: // [n8,R]
1320 case 0x08: // n8,R
1321 read_byte_sign_extended(info, &soffset, (*address)++);
1322 op->idx.offset = soffset;
1323 op->idx.offset_bits = M680X_OFFSET_BITS_8;
1324 break;
1325
1326 case 0x1d: // [n16,PCR]
1327 case 0x0d: // n16,PCR
1328 op->idx.base_reg = M680X_REG_PC;
1329 read_word(info, &offset, *address);
1330 *address += 2;
1331 op->idx.offset_addr = offset + *address;
1332 op->idx.offset = (int16_t)offset;
1333 op->idx.offset_bits = M680X_OFFSET_BITS_16;
1334 break;
1335
1336 case 0x19: // [n16,R]
1337 case 0x09: // n16,R
1338 read_word(info, &offset, *address);
1339 *address += 2;
1340 op->idx.offset = (int16_t)offset;
1341 op->idx.offset_bits = M680X_OFFSET_BITS_16;
1342 break;
1343
1344 case 0x1b: // [D,R]
1345 case 0x0b: // D,R
1346 op->idx.offset_reg = M680X_REG_D;
1347 break;
1348
1349 case 0x1f: // [n16]
1350 op->type = M680X_OP_EXTENDED;
1351 op->ext.indirect = true;
1352 read_word(info, &op->ext.address, *address);
1353 *address += 2;
1354 break;
1355
1356 default:
1357 op->idx.base_reg = M680X_REG_INVALID;
1358 break;
1359 }
1360 }
1361
1362 if (((info->insn == M680X_INS_LEAU) ||
1363 (info->insn == M680X_INS_LEAS) ||
1364 (info->insn == M680X_INS_LEAX) ||
1365 (info->insn == M680X_INS_LEAY)) &&
1366 (m680x->operands[0].reg == M680X_REG_X ||
1367 (m680x->operands[0].reg == M680X_REG_Y)))
1368 // Only LEAX and LEAY modify CC register
1369 add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1370 }
1371
1372
1373 m680x_reg g_idx12_to_reg_ids[4] = {
1374 M680X_REG_X, M680X_REG_Y, M680X_REG_S, M680X_REG_PC,
1375 };
1376
1377 m680x_reg g_or12_to_reg_ids[3] = {
1378 M680X_REG_A, M680X_REG_B, M680X_REG_D
1379 };
1380
1381 // CPU12 indexed mode handler
indexed12_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1382 static void indexed12_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1383 {
1384 cs_m680x *m680x = &info->m680x;
1385 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1386 uint8_t post_byte = 0;
1387 uint8_t offset8 = 0;
1388
1389 read_byte(info, &post_byte, (*address)++);
1390
1391 op->type = M680X_OP_INDEXED;
1392 set_operand_size(info, op, 1);
1393 op->idx.offset_reg = M680X_REG_INVALID;
1394
1395 if (!(post_byte & 0x20)) {
1396 // n5,R n5 is a 5-bit signed offset
1397 op->idx.base_reg = g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1398
1399 if ((post_byte & 0x10) == 0x10)
1400 op->idx.offset = post_byte | 0xfff0;
1401 else
1402 op->idx.offset = post_byte & 0x0f;
1403
1404 op->idx.offset_addr = op->idx.offset + *address;
1405 op->idx.offset_bits = M680X_OFFSET_BITS_5;
1406 }
1407 else {
1408 if ((post_byte & 0xe0) == 0xe0)
1409 op->idx.base_reg =
1410 g_idx12_to_reg_ids[(post_byte >> 3) & 0x03];
1411
1412 switch (post_byte & 0xe7) {
1413 case 0xe0:
1414 case 0xe1: // n9,R
1415 read_byte(info, &offset8, (*address)++);
1416 op->idx.offset = offset8;
1417
1418 if (post_byte & 0x01) // sign extension
1419 op->idx.offset |= 0xff00;
1420
1421 op->idx.offset_bits = M680X_OFFSET_BITS_9;
1422
1423 if (op->idx.base_reg == M680X_REG_PC)
1424 op->idx.offset_addr = op->idx.offset + *address;
1425
1426 break;
1427
1428 case 0xe3: // [n16,R]
1429 op->idx.flags |= M680X_IDX_INDIRECT;
1430
1431 // intentionally fall through
1432 case 0xe2: // n16,R
1433 read_word(info, (uint16_t *)&op->idx.offset, *address);
1434 (*address) += 2;
1435 op->idx.offset_bits = M680X_OFFSET_BITS_16;
1436
1437 if (op->idx.base_reg == M680X_REG_PC)
1438 op->idx.offset_addr = op->idx.offset + *address;
1439
1440 break;
1441
1442 case 0xe4: // A,R
1443 case 0xe5: // B,R
1444 case 0xe6: // D,R
1445 op->idx.offset_reg =
1446 g_or12_to_reg_ids[post_byte & 0x03];
1447 break;
1448
1449 case 0xe7: // [D,R]
1450 op->idx.offset_reg = M680X_REG_D;
1451 op->idx.flags |= M680X_IDX_INDIRECT;
1452 break;
1453
1454 default: // n,-r n,+r n,r- n,r+
1455 // PC is not allowed in this mode
1456 op->idx.base_reg =
1457 g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1458 op->idx.inc_dec = post_byte & 0x0f;
1459
1460 if (op->idx.inc_dec & 0x08) // evtl. sign extend value
1461 op->idx.inc_dec |= 0xf0;
1462
1463 if (op->idx.inc_dec >= 0)
1464 op->idx.inc_dec++;
1465
1466 if (post_byte & 0x10)
1467 op->idx.flags |= M680X_IDX_POST_INC_DEC;
1468
1469 break;
1470
1471 }
1472 }
1473 }
1474
index_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1475 static void index_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1476 {
1477 cs_m680x *m680x = &info->m680x;
1478 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1479
1480 op->type = M680X_OP_CONSTANT;
1481 read_byte(info, &op->const_val, (*address)++);
1482 };
1483
direct_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1484 static void direct_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1485 {
1486 cs_m680x *m680x = &info->m680x;
1487 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1488
1489 op->type = M680X_OP_DIRECT;
1490 set_operand_size(info, op, 1);
1491 read_byte(info, &op->direct_addr, (*address)++);
1492 };
1493
extended_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1494 static void extended_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1495 {
1496 cs_m680x *m680x = &info->m680x;
1497 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1498
1499 op->type = M680X_OP_EXTENDED;
1500 set_operand_size(info, op, 1);
1501 read_word(info, &op->ext.address, *address);
1502 *address += 2;
1503 }
1504
immediate_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1505 static void immediate_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1506 {
1507 cs_m680x *m680x = &info->m680x;
1508 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1509 uint16_t word = 0;
1510 int16_t sword = 0;
1511
1512 op->type = M680X_OP_IMMEDIATE;
1513 set_operand_size(info, op, 1);
1514
1515 switch (op->size) {
1516 case 1:
1517 read_byte_sign_extended(info, &sword, *address);
1518 op->imm = sword;
1519 break;
1520
1521 case 2:
1522 read_word(info, &word, *address);
1523 op->imm = (int16_t)word;
1524 break;
1525
1526 case 4:
1527 read_sdword(info, &op->imm, *address);
1528 break;
1529
1530 default:
1531 op->imm = 0;
1532 fprintf(stderr, "Internal error: Unexpected immediate byte "
1533 "size %d.\n", op->size);
1534 }
1535
1536 *address += op->size;
1537 }
1538
1539 // 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)1540 static void bit_move_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1541 {
1542 static const m680x_reg m680x_reg[] = {
1543 M680X_REG_CC, M680X_REG_A, M680X_REG_B, M680X_REG_INVALID,
1544 };
1545
1546 uint8_t post_byte = 0;
1547 cs_m680x *m680x = &info->m680x;
1548 cs_m680x_op *op;
1549
1550 read_byte(info, &post_byte, *address);
1551 (*address)++;
1552
1553 // operand[0] = register
1554 add_reg_operand(info, m680x_reg[post_byte >> 6]);
1555
1556 // operand[1] = bit index in source operand
1557 op = &m680x->operands[m680x->op_count++];
1558 op->type = M680X_OP_CONSTANT;
1559 op->const_val = (post_byte >> 3) & 0x07;
1560
1561 // operand[2] = bit index in destination operand
1562 op = &m680x->operands[m680x->op_count++];
1563 op->type = M680X_OP_CONSTANT;
1564 op->const_val = post_byte & 0x07;
1565
1566 direct_hdlr(MI, info, address);
1567 }
1568
1569 // handler for TFM instruction, e.g: TFM X+,Y+ Used by HD6309
tfm_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1570 static void tfm_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1571 {
1572 static const uint8_t inc_dec_r0[] = {
1573 1, -1, 1, 0,
1574 };
1575 static const uint8_t inc_dec_r1[] = {
1576 1, -1, 0, 1,
1577 };
1578 uint8_t regs = 0;
1579 uint8_t index = (MI->Opcode & 0xff) - 0x38;
1580
1581 read_byte(info, ®s, *address);
1582
1583 add_indexed_operand(info, g_tfr_exg_reg_ids[regs >> 4], true,
1584 inc_dec_r0[index], M680X_OFFSET_NONE, 0, true);
1585 add_indexed_operand(info, g_tfr_exg_reg_ids[regs & 0x0f], true,
1586 inc_dec_r1[index], M680X_OFFSET_NONE, 0, true);
1587
1588 add_reg_to_rw_list(MI, M680X_REG_W, READ | WRITE);
1589 }
1590
opidx_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1591 static void opidx_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1592 {
1593 cs_m680x *m680x = &info->m680x;
1594 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1595
1596 // bit index is coded in Opcode
1597 op->type = M680X_OP_CONSTANT;
1598 op->const_val = (MI->Opcode & 0x0e) >> 1;
1599 }
1600
1601 // handler for bit test and branch instruction. Used by M6805.
1602 // The bit index is part of the opcode.
1603 // Example: BRSET 3,<$40,LOOP
opidx_dir_rel_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1604 static void opidx_dir_rel_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1605 {
1606 cs_m680x *m680x = &info->m680x;
1607 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1608
1609 // bit index is coded in Opcode
1610 op->type = M680X_OP_CONSTANT;
1611 op->const_val = (MI->Opcode & 0x0e) >> 1;
1612 direct_hdlr(MI, info, address);
1613 relative8_hdlr(MI, info, address);
1614
1615 add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1616 }
1617
indexedX0_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1618 static void indexedX0_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1619 {
1620 add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_NONE,
1621 0, false);
1622 }
1623
indexedX16_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1624 static void indexedX16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1625 {
1626 uint16_t offset = 0;
1627
1628 read_word(info, &offset, *address);
1629 *address += 2;
1630 add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_16,
1631 offset, false);
1632 }
1633
imm_rel_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1634 static void imm_rel_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1635 {
1636 immediate_hdlr(MI, info, address);
1637 relative8_hdlr(MI, info, address);
1638 }
1639
indexedS_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1640 static void indexedS_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1641 {
1642 uint8_t offset = 0;
1643
1644 read_byte(info, &offset, (*address)++);
1645
1646 add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_8,
1647 (uint16_t)offset, false);
1648 }
1649
indexedS16_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1650 static void indexedS16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1651 {
1652 uint16_t offset = 0;
1653
1654 read_word(info, &offset, *address);
1655 address += 2;
1656
1657 add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_16,
1658 offset, false);
1659 }
1660
indexedX0p_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1661 static void indexedX0p_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1662 {
1663 add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_NONE,
1664 0, true);
1665 }
1666
indexedXp_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1667 static void indexedXp_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1668 {
1669 uint8_t offset = 0;
1670
1671 read_byte(info, &offset, (*address)++);
1672
1673 add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_BITS_8,
1674 (uint16_t)offset, false);
1675 }
1676
imm_idx12_x_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1677 static void imm_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1678 {
1679 cs_m680x *m680x = &info->m680x;
1680 cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1681
1682 indexed12_hdlr(MI, info, address);
1683 op->type = M680X_OP_IMMEDIATE;
1684
1685 if (info->insn == M680X_INS_MOVW) {
1686 uint16_t imm16 = 0;
1687
1688 read_word(info, &imm16, *address);
1689 op->imm = (int16_t)imm16;
1690 op->size = 2;
1691 }
1692 else {
1693 uint8_t imm8 = 0;
1694
1695 read_byte(info, &imm8, *address);
1696 op->imm = (int8_t)imm8;
1697 op->size = 1;
1698 }
1699
1700 set_operand_size(info, op, 1);
1701 }
1702
ext_idx12_x_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1703 static void ext_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1704 {
1705 cs_m680x *m680x = &info->m680x;
1706 cs_m680x_op *op0 = &m680x->operands[m680x->op_count++];
1707 uint16_t imm16 = 0;
1708
1709 indexed12_hdlr(MI, info, address);
1710 read_word(info, &imm16, *address);
1711 op0->type = M680X_OP_EXTENDED;
1712 op0->ext.address = (int16_t)imm16;
1713 set_operand_size(info, op0, 1);
1714 }
1715
1716 // handler for CPU12 DBEQ/DNBE/IBEQ/IBNE/TBEQ/TBNE instructions.
1717 // Example: DBNE X,$1000
loop_hdlr(MCInst * MI,m680x_info * info,uint16_t * address)1718 static void loop_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1719 {
1720 static const m680x_reg index_to_reg_id[] = {
1721 M680X_REG_A, M680X_REG_B, M680X_REG_INVALID, M680X_REG_INVALID,
1722 M680X_REG_D, M680X_REG_X, M680X_REG_Y, M680X_REG_S,
1723 };
1724 static const m680x_insn index_to_insn_id[] = {
1725 M680X_INS_DBEQ, M680X_INS_DBNE, M680X_INS_TBEQ, M680X_INS_TBNE,
1726 M680X_INS_IBEQ, M680X_INS_IBNE, M680X_INS_ILLGL, M680X_INS_ILLGL
1727 };
1728 cs_m680x *m680x = &info->m680x;
1729 uint8_t post_byte = 0;
1730 uint8_t rel = 0;
1731 cs_m680x_op *op;
1732
1733 read_byte(info, &post_byte, (*address)++);
1734
1735 info->insn = index_to_insn_id[(post_byte >> 5) & 0x07];
1736
1737 if (info->insn == M680X_INS_ILLGL) {
1738 fprintf(stderr, "Internal error: Unexpected post byte "
1739 "in loop instruction %02X.\n", post_byte);
1740 illegal_hdlr(MI, info, address);
1741 };
1742
1743 read_byte(info, &rel, (*address)++);
1744
1745 add_reg_operand(info, index_to_reg_id[post_byte & 0x07]);
1746
1747 op = &m680x->operands[m680x->op_count++];
1748
1749 op->type = M680X_OP_RELATIVE;
1750
1751 op->rel.offset = (post_byte & 0x10) ? 0xff00 | rel : rel;
1752
1753 op->rel.address = *address + op->rel.offset;
1754
1755 add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1756 }
1757
1758 static void (*const g_insn_handler[])(MCInst *, m680x_info *, uint16_t *) = {
1759 illegal_hdlr,
1760 relative8_hdlr,
1761 relative16_hdlr,
1762 immediate_hdlr, // 8-bit
1763 immediate_hdlr, // 16-bit
1764 immediate_hdlr, // 32-bit
1765 direct_hdlr,
1766 extended_hdlr,
1767 indexedX_hdlr,
1768 indexedY_hdlr,
1769 indexed09_hdlr,
1770 inherent_hdlr,
1771 reg_reg09_hdlr,
1772 reg_bits_hdlr,
1773 bit_move_hdlr,
1774 tfm_hdlr,
1775 opidx_hdlr,
1776 opidx_dir_rel_hdlr,
1777 indexedX0_hdlr,
1778 indexedX16_hdlr,
1779 imm_rel_hdlr,
1780 indexedS_hdlr,
1781 indexedS16_hdlr,
1782 indexedXp_hdlr,
1783 indexedX0p_hdlr,
1784 indexed12_hdlr,
1785 indexed12_hdlr, // subset of indexed12
1786 reg_reg12_hdlr,
1787 loop_hdlr,
1788 index_hdlr,
1789 imm_idx12_x_hdlr,
1790 imm_idx12_x_hdlr,
1791 ext_idx12_x_hdlr,
1792 }; /* handler function pointers */
1793
1794 /* Disasemble one instruction at address and store in str_buff */
m680x_disassemble(MCInst * MI,m680x_info * info,uint16_t address)1795 static unsigned int m680x_disassemble(MCInst *MI, m680x_info *info,
1796 uint16_t address)
1797 {
1798 cs_m680x *m680x = &info->m680x;
1799 cs_detail *detail = MI->flat_insn->detail;
1800 uint16_t base_address = address;
1801 insn_desc insn_description;
1802 e_access_mode access_mode;
1803
1804 if (detail != NULL) {
1805 memset(detail, 0, offsetof(cs_detail, m680x)+sizeof(cs_m680x));
1806 }
1807
1808 memset(&insn_description, 0, sizeof(insn_description));
1809 memset(m680x, 0, sizeof(*m680x));
1810 info->insn_size = 1;
1811
1812 if (decode_insn(info, address, &insn_description)) {
1813 m680x_reg reg;
1814
1815 if (insn_description.opcode > 0xff)
1816 address += 2; // 8-bit opcode + page prefix
1817 else
1818 address++; // 8-bit opcode only
1819
1820 info->insn = insn_description.insn;
1821
1822 MCInst_setOpcode(MI, insn_description.opcode);
1823
1824 reg = g_insn_props[info->insn].reg0;
1825
1826 if (reg != M680X_REG_INVALID) {
1827 if (reg == M680X_REG_HX &&
1828 (!info->cpu->reg_byte_size[reg]))
1829 reg = M680X_REG_X;
1830
1831 add_reg_operand(info, reg);
1832 // First (or second) operand is a register which is
1833 // part of the mnemonic
1834 m680x->flags |= M680X_FIRST_OP_IN_MNEM;
1835 reg = g_insn_props[info->insn].reg1;
1836
1837 if (reg != M680X_REG_INVALID) {
1838 if (reg == M680X_REG_HX &&
1839 (!info->cpu->reg_byte_size[reg]))
1840 reg = M680X_REG_X;
1841
1842 add_reg_operand(info, reg);
1843 m680x->flags |= M680X_SECOND_OP_IN_MNEM;
1844 }
1845 }
1846
1847 // Call addressing mode specific instruction handler
1848 (g_insn_handler[insn_description.hid[0]])(MI, info,
1849 &address);
1850 (g_insn_handler[insn_description.hid[1]])(MI, info,
1851 &address);
1852
1853 add_insn_group(detail, g_insn_props[info->insn].group);
1854
1855 if (g_insn_props[info->insn].cc_modified &&
1856 (info->cpu->insn_cc_not_modified[0] != info->insn) &&
1857 (info->cpu->insn_cc_not_modified[1] != info->insn))
1858 add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1859
1860 access_mode = g_insn_props[info->insn].access_mode;
1861
1862 // Fix for M6805 BSET/BCLR. It has a differnt operand order
1863 // in comparison to the M6811
1864 if ((info->cpu->insn_cc_not_modified[0] == info->insn) ||
1865 (info->cpu->insn_cc_not_modified[1] == info->insn))
1866 access_mode = rmmm;
1867
1868 build_regs_read_write_counts(MI, info, access_mode);
1869 add_operators_access(MI, info, access_mode);
1870
1871 if (g_insn_props[info->insn].update_reg_access)
1872 set_changed_regs_read_write_counts(MI, info);
1873
1874 info->insn_size = insn_description.insn_size;
1875
1876 return info->insn_size;
1877 }
1878 else
1879 MCInst_setOpcode(MI, insn_description.opcode);
1880
1881 // Illegal instruction
1882 address = base_address;
1883 illegal_hdlr(MI, info, &address);
1884 return 1;
1885 }
1886
1887 // Tables to get the byte size of a register on the CPU
1888 // based on an enum m680x_reg value.
1889 // Invalid registers return 0.
1890 static const uint8_t g_m6800_reg_byte_size[22] = {
1891 // A B E F 0 D W CC DP MD HX H X Y S U V Q PC T2 T3
1892 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 0, 0
1893 };
1894
1895 static const uint8_t g_m6805_reg_byte_size[22] = {
1896 // A B E F 0 D W CC DP MD HX H X Y S U V Q PC T2 T3
1897 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 2, 0, 0
1898 };
1899
1900 static const uint8_t g_m6808_reg_byte_size[22] = {
1901 // A B E F 0 D W CC DP MD HX H X Y S U V Q PC T2 T3
1902 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 1, 1, 0, 2, 0, 0, 0, 2, 0, 0
1903 };
1904
1905 static const uint8_t g_m6801_reg_byte_size[22] = {
1906 // A B E F 0 D W CC DP MD HX H X Y S U V Q PC T2 T3
1907 0, 1, 1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 0, 0
1908 };
1909
1910 static const uint8_t g_m6811_reg_byte_size[22] = {
1911 // A B E F 0 D W CC DP MD HX H X Y S U V Q PC T2 T3
1912 0, 1, 1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 2, 0, 0
1913 };
1914
1915 static const uint8_t g_cpu12_reg_byte_size[22] = {
1916 // A B E F 0 D W CC DP MD HX H X Y S U V Q PC T2 T3
1917 0, 1, 1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 2, 2, 2
1918 };
1919
1920 static const uint8_t g_m6809_reg_byte_size[22] = {
1921 // A B E F 0 D W CC DP MD HX H X Y S U V Q PC T2 T3
1922 0, 1, 1, 0, 0, 0, 2, 0, 1, 1, 0, 0, 0, 2, 2, 2, 2, 0, 0, 2, 0, 0
1923 };
1924
1925 static const uint8_t g_hd6309_reg_byte_size[22] = {
1926 // A B E F 0 D W CC DP MD HX H X Y S U V Q PC T2 T3
1927 0, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 0, 0, 2, 2, 2, 2, 2, 4, 2, 0, 0
1928 };
1929
1930 // Table to check for a valid register nibble on the M6809 CPU
1931 // used for TFR and EXG instruction.
1932 static const bool m6809_tfr_reg_valid[16] = {
1933 true, true, true, true, true, true, false, false,
1934 true, true, true, true, false, false, false, false,
1935 };
1936
1937 static const cpu_tables g_cpu_tables[] = {
1938 {
1939 // M680X_CPU_TYPE_INVALID
1940 NULL,
1941 { NULL, NULL },
1942 { 0, 0 },
1943 { 0x00, 0x00, 0x00 },
1944 { NULL, NULL, NULL },
1945 { 0, 0, 0 },
1946 NULL,
1947 NULL,
1948 { M680X_INS_INVLD, M680X_INS_INVLD }
1949 },
1950 {
1951 // M680X_CPU_TYPE_6301
1952 &g_m6800_inst_page1_table[0],
1953 { &g_m6801_inst_overlay_table[0], &g_hd6301_inst_overlay_table[0] },
1954 {
1955 ARR_SIZE(g_m6801_inst_overlay_table),
1956 ARR_SIZE(g_hd6301_inst_overlay_table)
1957 },
1958 { 0x00, 0x00, 0x00 },
1959 { NULL, NULL, NULL },
1960 { 0, 0, 0 },
1961 &g_m6801_reg_byte_size[0],
1962 NULL,
1963 { M680X_INS_INVLD, M680X_INS_INVLD }
1964 },
1965 {
1966 // M680X_CPU_TYPE_6309
1967 &g_m6809_inst_page1_table[0],
1968 { &g_hd6309_inst_overlay_table[0], NULL },
1969 { ARR_SIZE(g_hd6309_inst_overlay_table), 0 },
1970 { 0x10, 0x11, 0x00 },
1971 { &g_hd6309_inst_page2_table[0], &g_hd6309_inst_page3_table[0], NULL },
1972 {
1973 ARR_SIZE(g_hd6309_inst_page2_table),
1974 ARR_SIZE(g_hd6309_inst_page3_table),
1975 0
1976 },
1977 &g_hd6309_reg_byte_size[0],
1978 NULL,
1979 { M680X_INS_INVLD, M680X_INS_INVLD }
1980 },
1981 {
1982 // M680X_CPU_TYPE_6800
1983 &g_m6800_inst_page1_table[0],
1984 { NULL, NULL },
1985 { 0, 0 },
1986 { 0x00, 0x00, 0x00 },
1987 { NULL, NULL, NULL },
1988 { 0, 0, 0 },
1989 &g_m6800_reg_byte_size[0],
1990 NULL,
1991 { M680X_INS_INVLD, M680X_INS_INVLD }
1992 },
1993 {
1994 // M680X_CPU_TYPE_6801
1995 &g_m6800_inst_page1_table[0],
1996 { &g_m6801_inst_overlay_table[0], NULL },
1997 { ARR_SIZE(g_m6801_inst_overlay_table), 0 },
1998 { 0x00, 0x00, 0x00 },
1999 { NULL, NULL, NULL },
2000 { 0, 0, 0 },
2001 &g_m6801_reg_byte_size[0],
2002 NULL,
2003 { M680X_INS_INVLD, M680X_INS_INVLD }
2004 },
2005 {
2006 // M680X_CPU_TYPE_6805
2007 &g_m6805_inst_page1_table[0],
2008 { NULL, NULL },
2009 { 0, 0 },
2010 { 0x00, 0x00, 0x00 },
2011 { NULL, NULL, NULL },
2012 { 0, 0, 0 },
2013 &g_m6805_reg_byte_size[0],
2014 NULL,
2015 { M680X_INS_BCLR, M680X_INS_BSET }
2016 },
2017 {
2018 // M680X_CPU_TYPE_6808
2019 &g_m6805_inst_page1_table[0],
2020 { &g_m6808_inst_overlay_table[0], NULL },
2021 { ARR_SIZE(g_m6808_inst_overlay_table), 0 },
2022 { 0x9E, 0x00, 0x00 },
2023 { &g_m6808_inst_page2_table[0], NULL, NULL },
2024 { ARR_SIZE(g_m6808_inst_page2_table), 0, 0 },
2025 &g_m6808_reg_byte_size[0],
2026 NULL,
2027 { M680X_INS_BCLR, M680X_INS_BSET }
2028 },
2029 {
2030 // M680X_CPU_TYPE_6809
2031 &g_m6809_inst_page1_table[0],
2032 { NULL, NULL },
2033 { 0, 0 },
2034 { 0x10, 0x11, 0x00 },
2035 {
2036 &g_m6809_inst_page2_table[0],
2037 &g_m6809_inst_page3_table[0],
2038 NULL
2039 },
2040 {
2041 ARR_SIZE(g_m6809_inst_page2_table),
2042 ARR_SIZE(g_m6809_inst_page3_table),
2043 0
2044 },
2045 &g_m6809_reg_byte_size[0],
2046 &m6809_tfr_reg_valid[0],
2047 { M680X_INS_INVLD, M680X_INS_INVLD }
2048 },
2049 {
2050 // M680X_CPU_TYPE_6811
2051 &g_m6800_inst_page1_table[0],
2052 {
2053 &g_m6801_inst_overlay_table[0],
2054 &g_m6811_inst_overlay_table[0]
2055 },
2056 {
2057 ARR_SIZE(g_m6801_inst_overlay_table),
2058 ARR_SIZE(g_m6811_inst_overlay_table)
2059 },
2060 { 0x18, 0x1A, 0xCD },
2061 {
2062 &g_m6811_inst_page2_table[0],
2063 &g_m6811_inst_page3_table[0],
2064 &g_m6811_inst_page4_table[0]
2065 },
2066 {
2067 ARR_SIZE(g_m6811_inst_page2_table),
2068 ARR_SIZE(g_m6811_inst_page3_table),
2069 ARR_SIZE(g_m6811_inst_page4_table)
2070 },
2071 &g_m6811_reg_byte_size[0],
2072 NULL,
2073 { M680X_INS_INVLD, M680X_INS_INVLD }
2074 },
2075 {
2076 // M680X_CPU_TYPE_CPU12
2077 &g_cpu12_inst_page1_table[0],
2078 { NULL, NULL },
2079 { 0, 0 },
2080 { 0x18, 0x00, 0x00 },
2081 { &g_cpu12_inst_page2_table[0], NULL, NULL },
2082 { ARR_SIZE(g_cpu12_inst_page2_table), 0, 0 },
2083 &g_cpu12_reg_byte_size[0],
2084 NULL,
2085 { M680X_INS_INVLD, M680X_INS_INVLD }
2086 },
2087 {
2088 // M680X_CPU_TYPE_HCS08
2089 &g_m6805_inst_page1_table[0],
2090 {
2091 &g_m6808_inst_overlay_table[0],
2092 &g_hcs08_inst_overlay_table[0]
2093 },
2094 {
2095 ARR_SIZE(g_m6808_inst_overlay_table),
2096 ARR_SIZE(g_hcs08_inst_overlay_table)
2097 },
2098 { 0x9E, 0x00, 0x00 },
2099 { &g_hcs08_inst_page2_table[0], NULL, NULL },
2100 { ARR_SIZE(g_hcs08_inst_page2_table), 0, 0 },
2101 &g_m6808_reg_byte_size[0],
2102 NULL,
2103 { M680X_INS_BCLR, M680X_INS_BSET }
2104 },
2105 };
2106
2107 static const char *s_cpu_type[] = {
2108 "INVALID", "6301", "6309", "6800", "6801", "6805", "6808",
2109 "6809", "6811", "CPU12", "HCS08",
2110 };
2111
m680x_setup_internals(m680x_info * info,e_cpu_type cpu_type,uint16_t address,const uint8_t * code,uint16_t code_len)2112 static bool m680x_setup_internals(m680x_info *info, e_cpu_type cpu_type,
2113 uint16_t address,
2114 const uint8_t *code, uint16_t code_len)
2115 {
2116 if (cpu_type == M680X_CPU_TYPE_INVALID) {
2117 fprintf(stderr, "M680X_CPU_TYPE_%s is not suppported\n",
2118 s_cpu_type[cpu_type]);
2119 return false;
2120 }
2121
2122 info->code = code;
2123 info->size = code_len;
2124 info->offset = address;
2125 info->cpu_type = cpu_type;
2126
2127 info->cpu = &g_cpu_tables[info->cpu_type];
2128
2129 return true;
2130 }
2131
M680X_getInstruction(csh ud,const uint8_t * code,size_t code_len,MCInst * MI,uint16_t * size,uint64_t address,void * inst_info)2132 bool M680X_getInstruction(csh ud, const uint8_t *code, size_t code_len,
2133 MCInst *MI, uint16_t *size, uint64_t address, void *inst_info)
2134 {
2135 unsigned int insn_size = 0;
2136 e_cpu_type cpu_type = M680X_CPU_TYPE_INVALID; // No default CPU type
2137 cs_struct *handle = (cs_struct *)ud;
2138 m680x_info *info = (m680x_info *)handle->printer_info;
2139
2140 MCInst_clear(MI);
2141
2142 if (handle->mode & CS_MODE_M680X_6800)
2143 cpu_type = M680X_CPU_TYPE_6800;
2144
2145 else if (handle->mode & CS_MODE_M680X_6801)
2146 cpu_type = M680X_CPU_TYPE_6801;
2147
2148 else if (handle->mode & CS_MODE_M680X_6805)
2149 cpu_type = M680X_CPU_TYPE_6805;
2150
2151 else if (handle->mode & CS_MODE_M680X_6808)
2152 cpu_type = M680X_CPU_TYPE_6808;
2153
2154 else if (handle->mode & CS_MODE_M680X_HCS08)
2155 cpu_type = M680X_CPU_TYPE_HCS08;
2156
2157 else if (handle->mode & CS_MODE_M680X_6809)
2158 cpu_type = M680X_CPU_TYPE_6809;
2159
2160 else if (handle->mode & CS_MODE_M680X_6301)
2161 cpu_type = M680X_CPU_TYPE_6301;
2162
2163 else if (handle->mode & CS_MODE_M680X_6309)
2164 cpu_type = M680X_CPU_TYPE_6309;
2165
2166 else if (handle->mode & CS_MODE_M680X_6811)
2167 cpu_type = M680X_CPU_TYPE_6811;
2168
2169 else if (handle->mode & CS_MODE_M680X_CPU12)
2170 cpu_type = M680X_CPU_TYPE_CPU12;
2171
2172 if (cpu_type != M680X_CPU_TYPE_INVALID &&
2173 m680x_setup_internals(info, cpu_type, (uint16_t)address, code,
2174 code_len))
2175 insn_size = m680x_disassemble(MI, info, (uint16_t)address);
2176
2177 if (insn_size == 0) {
2178 *size = 1;
2179 return false;
2180 }
2181
2182 // Make sure we always stay within range
2183 if (insn_size > code_len) {
2184 *size = (uint16_t)code_len;
2185 return false;
2186 }
2187 else
2188 *size = (uint16_t)insn_size;
2189
2190 return true;
2191 }
2192
M680X_disassembler_init(cs_struct * ud)2193 cs_err M680X_disassembler_init(cs_struct *ud)
2194 {
2195 if (M680X_REG_ENDING != ARR_SIZE(g_m6800_reg_byte_size)) {
2196 fprintf(stderr, "Internal error: Size mismatch in enum "
2197 "m680x_reg and g_m6800_reg_byte_size\n");
2198
2199 return CS_ERR_MODE;
2200 }
2201
2202 if (M680X_REG_ENDING != ARR_SIZE(g_m6801_reg_byte_size)) {
2203 fprintf(stderr, "Internal error: Size mismatch in enum "
2204 "m680x_reg and g_m6801_reg_byte_size\n");
2205
2206 return CS_ERR_MODE;
2207 }
2208
2209 if (M680X_REG_ENDING != ARR_SIZE(g_m6805_reg_byte_size)) {
2210 fprintf(stderr, "Internal error: Size mismatch in enum "
2211 "m680x_reg and g_m6805_reg_byte_size\n");
2212
2213 return CS_ERR_MODE;
2214 }
2215
2216 if (M680X_REG_ENDING != ARR_SIZE(g_m6808_reg_byte_size)) {
2217 fprintf(stderr, "Internal error: Size mismatch in enum "
2218 "m680x_reg and g_m6808_reg_byte_size\n");
2219
2220 return CS_ERR_MODE;
2221 }
2222
2223 if (M680X_REG_ENDING != ARR_SIZE(g_m6811_reg_byte_size)) {
2224 fprintf(stderr, "Internal error: Size mismatch in enum "
2225 "m680x_reg and g_m6811_reg_byte_size\n");
2226
2227 return CS_ERR_MODE;
2228 }
2229
2230 if (M680X_REG_ENDING != ARR_SIZE(g_cpu12_reg_byte_size)) {
2231 fprintf(stderr, "Internal error: Size mismatch in enum "
2232 "m680x_reg and g_cpu12_reg_byte_size\n");
2233
2234 return CS_ERR_MODE;
2235 }
2236
2237 if (M680X_REG_ENDING != ARR_SIZE(g_m6809_reg_byte_size)) {
2238 fprintf(stderr, "Internal error: Size mismatch in enum "
2239 "m680x_reg and g_m6809_reg_byte_size\n");
2240
2241 return CS_ERR_MODE;
2242 }
2243
2244 if (M680X_INS_ENDING != ARR_SIZE(g_insn_props)) {
2245 fprintf(stderr, "Internal error: Size mismatch in enum "
2246 "m680x_insn and g_insn_props\n");
2247
2248 return CS_ERR_MODE;
2249 }
2250
2251 if (M680X_CPU_TYPE_ENDING != ARR_SIZE(s_cpu_type)) {
2252 fprintf(stderr, "Internal error: Size mismatch in enum "
2253 "e_cpu_type and s_cpu_type\n");
2254
2255 return CS_ERR_MODE;
2256 }
2257
2258 if (M680X_CPU_TYPE_ENDING != ARR_SIZE(g_cpu_tables)) {
2259 fprintf(stderr, "Internal error: Size mismatch in enum "
2260 "e_cpu_type and g_cpu_tables\n");
2261
2262 return CS_ERR_MODE;
2263 }
2264
2265 if (HANDLER_ID_ENDING != ARR_SIZE(g_insn_handler)) {
2266 fprintf(stderr, "Internal error: Size mismatch in enum "
2267 "insn_hdlr_id and g_insn_handler\n");
2268
2269 return CS_ERR_MODE;
2270 }
2271
2272 if (ACCESS_MODE_ENDING != MATRIX_SIZE(g_access_mode_to_access)) {
2273 fprintf(stderr, "Internal error: Size mismatch in enum "
2274 "e_access_mode and g_access_mode_to_access\n");
2275
2276 return CS_ERR_MODE;
2277 }
2278
2279 return CS_ERR_OK;
2280 }
2281
2282 #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)2283 void M680X_reg_access(const cs_insn *insn,
2284 cs_regs regs_read, uint8_t *regs_read_count,
2285 cs_regs regs_write, uint8_t *regs_write_count)
2286 {
2287 if (insn->detail == NULL) {
2288 *regs_read_count = 0;
2289 *regs_write_count = 0;
2290 }
2291 else {
2292 *regs_read_count = insn->detail->regs_read_count;
2293 *regs_write_count = insn->detail->regs_write_count;
2294
2295 memcpy(regs_read, insn->detail->regs_read,
2296 *regs_read_count * sizeof(insn->detail->regs_read[0]));
2297 memcpy(regs_write, insn->detail->regs_write,
2298 *regs_write_count *
2299 sizeof(insn->detail->regs_write[0]));
2300 }
2301 }
2302 #endif
2303
2304 #endif
2305
2306