Coverage Report

Created: 2025-11-24 06:12

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