Coverage Report

Created: 2026-02-26 07:11

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