Coverage Report

Created: 2025-07-18 06:43

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