Coverage Report

Created: 2025-08-29 06:29

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