Coverage Report

Created: 2025-11-09 07:00

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