Coverage Report

Created: 2025-10-12 06:32

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