Coverage Report

Created: 2025-10-12 06:32

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