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, &reg_bits, (*address)++);
1096 
1097 	switch (op0->reg) {
1098 	case M680X_REG_U:
1099 		reg_to_reg_ids = &reg_u_reg_ids[0];
1100 		break;
1101 
1102 	case M680X_REG_S:
1103 		reg_to_reg_ids = &reg_s_reg_ids[0];
1104 		break;
1105 
1106 	default:
1107 		CS_ASSERT(0 && "Unexpected operand0 register");
1108 		break;
1109 	}
1110 
1111 	if ((info->insn == M680X_INS_PULU ||
1112 			(info->insn == M680X_INS_PULS)) &&
1113 		((reg_bits & 0x80) != 0))
1114 		// PULS xxx,PC or PULU xxx,PC which is like return from
1115 		// subroutine (RTS)
1116 		add_insn_group(MI->flat_insn->detail, M680X_GRP_RET);
1117 
1118 	for (bit_index = 0; bit_index < 8; ++bit_index) {
1119 		if (reg_bits & (1 << bit_index))
1120 			add_reg_operand(info, reg_to_reg_ids[bit_index]);
1121 	}
1122 }
1123 
1124 static const m680x_reg g_tfr_exg_reg_ids[] = {
1125 	/* 16-bit registers */
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, &regs, (*address)++);
1138 
1139 	add_reg_operand(info, g_tfr_exg_reg_ids[regs >> 4]);
1140 	add_reg_operand(info, g_tfr_exg_reg_ids[regs & 0x0f]);
1141 
1142 	if ((regs & 0x0f) == 0x05) {
1143 		// EXG xxx,PC or TFR xxx,PC which is like a JMP
1144 		add_insn_group(MI->flat_insn->detail, M680X_GRP_JUMP);
1145 	}
1146 }
1147 
1148 
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, &regs, (*address)++);
1162 
1163 	// The opcode of this instruction depends on
1164 	// the msb of its post byte.
1165 	if (regs & 0x80)
1166 		info->insn = M680X_INS_EXG;
1167 	else
1168 		info->insn = M680X_INS_TFR;
1169 
1170 	add_reg_operand(info, g_tfr_exg12_reg0_ids[(regs >> 4) & 0x07]);
1171 	add_reg_operand(info, g_tfr_exg12_reg1_ids[regs & 0x07]);
1172 }
1173 
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, &regs, *address);
1601 
1602 	add_indexed_operand(info, g_tfr_exg_reg_ids[regs >> 4], true,
1603 		inc_dec_r0[index], M680X_OFFSET_NONE, 0, true);
1604 	add_indexed_operand(info, g_tfr_exg_reg_ids[regs & 0x0f], true,
1605 		inc_dec_r1[index], M680X_OFFSET_NONE, 0, true);
1606 
1607 	add_reg_to_rw_list(MI, M680X_REG_W, READ | WRITE);
1608 }
1609 
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