Coverage Report

Created: 2025-10-10 06:20

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
60.8k
#define READ CS_AC_READ
109
66.3k
#define WRITE CS_AC_WRITE
110
75.8k
#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
137k
{
156
137k
  if (address < info->offset ||
157
137k
      (uint32_t)(address - info->offset) >= info->size)
158
    // out of code buffer range
159
361
    return false;
160
161
137k
  *byte = info->code[address - info->offset];
162
163
137k
  return true;
164
137k
}
165
166
static bool read_byte_sign_extended(const m680x_info *info, int16_t *word,
167
            uint16_t address)
168
7.80k
{
169
7.80k
  if (address < info->offset ||
170
7.80k
      (uint32_t)(address - info->offset) >= info->size)
171
    // out of code buffer range
172
0
    return false;
173
174
7.80k
  *word = (int16_t)info->code[address - info->offset];
175
176
7.80k
  if (*word & 0x80)
177
2.49k
    *word |= 0xFF00;
178
179
7.80k
  return true;
180
7.80k
}
181
182
static bool read_word(const m680x_info *info, uint16_t *word, uint16_t address)
183
9.20k
{
184
9.20k
  if (address < info->offset ||
185
9.20k
      (uint32_t)(address + 1 - info->offset) >= info->size)
186
    // out of code buffer range
187
6
    return false;
188
189
9.20k
  *word = (uint16_t)info->code[address - info->offset] << 8;
190
9.20k
  *word |= (uint16_t)info->code[address + 1 - info->offset];
191
192
9.20k
  return true;
193
9.20k
}
194
195
static bool read_sdword(const m680x_info *info, int32_t *sdword,
196
      uint16_t address)
197
169
{
198
169
  if (address < info->offset ||
199
169
      (uint32_t)(address + 3 - info->offset) >= info->size)
200
    // out of code buffer range
201
0
    return false;
202
203
169
  *sdword = (uint32_t)info->code[address - info->offset] << 24;
204
169
  *sdword |= (uint32_t)info->code[address + 1 - info->offset] << 16;
205
169
  *sdword |= (uint32_t)info->code[address + 2 - info->offset] << 8;
206
169
  *sdword |= (uint32_t)info->code[address + 3 - info->offset];
207
208
169
  return true;
209
169
}
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
26.6k
{
218
  // As part of the algorithm last may get negative.
219
  // => signed integer has to be used.
220
26.6k
  int first = 0;
221
26.6k
  int last = (int)table_size - 1;
222
26.6k
  int middle = (first + last) / 2;
223
224
125k
  while (first <= last) {
225
114k
    if (inst_pageX_table[middle].opcode < opcode) {
226
39.6k
      first = middle + 1;
227
74.7k
    } else if (inst_pageX_table[middle].opcode == opcode) {
228
15.9k
      return middle; /* item found */
229
15.9k
    } else
230
58.8k
      last = middle - 1;
231
232
98.5k
    middle = (first + last) / 2;
233
98.5k
  }
234
235
10.7k
  if (first > last)
236
10.7k
    return -1; /* item not found */
237
238
0
  return -2;
239
10.7k
}
240
241
void M680X_get_insn_id(cs_struct *handle, cs_insn *insn, unsigned int id)
242
53.2k
{
243
53.2k
  const m680x_info *const info = (const m680x_info *)handle->printer_info;
244
53.2k
  const cpu_tables *cpu = info->cpu;
245
53.2k
  uint8_t insn_prefix = (id >> 8) & 0xff;
246
  // opcode is the first instruction byte without the prefix.
247
53.2k
  uint8_t opcode = id & 0xff;
248
53.2k
  int index;
249
53.2k
  int i;
250
251
53.2k
  insn->id = M680X_INS_ILLGL;
252
253
129k
  for (i = 0; i < ARR_SIZE(cpu->pageX_prefix); ++i) {
254
126k
    if (cpu->pageX_table_size[i] == 0 ||
255
82.9k
        (cpu->inst_pageX_table[i] == NULL))
256
43.6k
      break;
257
258
82.9k
    if (cpu->pageX_prefix[i] == insn_prefix) {
259
6.62k
      index = binary_search(cpu->inst_pageX_table[i],
260
6.62k
                cpu->pageX_table_size[i], opcode);
261
6.62k
      insn->id =
262
6.62k
        (index >= 0) ?
263
4.32k
          cpu->inst_pageX_table[i][index].insn :
264
6.62k
          M680X_INS_ILLGL;
265
6.62k
      return;
266
6.62k
    }
267
82.9k
  }
268
269
46.6k
  if (insn_prefix != 0)
270
0
    return;
271
272
46.6k
  insn->id = cpu->inst_page1_table[id].insn;
273
274
46.6k
  if (insn->id != M680X_INS_ILLGL)
275
41.0k
    return;
276
277
  // Check if opcode byte is present in an overlay table
278
8.72k
  for (i = 0; i < ARR_SIZE(cpu->overlay_table_size); ++i) {
279
8.52k
    if (cpu->overlay_table_size[i] == 0 ||
280
6.72k
        (cpu->inst_overlay_table[i] == NULL))
281
1.79k
      break;
282
283
6.72k
    if ((index = binary_search(cpu->inst_overlay_table[i],
284
6.72k
             cpu->overlay_table_size[i],
285
6.72k
             opcode)) >= 0) {
286
3.63k
      insn->id = cpu->inst_overlay_table[i][index].insn;
287
3.63k
      return;
288
3.63k
    }
289
6.72k
  }
290
5.63k
}
291
292
static void add_insn_group(cs_detail *detail, m680x_group_type group)
293
50.5k
{
294
50.5k
  if (detail != NULL && (group != M680X_GRP_INVALID) &&
295
12.6k
      (group != M680X_GRP_ENDING))
296
12.6k
    detail->groups[detail->groups_count++] = (uint8_t)group;
297
50.5k
}
298
299
static bool exists_reg_list(uint16_t *regs, uint8_t count, m680x_reg reg)
300
149k
{
301
149k
  uint8_t i;
302
303
262k
  for (i = 0; i < count; ++i) {
304
117k
    if (regs[i] == (uint16_t)reg)
305
4.39k
      return true;
306
117k
  }
307
308
145k
  return false;
309
149k
}
310
311
static void add_reg_to_rw_list(MCInst *MI, m680x_reg reg, e_access access)
312
102k
{
313
102k
  cs_detail *detail = MI->flat_insn->detail;
314
315
102k
  if (detail == NULL || (reg == M680X_REG_INVALID))
316
0
    return;
317
318
102k
  switch (access) {
319
47.9k
  case MODIFY:
320
47.9k
    if (!exists_reg_list(detail->regs_read, detail->regs_read_count,
321
47.9k
             reg))
322
47.0k
      detail->regs_read[detail->regs_read_count++] =
323
47.0k
        (uint16_t)reg;
324
325
    // intentionally fall through
326
327
63.0k
  case WRITE:
328
63.0k
    if (!exists_reg_list(detail->regs_write,
329
63.0k
             detail->regs_write_count, reg))
330
61.7k
      detail->regs_write[detail->regs_write_count++] =
331
61.7k
        (uint16_t)reg;
332
333
63.0k
    break;
334
335
38.9k
  case READ:
336
38.9k
    if (!exists_reg_list(detail->regs_read, detail->regs_read_count,
337
38.9k
             reg))
338
36.7k
      detail->regs_read[detail->regs_read_count++] =
339
36.7k
        (uint16_t)reg;
340
341
38.9k
    break;
342
343
0
  case UNCHANGED:
344
0
  default:
345
0
    break;
346
102k
  }
347
102k
}
348
349
static void update_am_reg_list(MCInst *MI, m680x_info *info, cs_m680x_op *op,
350
             e_access access)
351
74.6k
{
352
74.6k
  if (MI->flat_insn->detail == NULL)
353
0
    return;
354
355
74.6k
  switch (op->type) {
356
35.5k
  case M680X_OP_REGISTER:
357
35.5k
    add_reg_to_rw_list(MI, op->reg, access);
358
35.5k
    break;
359
360
15.1k
  case M680X_OP_INDEXED:
361
15.1k
    add_reg_to_rw_list(MI, op->idx.base_reg, READ);
362
363
15.1k
    if (op->idx.base_reg == M680X_REG_X &&
364
7.15k
        info->cpu->reg_byte_size[M680X_REG_H])
365
2.15k
      add_reg_to_rw_list(MI, M680X_REG_H, READ);
366
367
15.1k
    if (op->idx.offset_reg != M680X_REG_INVALID)
368
1.11k
      add_reg_to_rw_list(MI, op->idx.offset_reg, READ);
369
370
15.1k
    if (op->idx.inc_dec) {
371
2.50k
      add_reg_to_rw_list(MI, op->idx.base_reg, WRITE);
372
373
2.50k
      if (op->idx.base_reg == M680X_REG_X &&
374
1.38k
          info->cpu->reg_byte_size[M680X_REG_H])
375
462
        add_reg_to_rw_list(MI, M680X_REG_H, WRITE);
376
2.50k
    }
377
378
15.1k
    break;
379
380
23.8k
  default:
381
23.8k
    break;
382
74.6k
  }
383
74.6k
}
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
157k
{
458
157k
  int idx = (operator_index > 3) ? 3 : operator_index;
459
460
157k
  return g_access_mode_to_access[idx][access_mode];
461
157k
}
462
463
static void build_regs_read_write_counts(MCInst *MI, m680x_info *info,
464
           e_access_mode access_mode)
465
46.0k
{
466
46.0k
  cs_m680x *m680x = &info->m680x;
467
46.0k
  int i;
468
469
46.0k
  if (MI->flat_insn->detail == NULL || (!m680x->op_count))
470
5.19k
    return;
471
472
115k
  for (i = 0; i < m680x->op_count; ++i) {
473
74.6k
    e_access access = get_access(i, access_mode);
474
74.6k
    update_am_reg_list(MI, info, &m680x->operands[i], access);
475
74.6k
  }
476
40.8k
}
477
478
static void add_operators_access(MCInst *MI, m680x_info *info,
479
         e_access_mode access_mode)
480
46.0k
{
481
46.0k
  cs_m680x *m680x = &info->m680x;
482
46.0k
  int offset = 0;
483
46.0k
  int i;
484
485
46.0k
  if (MI->flat_insn->detail == NULL || (!m680x->op_count) ||
486
40.8k
      (access_mode == uuuu))
487
10.5k
    return;
488
489
104k
  for (i = 0; i < m680x->op_count; ++i) {
490
69.0k
    e_access access;
491
492
    // Ugly fix: MULD has a register operand, an immediate operand
493
    // AND an implicitly changed register W
494
69.0k
    if (info->insn == M680X_INS_MULD && (i == 1))
495
12
      offset = 1;
496
497
69.0k
    access = get_access(i + offset, access_mode);
498
69.0k
    m680x->operands[i].access = access;
499
69.0k
  }
500
35.5k
}
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
4.85k
{
510
  //TABLE
511
267k
#define EOL M680X_REG_INVALID
512
4.85k
  static const insn_to_changed_regs changed_regs[] = {
513
4.85k
    { M680X_INS_BSR, mmmm, { M680X_REG_S, EOL } },
514
4.85k
    { M680X_INS_CALL, mmmm, { M680X_REG_S, EOL } },
515
4.85k
    {
516
4.85k
      M680X_INS_CWAI,
517
4.85k
      mrrr,
518
4.85k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
519
4.85k
        M680X_REG_X, M680X_REG_DP, M680X_REG_D, M680X_REG_CC,
520
4.85k
        EOL },
521
4.85k
    },
522
4.85k
    { M680X_INS_DAA, mrrr, { M680X_REG_A, EOL } },
523
4.85k
    { M680X_INS_DIV,
524
4.85k
      mmrr,
525
4.85k
      { M680X_REG_A, M680X_REG_H, M680X_REG_X, EOL } },
526
4.85k
    { M680X_INS_EDIV,
527
4.85k
      mmrr,
528
4.85k
      { M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL } },
529
4.85k
    { M680X_INS_EDIVS,
530
4.85k
      mmrr,
531
4.85k
      { M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL } },
532
4.85k
    { M680X_INS_EMACS, mrrr, { M680X_REG_X, M680X_REG_Y, EOL } },
533
4.85k
    { M680X_INS_EMAXM, rrrr, { M680X_REG_D, EOL } },
534
4.85k
    { M680X_INS_EMINM, rrrr, { M680X_REG_D, EOL } },
535
4.85k
    { M680X_INS_EMUL, mmrr, { M680X_REG_D, M680X_REG_Y, EOL } },
536
4.85k
    { M680X_INS_EMULS, mmrr, { M680X_REG_D, M680X_REG_Y, EOL } },
537
4.85k
    { M680X_INS_ETBL, wmmm, { M680X_REG_A, M680X_REG_B, EOL } },
538
4.85k
    { M680X_INS_FDIV, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
539
4.85k
    { M680X_INS_IDIV, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
540
4.85k
    { M680X_INS_IDIVS, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
541
4.85k
    { M680X_INS_JSR, mmmm, { M680X_REG_S, EOL } },
542
4.85k
    { M680X_INS_LBSR, mmmm, { M680X_REG_S, EOL } },
543
4.85k
    { M680X_INS_MAXM, rrrr, { M680X_REG_A, EOL } },
544
4.85k
    { M680X_INS_MINM, rrrr, { M680X_REG_A, EOL } },
545
4.85k
    { M680X_INS_MEM,
546
4.85k
      mmrr,
547
4.85k
      { M680X_REG_X, M680X_REG_Y, M680X_REG_A, EOL } },
548
4.85k
    { M680X_INS_MUL, mmmm, { M680X_REG_A, M680X_REG_B, EOL } },
549
4.85k
    { M680X_INS_MULD, mwrr, { M680X_REG_D, M680X_REG_W, EOL } },
550
4.85k
    { M680X_INS_PSHA, rmmm, { M680X_REG_A, M680X_REG_S, EOL } },
551
4.85k
    { M680X_INS_PSHB, rmmm, { M680X_REG_B, M680X_REG_S, EOL } },
552
4.85k
    { M680X_INS_PSHC, rmmm, { M680X_REG_CC, M680X_REG_S, EOL } },
553
4.85k
    { M680X_INS_PSHD, rmmm, { M680X_REG_D, M680X_REG_S, EOL } },
554
4.85k
    { M680X_INS_PSHH, rmmm, { M680X_REG_H, M680X_REG_S, EOL } },
555
4.85k
    { M680X_INS_PSHX, rmmm, { M680X_REG_X, M680X_REG_S, EOL } },
556
4.85k
    { M680X_INS_PSHY, rmmm, { M680X_REG_Y, M680X_REG_S, EOL } },
557
4.85k
    { M680X_INS_PULA, wmmm, { M680X_REG_A, M680X_REG_S, EOL } },
558
4.85k
    { M680X_INS_PULB, wmmm, { M680X_REG_B, M680X_REG_S, EOL } },
559
4.85k
    { M680X_INS_PULC, wmmm, { M680X_REG_CC, M680X_REG_S, EOL } },
560
4.85k
    { M680X_INS_PULD, wmmm, { M680X_REG_D, M680X_REG_S, EOL } },
561
4.85k
    { M680X_INS_PULH, wmmm, { M680X_REG_H, M680X_REG_S, EOL } },
562
4.85k
    { M680X_INS_PULX, wmmm, { M680X_REG_X, M680X_REG_S, EOL } },
563
4.85k
    { M680X_INS_PULY, wmmm, { M680X_REG_Y, M680X_REG_S, EOL } },
564
4.85k
    { M680X_INS_REV,
565
4.85k
      mmrr,
566
4.85k
      { M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL } },
567
4.85k
    { M680X_INS_REVW,
568
4.85k
      mmmm,
569
4.85k
      { M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL } },
570
4.85k
    { M680X_INS_RTC, mwww, { M680X_REG_S, M680X_REG_PC, EOL } },
571
4.85k
    {
572
4.85k
      M680X_INS_RTI,
573
4.85k
      mwww,
574
4.85k
      { M680X_REG_S, M680X_REG_CC, M680X_REG_B, M680X_REG_A,
575
4.85k
        M680X_REG_DP, M680X_REG_X, M680X_REG_Y, M680X_REG_U,
576
4.85k
        M680X_REG_PC, EOL },
577
4.85k
    },
578
4.85k
    { M680X_INS_RTS, mwww, { M680X_REG_S, M680X_REG_PC, EOL } },
579
4.85k
    { M680X_INS_SEX, wrrr, { M680X_REG_A, M680X_REG_B, EOL } },
580
4.85k
    { M680X_INS_SEXW, rwww, { M680X_REG_W, M680X_REG_D, EOL } },
581
4.85k
    { M680X_INS_SWI,
582
4.85k
      mmrr,
583
4.85k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
584
4.85k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
585
4.85k
        M680X_REG_CC, EOL } },
586
4.85k
    {
587
4.85k
      M680X_INS_SWI2,
588
4.85k
      mmrr,
589
4.85k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
590
4.85k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
591
4.85k
        M680X_REG_CC, EOL },
592
4.85k
    },
593
4.85k
    {
594
4.85k
      M680X_INS_SWI3,
595
4.85k
      mmrr,
596
4.85k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
597
4.85k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
598
4.85k
        M680X_REG_CC, EOL },
599
4.85k
    },
600
4.85k
    { M680X_INS_TBL, wrrr, { M680X_REG_A, M680X_REG_B, EOL } },
601
4.85k
    { M680X_INS_WAI,
602
4.85k
      mrrr,
603
4.85k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_X, M680X_REG_A,
604
4.85k
        M680X_REG_B, M680X_REG_CC, EOL } },
605
4.85k
    { M680X_INS_WAV,
606
4.85k
      rmmm,
607
4.85k
      { M680X_REG_A, M680X_REG_B, M680X_REG_X, M680X_REG_Y, EOL } },
608
4.85k
    { M680X_INS_WAVR,
609
4.85k
      rmmm,
610
4.85k
      { M680X_REG_A, M680X_REG_B, M680X_REG_X, M680X_REG_Y, EOL } },
611
4.85k
  };
612
613
4.85k
  int i, j;
614
615
4.85k
  if (MI->flat_insn->detail == NULL)
616
0
    return;
617
618
252k
  for (i = 0; i < ARR_SIZE(changed_regs); ++i) {
619
247k
    if (info->insn == changed_regs[i].insn) {
620
4.85k
      e_access_mode access_mode = changed_regs[i].access_mode;
621
622
19.8k
      for (j = 0; changed_regs[i].regs[j] != EOL; ++j) {
623
15.0k
        e_access access;
624
625
15.0k
        m680x_reg reg = changed_regs[i].regs[j];
626
627
15.0k
        if (!info->cpu->reg_byte_size[reg]) {
628
1.38k
          if (info->insn != M680X_INS_MUL)
629
1.34k
            continue;
630
631
          // Hack for M68HC05: MUL uses reg. A,X
632
36
          reg = M680X_REG_X;
633
36
        }
634
635
13.6k
        access = get_access(j, access_mode);
636
13.6k
        add_reg_to_rw_list(MI, reg, access);
637
13.6k
      }
638
4.85k
    }
639
247k
  }
640
641
4.85k
#undef EOL
642
4.85k
}
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
7.01k
{
657
7.01k
  uint8_t ir = 0;
658
7.01k
  uint8_t post_byte;
659
660
  // Read the indexed addressing post byte.
661
7.01k
  if (!read_byte(info, &post_byte, address))
662
32
    return -1;
663
664
  // Depending on the indexed addressing mode more bytes have to be read.
665
6.98k
  switch (post_byte & 0x9F) {
666
527
  case 0x87:
667
683
  case 0x8A:
668
744
  case 0x8E:
669
901
  case 0x8F:
670
943
  case 0x90:
671
981
  case 0x92:
672
1.00k
  case 0x97:
673
1.02k
  case 0x9A:
674
1.19k
  case 0x9E:
675
1.19k
    return -1; // illegal indexed post bytes
676
677
267
  case 0x88: // n8,R
678
305
  case 0x8C: // n8,PCR
679
706
  case 0x98: // [n8,R]
680
847
  case 0x9C: // [n8,PCR]
681
847
    if (!read_byte(info, &ir, address + 1))
682
2
      return -1;
683
845
    return 2;
684
685
63
  case 0x89: // n16,R
686
241
  case 0x8D: // n16,PCR
687
410
  case 0x99: // [n16,R]
688
432
  case 0x9D: // [n16,PCR]
689
432
    if (!read_byte(info, &ir, address + 2))
690
13
      return -1;
691
419
    return 3;
692
693
378
  case 0x9F: // [n]
694
378
    if ((post_byte & 0x60) != 0 ||
695
178
        !read_byte(info, &ir, address + 2))
696
200
      return -1;
697
178
    return 3;
698
6.98k
  }
699
700
  // Any other indexed post byte is valid and
701
  // no additional bytes have to be read.
702
4.13k
  return 1;
703
6.98k
}
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
6.31k
{
711
6.31k
  uint8_t ir;
712
6.31k
  uint8_t post_byte;
713
714
  // Read the indexed addressing post byte.
715
6.31k
  if (!read_byte(info, &post_byte, address))
716
36
    return -1;
717
718
  // Depending on the indexed addressing mode more bytes have to be read.
719
6.27k
  if (!(post_byte & 0x20)) // n5,R
720
2.21k
    return 1;
721
722
4.06k
  switch (post_byte & 0xe7) {
723
350
  case 0xe0:
724
864
  case 0xe1: // n9,R
725
864
    if (is_subset)
726
147
      return -1;
727
728
717
    if (!read_byte(info, &ir, address))
729
0
      return -1;
730
717
    return 2;
731
732
808
  case 0xe2: // n16,R
733
1.40k
  case 0xe3: // [n16,R]
734
1.40k
    if (is_subset)
735
142
      return -1;
736
737
1.25k
    if (!read_byte(info, &ir, address + 1))
738
20
      return -1;
739
1.23k
    return 3;
740
741
194
  case 0xe4: // A,R
742
284
  case 0xe5: // B,R
743
526
  case 0xe6: // D,R
744
625
  case 0xe7: // [D,R]
745
1.79k
  default: // n,-r n,+r n,r- n,r+
746
1.79k
    break;
747
4.06k
  }
748
749
1.79k
  return 1;
750
4.06k
}
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
1.32k
{
755
1.32k
  if (info->cpu->tfr_reg_valid != NULL)
756
455
    return info->cpu->tfr_reg_valid[reg_nibble];
757
758
870
  return true; // e.g. for the M6309 all registers are valid
759
1.32k
}
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
230
{
765
230
  return !(post_byte & 0x08);
766
230
}
767
768
static bool is_tfm_reg_valid(const m680x_info *info, uint8_t reg_nibble)
769
681
{
770
  // HD6809 TFM instruction: Only register X,Y,U,S,D is allowed
771
681
  return reg_nibble <= 4;
772
681
}
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
773
{
779
773
  uint8_t post_byte;
780
773
  uint8_t rr;
781
782
773
  if (!read_byte(info, &post_byte, address))
783
1
    return -1;
784
785
  // According to documentation bit 3 is don't care and not checked here.
786
772
  if ((post_byte >= 0xc0) || ((post_byte & 0x07) == 2) ||
787
407
      ((post_byte & 0x07) == 3))
788
400
    return -1;
789
790
372
  if (!read_byte(info, &rr, address + 1))
791
3
    return -1;
792
793
369
  return 2;
794
372
}
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
575
{
802
575
  uint8_t post_byte;
803
575
  uint8_t rr;
804
805
575
  if (!read_byte(info, &post_byte, address))
806
0
    return -1;
807
808
575
  if ((post_byte & 0xc0) == 0xc0)
809
255
    return -1; // Invalid register specified
810
320
  else {
811
320
    if (!read_byte(info, &rr, address + 1))
812
1
      return -1;
813
320
  }
814
815
319
  return 2;
816
575
}
817
818
static bool is_sufficient_code_size(const m680x_info *info, uint16_t address,
819
            insn_desc *insn_description)
820
49.0k
{
821
49.0k
  int i;
822
49.0k
  bool retval = true;
823
49.0k
  uint16_t size = 0;
824
49.0k
  int sz;
825
826
141k
  for (i = 0; i < 2; i++) {
827
95.1k
    uint8_t ir = 0;
828
95.1k
    bool is_subset = false;
829
830
95.1k
    switch (insn_description->hid[i]) {
831
171
    case imm32_hid:
832
171
      if ((retval = read_byte(info, &ir, address + size + 3)))
833
169
        size += 4;
834
171
      break;
835
836
5.72k
    case ext_hid:
837
6.40k
    case imm16_hid:
838
6.85k
    case rel16_hid:
839
7.28k
    case imm8rel_hid:
840
7.73k
    case opidxdr_hid:
841
7.95k
    case idxX16_hid:
842
7.97k
    case idxS16_hid:
843
7.97k
      if ((retval = read_byte(info, &ir, address + size + 1)))
844
7.84k
        size += 2;
845
7.97k
      break;
846
847
2.73k
    case rel8_hid:
848
8.54k
    case dir_hid:
849
10.3k
    case rbits_hid:
850
13.3k
    case imm8_hid:
851
14.4k
    case idxX_hid:
852
14.7k
    case idxXp_hid:
853
15.0k
    case idxY_hid:
854
15.1k
    case idxS_hid:
855
15.3k
    case index_hid:
856
15.3k
      if ((retval = read_byte(info, &ir, address + size)))
857
15.2k
        size++;
858
15.3k
      break;
859
860
0
    case illgl_hid:
861
54.1k
    case inh_hid:
862
55.2k
    case idxX0_hid:
863
55.4k
    case idxX0p_hid:
864
55.7k
    case opidx_hid:
865
55.7k
      retval = true;
866
55.7k
      break;
867
868
7.01k
    case idx09_hid:
869
7.01k
      sz = get_indexed09_post_byte_size(info, address + size);
870
7.01k
      if (sz >= 0)
871
5.57k
        size += sz;
872
1.43k
      else
873
1.43k
        retval = false;
874
7.01k
      break;
875
876
338
    case idx12s_hid:
877
338
      is_subset = true;
878
879
      // intentionally fall through
880
881
4.96k
    case idx12_hid:
882
4.96k
      sz = get_indexed12_post_byte_size(info, address + size,
883
4.96k
                is_subset);
884
4.96k
      if (sz >= 0)
885
4.62k
        size += sz;
886
333
      else
887
333
        retval = false;
888
4.96k
      break;
889
890
115
    case exti12x_hid:
891
409
    case imm16i12x_hid:
892
409
      sz = get_indexed12_post_byte_size(info, address + size,
893
409
                false);
894
409
      if (sz >= 0) {
895
405
        size += sz;
896
405
        if ((retval = read_byte(info, &ir,
897
405
              address + size + 1)))
898
393
          size += 2;
899
405
      } else
900
4
        retval = false;
901
409
      break;
902
903
940
    case imm8i12x_hid:
904
940
      sz = get_indexed12_post_byte_size(info, address + size,
905
940
                false);
906
940
      if (sz >= 0) {
907
932
        size += sz;
908
932
        if ((retval = read_byte(info, &ir,
909
932
              address + size)))
910
926
          size++;
911
932
      } else
912
8
        retval = false;
913
940
      break;
914
915
362
    case tfm_hid:
916
362
      if ((retval = read_byte(info, &ir, address + size))) {
917
362
        size++;
918
362
        retval = is_tfm_reg_valid(info,
919
362
                (ir >> 4) & 0x0F) &&
920
319
           is_tfm_reg_valid(info, ir & 0x0F);
921
362
      }
922
362
      break;
923
924
671
    case rr09_hid:
925
671
      if ((retval = read_byte(info, &ir, address + size))) {
926
667
        size++;
927
667
        retval = is_tfr09_reg_valid(info,
928
667
                  (ir >> 4) & 0x0F) &&
929
658
           is_tfr09_reg_valid(info, ir & 0x0F);
930
667
      }
931
671
      break;
932
933
233
    case rr12_hid:
934
233
      if ((retval = read_byte(info, &ir, address + size))) {
935
230
        size++;
936
230
        retval = is_exg_tfr12_post_byte_valid(info, ir);
937
230
      }
938
233
      break;
939
940
575
    case bitmv_hid:
941
575
      sz = get_bitmv_post_byte_size(info, address + size);
942
575
      if (sz >= 0)
943
319
        size += sz;
944
256
      else
945
256
        retval = false;
946
575
      break;
947
948
773
    case loop_hid:
949
773
      sz = get_loop_post_byte_size(info, address + size);
950
773
      if (sz >= 0)
951
369
        size += sz;
952
404
      else
953
404
        retval = false;
954
773
      break;
955
956
0
    default:
957
0
      CS_ASSERT(0 && "Unexpected instruction handler id");
958
0
      retval = false;
959
0
      break;
960
95.1k
    }
961
962
95.1k
    if (!retval)
963
2.96k
      return false;
964
95.1k
  }
965
966
46.0k
  insn_description->insn_size += size;
967
968
46.0k
  return retval;
969
49.0k
}
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
53.3k
{
976
53.3k
  const inst_pageX *inst_table = NULL;
977
53.3k
  const cpu_tables *cpu = info->cpu;
978
53.3k
  size_t table_size = 0;
979
53.3k
  uint16_t base_address = address;
980
53.3k
  uint8_t ir; // instruction register
981
53.3k
  int i;
982
53.3k
  int index;
983
984
53.3k
  if (!read_byte(info, &ir, address++))
985
0
    return false;
986
987
53.3k
  insn_description->insn = M680X_INS_ILLGL;
988
53.3k
  insn_description->opcode = ir;
989
990
  // Check if a page prefix byte is present
991
129k
  for (i = 0; i < ARR_SIZE(cpu->pageX_table_size); ++i) {
992
126k
    if (cpu->pageX_table_size[i] == 0 ||
993
82.9k
        (cpu->inst_pageX_table[i] == NULL))
994
43.6k
      break;
995
996
82.9k
    if ((cpu->pageX_prefix[i] == ir)) {
997
      // Get pageX instruction and handler id.
998
      // Abort for illegal instr.
999
6.62k
      inst_table = cpu->inst_pageX_table[i];
1000
6.62k
      table_size = cpu->pageX_table_size[i];
1001
1002
6.62k
      if (!read_byte(info, &ir, address++))
1003
5
        return false;
1004
1005
6.62k
      insn_description->opcode =
1006
6.62k
        (insn_description->opcode << 8) | ir;
1007
1008
6.62k
      if ((index = binary_search(inst_table, table_size,
1009
6.62k
               ir)) < 0)
1010
2.29k
        return false;
1011
1012
4.32k
      insn_description->hid[0] =
1013
4.32k
        inst_table[index].handler_id1;
1014
4.32k
      insn_description->hid[1] =
1015
4.32k
        inst_table[index].handler_id2;
1016
4.32k
      insn_description->insn = inst_table[index].insn;
1017
4.32k
      break;
1018
6.62k
    }
1019
82.9k
  }
1020
1021
51.0k
  if (insn_description->insn == M680X_INS_ILLGL) {
1022
    // Get page1 insn description
1023
46.6k
    insn_description->insn = cpu->inst_page1_table[ir].insn;
1024
46.6k
    insn_description->hid[0] =
1025
46.6k
      cpu->inst_page1_table[ir].handler_id1;
1026
46.6k
    insn_description->hid[1] =
1027
46.6k
      cpu->inst_page1_table[ir].handler_id2;
1028
46.6k
  }
1029
1030
51.0k
  if (insn_description->insn == M680X_INS_ILLGL) {
1031
    // Check if opcode byte is present in an overlay table
1032
8.72k
    for (i = 0; i < ARR_SIZE(cpu->overlay_table_size); ++i) {
1033
8.51k
      if (cpu->overlay_table_size[i] == 0 ||
1034
6.72k
          (cpu->inst_overlay_table[i] == NULL))
1035
1.79k
        break;
1036
1037
6.72k
      inst_table = cpu->inst_overlay_table[i];
1038
6.72k
      table_size = cpu->overlay_table_size[i];
1039
1040
6.72k
      if ((index = binary_search(inst_table, table_size,
1041
6.72k
               ir)) >= 0) {
1042
3.63k
        insn_description->hid[0] =
1043
3.63k
          inst_table[index].handler_id1;
1044
3.63k
        insn_description->hid[1] =
1045
3.63k
          inst_table[index].handler_id2;
1046
3.63k
        insn_description->insn = inst_table[index].insn;
1047
3.63k
        break;
1048
3.63k
      }
1049
6.72k
    }
1050
5.63k
  }
1051
1052
51.0k
  insn_description->insn_size = address - base_address;
1053
1054
51.0k
  return (insn_description->insn != M680X_INS_ILLGL) &&
1055
49.0k
         (insn_description->insn != M680X_INS_INVLD) &&
1056
49.0k
         is_sufficient_code_size(info, address, insn_description);
1057
53.3k
}
1058
1059
static void illegal_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1060
7.26k
{
1061
7.26k
  cs_m680x_op *op0 = &info->m680x.operands[info->m680x.op_count++];
1062
7.26k
  uint8_t temp8 = 0;
1063
1064
7.26k
  info->insn = M680X_INS_ILLGL;
1065
7.26k
  read_byte(info, &temp8, (*address)++);
1066
7.26k
  op0->imm = (int32_t)temp8 & 0xff;
1067
7.26k
  op0->type = M680X_OP_IMMEDIATE;
1068
7.26k
  op0->size = 1;
1069
7.26k
}
1070
1071
static void inherent_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1072
54.1k
{
1073
  // There is nothing to do here :-)
1074
54.1k
}
1075
1076
static void add_reg_operand(m680x_info *info, m680x_reg reg)
1077
35.5k
{
1078
35.5k
  cs_m680x *m680x = &info->m680x;
1079
35.5k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1080
1081
35.5k
  op->type = M680X_OP_REGISTER;
1082
35.5k
  op->reg = reg;
1083
35.5k
  op->size = info->cpu->reg_byte_size[reg];
1084
35.5k
}
1085
1086
static void set_operand_size(m680x_info *info, cs_m680x_op *op,
1087
           uint8_t default_size)
1088
33.0k
{
1089
33.0k
  cs_m680x *m680x = &info->m680x;
1090
1091
33.0k
  if (info->insn == M680X_INS_JMP || info->insn == M680X_INS_JSR)
1092
2.31k
    op->size = 0;
1093
30.7k
  else if (info->insn == M680X_INS_DIVD ||
1094
30.6k
     ((info->insn == M680X_INS_AIS ||
1095
30.5k
       info->insn == M680X_INS_AIX) &&
1096
215
      op->type != M680X_OP_REGISTER))
1097
295
    op->size = 1;
1098
30.4k
  else if (info->insn == M680X_INS_DIVQ || info->insn == M680X_INS_MOVW)
1099
1.36k
    op->size = 2;
1100
29.0k
  else if (info->insn == M680X_INS_EMACS)
1101
65
    op->size = 4;
1102
29.0k
  else if ((m680x->op_count > 0) &&
1103
29.0k
     (m680x->operands[0].type == M680X_OP_REGISTER))
1104
18.1k
    op->size = m680x->operands[0].size;
1105
10.8k
  else
1106
10.8k
    op->size = default_size;
1107
33.0k
}
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
1.76k
{
1121
1.76k
  cs_m680x_op *op0 = &info->m680x.operands[0];
1122
1.76k
  uint8_t reg_bits = 0;
1123
1.76k
  uint16_t bit_index;
1124
1.76k
  const m680x_reg *reg_to_reg_ids = NULL;
1125
1126
1.76k
  read_byte(info, &reg_bits, (*address)++);
1127
1128
1.76k
  switch (op0->reg) {
1129
1.38k
  case M680X_REG_U:
1130
1.38k
    reg_to_reg_ids = &reg_u_reg_ids[0];
1131
1.38k
    break;
1132
1133
383
  case M680X_REG_S:
1134
383
    reg_to_reg_ids = &reg_s_reg_ids[0];
1135
383
    break;
1136
1137
0
  default:
1138
0
    CS_ASSERT(0 && "Unexpected operand0 register");
1139
0
    break;
1140
1.76k
  }
1141
1142
1.76k
  if ((info->insn == M680X_INS_PULU || (info->insn == M680X_INS_PULS)) &&
1143
578
      ((reg_bits & 0x80) != 0))
1144
    // PULS xxx,PC or PULU xxx,PC which is like return from
1145
    // subroutine (RTS)
1146
125
    add_insn_group(MI->flat_insn->detail, M680X_GRP_RET);
1147
1148
15.9k
  for (bit_index = 0; bit_index < 8; ++bit_index) {
1149
14.1k
    if (reg_bits & (1 << bit_index) && reg_to_reg_ids)
1150
7.08k
      add_reg_operand(info, reg_to_reg_ids[bit_index]);
1151
14.1k
  }
1152
1.76k
}
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
472
{
1177
472
  uint8_t regs = 0;
1178
1179
472
  read_byte(info, &regs, (*address)++);
1180
1181
472
  add_reg_operand(info, g_tfr_exg_reg_ids[regs >> 4]);
1182
472
  add_reg_operand(info, g_tfr_exg_reg_ids[regs & 0x0f]);
1183
1184
472
  if ((regs & 0x0f) == 0x05) {
1185
    // EXG xxx,PC or TFR xxx,PC which is like a JMP
1186
29
    add_insn_group(MI->flat_insn->detail, M680X_GRP_JUMP);
1187
29
  }
1188
472
}
1189
1190
static void reg_reg12_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1191
197
{
1192
197
  static const m680x_reg g_tfr_exg12_reg0_ids[] = {
1193
197
    M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP3,
1194
197
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,  M680X_REG_S,
1195
197
  };
1196
197
  static const m680x_reg g_tfr_exg12_reg1_ids[] = {
1197
197
    M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP2,
1198
197
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,  M680X_REG_S,
1199
197
  };
1200
197
  uint8_t regs = 0;
1201
1202
197
  read_byte(info, &regs, (*address)++);
1203
1204
  // The opcode of this instruction depends on
1205
  // the msb of its post byte.
1206
197
  if (regs & 0x80)
1207
179
    info->insn = M680X_INS_EXG;
1208
18
  else
1209
18
    info->insn = M680X_INS_TFR;
1210
1211
197
  add_reg_operand(info, g_tfr_exg12_reg0_ids[(regs >> 4) & 0x07]);
1212
197
  add_reg_operand(info, g_tfr_exg12_reg1_ids[regs & 0x07]);
1213
197
}
1214
1215
static void add_rel_operand(m680x_info *info, int16_t offset, uint16_t address)
1216
4.01k
{
1217
4.01k
  cs_m680x *m680x = &info->m680x;
1218
4.01k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1219
1220
4.01k
  op->type = M680X_OP_RELATIVE;
1221
4.01k
  op->size = 0;
1222
4.01k
  op->rel.offset = offset;
1223
4.01k
  op->rel.address = address;
1224
4.01k
}
1225
1226
static void relative8_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1227
3.57k
{
1228
3.57k
  int16_t offset = 0;
1229
1230
3.57k
  read_byte_sign_extended(info, &offset, (*address)++);
1231
3.57k
  add_rel_operand(info, offset, *address + offset);
1232
3.57k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1233
1234
3.57k
  if ((info->insn != M680X_INS_BRA) && (info->insn != M680X_INS_BSR) &&
1235
3.16k
      (info->insn != M680X_INS_BRN))
1236
3.03k
    add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1237
3.57k
}
1238
1239
static void relative16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1240
446
{
1241
446
  uint16_t offset = 0;
1242
1243
446
  read_word(info, &offset, *address);
1244
446
  *address += 2;
1245
446
  add_rel_operand(info, (int16_t)offset, *address + offset);
1246
446
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1247
1248
446
  if ((info->insn != M680X_INS_LBRA) && (info->insn != M680X_INS_LBSR) &&
1249
177
      (info->insn != M680X_INS_LBRN))
1250
49
    add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1251
446
}
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
3.84k
{
1265
3.84k
  cs_m680x *m680x = &info->m680x;
1266
3.84k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1267
1268
3.84k
  op->type = M680X_OP_INDEXED;
1269
3.84k
  set_operand_size(info, op, 1);
1270
3.84k
  op->idx.base_reg = base_reg;
1271
3.84k
  op->idx.offset_reg = M680X_REG_INVALID;
1272
3.84k
  op->idx.inc_dec = inc_dec;
1273
1274
3.84k
  if (inc_dec && post_inc_dec)
1275
789
    op->idx.flags |= M680X_IDX_POST_INC_DEC;
1276
1277
3.84k
  if (offset_bits != M680X_OFFSET_NONE) {
1278
2.00k
    op->idx.offset = offset;
1279
2.00k
    op->idx.offset_addr = 0;
1280
2.00k
  }
1281
1282
3.84k
  op->idx.offset_bits = offset_bits;
1283
3.84k
  op->idx.flags |= (no_comma ? M680X_IDX_NO_COMMA : 0);
1284
3.84k
}
1285
1286
// M6800/1/2/3 indexed mode handler
1287
static void indexedX_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1288
1.14k
{
1289
1.14k
  uint8_t offset = 0;
1290
1291
1.14k
  read_byte(info, &offset, (*address)++);
1292
1293
1.14k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_8,
1294
1.14k
          (uint16_t)offset, false);
1295
1.14k
}
1296
1297
static void indexedY_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1298
301
{
1299
301
  uint8_t offset = 0;
1300
1301
301
  read_byte(info, &offset, (*address)++);
1302
1303
301
  add_indexed_operand(info, M680X_REG_Y, false, 0, M680X_OFFSET_BITS_8,
1304
301
          (uint16_t)offset, false);
1305
301
}
1306
1307
// M6809/M6309 indexed mode handler
1308
static void indexed09_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1309
5.57k
{
1310
5.57k
  cs_m680x *m680x = &info->m680x;
1311
5.57k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1312
5.57k
  uint8_t post_byte = 0;
1313
5.57k
  uint16_t offset = 0;
1314
5.57k
  int16_t soffset = 0;
1315
1316
5.57k
  read_byte(info, &post_byte, (*address)++);
1317
1318
5.57k
  op->type = M680X_OP_INDEXED;
1319
5.57k
  set_operand_size(info, op, 1);
1320
5.57k
  op->idx.base_reg = g_rr5_to_reg_ids[(post_byte >> 5) & 0x03];
1321
5.57k
  op->idx.offset_reg = M680X_REG_INVALID;
1322
1323
5.57k
  if (!(post_byte & 0x80)) {
1324
    // n5,R
1325
2.13k
    if ((post_byte & 0x10) == 0x10)
1326
1.17k
      op->idx.offset = post_byte | 0xfff0;
1327
960
    else
1328
960
      op->idx.offset = post_byte & 0x0f;
1329
1330
2.13k
    op->idx.offset_addr = op->idx.offset + *address;
1331
2.13k
    op->idx.offset_bits = M680X_OFFSET_BITS_5;
1332
3.44k
  } else {
1333
3.44k
    if ((post_byte & 0x10) == 0x10)
1334
1.16k
      op->idx.flags |= M680X_IDX_INDIRECT;
1335
1336
    // indexed addressing
1337
3.44k
    switch (post_byte & 0x1f) {
1338
59
    case 0x00: // ,R+
1339
59
      op->idx.inc_dec = 1;
1340
59
      op->idx.flags |= M680X_IDX_POST_INC_DEC;
1341
59
      break;
1342
1343
28
    case 0x11: // [,R++]
1344
80
    case 0x01: // ,R++
1345
80
      op->idx.inc_dec = 2;
1346
80
      op->idx.flags |= M680X_IDX_POST_INC_DEC;
1347
80
      break;
1348
1349
175
    case 0x02: // ,-R
1350
175
      op->idx.inc_dec = -1;
1351
175
      break;
1352
1353
55
    case 0x13: // [,--R]
1354
233
    case 0x03: // ,--R
1355
233
      op->idx.inc_dec = -2;
1356
233
      break;
1357
1358
49
    case 0x14: // [,R]
1359
965
    case 0x04: // ,R
1360
965
      break;
1361
1362
30
    case 0x15: // [B,R]
1363
371
    case 0x05: // B,R
1364
371
      op->idx.offset_reg = M680X_REG_B;
1365
371
      break;
1366
1367
55
    case 0x16: // [A,R]
1368
75
    case 0x06: // A,R
1369
75
      op->idx.offset_reg = M680X_REG_A;
1370
75
      break;
1371
1372
140
    case 0x1c: // [n8,PCR]
1373
178
    case 0x0c: // n8,PCR
1374
178
      op->idx.base_reg = M680X_REG_PC;
1375
178
      read_byte_sign_extended(info, &soffset, (*address)++);
1376
178
      op->idx.offset_addr = offset + *address;
1377
178
      op->idx.offset = soffset;
1378
178
      op->idx.offset_bits = M680X_OFFSET_BITS_8;
1379
178
      break;
1380
1381
401
    case 0x18: // [n8,R]
1382
667
    case 0x08: // n8,R
1383
667
      read_byte_sign_extended(info, &soffset, (*address)++);
1384
667
      op->idx.offset = soffset;
1385
667
      op->idx.offset_bits = M680X_OFFSET_BITS_8;
1386
667
      break;
1387
1388
22
    case 0x1d: // [n16,PCR]
1389
194
    case 0x0d: // n16,PCR
1390
194
      op->idx.base_reg = M680X_REG_PC;
1391
194
      read_word(info, &offset, *address);
1392
194
      *address += 2;
1393
194
      op->idx.offset_addr = offset + *address;
1394
194
      op->idx.offset = (int16_t)offset;
1395
194
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1396
194
      break;
1397
1398
167
    case 0x19: // [n16,R]
1399
225
    case 0x09: // n16,R
1400
225
      read_word(info, &offset, *address);
1401
225
      *address += 2;
1402
225
      op->idx.offset = (int16_t)offset;
1403
225
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1404
225
      break;
1405
1406
35
    case 0x1b: // [D,R]
1407
49
    case 0x0b: // D,R
1408
49
      op->idx.offset_reg = M680X_REG_D;
1409
49
      break;
1410
1411
178
    case 0x1f: // [n16]
1412
178
      op->type = M680X_OP_EXTENDED;
1413
178
      op->ext.indirect = true;
1414
178
      read_word(info, &op->ext.address, *address);
1415
178
      *address += 2;
1416
178
      break;
1417
1418
0
    default:
1419
0
      op->idx.base_reg = M680X_REG_INVALID;
1420
0
      break;
1421
3.44k
    }
1422
3.44k
  }
1423
1424
5.57k
  if (((info->insn == M680X_INS_LEAU) || (info->insn == M680X_INS_LEAS) ||
1425
5.11k
       (info->insn == M680X_INS_LEAX) ||
1426
5.05k
       (info->insn == M680X_INS_LEAY)) &&
1427
647
      (m680x->operands[0].reg == M680X_REG_X ||
1428
583
       (m680x->operands[0].reg == M680X_REG_Y)))
1429
    // Only LEAX and LEAY modify CC register
1430
187
    add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1431
5.57k
}
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
5.94k
{
1446
5.94k
  cs_m680x *m680x = &info->m680x;
1447
5.94k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1448
5.94k
  uint8_t post_byte = 0;
1449
5.94k
  uint8_t offset8 = 0;
1450
1451
5.94k
  read_byte(info, &post_byte, (*address)++);
1452
1453
5.94k
  op->type = M680X_OP_INDEXED;
1454
5.94k
  set_operand_size(info, op, 1);
1455
5.94k
  op->idx.offset_reg = M680X_REG_INVALID;
1456
1457
5.94k
  if (!(post_byte & 0x20)) {
1458
    // n5,R      n5 is a 5-bit signed offset
1459
2.20k
    op->idx.base_reg = g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1460
1461
2.20k
    if ((post_byte & 0x10) == 0x10)
1462
737
      op->idx.offset = post_byte | 0xfff0;
1463
1.46k
    else
1464
1.46k
      op->idx.offset = post_byte & 0x0f;
1465
1466
2.20k
    op->idx.offset_addr = op->idx.offset + *address;
1467
2.20k
    op->idx.offset_bits = M680X_OFFSET_BITS_5;
1468
3.73k
  } else {
1469
3.73k
    if ((post_byte & 0xe0) == 0xe0)
1470
2.56k
      op->idx.base_reg =
1471
2.56k
        g_idx12_to_reg_ids[(post_byte >> 3) & 0x03];
1472
1473
3.73k
    switch (post_byte & 0xe7) {
1474
347
    case 0xe0:
1475
711
    case 0xe1: // n9,R
1476
711
      read_byte(info, &offset8, (*address)++);
1477
711
      op->idx.offset = offset8;
1478
1479
711
      if (post_byte & 0x01) // sign extension
1480
364
        op->idx.offset |= 0xff00;
1481
1482
711
      op->idx.offset_bits = M680X_OFFSET_BITS_9;
1483
1484
711
      if (op->idx.base_reg == M680X_REG_PC)
1485
286
        op->idx.offset_addr = op->idx.offset + *address;
1486
1487
711
      break;
1488
1489
503
    case 0xe3: // [n16,R]
1490
503
      op->idx.flags |= M680X_IDX_INDIRECT;
1491
1492
    // intentionally fall through
1493
1.23k
    case 0xe2: // n16,R
1494
1.23k
      read_word(info, (uint16_t *)&op->idx.offset, *address);
1495
1.23k
      (*address) += 2;
1496
1.23k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1497
1498
1.23k
      if (op->idx.base_reg == M680X_REG_PC)
1499
209
        op->idx.offset_addr = op->idx.offset + *address;
1500
1501
1.23k
      break;
1502
1503
193
    case 0xe4: // A,R
1504
282
    case 0xe5: // B,R
1505
524
    case 0xe6: // D,R
1506
524
      op->idx.offset_reg =
1507
524
        g_or12_to_reg_ids[post_byte & 0x03];
1508
524
      break;
1509
1510
99
    case 0xe7: // [D,R]
1511
99
      op->idx.offset_reg = M680X_REG_D;
1512
99
      op->idx.flags |= M680X_IDX_INDIRECT;
1513
99
      break;
1514
1515
1.16k
    default: // n,-r n,+r n,r- n,r+
1516
      // PC is not allowed in this mode
1517
1.16k
      op->idx.base_reg =
1518
1.16k
        g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1519
1.16k
      op->idx.inc_dec = post_byte & 0x0f;
1520
1521
1.16k
      if (op->idx.inc_dec & 0x08) // evtl. sign extend value
1522
494
        op->idx.inc_dec |= 0xf0;
1523
1524
1.16k
      if (op->idx.inc_dec >= 0)
1525
675
        op->idx.inc_dec++;
1526
1527
1.16k
      if (post_byte & 0x10)
1528
365
        op->idx.flags |= M680X_IDX_POST_INC_DEC;
1529
1530
1.16k
      break;
1531
3.73k
    }
1532
3.73k
  }
1533
5.94k
}
1534
1535
static void index_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1536
229
{
1537
229
  cs_m680x *m680x = &info->m680x;
1538
229
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1539
1540
229
  op->type = M680X_OP_CONSTANT;
1541
229
  read_byte(info, &op->const_val, (*address)++);
1542
229
};
1543
1544
static void direct_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1545
6.52k
{
1546
6.52k
  cs_m680x *m680x = &info->m680x;
1547
6.52k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1548
1549
6.52k
  op->type = M680X_OP_DIRECT;
1550
6.52k
  set_operand_size(info, op, 1);
1551
6.52k
  read_byte(info, &op->direct_addr, (*address)++);
1552
6.52k
};
1553
1554
static void extended_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1555
5.62k
{
1556
5.62k
  cs_m680x *m680x = &info->m680x;
1557
5.62k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1558
1559
5.62k
  op->type = M680X_OP_EXTENDED;
1560
5.62k
  set_operand_size(info, op, 1);
1561
5.62k
  read_word(info, &op->ext.address, *address);
1562
5.62k
  *address += 2;
1563
5.62k
}
1564
1565
static void immediate_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1566
4.22k
{
1567
4.22k
  cs_m680x *m680x = &info->m680x;
1568
4.22k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1569
4.22k
  uint16_t word = 0;
1570
4.22k
  int16_t sword = 0;
1571
1572
4.22k
  op->type = M680X_OP_IMMEDIATE;
1573
4.22k
  set_operand_size(info, op, 1);
1574
1575
4.22k
  switch (op->size) {
1576
3.38k
  case 1:
1577
3.38k
    read_byte_sign_extended(info, &sword, *address);
1578
3.38k
    op->imm = sword;
1579
3.38k
    break;
1580
1581
671
  case 2:
1582
671
    read_word(info, &word, *address);
1583
671
    op->imm = (int16_t)word;
1584
671
    break;
1585
1586
169
  case 4:
1587
169
    read_sdword(info, &op->imm, *address);
1588
169
    break;
1589
1590
0
  default:
1591
0
    op->imm = 0;
1592
0
    CS_ASSERT(0 && "Unexpected immediate byte size");
1593
4.22k
  }
1594
1595
4.22k
  *address += op->size;
1596
4.22k
}
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
319
{
1601
319
  static const m680x_reg m680x_reg[] = {
1602
319
    M680X_REG_CC,
1603
319
    M680X_REG_A,
1604
319
    M680X_REG_B,
1605
319
    M680X_REG_INVALID,
1606
319
  };
1607
1608
319
  uint8_t post_byte = 0;
1609
319
  cs_m680x *m680x = &info->m680x;
1610
319
  cs_m680x_op *op;
1611
1612
319
  read_byte(info, &post_byte, *address);
1613
319
  (*address)++;
1614
1615
  // operand[0] = register
1616
319
  add_reg_operand(info, m680x_reg[post_byte >> 6]);
1617
1618
  // operand[1] = bit index in source operand
1619
319
  op = &m680x->operands[m680x->op_count++];
1620
319
  op->type = M680X_OP_CONSTANT;
1621
319
  op->const_val = (post_byte >> 3) & 0x07;
1622
1623
  // operand[2] = bit index in destination operand
1624
319
  op = &m680x->operands[m680x->op_count++];
1625
319
  op->type = M680X_OP_CONSTANT;
1626
319
  op->const_val = post_byte & 0x07;
1627
1628
319
  direct_hdlr(MI, info, address);
1629
319
}
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
306
{
1634
306
  static const uint8_t inc_dec_r0[] = {
1635
306
    1,
1636
306
    -1,
1637
306
    1,
1638
306
    0,
1639
306
  };
1640
306
  static const uint8_t inc_dec_r1[] = {
1641
306
    1,
1642
306
    -1,
1643
306
    0,
1644
306
    1,
1645
306
  };
1646
306
  uint8_t regs = 0;
1647
306
  uint8_t index = (MI->Opcode & 0xff) - 0x38;
1648
1649
306
  read_byte(info, &regs, *address);
1650
1651
306
  add_indexed_operand(info, g_tfr_exg_reg_ids[regs >> 4], true,
1652
306
          inc_dec_r0[index], M680X_OFFSET_NONE, 0, true);
1653
306
  add_indexed_operand(info, g_tfr_exg_reg_ids[regs & 0x0f], true,
1654
306
          inc_dec_r1[index], M680X_OFFSET_NONE, 0, true);
1655
1656
306
  add_reg_to_rw_list(MI, M680X_REG_W, READ | WRITE);
1657
306
}
1658
1659
static void opidx_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1660
278
{
1661
278
  cs_m680x *m680x = &info->m680x;
1662
278
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1663
1664
  // bit index is coded in Opcode
1665
278
  op->type = M680X_OP_CONSTANT;
1666
278
  op->const_val = (MI->Opcode & 0x0e) >> 1;
1667
278
}
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
434
{
1674
434
  cs_m680x *m680x = &info->m680x;
1675
434
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1676
1677
  // bit index is coded in Opcode
1678
434
  op->type = M680X_OP_CONSTANT;
1679
434
  op->const_val = (MI->Opcode & 0x0e) >> 1;
1680
434
  direct_hdlr(MI, info, address);
1681
434
  relative8_hdlr(MI, info, address);
1682
1683
434
  add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1684
434
}
1685
1686
static void indexedX0_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1687
1.02k
{
1688
1.02k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_NONE, 0,
1689
1.02k
          false);
1690
1.02k
}
1691
1692
static void indexedX16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1693
220
{
1694
220
  uint16_t offset = 0;
1695
1696
220
  read_word(info, &offset, *address);
1697
220
  *address += 2;
1698
220
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_16,
1699
220
          offset, false);
1700
220
}
1701
1702
static void imm_rel_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1703
426
{
1704
426
  immediate_hdlr(MI, info, address);
1705
426
  relative8_hdlr(MI, info, address);
1706
426
}
1707
1708
static void indexedS_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1709
56
{
1710
56
  uint8_t offset = 0;
1711
1712
56
  read_byte(info, &offset, (*address)++);
1713
1714
56
  add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_8,
1715
56
          (uint16_t)offset, false);
1716
56
}
1717
1718
static void indexedS16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1719
23
{
1720
23
  uint16_t offset = 0;
1721
1722
23
  read_word(info, &offset, *address);
1723
23
  *address += 2;
1724
1725
23
  add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_16,
1726
23
          offset, false);
1727
23
}
1728
1729
static void indexedX0p_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1730
205
{
1731
205
  add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_NONE, 0,
1732
205
          true);
1733
205
}
1734
1735
static void indexedXp_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1736
257
{
1737
257
  uint8_t offset = 0;
1738
1739
257
  read_byte(info, &offset, (*address)++);
1740
1741
257
  add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_BITS_8,
1742
257
          (uint16_t)offset, false);
1743
257
}
1744
1745
static void imm_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1746
1.20k
{
1747
1.20k
  cs_m680x *m680x = &info->m680x;
1748
1.20k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1749
1750
1.20k
  indexed12_hdlr(MI, info, address);
1751
1.20k
  op->type = M680X_OP_IMMEDIATE;
1752
1753
1.20k
  if (info->insn == M680X_INS_MOVW) {
1754
282
    uint16_t imm16 = 0;
1755
1756
282
    read_word(info, &imm16, *address);
1757
282
    op->imm = (int16_t)imm16;
1758
282
    op->size = 2;
1759
926
  } else {
1760
926
    uint8_t imm8 = 0;
1761
1762
926
    read_byte(info, &imm8, *address);
1763
926
    op->imm = (int8_t)imm8;
1764
926
    op->size = 1;
1765
926
  }
1766
1767
1.20k
  set_operand_size(info, op, 1);
1768
1.20k
}
1769
1770
static void ext_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1771
111
{
1772
111
  cs_m680x *m680x = &info->m680x;
1773
111
  cs_m680x_op *op0 = &m680x->operands[m680x->op_count++];
1774
111
  uint16_t imm16 = 0;
1775
1776
111
  indexed12_hdlr(MI, info, address);
1777
111
  read_word(info, &imm16, *address);
1778
111
  op0->type = M680X_OP_EXTENDED;
1779
111
  op0->ext.address = (int16_t)imm16;
1780
111
  set_operand_size(info, op0, 1);
1781
111
}
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
369
{
1787
369
  static const m680x_reg index_to_reg_id[] = {
1788
369
    M680X_REG_A, M680X_REG_B, M680X_REG_INVALID, M680X_REG_INVALID,
1789
369
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,       M680X_REG_S,
1790
369
  };
1791
369
  static const m680x_insn index_to_insn_id[] = {
1792
369
    M680X_INS_DBEQ, M680X_INS_DBNE, M680X_INS_TBEQ,  M680X_INS_TBNE,
1793
369
    M680X_INS_IBEQ, M680X_INS_IBNE, M680X_INS_ILLGL, M680X_INS_ILLGL
1794
369
  };
1795
369
  cs_m680x *m680x = &info->m680x;
1796
369
  uint8_t post_byte = 0;
1797
369
  uint8_t rel = 0;
1798
369
  cs_m680x_op *op;
1799
1800
369
  read_byte(info, &post_byte, (*address)++);
1801
1802
369
  info->insn = index_to_insn_id[(post_byte >> 5) & 0x07];
1803
1804
369
  if (info->insn == M680X_INS_ILLGL) {
1805
0
    illegal_hdlr(MI, info, address);
1806
0
  };
1807
1808
369
  read_byte(info, &rel, (*address)++);
1809
1810
369
  add_reg_operand(info, index_to_reg_id[post_byte & 0x07]);
1811
1812
369
  op = &m680x->operands[m680x->op_count++];
1813
1814
369
  op->type = M680X_OP_RELATIVE;
1815
1816
369
  op->rel.offset = (post_byte & 0x10) ? (int16_t)(0xff00 | rel) : rel;
1817
1818
369
  op->rel.address = *address + op->rel.offset;
1819
1820
369
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1821
369
}
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
53.3k
{
1842
53.3k
  cs_m680x *m680x = &info->m680x;
1843
53.3k
  cs_detail *detail = MI->flat_insn->detail;
1844
53.3k
  uint16_t base_address = address;
1845
53.3k
  insn_desc insn_description;
1846
53.3k
  e_access_mode access_mode;
1847
1848
53.3k
  if (detail != NULL) {
1849
53.3k
    memset(detail, 0,
1850
53.3k
           offsetof(cs_detail, m680x) + sizeof(cs_m680x));
1851
53.3k
  }
1852
1853
53.3k
  memset(&insn_description, 0, sizeof(insn_description));
1854
53.3k
  memset(m680x, 0, sizeof(*m680x));
1855
53.3k
  info->insn_size = 1;
1856
1857
53.3k
  if (decode_insn(info, address, &insn_description)) {
1858
46.0k
    m680x_reg reg;
1859
1860
46.0k
    if (insn_description.opcode > 0xff)
1861
3.68k
      address += 2; // 8-bit opcode + page prefix
1862
42.3k
    else
1863
42.3k
      address++; // 8-bit opcode only
1864
1865
46.0k
    info->insn = insn_description.insn;
1866
1867
46.0k
    MCInst_setOpcode(MI, insn_description.opcode);
1868
1869
46.0k
    reg = g_insn_props[info->insn].reg0;
1870
1871
46.0k
    if (reg != M680X_REG_INVALID) {
1872
25.5k
      if (reg == M680X_REG_HX &&
1873
439
          (!info->cpu->reg_byte_size[reg]))
1874
13
        reg = M680X_REG_X;
1875
1876
25.5k
      add_reg_operand(info, reg);
1877
      // First (or second) operand is a register which is
1878
      // part of the mnemonic
1879
25.5k
      m680x->flags |= M680X_FIRST_OP_IN_MNEM;
1880
25.5k
      reg = g_insn_props[info->insn].reg1;
1881
1882
25.5k
      if (reg != M680X_REG_INVALID) {
1883
957
        if (reg == M680X_REG_HX &&
1884
185
            (!info->cpu->reg_byte_size[reg]))
1885
120
          reg = M680X_REG_X;
1886
1887
957
        add_reg_operand(info, reg);
1888
957
        m680x->flags |= M680X_SECOND_OP_IN_MNEM;
1889
957
      }
1890
25.5k
    }
1891
1892
    // Call addressing mode specific instruction handler
1893
46.0k
    (g_insn_handler[insn_description.hid[0]])(MI, info, &address);
1894
46.0k
    (g_insn_handler[insn_description.hid[1]])(MI, info, &address);
1895
1896
46.0k
    add_insn_group(detail, g_insn_props[info->insn].group);
1897
1898
46.0k
    if (g_insn_props[info->insn].cc_modified &&
1899
27.5k
        (info->cpu->insn_cc_not_modified[0] != info->insn) &&
1900
27.5k
        (info->cpu->insn_cc_not_modified[1] != info->insn))
1901
27.3k
      add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1902
1903
46.0k
    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
46.0k
    if ((info->cpu->insn_cc_not_modified[0] == info->insn) ||
1908
45.9k
        (info->cpu->insn_cc_not_modified[1] == info->insn))
1909
278
      access_mode = rmmm;
1910
1911
46.0k
    build_regs_read_write_counts(MI, info, access_mode);
1912
46.0k
    add_operators_access(MI, info, access_mode);
1913
1914
46.0k
    if (g_insn_props[info->insn].update_reg_access)
1915
4.85k
      set_changed_regs_read_write_counts(MI, info);
1916
1917
46.0k
    info->insn_size = (uint8_t)insn_description.insn_size;
1918
1919
46.0k
    return info->insn_size;
1920
46.0k
  } else
1921
7.26k
    MCInst_setOpcode(MI, insn_description.opcode);
1922
1923
  // Illegal instruction
1924
7.26k
  address = base_address;
1925
7.26k
  illegal_hdlr(MI, info, &address);
1926
7.26k
  return 1;
1927
53.3k
}
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
53.3k
{
2105
53.3k
  if (cpu_type == M680X_CPU_TYPE_INVALID) {
2106
0
    return false;
2107
0
  }
2108
2109
53.3k
  info->code = code;
2110
53.3k
  info->size = code_len;
2111
53.3k
  info->offset = address;
2112
53.3k
  info->cpu_type = cpu_type;
2113
2114
53.3k
  info->cpu = &g_cpu_tables[info->cpu_type];
2115
2116
53.3k
  return true;
2117
53.3k
}
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
53.3k
{
2123
53.3k
  unsigned int insn_size = 0;
2124
53.3k
  e_cpu_type cpu_type = M680X_CPU_TYPE_INVALID; // No default CPU type
2125
53.3k
  cs_struct *handle = (cs_struct *)ud;
2126
53.3k
  m680x_info *info = (m680x_info *)handle->printer_info;
2127
2128
53.3k
  MCInst_clear(MI);
2129
2130
53.3k
  if (handle->mode & CS_MODE_M680X_6800)
2131
403
    cpu_type = M680X_CPU_TYPE_6800;
2132
2133
52.9k
  else if (handle->mode & CS_MODE_M680X_6801)
2134
184
    cpu_type = M680X_CPU_TYPE_6801;
2135
2136
52.7k
  else if (handle->mode & CS_MODE_M680X_6805)
2137
522
    cpu_type = M680X_CPU_TYPE_6805;
2138
2139
52.2k
  else if (handle->mode & CS_MODE_M680X_6808)
2140
1.98k
    cpu_type = M680X_CPU_TYPE_6808;
2141
2142
50.2k
  else if (handle->mode & CS_MODE_M680X_HCS08)
2143
3.44k
    cpu_type = M680X_CPU_TYPE_HCS08;
2144
2145
46.7k
  else if (handle->mode & CS_MODE_M680X_6809)
2146
1.93k
    cpu_type = M680X_CPU_TYPE_6809;
2147
2148
44.8k
  else if (handle->mode & CS_MODE_M680X_6301)
2149
527
    cpu_type = M680X_CPU_TYPE_6301;
2150
2151
44.3k
  else if (handle->mode & CS_MODE_M680X_6309)
2152
21.5k
    cpu_type = M680X_CPU_TYPE_6309;
2153
2154
22.8k
  else if (handle->mode & CS_MODE_M680X_6811)
2155
4.38k
    cpu_type = M680X_CPU_TYPE_6811;
2156
2157
18.4k
  else if (handle->mode & CS_MODE_M680X_CPU12)
2158
18.4k
    cpu_type = M680X_CPU_TYPE_CPU12;
2159
2160
53.3k
  if (cpu_type != M680X_CPU_TYPE_INVALID &&
2161
53.3k
      m680x_setup_internals(info, cpu_type, (uint16_t)address, code,
2162
53.3k
          (uint16_t)code_len))
2163
53.3k
    insn_size = m680x_disassemble(MI, info, (uint16_t)address);
2164
2165
53.3k
  if (insn_size == 0) {
2166
0
    *size = 1;
2167
0
    return false;
2168
0
  }
2169
2170
  // Make sure we always stay within range
2171
53.3k
  if (insn_size > code_len) {
2172
12
    *size = (uint16_t)code_len;
2173
12
    return false;
2174
12
  } else
2175
53.2k
    *size = (uint16_t)insn_size;
2176
2177
53.2k
  return true;
2178
53.3k
}
2179
2180
cs_err M680X_disassembler_init(cs_struct *ud)
2181
728
{
2182
728
  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
728
  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
728
  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
728
  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
728
  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
728
  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
728
  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
728
  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
728
  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
728
  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
728
  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
728
  return CS_ERR_OK;
2250
728
}
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