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, &reg_bits, (*address)++);
1075 
1076 	switch (op0->reg) {
1077 	case M680X_REG_U:
1078 		reg_to_reg_ids = &reg_u_reg_ids[0];
1079 		break;
1080 
1081 	case M680X_REG_S:
1082 		reg_to_reg_ids = &reg_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, &regs, (*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, &regs, (*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, &regs, *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->imm = (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