Coverage Report

Created: 2024-08-21 06:24

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