Coverage Report

Created: 2026-01-09 06:55

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