Coverage Report

Created: 2025-08-29 06:29

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