Coverage Report

Created: 2026-06-06 06:15

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
  srt_hid,
75
  tny_hid,
76
  dirdir_hid,
77
  immdir_hid,
78
  HANDLER_ID_ENDING,
79
} insn_hdlr_id;
80
81
// Access modes for the first 4 operands. If there are more than
82
// four operands they use the same access mode as the 4th operand.
83
//
84
// u: unchanged
85
// r: (r)read access
86
// w: (w)write access
87
// m: (m)odify access (= read + write)
88
//
89
typedef enum e_access_mode {
90
91
  uuuu,
92
  rrrr,
93
  wwww,
94
  rwww,
95
  rrrm,
96
  rmmm,
97
  wrrr,
98
  mrrr,
99
  mwww,
100
  mmmm,
101
  mwrr,
102
  mmrr,
103
  wmmm,
104
  rruu,
105
  muuu,
106
  ACCESS_MODE_ENDING,
107
} e_access_mode;
108
109
// Access type values are compatible with enum cs_ac_type:
110
typedef cs_ac_type e_access;
111
0
#define UNCHANGED CS_AC_INVALID
112
386k
#define READ CS_AC_READ
113
489k
#define WRITE CS_AC_WRITE
114
596k
#define MODIFY CS_AC_READ_WRITE
115
116
/* Properties of one instruction in PAGE1 (without prefix) */
117
typedef struct inst_page1 {
118
  unsigned insn : 9; // A value of type m680x_insn
119
  unsigned handler_id1 : 6; // Type insn_hdlr_id, first instr. handler id
120
  unsigned handler_id2 : 6; // Type insn_hdlr_id, second instr. handler id
121
} inst_page1;
122
123
/* Properties of one instruction in any other PAGE X */
124
typedef struct inst_pageX {
125
  unsigned opcode : 8; // The opcode byte
126
  unsigned insn : 9; // A value of type m680x_insn
127
  unsigned handler_id1 : 6; // Type insn_hdlr_id, first instr. handler id
128
  unsigned handler_id2 : 6; // Type insn_hdlr_id, second instr. handler id
129
} inst_pageX;
130
131
typedef struct insn_props {
132
  unsigned group : 4;
133
  unsigned access_mode : 5; // A value of type e_access_mode
134
  unsigned reg0 : 5; // A value of type m680x_reg
135
  unsigned reg1 : 5; // A value of type m680x_reg
136
  bool cc_modified : 1;
137
  bool update_reg_access : 1;
138
} insn_props;
139
140
#include "m6800.inc"
141
#include "m6801.inc"
142
#include "hd6301.inc"
143
#include "m6811.inc"
144
#include "cpu12.inc"
145
#include "m6805.inc"
146
#include "m6808.inc"
147
#include "hcs08.inc"
148
#include "m6809.inc"
149
#include "hd6309.inc"
150
#include "rs08.inc"
151
#include "hcs12x.inc"
152
153
#include "insn_props.inc"
154
155
//////////////////////////////////////////////////////////////////////////////
156
157
// M680X instructions have 1 up to 8 bytes (CPU12: MOVW IDX2,IDX2).
158
// A reader is needed to read a byte or word from a given memory address.
159
// See also X86 reader(...)
160
static bool read_byte(const m680x_info *info, uint8_t *byte, uint16_t address)
161
908k
{
162
908k
  if (address < info->offset ||
163
908k
      (uint32_t)(address - info->offset) >= info->size)
164
    // out of code buffer range
165
1.74k
    return false;
166
167
907k
  *byte = info->code[address - info->offset];
168
169
907k
  return true;
170
908k
}
171
172
static bool read_byte_sign_extended(const m680x_info *info, int16_t *word,
173
            uint16_t address)
174
58.5k
{
175
58.5k
  if (address < info->offset ||
176
58.5k
      (uint32_t)(address - info->offset) >= info->size)
177
    // out of code buffer range
178
0
    return false;
179
180
58.5k
  *word = (int16_t)info->code[address - info->offset];
181
182
58.5k
  if (*word & 0x80)
183
21.6k
    *word |= 0xFF00;
184
185
58.5k
  return true;
186
58.5k
}
187
188
static bool read_word(const m680x_info *info, uint16_t *word, uint16_t address)
189
71.8k
{
190
71.8k
  if (address < info->offset ||
191
71.8k
      (uint32_t)(address + 1 - info->offset) >= info->size)
192
    // out of code buffer range
193
9
    return false;
194
195
71.8k
  *word = (uint16_t)info->code[address - info->offset] << 8;
196
71.8k
  *word |= (uint16_t)info->code[address + 1 - info->offset];
197
198
71.8k
  return true;
199
71.8k
}
200
201
static bool read_sdword(const m680x_info *info, int32_t *sdword,
202
      uint16_t address)
203
914
{
204
914
  if (address < info->offset ||
205
914
      (uint32_t)(address + 3 - info->offset) >= info->size)
206
    // out of code buffer range
207
0
    return false;
208
209
914
  *sdword = (uint32_t)info->code[address - info->offset] << 24;
210
914
  *sdword |= (uint32_t)info->code[address + 1 - info->offset] << 16;
211
914
  *sdword |= (uint32_t)info->code[address + 2 - info->offset] << 8;
212
914
  *sdword |= (uint32_t)info->code[address + 3 - info->offset];
213
214
914
  return true;
215
914
}
216
217
// For PAGE2 and PAGE3 opcodes when using an array of inst_page1 most
218
// entries have M680X_INS_ILLGL. To avoid wasting memory an inst_pageX is
219
// used which contains the opcode. Using a binary search for the right opcode
220
// is much faster (= O(log n) ) in comparison to a linear search ( = O(n) ).
221
static int binary_search(const inst_pageX *const inst_pageX_table,
222
       size_t table_size, unsigned int opcode)
223
135k
{
224
  // As part of the algorithm last may get negative.
225
  // => signed integer has to be used.
226
135k
  int first = 0;
227
135k
  int last = (int)table_size - 1;
228
135k
  int middle = (first + last) / 2;
229
230
681k
  while (first <= last) {
231
624k
    if (inst_pageX_table[middle].opcode < opcode) {
232
195k
      first = middle + 1;
233
428k
    } else if (inst_pageX_table[middle].opcode == opcode) {
234
78.4k
      return middle; /* item found */
235
78.4k
    } else
236
350k
      last = middle - 1;
237
238
546k
    middle = (first + last) / 2;
239
546k
  }
240
241
57.1k
  if (first > last)
242
57.1k
    return -1; /* item not found */
243
244
0
  return -2;
245
57.1k
}
246
247
void M680X_get_insn_id(cs_struct *handle, cs_insn *insn, unsigned int id)
248
384k
{
249
384k
  const m680x_info *const info = (const m680x_info *)handle->printer_info;
250
384k
  const cpu_tables *cpu = info->cpu;
251
384k
  uint8_t insn_prefix = (id >> 8) & 0xff;
252
  // opcode is the first instruction byte without the prefix.
253
384k
  uint8_t opcode = id & 0xff;
254
384k
  int index;
255
384k
  int i;
256
257
384k
  insn->id = M680X_INS_ILLGL;
258
259
922k
  for (i = 0; i < ARR_SIZE(cpu->pageX_prefix); ++i) {
260
898k
    if (cpu->pageX_table_size[i] == 0 ||
261
570k
        (cpu->inst_pageX_table[i] == NULL))
262
328k
      break;
263
264
570k
    if (cpu->pageX_prefix[i] == insn_prefix) {
265
32.0k
      index = binary_search(cpu->inst_pageX_table[i],
266
32.0k
                cpu->pageX_table_size[i], opcode);
267
32.0k
      insn->id =
268
32.0k
        (index >= 0) ?
269
19.6k
          cpu->inst_pageX_table[i][index].insn :
270
32.0k
          M680X_INS_ILLGL;
271
32.0k
      return;
272
32.0k
    }
273
570k
  }
274
275
352k
  if (insn_prefix != 0)
276
0
    return;
277
278
352k
  insn->id = cpu->inst_page1_table[id].insn;
279
280
352k
  if (insn->id != M680X_INS_ILLGL)
281
318k
    return;
282
283
  // Check if opcode byte is present in an overlay table
284
49.5k
  for (i = 0; i < ARR_SIZE(cpu->overlay_table_size); ++i) {
285
46.6k
    if (cpu->overlay_table_size[i] == 0 ||
286
35.7k
        (cpu->inst_overlay_table[i] == NULL))
287
10.9k
      break;
288
289
35.7k
    if ((index = binary_search(cpu->inst_overlay_table[i],
290
35.7k
             cpu->overlay_table_size[i],
291
35.7k
             opcode)) >= 0) {
292
19.5k
      insn->id = cpu->inst_overlay_table[i][index].insn;
293
19.5k
      return;
294
19.5k
    }
295
35.7k
  }
296
33.2k
}
297
298
static void add_insn_group(cs_detail *detail, m680x_group_type group)
299
378k
{
300
378k
  if (detail != NULL && (group != M680X_GRP_INVALID) &&
301
91.9k
      (group != M680X_GRP_ENDING))
302
91.9k
    detail->groups[detail->groups_count++] = (uint8_t)group;
303
378k
}
304
305
static bool exists_reg_list(uint16_t *regs, uint8_t count, m680x_reg reg)
306
1.08M
{
307
1.08M
  uint8_t i;
308
309
1.80M
  for (i = 0; i < count; ++i) {
310
755k
    if (regs[i] == (uint16_t)reg)
311
31.6k
      return true;
312
755k
  }
313
314
1.04M
  return false;
315
1.08M
}
316
317
static void add_reg_to_rw_list(MCInst *MI, m680x_reg reg, e_access access)
318
708k
{
319
708k
  cs_detail *detail = MI->flat_insn->detail;
320
321
708k
  if (detail == NULL || (reg == M680X_REG_INVALID))
322
0
    return;
323
324
708k
  switch (access) {
325
372k
  case MODIFY:
326
372k
    if (!exists_reg_list(detail->regs_read, detail->regs_read_count,
327
372k
             reg))
328
365k
      detail->regs_read[detail->regs_read_count++] =
329
365k
        (uint16_t)reg;
330
331
    // intentionally fall through
332
333
465k
  case WRITE:
334
465k
    if (!exists_reg_list(detail->regs_write,
335
465k
             detail->regs_write_count, reg))
336
457k
      detail->regs_write[detail->regs_write_count++] =
337
457k
        (uint16_t)reg;
338
339
465k
    break;
340
341
242k
  case READ:
342
242k
    if (!exists_reg_list(detail->regs_read, detail->regs_read_count,
343
242k
             reg))
344
225k
      detail->regs_read[detail->regs_read_count++] =
345
225k
        (uint16_t)reg;
346
347
242k
    break;
348
349
0
  case UNCHANGED:
350
0
  default:
351
0
    break;
352
708k
  }
353
708k
}
354
355
static void update_am_reg_list(MCInst *MI, m680x_info *info, cs_m680x_op *op,
356
             e_access access)
357
496k
{
358
496k
  if (MI->flat_insn->detail == NULL)
359
0
    return;
360
361
496k
  switch (op->type) {
362
219k
  case M680X_OP_REGISTER:
363
219k
    add_reg_to_rw_list(MI, op->reg, access);
364
219k
    break;
365
366
93.7k
  case M680X_OP_INDEXED:
367
93.7k
    add_reg_to_rw_list(MI, op->idx.base_reg, READ);
368
369
93.7k
    if (op->idx.base_reg == M680X_REG_X &&
370
40.7k
        info->cpu->reg_byte_size[M680X_REG_H])
371
14.1k
      add_reg_to_rw_list(MI, M680X_REG_H, READ);
372
373
93.7k
    if (op->idx.offset_reg != M680X_REG_INVALID)
374
8.93k
      add_reg_to_rw_list(MI, op->idx.offset_reg, READ);
375
376
93.7k
    if (op->idx.inc_dec) {
377
19.6k
      add_reg_to_rw_list(MI, op->idx.base_reg, WRITE);
378
379
19.6k
      if (op->idx.base_reg == M680X_REG_X &&
380
6.60k
          info->cpu->reg_byte_size[M680X_REG_H])
381
3.00k
        add_reg_to_rw_list(MI, M680X_REG_H, WRITE);
382
19.6k
    }
383
384
93.7k
    break;
385
386
182k
  default:
387
182k
    break;
388
496k
  }
389
496k
}
390
391
static const e_access g_access_mode_to_access[4][15] = {
392
  {
393
    UNCHANGED,
394
    READ,
395
    WRITE,
396
    READ,
397
    READ,
398
    READ,
399
    WRITE,
400
    MODIFY,
401
    MODIFY,
402
    MODIFY,
403
    MODIFY,
404
    MODIFY,
405
    WRITE,
406
    READ,
407
    MODIFY,
408
  },
409
  {
410
    UNCHANGED,
411
    READ,
412
    WRITE,
413
    WRITE,
414
    READ,
415
    MODIFY,
416
    READ,
417
    READ,
418
    WRITE,
419
    MODIFY,
420
    WRITE,
421
    MODIFY,
422
    MODIFY,
423
    READ,
424
    UNCHANGED,
425
  },
426
  {
427
    UNCHANGED,
428
    READ,
429
    WRITE,
430
    WRITE,
431
    READ,
432
    MODIFY,
433
    READ,
434
    READ,
435
    WRITE,
436
    MODIFY,
437
    READ,
438
    READ,
439
    MODIFY,
440
    UNCHANGED,
441
    UNCHANGED,
442
  },
443
  {
444
    UNCHANGED,
445
    READ,
446
    WRITE,
447
    WRITE,
448
    MODIFY,
449
    MODIFY,
450
    READ,
451
    READ,
452
    WRITE,
453
    MODIFY,
454
    READ,
455
    READ,
456
    MODIFY,
457
    UNCHANGED,
458
    UNCHANGED,
459
  },
460
};
461
462
static e_access get_access(int operator_index, e_access_mode access_mode)
463
1.05M
{
464
1.05M
  int idx = (operator_index > 3) ? 3 : operator_index;
465
466
1.05M
  return g_access_mode_to_access[idx][access_mode];
467
1.05M
}
468
469
static void build_regs_read_write_counts(MCInst *MI, m680x_info *info,
470
           e_access_mode access_mode)
471
343k
{
472
343k
  cs_m680x *m680x = &info->m680x;
473
343k
  int i;
474
475
343k
  if (MI->flat_insn->detail == NULL || (!m680x->op_count))
476
47.0k
    return;
477
478
792k
  for (i = 0; i < m680x->op_count; ++i) {
479
496k
    e_access access = get_access(i, access_mode);
480
496k
    update_am_reg_list(MI, info, &m680x->operands[i], access);
481
496k
  }
482
296k
}
483
484
static void add_operators_access(MCInst *MI, m680x_info *info,
485
         e_access_mode access_mode)
486
343k
{
487
343k
  cs_m680x *m680x = &info->m680x;
488
343k
  int offset = 0;
489
343k
  int i;
490
491
343k
  if (MI->flat_insn->detail == NULL || (!m680x->op_count) ||
492
296k
      (access_mode == uuuu))
493
84.0k
    return;
494
495
717k
  for (i = 0; i < m680x->op_count; ++i) {
496
458k
    e_access access;
497
498
    // Ugly fix: MULD has a register operand, an immediate operand
499
    // AND an implicitly changed register W
500
458k
    if (info->insn == M680X_INS_MULD && (i == 1))
501
371
      offset = 1;
502
503
458k
    access = get_access(i + offset, access_mode);
504
458k
    m680x->operands[i].access = access;
505
458k
  }
506
259k
}
507
508
typedef struct insn_to_changed_regs {
509
  m680x_insn insn;
510
  e_access_mode access_mode;
511
  m680x_reg regs[10];
512
} insn_to_changed_regs;
513
514
static void set_changed_regs_read_write_counts(MCInst *MI, m680x_info *info)
515
35.8k
{
516
  //TABLE
517
1.96M
#define EOL M680X_REG_INVALID
518
35.8k
  static const insn_to_changed_regs changed_regs[] = {
519
35.8k
    { M680X_INS_BSR, mmmm, { M680X_REG_S, EOL } },
520
35.8k
    { M680X_INS_CALL, mmmm, { M680X_REG_S, EOL } },
521
35.8k
    {
522
35.8k
      M680X_INS_CWAI,
523
35.8k
      mrrr,
524
35.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
525
35.8k
        M680X_REG_X, M680X_REG_DP, M680X_REG_D, M680X_REG_CC,
526
35.8k
        EOL },
527
35.8k
    },
528
35.8k
    { M680X_INS_DAA, mrrr, { M680X_REG_A, EOL } },
529
35.8k
    { M680X_INS_DIV,
530
35.8k
      mmrr,
531
35.8k
      { M680X_REG_A, M680X_REG_H, M680X_REG_X, EOL } },
532
35.8k
    { M680X_INS_EDIV,
533
35.8k
      mmrr,
534
35.8k
      { M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL } },
535
35.8k
    { M680X_INS_EDIVS,
536
35.8k
      mmrr,
537
35.8k
      { M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL } },
538
35.8k
    { M680X_INS_EMACS, mrrr, { M680X_REG_X, M680X_REG_Y, EOL } },
539
35.8k
    { M680X_INS_EMAXM, rrrr, { M680X_REG_D, EOL } },
540
35.8k
    { M680X_INS_EMINM, rrrr, { M680X_REG_D, EOL } },
541
35.8k
    { M680X_INS_EMUL, mmrr, { M680X_REG_D, M680X_REG_Y, EOL } },
542
35.8k
    { M680X_INS_EMULS, mmrr, { M680X_REG_D, M680X_REG_Y, EOL } },
543
35.8k
    { M680X_INS_ETBL, wmmm, { M680X_REG_A, M680X_REG_B, EOL } },
544
35.8k
    { M680X_INS_FDIV, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
545
35.8k
    { M680X_INS_IDIV, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
546
35.8k
    { M680X_INS_IDIVS, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
547
35.8k
    { M680X_INS_JSR, mmmm, { M680X_REG_S, EOL } },
548
35.8k
    { M680X_INS_LBSR, mmmm, { M680X_REG_S, EOL } },
549
35.8k
    { M680X_INS_MAXM, rrrr, { M680X_REG_A, EOL } },
550
35.8k
    { M680X_INS_MINM, rrrr, { M680X_REG_A, EOL } },
551
35.8k
    { M680X_INS_MEM,
552
35.8k
      mmrr,
553
35.8k
      { M680X_REG_X, M680X_REG_Y, M680X_REG_A, EOL } },
554
35.8k
    { M680X_INS_MUL, mmmm, { M680X_REG_A, M680X_REG_B, EOL } },
555
35.8k
    { M680X_INS_MULD, mwrr, { M680X_REG_D, M680X_REG_W, EOL } },
556
35.8k
    { M680X_INS_PSHA, rmmm, { M680X_REG_A, M680X_REG_S, EOL } },
557
35.8k
    { M680X_INS_PSHB, rmmm, { M680X_REG_B, M680X_REG_S, EOL } },
558
35.8k
    { M680X_INS_PSHC, rmmm, { M680X_REG_CC, M680X_REG_S, EOL } },
559
35.8k
    { M680X_INS_PSHD, rmmm, { M680X_REG_D, M680X_REG_S, EOL } },
560
35.8k
    { M680X_INS_PSHH, rmmm, { M680X_REG_H, M680X_REG_S, EOL } },
561
35.8k
    { M680X_INS_PSHX, rmmm, { M680X_REG_X, M680X_REG_S, EOL } },
562
35.8k
    { M680X_INS_PSHY, rmmm, { M680X_REG_Y, M680X_REG_S, EOL } },
563
35.8k
    { M680X_INS_PULA, wmmm, { M680X_REG_A, M680X_REG_S, EOL } },
564
35.8k
    { M680X_INS_PULB, wmmm, { M680X_REG_B, M680X_REG_S, EOL } },
565
35.8k
    { M680X_INS_PULC, wmmm, { M680X_REG_CC, M680X_REG_S, EOL } },
566
35.8k
    { M680X_INS_PULD, wmmm, { M680X_REG_D, M680X_REG_S, EOL } },
567
35.8k
    { M680X_INS_PULH, wmmm, { M680X_REG_H, M680X_REG_S, EOL } },
568
35.8k
    { M680X_INS_PULX, wmmm, { M680X_REG_X, M680X_REG_S, EOL } },
569
35.8k
    { M680X_INS_PULY, wmmm, { M680X_REG_Y, M680X_REG_S, EOL } },
570
35.8k
    { M680X_INS_REV,
571
35.8k
      mmrr,
572
35.8k
      { M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL } },
573
35.8k
    { M680X_INS_REVW,
574
35.8k
      mmmm,
575
35.8k
      { M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL } },
576
35.8k
    { M680X_INS_RTC, mwww, { M680X_REG_S, M680X_REG_PC, EOL } },
577
35.8k
    {
578
35.8k
      M680X_INS_RTI,
579
35.8k
      mwww,
580
35.8k
      { M680X_REG_S, M680X_REG_CC, M680X_REG_B, M680X_REG_A,
581
35.8k
        M680X_REG_DP, M680X_REG_X, M680X_REG_Y, M680X_REG_U,
582
35.8k
        M680X_REG_PC, EOL },
583
35.8k
    },
584
35.8k
    { M680X_INS_RTS, mwww, { M680X_REG_S, M680X_REG_PC, EOL } },
585
35.8k
    { M680X_INS_SEX, wrrr, { M680X_REG_A, M680X_REG_B, EOL } },
586
35.8k
    { M680X_INS_SEXW, rwww, { M680X_REG_W, M680X_REG_D, EOL } },
587
35.8k
    { M680X_INS_SWI,
588
35.8k
      mmrr,
589
35.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
590
35.8k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
591
35.8k
        M680X_REG_CC, EOL } },
592
35.8k
    {
593
35.8k
      M680X_INS_SWI2,
594
35.8k
      mmrr,
595
35.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
596
35.8k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
597
35.8k
        M680X_REG_CC, EOL },
598
35.8k
    },
599
35.8k
    {
600
35.8k
      M680X_INS_SWI3,
601
35.8k
      mmrr,
602
35.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
603
35.8k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
604
35.8k
        M680X_REG_CC, EOL },
605
35.8k
    },
606
35.8k
    { M680X_INS_TBL, wrrr, { M680X_REG_A, M680X_REG_B, EOL } },
607
35.8k
    { M680X_INS_WAI,
608
35.8k
      mrrr,
609
35.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_X, M680X_REG_A,
610
35.8k
        M680X_REG_B, M680X_REG_CC, EOL } },
611
35.8k
    { M680X_INS_WAV,
612
35.8k
      rmmm,
613
35.8k
      { M680X_REG_A, M680X_REG_B, M680X_REG_X, M680X_REG_Y, EOL } },
614
35.8k
    { M680X_INS_WAVR,
615
35.8k
      rmmm,
616
35.8k
      { M680X_REG_A, M680X_REG_B, M680X_REG_X, M680X_REG_Y, EOL } },
617
35.8k
  };
618
619
35.8k
  int i, j;
620
621
35.8k
  if (MI->flat_insn->detail == NULL)
622
0
    return;
623
624
1.86M
  for (i = 0; i < ARR_SIZE(changed_regs); ++i) {
625
1.82M
    if (info->insn == changed_regs[i].insn) {
626
35.8k
      e_access_mode access_mode = changed_regs[i].access_mode;
627
628
141k
      for (j = 0; changed_regs[i].regs[j] != EOL; ++j) {
629
105k
        e_access access;
630
631
105k
        m680x_reg reg = changed_regs[i].regs[j];
632
633
105k
        if (!info->cpu->reg_byte_size[reg]) {
634
8.81k
          if (info->insn != M680X_INS_MUL)
635
8.26k
            continue;
636
637
          // Hack for M68HC05: MUL uses reg. A,X
638
555
          reg = M680X_REG_X;
639
555
        }
640
641
97.2k
        access = get_access(j, access_mode);
642
97.2k
        add_reg_to_rw_list(MI, reg, access);
643
97.2k
      }
644
35.8k
    }
645
1.82M
  }
646
647
35.8k
#undef EOL
648
35.8k
}
649
650
typedef struct insn_desc {
651
  uint32_t opcode;
652
  m680x_insn insn;
653
  insn_hdlr_id hid[2];
654
  uint16_t insn_size;
655
} insn_desc;
656
657
// If successful return the additional byte size needed for M6809
658
// indexed addressing mode (including the indexed addressing post_byte).
659
// On error return -1.
660
static int get_indexed09_post_byte_size(const m680x_info *info,
661
          uint16_t address)
662
40.1k
{
663
40.1k
  uint8_t ir = 0;
664
40.1k
  uint8_t post_byte;
665
666
  // Read the indexed addressing post byte.
667
40.1k
  if (!read_byte(info, &post_byte, address))
668
178
    return -1;
669
670
  // Depending on the indexed addressing mode more bytes have to be read.
671
39.9k
  switch (post_byte & 0x9F) {
672
864
  case 0x87:
673
1.54k
  case 0x8A:
674
3.40k
  case 0x8E:
675
4.73k
  case 0x8F:
676
5.53k
  case 0x90:
677
6.18k
  case 0x92:
678
6.65k
  case 0x97:
679
7.00k
  case 0x9A:
680
7.43k
  case 0x9E:
681
7.43k
    return -1; // illegal indexed post bytes
682
683
1.64k
  case 0x88: // n8,R
684
2.77k
  case 0x8C: // n8,PCR
685
3.38k
  case 0x98: // [n8,R]
686
4.15k
  case 0x9C: // [n8,PCR]
687
4.15k
    if (!read_byte(info, &ir, address + 1))
688
23
      return -1;
689
4.13k
    return 2;
690
691
978
  case 0x89: // n16,R
692
2.10k
  case 0x8D: // n16,PCR
693
2.89k
  case 0x99: // [n16,R]
694
3.76k
  case 0x9D: // [n16,PCR]
695
3.76k
    if (!read_byte(info, &ir, address + 2))
696
48
      return -1;
697
3.72k
    return 3;
698
699
1.02k
  case 0x9F: // [n]
700
1.02k
    if ((post_byte & 0x60) != 0 ||
701
412
        !read_byte(info, &ir, address + 2))
702
625
      return -1;
703
400
    return 3;
704
39.9k
  }
705
706
  // Any other indexed post byte is valid and
707
  // no additional bytes have to be read.
708
23.5k
  return 1;
709
39.9k
}
710
711
// If successful return the additional byte size needed for CPU12
712
// indexed addressing mode (including the indexed addressing post_byte).
713
// On error return -1.
714
static int get_indexed12_post_byte_size(const m680x_info *info,
715
          uint16_t address, bool is_subset)
716
38.0k
{
717
38.0k
  uint8_t ir;
718
38.0k
  uint8_t post_byte;
719
720
  // Read the indexed addressing post byte.
721
38.0k
  if (!read_byte(info, &post_byte, address))
722
131
    return -1;
723
724
  // Depending on the indexed addressing mode more bytes have to be read.
725
37.8k
  if (!(post_byte & 0x20)) // n5,R
726
12.1k
    return 1;
727
728
25.7k
  switch (post_byte & 0xe7) {
729
2.16k
  case 0xe0:
730
4.94k
  case 0xe1: // n9,R
731
4.94k
    if (is_subset)
732
342
      return -1;
733
734
4.60k
    if (!read_byte(info, &ir, address))
735
0
      return -1;
736
4.60k
    return 2;
737
738
2.48k
  case 0xe2: // n16,R
739
4.50k
  case 0xe3: // [n16,R]
740
4.50k
    if (is_subset)
741
468
      return -1;
742
743
4.03k
    if (!read_byte(info, &ir, address + 1))
744
21
      return -1;
745
4.01k
    return 3;
746
747
827
  case 0xe4: // A,R
748
1.75k
  case 0xe5: // B,R
749
2.25k
  case 0xe6: // D,R
750
4.25k
  case 0xe7: // [D,R]
751
16.3k
  default: // n,-r n,+r n,r- n,r+
752
16.3k
    break;
753
25.7k
  }
754
755
16.3k
  return 1;
756
25.7k
}
757
758
// Check for M6809/HD6309 TFR/EXG instruction for valid register
759
static bool is_tfr09_reg_valid(const m680x_info *info, uint8_t reg_nibble)
760
7.29k
{
761
7.29k
  if (info->cpu->tfr_reg_valid != NULL)
762
2.29k
    return info->cpu->tfr_reg_valid[reg_nibble];
763
764
5.00k
  return true; // e.g. for the M6309 all registers are valid
765
7.29k
}
766
767
// Check for CPU12 TFR/EXG instruction for valid register
768
static bool is_exg_tfr12_post_byte_valid(const m680x_info *info,
769
           uint8_t post_byte)
770
1.95k
{
771
1.95k
  return !(post_byte & 0x08);
772
1.95k
}
773
774
static bool is_tfm_reg_valid(const m680x_info *info, uint8_t reg_nibble)
775
2.74k
{
776
  // HD6809 TFM instruction: Only register X,Y,U,S,D is allowed
777
2.74k
  return reg_nibble <= 4;
778
2.74k
}
779
780
// If successful return the additional byte size needed for CPU12
781
// loop instructions DBEQ/DBNE/IBEQ/IBNE/TBEQ/TBNE (including the post byte).
782
// On error return -1.
783
static int get_loop_post_byte_size(const m680x_info *info, uint16_t address)
784
4.15k
{
785
4.15k
  uint8_t post_byte;
786
4.15k
  uint8_t rr;
787
788
4.15k
  if (!read_byte(info, &post_byte, address))
789
15
    return -1;
790
791
  // According to documentation bit 3 is don't care and not checked here.
792
4.13k
  if ((post_byte >= 0xc0) || ((post_byte & 0x07) == 2) ||
793
2.80k
      ((post_byte & 0x07) == 3))
794
1.67k
    return -1;
795
796
2.46k
  if (!read_byte(info, &rr, address + 1))
797
6
    return -1;
798
799
2.45k
  return 2;
800
2.46k
}
801
802
// If successful return the additional byte size needed for HD6309
803
// bit move instructions BAND/BEOR/BIAND/BIEOR/BIOR/BOR/LDBT/STBT
804
// (including the post byte).
805
// On error return -1.
806
static int get_bitmv_post_byte_size(const m680x_info *info, uint16_t address)
807
1.07k
{
808
1.07k
  uint8_t post_byte;
809
1.07k
  uint8_t rr;
810
811
1.07k
  if (!read_byte(info, &post_byte, address))
812
5
    return -1;
813
814
1.06k
  if ((post_byte & 0xc0) == 0xc0)
815
453
    return -1; // Invalid register specified
816
616
  else {
817
616
    if (!read_byte(info, &rr, address + 1))
818
6
      return -1;
819
616
  }
820
821
610
  return 2;
822
1.06k
}
823
824
static bool is_sufficient_code_size(const m680x_info *info, uint16_t address,
825
            insn_desc *insn_description)
826
133k
{
827
133k
  int i;
828
133k
  bool retval = true;
829
133k
  uint16_t size = 0;
830
133k
  int sz;
831
832
391k
  for (i = 0; i < 2; i++) {
833
262k
    uint8_t ir = 0;
834
262k
    bool is_subset = false;
835
836
262k
    switch (insn_description->hid[i]) {
837
90
    case imm32_hid:
838
90
      if ((retval = read_byte(info, &ir, address + size + 3)))
839
73
        size += 4;
840
90
      break;
841
842
17.4k
    case ext_hid:
843
18.8k
    case imm16_hid:
844
19.8k
    case rel16_hid:
845
20.8k
    case imm8rel_hid:
846
21.9k
    case opidxdr_hid:
847
22.3k
    case idxX16_hid:
848
22.4k
    case idxS16_hid:
849
22.4k
    case dirdir_hid:
850
22.5k
    case immdir_hid:
851
22.5k
      if ((retval = read_byte(info, &ir, address + size + 1)))
852
22.3k
        size += 2;
853
22.5k
      break;
854
855
10.4k
    case rel8_hid:
856
28.2k
    case dir_hid:
857
29.6k
    case rbits_hid:
858
37.4k
    case imm8_hid:
859
40.8k
    case idxX_hid:
860
41.8k
    case idxXp_hid:
861
42.7k
    case idxY_hid:
862
42.8k
    case idxS_hid:
863
43.1k
    case index_hid:
864
43.1k
      if ((retval = read_byte(info, &ir, address + size)))
865
42.8k
        size++;
866
43.1k
      break;
867
868
0
    case illgl_hid:
869
160k
    case inh_hid:
870
162k
    case idxX0_hid:
871
162k
    case idxX0p_hid:
872
163k
    case opidx_hid:
873
164k
    case srt_hid:
874
165k
    case tny_hid:
875
165k
      retval = true;
876
165k
      break;
877
878
13.6k
    case idx09_hid:
879
13.6k
      sz = get_indexed09_post_byte_size(info, address + size);
880
13.6k
      if (sz >= 0)
881
10.9k
        size += sz;
882
2.72k
      else
883
2.72k
        retval = false;
884
13.6k
      break;
885
886
220
    case idx12s_hid:
887
220
      is_subset = true;
888
889
      // intentionally fall through
890
891
11.5k
    case idx12_hid:
892
11.5k
      sz = get_indexed12_post_byte_size(info, address + size,
893
11.5k
                is_subset);
894
11.5k
      if (sz >= 0)
895
11.3k
        size += sz;
896
185
      else
897
185
        retval = false;
898
11.5k
      break;
899
900
627
    case exti12x_hid:
901
1.13k
    case imm16i12x_hid:
902
1.13k
      sz = get_indexed12_post_byte_size(info, address + size,
903
1.13k
                false);
904
1.13k
      if (sz >= 0) {
905
1.13k
        size += sz;
906
1.13k
        if ((retval = read_byte(info, &ir,
907
1.13k
              address + size + 1)))
908
1.13k
          size += 2;
909
1.13k
      } else
910
1
        retval = false;
911
1.13k
      break;
912
913
505
    case imm8i12x_hid:
914
505
      sz = get_indexed12_post_byte_size(info, address + size,
915
505
                false);
916
505
      if (sz >= 0) {
917
501
        size += sz;
918
501
        if ((retval = read_byte(info, &ir,
919
501
              address + size)))
920
497
          size++;
921
501
      } else
922
4
        retval = false;
923
505
      break;
924
925
444
    case tfm_hid:
926
444
      if ((retval = read_byte(info, &ir, address + size))) {
927
443
        size++;
928
443
        retval = is_tfm_reg_valid(info,
929
443
                (ir >> 4) & 0x0F) &&
930
376
           is_tfm_reg_valid(info, ir & 0x0F);
931
443
      }
932
444
      break;
933
934
1.23k
    case rr09_hid:
935
1.23k
      if ((retval = read_byte(info, &ir, address + size))) {
936
1.22k
        size++;
937
1.22k
        retval = is_tfr09_reg_valid(info,
938
1.22k
                  (ir >> 4) & 0x0F) &&
939
1.04k
           is_tfr09_reg_valid(info, ir & 0x0F);
940
1.22k
      }
941
1.23k
      break;
942
943
908
    case rr12_hid:
944
908
      if ((retval = read_byte(info, &ir, address + size))) {
945
904
        size++;
946
904
        retval = is_exg_tfr12_post_byte_valid(info, ir);
947
904
      }
948
908
      break;
949
950
317
    case bitmv_hid:
951
317
      sz = get_bitmv_post_byte_size(info, address + size);
952
317
      if (sz >= 0)
953
265
        size += sz;
954
52
      else
955
52
        retval = false;
956
317
      break;
957
958
1.82k
    case loop_hid:
959
1.82k
      sz = get_loop_post_byte_size(info, address + size);
960
1.82k
      if (sz >= 0)
961
1.48k
        size += sz;
962
336
      else
963
336
        retval = false;
964
1.82k
      break;
965
966
0
    default:
967
0
      CS_ASSERT(0 && "Unexpected instruction handler id");
968
0
      retval = false;
969
0
      break;
970
262k
    }
971
972
262k
    if (!retval)
973
4.55k
      return false;
974
262k
  }
975
976
128k
  insn_description->insn_size += size;
977
978
128k
  return retval;
979
133k
}
980
981
// Check for a valid M680X instruction AND for enough bytes in the code buffer
982
// Return an instruction description in insn_desc.
983
static bool decode_insn(const m680x_info *info, uint16_t address,
984
      insn_desc *insn_description)
985
384k
{
986
384k
  const inst_pageX *inst_table = NULL;
987
384k
  const cpu_tables *cpu = info->cpu;
988
384k
  size_t table_size = 0;
989
384k
  uint16_t base_address = address;
990
384k
  uint8_t ir; // instruction register
991
384k
  int i;
992
384k
  int index;
993
994
384k
  if (!read_byte(info, &ir, address++))
995
0
    return false;
996
997
384k
  insn_description->insn = M680X_INS_ILLGL;
998
384k
  insn_description->opcode = ir;
999
1000
  // Check if a page prefix byte is present
1001
922k
  for (i = 0; i < ARR_SIZE(cpu->pageX_table_size); ++i) {
1002
898k
    if (cpu->pageX_table_size[i] == 0 ||
1003
570k
        (cpu->inst_pageX_table[i] == NULL))
1004
328k
      break;
1005
1006
570k
    if ((cpu->pageX_prefix[i] == ir)) {
1007
      // Get pageX instruction and handler id.
1008
      // Abort for illegal instr.
1009
32.1k
      inst_table = cpu->inst_pageX_table[i];
1010
32.1k
      table_size = cpu->pageX_table_size[i];
1011
1012
32.1k
      if (!read_byte(info, &ir, address++))
1013
53
        return false;
1014
1015
32.0k
      insn_description->opcode =
1016
32.0k
        (insn_description->opcode << 8) | ir;
1017
1018
32.0k
      if ((index = binary_search(inst_table, table_size,
1019
32.0k
               ir)) < 0)
1020
12.3k
        return false;
1021
1022
19.6k
      insn_description->hid[0] =
1023
19.6k
        inst_table[index].handler_id1;
1024
19.6k
      insn_description->hid[1] =
1025
19.6k
        inst_table[index].handler_id2;
1026
19.6k
      insn_description->insn = inst_table[index].insn;
1027
19.6k
      break;
1028
32.0k
    }
1029
570k
  }
1030
1031
371k
  if (insn_description->insn == M680X_INS_ILLGL) {
1032
    // Get page1 insn description
1033
352k
    insn_description->insn = cpu->inst_page1_table[ir].insn;
1034
352k
    insn_description->hid[0] =
1035
352k
      cpu->inst_page1_table[ir].handler_id1;
1036
352k
    insn_description->hid[1] =
1037
352k
      cpu->inst_page1_table[ir].handler_id2;
1038
352k
  }
1039
1040
371k
  if (insn_description->insn == M680X_INS_ILLGL) {
1041
    // Check if opcode byte is present in an overlay table
1042
49.4k
    for (i = 0; i < ARR_SIZE(cpu->overlay_table_size); ++i) {
1043
46.6k
      if (cpu->overlay_table_size[i] == 0 ||
1044
35.7k
          (cpu->inst_overlay_table[i] == NULL))
1045
10.9k
        break;
1046
1047
35.7k
      inst_table = cpu->inst_overlay_table[i];
1048
35.7k
      table_size = cpu->overlay_table_size[i];
1049
1050
35.7k
      if ((index = binary_search(inst_table, table_size,
1051
35.7k
               ir)) >= 0) {
1052
19.5k
        insn_description->hid[0] =
1053
19.5k
          inst_table[index].handler_id1;
1054
19.5k
        insn_description->hid[1] =
1055
19.5k
          inst_table[index].handler_id2;
1056
19.5k
        insn_description->insn = inst_table[index].insn;
1057
19.5k
        break;
1058
19.5k
      }
1059
35.7k
    }
1060
33.2k
  }
1061
1062
371k
  insn_description->insn_size = address - base_address;
1063
1064
371k
  return (insn_description->insn != M680X_INS_ILLGL) &&
1065
357k
         (insn_description->insn != M680X_INS_INVLD) &&
1066
357k
         is_sufficient_code_size(info, address, insn_description);
1067
384k
}
1068
1069
static void illegal_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1070
41.0k
{
1071
41.0k
  cs_m680x_op *op0 = &info->m680x.operands[info->m680x.op_count++];
1072
41.0k
  uint8_t temp8 = 0;
1073
1074
41.0k
  info->insn = M680X_INS_ILLGL;
1075
41.0k
  read_byte(info, &temp8, (*address)++);
1076
41.0k
  op0->imm = (int32_t)temp8 & 0xff;
1077
41.0k
  op0->type = M680X_OP_IMMEDIATE;
1078
41.0k
  op0->size = 1;
1079
41.0k
}
1080
1081
static void inherent_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1082
419k
{
1083
  // There is nothing to do here :-)
1084
419k
}
1085
1086
static void add_reg_operand(m680x_info *info, m680x_reg reg)
1087
219k
{
1088
219k
  cs_m680x *m680x = &info->m680x;
1089
219k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1090
1091
219k
  op->type = M680X_OP_REGISTER;
1092
219k
  op->reg = reg;
1093
219k
  op->size = info->cpu->reg_byte_size[reg];
1094
219k
}
1095
1096
static void set_operand_size(m680x_info *info, cs_m680x_op *op,
1097
           uint8_t default_size)
1098
232k
{
1099
232k
  cs_m680x *m680x = &info->m680x;
1100
1101
232k
  if (info->insn == M680X_INS_JMP || info->insn == M680X_INS_JSR)
1102
13.2k
    op->size = 0;
1103
218k
  else if (info->insn == M680X_INS_DIVD ||
1104
218k
     ((info->insn == M680X_INS_AIS ||
1105
217k
       info->insn == M680X_INS_AIX) &&
1106
917
      op->type != M680X_OP_REGISTER))
1107
1.69k
    op->size = 1;
1108
217k
  else if (info->insn == M680X_INS_DIVQ || info->insn == M680X_INS_MOVW)
1109
7.60k
    op->size = 2;
1110
209k
  else if (info->insn == M680X_INS_EMACS)
1111
808
    op->size = 4;
1112
208k
  else if ((m680x->op_count > 0) &&
1113
208k
     (m680x->operands[0].type == M680X_OP_REGISTER))
1114
130k
    op->size = m680x->operands[0].size;
1115
78.3k
  else
1116
78.3k
    op->size = default_size;
1117
232k
}
1118
1119
static const m680x_reg reg_s_reg_ids[] = {
1120
  M680X_REG_CC, M680X_REG_A, M680X_REG_B, M680X_REG_DP,
1121
  M680X_REG_X,  M680X_REG_Y, M680X_REG_U, M680X_REG_PC,
1122
};
1123
1124
static const m680x_reg reg_u_reg_ids[] = {
1125
  M680X_REG_CC, M680X_REG_A, M680X_REG_B, M680X_REG_DP,
1126
  M680X_REG_X,  M680X_REG_Y, M680X_REG_S, M680X_REG_PC,
1127
};
1128
1129
static void reg_bits_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1130
1.38k
{
1131
1.38k
  cs_m680x_op *op0 = &info->m680x.operands[0];
1132
1.38k
  uint8_t reg_bits = 0;
1133
1.38k
  uint16_t bit_index;
1134
1.38k
  const m680x_reg *reg_to_reg_ids = NULL;
1135
1136
1.38k
  read_byte(info, &reg_bits, (*address)++);
1137
1138
1.38k
  switch (op0->reg) {
1139
505
  case M680X_REG_U:
1140
505
    reg_to_reg_ids = &reg_u_reg_ids[0];
1141
505
    break;
1142
1143
877
  case M680X_REG_S:
1144
877
    reg_to_reg_ids = &reg_s_reg_ids[0];
1145
877
    break;
1146
1147
0
  default:
1148
0
    CS_ASSERT(0 && "Unexpected operand0 register");
1149
0
    break;
1150
1.38k
  }
1151
1152
1.38k
  if ((info->insn == M680X_INS_PULU || (info->insn == M680X_INS_PULS)) &&
1153
880
      ((reg_bits & 0x80) != 0))
1154
    // PULS xxx,PC or PULU xxx,PC which is like return from
1155
    // subroutine (RTS)
1156
302
    add_insn_group(MI->flat_insn->detail, M680X_GRP_RET);
1157
1158
12.4k
  for (bit_index = 0; bit_index < 8; ++bit_index) {
1159
11.0k
    if (reg_bits & (1 << bit_index) && reg_to_reg_ids)
1160
6.28k
      add_reg_operand(info, reg_to_reg_ids[bit_index]);
1161
11.0k
  }
1162
1.38k
}
1163
1164
static const m680x_reg g_tfr_exg_reg_ids[] = {
1165
  /* 16-bit registers */
1166
  M680X_REG_D,
1167
  M680X_REG_X,
1168
  M680X_REG_Y,
1169
  M680X_REG_U,
1170
  M680X_REG_S,
1171
  M680X_REG_PC,
1172
  M680X_REG_W,
1173
  M680X_REG_V,
1174
  /* 8-bit registers */
1175
  M680X_REG_A,
1176
  M680X_REG_B,
1177
  M680X_REG_CC,
1178
  M680X_REG_DP,
1179
  M680X_REG_0,
1180
  M680X_REG_0,
1181
  M680X_REG_E,
1182
  M680X_REG_F,
1183
};
1184
1185
static void reg_reg09_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1186
2.85k
{
1187
2.85k
  uint8_t regs = 0;
1188
1189
2.85k
  read_byte(info, &regs, (*address)++);
1190
1191
2.85k
  add_reg_operand(info, g_tfr_exg_reg_ids[regs >> 4]);
1192
2.85k
  add_reg_operand(info, g_tfr_exg_reg_ids[regs & 0x0f]);
1193
1194
2.85k
  if ((regs & 0x0f) == 0x05) {
1195
    // EXG xxx,PC or TFR xxx,PC which is like a JMP
1196
297
    add_insn_group(MI->flat_insn->detail, M680X_GRP_JUMP);
1197
297
  }
1198
2.85k
}
1199
1200
static void reg_reg12_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1201
1.57k
{
1202
1.57k
  static const m680x_reg g_tfr_exg12_reg0_ids[] = {
1203
1.57k
    M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP3,
1204
1.57k
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,  M680X_REG_S,
1205
1.57k
  };
1206
1.57k
  static const m680x_reg g_tfr_exg12_reg1_ids[] = {
1207
1.57k
    M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP2,
1208
1.57k
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,  M680X_REG_S,
1209
1.57k
  };
1210
1.57k
  uint8_t regs = 0;
1211
1212
1.57k
  read_byte(info, &regs, (*address)++);
1213
1214
  // The opcode of this instruction depends on
1215
  // the msb of its post byte.
1216
1.57k
  if (regs & 0x80)
1217
1.23k
    info->insn = M680X_INS_EXG;
1218
336
  else
1219
336
    info->insn = M680X_INS_TFR;
1220
1221
1.57k
  add_reg_operand(info, g_tfr_exg12_reg0_ids[(regs >> 4) & 0x07]);
1222
1.57k
  add_reg_operand(info, g_tfr_exg12_reg1_ids[regs & 0x07]);
1223
1.57k
}
1224
1225
static void add_rel_operand(m680x_info *info, int16_t offset, uint16_t address)
1226
32.1k
{
1227
32.1k
  cs_m680x *m680x = &info->m680x;
1228
32.1k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1229
1230
32.1k
  op->type = M680X_OP_RELATIVE;
1231
32.1k
  op->size = 0;
1232
32.1k
  op->rel.offset = offset;
1233
32.1k
  op->rel.address = address;
1234
32.1k
}
1235
1236
static void relative8_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1237
29.9k
{
1238
29.9k
  int16_t offset = 0;
1239
1240
29.9k
  read_byte_sign_extended(info, &offset, (*address)++);
1241
29.9k
  add_rel_operand(info, offset, *address + offset);
1242
29.9k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1243
1244
29.9k
  if ((info->insn != M680X_INS_BRA) && (info->insn != M680X_INS_BSR) &&
1245
27.4k
      (info->insn != M680X_INS_BRN))
1246
26.0k
    add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1247
29.9k
}
1248
1249
static void relative16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1250
2.21k
{
1251
2.21k
  uint16_t offset = 0;
1252
1253
2.21k
  read_word(info, &offset, *address);
1254
2.21k
  *address += 2;
1255
2.21k
  add_rel_operand(info, (int16_t)offset, *address + offset);
1256
2.21k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1257
1258
2.21k
  if ((info->insn != M680X_INS_LBRA) && (info->insn != M680X_INS_LBSR) &&
1259
793
      (info->insn != M680X_INS_LBRN))
1260
585
    add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1261
2.21k
}
1262
1263
static const m680x_reg g_rr5_to_reg_ids[] = {
1264
  M680X_REG_X,
1265
  M680X_REG_Y,
1266
  M680X_REG_U,
1267
  M680X_REG_S,
1268
};
1269
1270
static void add_indexed_operand(m680x_info *info, m680x_reg base_reg,
1271
        bool post_inc_dec, uint8_t inc_dec,
1272
        uint8_t offset_bits, uint16_t offset,
1273
        bool no_comma)
1274
25.2k
{
1275
25.2k
  cs_m680x *m680x = &info->m680x;
1276
25.2k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1277
1278
25.2k
  op->type = M680X_OP_INDEXED;
1279
25.2k
  set_operand_size(info, op, 1);
1280
25.2k
  op->idx.base_reg = base_reg;
1281
25.2k
  op->idx.offset_reg = M680X_REG_INVALID;
1282
25.2k
  op->idx.inc_dec = inc_dec;
1283
1284
25.2k
  if (inc_dec && post_inc_dec)
1285
3.83k
    op->idx.flags |= M680X_IDX_POST_INC_DEC;
1286
1287
25.2k
  if (offset_bits != M680X_OFFSET_NONE) {
1288
15.0k
    op->idx.offset = offset;
1289
15.0k
    op->idx.offset_addr = 0;
1290
15.0k
  }
1291
1292
25.2k
  op->idx.offset_bits = offset_bits;
1293
25.2k
  op->idx.flags |= (no_comma ? M680X_IDX_NO_COMMA : 0);
1294
25.2k
}
1295
1296
// M6800/1/2/3 indexed mode handler
1297
static void indexedX_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1298
8.29k
{
1299
8.29k
  uint8_t offset = 0;
1300
1301
8.29k
  read_byte(info, &offset, (*address)++);
1302
1303
8.29k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_8,
1304
8.29k
          (uint16_t)offset, false);
1305
8.29k
}
1306
1307
static void indexedY_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1308
2.04k
{
1309
2.04k
  uint8_t offset = 0;
1310
1311
2.04k
  read_byte(info, &offset, (*address)++);
1312
1313
2.04k
  add_indexed_operand(info, M680X_REG_Y, false, 0, M680X_OFFSET_BITS_8,
1314
2.04k
          (uint16_t)offset, false);
1315
2.04k
}
1316
1317
// M6809/M6309 indexed mode handler
1318
static void indexed09_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1319
31.8k
{
1320
31.8k
  cs_m680x *m680x = &info->m680x;
1321
31.8k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1322
31.8k
  uint8_t post_byte = 0;
1323
31.8k
  uint16_t offset = 0;
1324
31.8k
  int16_t soffset = 0;
1325
1326
31.8k
  read_byte(info, &post_byte, (*address)++);
1327
1328
31.8k
  op->type = M680X_OP_INDEXED;
1329
31.8k
  set_operand_size(info, op, 1);
1330
31.8k
  op->idx.base_reg = g_rr5_to_reg_ids[(post_byte >> 5) & 0x03];
1331
31.8k
  op->idx.offset_reg = M680X_REG_INVALID;
1332
1333
31.8k
  if (!(post_byte & 0x80)) {
1334
    // n5,R
1335
13.6k
    if ((post_byte & 0x10) == 0x10)
1336
5.61k
      op->idx.offset = post_byte | 0xfff0;
1337
7.99k
    else
1338
7.99k
      op->idx.offset = post_byte & 0x0f;
1339
1340
13.6k
    op->idx.offset_addr = op->idx.offset + *address;
1341
13.6k
    op->idx.offset_bits = M680X_OFFSET_BITS_5;
1342
18.2k
  } else {
1343
18.2k
    if ((post_byte & 0x10) == 0x10)
1344
6.14k
      op->idx.flags |= M680X_IDX_INDIRECT;
1345
1346
    // indexed addressing
1347
18.2k
    switch (post_byte & 0x1f) {
1348
928
    case 0x00: // ,R+
1349
928
      op->idx.inc_dec = 1;
1350
928
      op->idx.flags |= M680X_IDX_POST_INC_DEC;
1351
928
      break;
1352
1353
400
    case 0x11: // [,R++]
1354
1.18k
    case 0x01: // ,R++
1355
1.18k
      op->idx.inc_dec = 2;
1356
1.18k
      op->idx.flags |= M680X_IDX_POST_INC_DEC;
1357
1.18k
      break;
1358
1359
582
    case 0x02: // ,-R
1360
582
      op->idx.inc_dec = -1;
1361
582
      break;
1362
1363
533
    case 0x13: // [,--R]
1364
1.08k
    case 0x03: // ,--R
1365
1.08k
      op->idx.inc_dec = -2;
1366
1.08k
      break;
1367
1368
484
    case 0x14: // [,R]
1369
1.51k
    case 0x04: // ,R
1370
1.51k
      break;
1371
1372
624
    case 0x15: // [B,R]
1373
1.75k
    case 0x05: // B,R
1374
1.75k
      op->idx.offset_reg = M680X_REG_B;
1375
1.75k
      break;
1376
1377
254
    case 0x16: // [A,R]
1378
1.50k
    case 0x06: // A,R
1379
1.50k
      op->idx.offset_reg = M680X_REG_A;
1380
1.50k
      break;
1381
1382
763
    case 0x1c: // [n8,PCR]
1383
1.88k
    case 0x0c: // n8,PCR
1384
1.88k
      op->idx.base_reg = M680X_REG_PC;
1385
1.88k
      read_byte_sign_extended(info, &soffset, (*address)++);
1386
1.88k
      op->idx.offset_addr = offset + *address;
1387
1.88k
      op->idx.offset = soffset;
1388
1.88k
      op->idx.offset_bits = M680X_OFFSET_BITS_8;
1389
1.88k
      break;
1390
1391
611
    case 0x18: // [n8,R]
1392
2.25k
    case 0x08: // n8,R
1393
2.25k
      read_byte_sign_extended(info, &soffset, (*address)++);
1394
2.25k
      op->idx.offset = soffset;
1395
2.25k
      op->idx.offset_bits = M680X_OFFSET_BITS_8;
1396
2.25k
      break;
1397
1398
867
    case 0x1d: // [n16,PCR]
1399
1.97k
    case 0x0d: // n16,PCR
1400
1.97k
      op->idx.base_reg = M680X_REG_PC;
1401
1.97k
      read_word(info, &offset, *address);
1402
1.97k
      *address += 2;
1403
1.97k
      op->idx.offset_addr = offset + *address;
1404
1.97k
      op->idx.offset = (int16_t)offset;
1405
1.97k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1406
1.97k
      break;
1407
1408
781
    case 0x19: // [n16,R]
1409
1.74k
    case 0x09: // n16,R
1410
1.74k
      read_word(info, &offset, *address);
1411
1.74k
      *address += 2;
1412
1.74k
      op->idx.offset = (int16_t)offset;
1413
1.74k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1414
1.74k
      break;
1415
1416
429
    case 0x1b: // [D,R]
1417
1.42k
    case 0x0b: // D,R
1418
1.42k
      op->idx.offset_reg = M680X_REG_D;
1419
1.42k
      break;
1420
1421
400
    case 0x1f: // [n16]
1422
400
      op->type = M680X_OP_EXTENDED;
1423
400
      op->ext.indirect = true;
1424
400
      read_word(info, &op->ext.address, *address);
1425
400
      *address += 2;
1426
400
      break;
1427
1428
0
    default:
1429
0
      op->idx.base_reg = M680X_REG_INVALID;
1430
0
      break;
1431
18.2k
    }
1432
18.2k
  }
1433
1434
31.8k
  if (((info->insn == M680X_INS_LEAU) || (info->insn == M680X_INS_LEAS) ||
1435
30.0k
       (info->insn == M680X_INS_LEAX) ||
1436
28.7k
       (info->insn == M680X_INS_LEAY)) &&
1437
3.96k
      (m680x->operands[0].reg == M680X_REG_X ||
1438
2.69k
       (m680x->operands[0].reg == M680X_REG_Y)))
1439
    // Only LEAX and LEAY modify CC register
1440
2.16k
    add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1441
31.8k
}
1442
1443
static const m680x_reg g_idx12_to_reg_ids[4] = {
1444
  M680X_REG_X,
1445
  M680X_REG_Y,
1446
  M680X_REG_S,
1447
  M680X_REG_PC,
1448
};
1449
1450
static const m680x_reg g_or12_to_reg_ids[3] = { M680X_REG_A, M680X_REG_B,
1451
            M680X_REG_D };
1452
1453
// CPU12 indexed mode handler
1454
static void indexed12_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1455
36.9k
{
1456
36.9k
  cs_m680x *m680x = &info->m680x;
1457
36.9k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1458
36.9k
  uint8_t post_byte = 0;
1459
36.9k
  uint8_t offset8 = 0;
1460
1461
36.9k
  read_byte(info, &post_byte, (*address)++);
1462
1463
36.9k
  op->type = M680X_OP_INDEXED;
1464
36.9k
  set_operand_size(info, op, 1);
1465
36.9k
  op->idx.offset_reg = M680X_REG_INVALID;
1466
1467
36.9k
  if (!(post_byte & 0x20)) {
1468
    // n5,R      n5 is a 5-bit signed offset
1469
12.0k
    op->idx.base_reg = g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1470
1471
12.0k
    if ((post_byte & 0x10) == 0x10)
1472
4.68k
      op->idx.offset = post_byte | 0xfff0;
1473
7.40k
    else
1474
7.40k
      op->idx.offset = post_byte & 0x0f;
1475
1476
12.0k
    op->idx.offset_addr = op->idx.offset + *address;
1477
12.0k
    op->idx.offset_bits = M680X_OFFSET_BITS_5;
1478
24.9k
  } else {
1479
24.9k
    if ((post_byte & 0xe0) == 0xe0)
1480
12.8k
      op->idx.base_reg =
1481
12.8k
        g_idx12_to_reg_ids[(post_byte >> 3) & 0x03];
1482
1483
24.9k
    switch (post_byte & 0xe7) {
1484
2.11k
    case 0xe0:
1485
4.59k
    case 0xe1: // n9,R
1486
4.59k
      read_byte(info, &offset8, (*address)++);
1487
4.59k
      op->idx.offset = offset8;
1488
1489
4.59k
      if (post_byte & 0x01) // sign extension
1490
2.47k
        op->idx.offset |= 0xff00;
1491
1492
4.59k
      op->idx.offset_bits = M680X_OFFSET_BITS_9;
1493
1494
4.59k
      if (op->idx.base_reg == M680X_REG_PC)
1495
2.41k
        op->idx.offset_addr = op->idx.offset + *address;
1496
1497
4.59k
      break;
1498
1499
1.71k
    case 0xe3: // [n16,R]
1500
1.71k
      op->idx.flags |= M680X_IDX_INDIRECT;
1501
1502
    // intentionally fall through
1503
4.00k
    case 0xe2: // n16,R
1504
4.00k
      read_word(info, (uint16_t *)&op->idx.offset, *address);
1505
4.00k
      (*address) += 2;
1506
4.00k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1507
1508
4.00k
      if (op->idx.base_reg == M680X_REG_PC)
1509
1.24k
        op->idx.offset_addr = op->idx.offset + *address;
1510
1511
4.00k
      break;
1512
1513
827
    case 0xe4: // A,R
1514
1.75k
    case 0xe5: // B,R
1515
2.25k
    case 0xe6: // D,R
1516
2.25k
      op->idx.offset_reg =
1517
2.25k
        g_or12_to_reg_ids[post_byte & 0x03];
1518
2.25k
      break;
1519
1520
1.99k
    case 0xe7: // [D,R]
1521
1.99k
      op->idx.offset_reg = M680X_REG_D;
1522
1.99k
      op->idx.flags |= M680X_IDX_INDIRECT;
1523
1.99k
      break;
1524
1525
12.0k
    default: // n,-r n,+r n,r- n,r+
1526
      // PC is not allowed in this mode
1527
12.0k
      op->idx.base_reg =
1528
12.0k
        g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1529
12.0k
      op->idx.inc_dec = post_byte & 0x0f;
1530
1531
12.0k
      if (op->idx.inc_dec & 0x08) // evtl. sign extend value
1532
5.92k
        op->idx.inc_dec |= 0xf0;
1533
1534
12.0k
      if (op->idx.inc_dec >= 0)
1535
6.13k
        op->idx.inc_dec++;
1536
1537
12.0k
      if (post_byte & 0x10)
1538
3.62k
        op->idx.flags |= M680X_IDX_POST_INC_DEC;
1539
1540
12.0k
      break;
1541
24.9k
    }
1542
24.9k
  }
1543
36.9k
}
1544
1545
static void index_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1546
1.00k
{
1547
1.00k
  cs_m680x *m680x = &info->m680x;
1548
1.00k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1549
1550
1.00k
  op->type = M680X_OP_CONSTANT;
1551
1.00k
  read_byte(info, &op->const_val, (*address)++);
1552
1.00k
};
1553
1554
static void direct_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1555
50.8k
{
1556
50.8k
  cs_m680x *m680x = &info->m680x;
1557
50.8k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1558
1559
50.8k
  op->type = M680X_OP_DIRECT;
1560
50.8k
  set_operand_size(info, op, 1);
1561
50.8k
  read_byte(info, &op->direct_addr, (*address)++);
1562
50.8k
};
1563
1564
static void extended_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1565
51.4k
{
1566
51.4k
  cs_m680x *m680x = &info->m680x;
1567
51.4k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1568
1569
51.4k
  op->type = M680X_OP_EXTENDED;
1570
51.4k
  set_operand_size(info, op, 1);
1571
51.4k
  read_word(info, &op->ext.address, *address);
1572
51.4k
  *address += 2;
1573
51.4k
}
1574
1575
static void immediate_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1576
29.3k
{
1577
29.3k
  cs_m680x *m680x = &info->m680x;
1578
29.3k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1579
29.3k
  uint16_t word = 0;
1580
29.3k
  int16_t sword = 0;
1581
1582
29.3k
  op->type = M680X_OP_IMMEDIATE;
1583
29.3k
  set_operand_size(info, op, 1);
1584
1585
29.3k
  switch (op->size) {
1586
24.4k
  case 1:
1587
24.4k
    read_byte_sign_extended(info, &sword, *address);
1588
24.4k
    op->imm = sword;
1589
24.4k
    break;
1590
1591
4.01k
  case 2:
1592
4.01k
    read_word(info, &word, *address);
1593
4.01k
    op->imm = (int16_t)word;
1594
4.01k
    break;
1595
1596
914
  case 4:
1597
914
    read_sdword(info, &op->imm, *address);
1598
914
    break;
1599
1600
0
  default:
1601
0
    op->imm = 0;
1602
0
    CS_ASSERT(0 && "Unexpected immediate byte size");
1603
29.3k
  }
1604
1605
29.3k
  *address += op->size;
1606
29.3k
}
1607
1608
// handler for bit move instructions, e.g: BAND A,5,1,$40  Used by HD6309
1609
static void bit_move_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1610
610
{
1611
610
  static const m680x_reg m680x_reg[] = {
1612
610
    M680X_REG_CC,
1613
610
    M680X_REG_A,
1614
610
    M680X_REG_B,
1615
610
    M680X_REG_INVALID,
1616
610
  };
1617
1618
610
  uint8_t post_byte = 0;
1619
610
  cs_m680x *m680x = &info->m680x;
1620
610
  cs_m680x_op *op;
1621
1622
610
  read_byte(info, &post_byte, *address);
1623
610
  (*address)++;
1624
1625
  // operand[0] = register
1626
610
  add_reg_operand(info, m680x_reg[post_byte >> 6]);
1627
1628
  // operand[1] = bit index in source operand
1629
610
  op = &m680x->operands[m680x->op_count++];
1630
610
  op->type = M680X_OP_CONSTANT;
1631
610
  op->const_val = (post_byte >> 3) & 0x07;
1632
1633
  // operand[2] = bit index in destination operand
1634
610
  op = &m680x->operands[m680x->op_count++];
1635
610
  op->type = M680X_OP_CONSTANT;
1636
610
  op->const_val = post_byte & 0x07;
1637
1638
610
  direct_hdlr(MI, info, address);
1639
610
}
1640
1641
// handler for TFM instruction, e.g: TFM X+,Y+  Used by HD6309
1642
static void tfm_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1643
776
{
1644
776
  static const uint8_t inc_dec_r0[] = {
1645
776
    1,
1646
776
    -1,
1647
776
    1,
1648
776
    0,
1649
776
  };
1650
776
  static const uint8_t inc_dec_r1[] = {
1651
776
    1,
1652
776
    -1,
1653
776
    0,
1654
776
    1,
1655
776
  };
1656
776
  uint8_t regs = 0;
1657
776
  uint8_t index = (MI->Opcode & 0xff) - 0x38;
1658
1659
776
  read_byte(info, &regs, *address);
1660
1661
776
  add_indexed_operand(info, g_tfr_exg_reg_ids[regs >> 4], true,
1662
776
          inc_dec_r0[index], M680X_OFFSET_NONE, 0, true);
1663
776
  add_indexed_operand(info, g_tfr_exg_reg_ids[regs & 0x0f], true,
1664
776
          inc_dec_r1[index], M680X_OFFSET_NONE, 0, true);
1665
1666
776
  add_reg_to_rw_list(MI, M680X_REG_W, READ | WRITE);
1667
776
}
1668
1669
static void opidx_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1670
1.71k
{
1671
1.71k
  cs_m680x *m680x = &info->m680x;
1672
1.71k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1673
1674
  // bit index is coded in Opcode
1675
1.71k
  op->type = M680X_OP_CONSTANT;
1676
1.71k
  op->const_val = (MI->Opcode & 0x0e) >> 1;
1677
1.71k
}
1678
1679
// handler for bit test and branch instruction. Used by M6805.
1680
// The bit index is part of the opcode.
1681
// Example: BRSET 3,<$40,LOOP
1682
static void opidx_dir_rel_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1683
3.85k
{
1684
3.85k
  cs_m680x *m680x = &info->m680x;
1685
3.85k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1686
1687
  // bit index is coded in Opcode
1688
3.85k
  op->type = M680X_OP_CONSTANT;
1689
3.85k
  op->const_val = (MI->Opcode & 0x0e) >> 1;
1690
3.85k
  direct_hdlr(MI, info, address);
1691
3.85k
  relative8_hdlr(MI, info, address);
1692
1693
3.85k
  add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1694
3.85k
}
1695
1696
static void indexedX0_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1697
7.80k
{
1698
7.80k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_NONE, 0,
1699
7.80k
          false);
1700
7.80k
}
1701
1702
static void indexedX16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1703
1.69k
{
1704
1.69k
  uint16_t offset = 0;
1705
1706
1.69k
  read_word(info, &offset, *address);
1707
1.69k
  *address += 2;
1708
1.69k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_16,
1709
1.69k
          offset, false);
1710
1.69k
}
1711
1712
static void imm_rel_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1713
2.80k
{
1714
2.80k
  immediate_hdlr(MI, info, address);
1715
2.80k
  relative8_hdlr(MI, info, address);
1716
2.80k
}
1717
1718
static void indexedS_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1719
386
{
1720
386
  uint8_t offset = 0;
1721
1722
386
  read_byte(info, &offset, (*address)++);
1723
1724
386
  add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_8,
1725
386
          (uint16_t)offset, false);
1726
386
}
1727
1728
static void indexedS16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1729
509
{
1730
509
  uint16_t offset = 0;
1731
1732
509
  read_word(info, &offset, *address);
1733
509
  *address += 2;
1734
1735
509
  add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_16,
1736
509
          offset, false);
1737
509
}
1738
1739
static void indexedX0p_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1740
927
{
1741
927
  add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_NONE, 0,
1742
927
          true);
1743
927
}
1744
1745
static void indexedXp_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1746
2.08k
{
1747
2.08k
  uint8_t offset = 0;
1748
1749
2.08k
  read_byte(info, &offset, (*address)++);
1750
1751
2.08k
  add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_BITS_8,
1752
2.08k
          (uint16_t)offset, false);
1753
2.08k
}
1754
1755
static void imm_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1756
4.38k
{
1757
4.38k
  cs_m680x *m680x = &info->m680x;
1758
4.38k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1759
1760
4.38k
  indexed12_hdlr(MI, info, address);
1761
4.38k
  op->type = M680X_OP_IMMEDIATE;
1762
1763
4.38k
  if (info->insn == M680X_INS_MOVW) {
1764
1.80k
    uint16_t imm16 = 0;
1765
1766
1.80k
    read_word(info, &imm16, *address);
1767
1.80k
    op->imm = (int16_t)imm16;
1768
1.80k
    op->size = 2;
1769
2.57k
  } else {
1770
2.57k
    uint8_t imm8 = 0;
1771
1772
2.57k
    read_byte(info, &imm8, *address);
1773
2.57k
    op->imm = (int8_t)imm8;
1774
2.57k
    op->size = 1;
1775
2.57k
  }
1776
1777
4.38k
  set_operand_size(info, op, 1);
1778
4.38k
}
1779
1780
static void ext_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1781
2.06k
{
1782
2.06k
  cs_m680x *m680x = &info->m680x;
1783
2.06k
  cs_m680x_op *op0 = &m680x->operands[m680x->op_count++];
1784
2.06k
  uint16_t imm16 = 0;
1785
1786
2.06k
  indexed12_hdlr(MI, info, address);
1787
2.06k
  read_word(info, &imm16, *address);
1788
2.06k
  op0->type = M680X_OP_EXTENDED;
1789
2.06k
  op0->ext.address = (int16_t)imm16;
1790
2.06k
  set_operand_size(info, op0, 1);
1791
2.06k
}
1792
1793
// handler for CPU12 DBEQ/DNBE/IBEQ/IBNE/TBEQ/TBNE instructions.
1794
// Example: DBNE X,$1000
1795
static void loop_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1796
2.45k
{
1797
2.45k
  static const m680x_reg index_to_reg_id[] = {
1798
2.45k
    M680X_REG_A, M680X_REG_B, M680X_REG_INVALID, M680X_REG_INVALID,
1799
2.45k
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,       M680X_REG_S,
1800
2.45k
  };
1801
2.45k
  static const m680x_insn index_to_insn_id[] = {
1802
2.45k
    M680X_INS_DBEQ, M680X_INS_DBNE, M680X_INS_TBEQ,  M680X_INS_TBNE,
1803
2.45k
    M680X_INS_IBEQ, M680X_INS_IBNE, M680X_INS_ILLGL, M680X_INS_ILLGL
1804
2.45k
  };
1805
2.45k
  cs_m680x *m680x = &info->m680x;
1806
2.45k
  uint8_t post_byte = 0;
1807
2.45k
  uint8_t rel = 0;
1808
2.45k
  cs_m680x_op *op;
1809
1810
2.45k
  read_byte(info, &post_byte, (*address)++);
1811
1812
2.45k
  info->insn = index_to_insn_id[(post_byte >> 5) & 0x07];
1813
1814
2.45k
  if (info->insn == M680X_INS_ILLGL) {
1815
0
    illegal_hdlr(MI, info, address);
1816
0
  };
1817
1818
2.45k
  read_byte(info, &rel, (*address)++);
1819
1820
2.45k
  add_reg_operand(info, index_to_reg_id[post_byte & 0x07]);
1821
1822
2.45k
  op = &m680x->operands[m680x->op_count++];
1823
1824
2.45k
  op->type = M680X_OP_RELATIVE;
1825
1826
2.45k
  op->rel.offset = (post_byte & 0x10) ? (int16_t)(0xff00 | rel) : rel;
1827
1828
2.45k
  op->rel.address = *address + op->rel.offset;
1829
1830
2.45k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1831
2.45k
}
1832
1833
// handler for RS08 specific TNY instruction
1834
// The operand address is embedded in the the least 4 significant bits of the opcode
1835
static void tny_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1836
1.01k
{
1837
1.01k
  cs_m680x *m680x = &info->m680x;
1838
1.01k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1839
1840
1.01k
  op->type = M680X_OP_DIRECT;
1841
1.01k
  op->direct_addr = (uint8_t)(MI->Opcode & 0x0F);
1842
1.01k
  op->size = 1;
1843
1.01k
}
1844
1845
// handler for RS08 specific SRT instruction
1846
// The operand address is embedded in the the least 5 significant bits of the opcode
1847
static void srt_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1848
814
{
1849
814
  cs_m680x *m680x = &info->m680x;
1850
814
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1851
1852
814
  op->type = M680X_OP_DIRECT;
1853
814
  op->direct_addr = (uint8_t)(MI->Opcode & 0x1F);
1854
814
  op->size = 1;
1855
814
}
1856
1857
static void dirdir_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1858
44
{
1859
44
  direct_hdlr(MI, info, address);
1860
44
  direct_hdlr(MI, info, address);
1861
44
}
1862
1863
static void immdir_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1864
65
{
1865
65
  immediate_hdlr(MI, info, address);
1866
65
  direct_hdlr(MI, info, address);
1867
65
}
1868
1869
static void (*const g_insn_handler[])(MCInst *, m680x_info *, uint16_t *) = {
1870
  illegal_hdlr,   relative8_hdlr,   relative16_hdlr,
1871
  immediate_hdlr, // 8-bit
1872
  immediate_hdlr, // 16-bit
1873
  immediate_hdlr, // 32-bit
1874
  direct_hdlr,    extended_hdlr,    indexedX_hdlr,   indexedY_hdlr,
1875
  indexed09_hdlr,   inherent_hdlr,    reg_reg09_hdlr,  reg_bits_hdlr,
1876
  bit_move_hdlr,    tfm_hdlr,     opidx_hdlr,      opidx_dir_rel_hdlr,
1877
  indexedX0_hdlr,   indexedX16_hdlr,  imm_rel_hdlr,    indexedS_hdlr,
1878
  indexedS16_hdlr,  indexedXp_hdlr,   indexedX0p_hdlr, indexed12_hdlr,
1879
  indexed12_hdlr, // subset of indexed12
1880
  reg_reg12_hdlr,   loop_hdlr,      index_hdlr,      imm_idx12_x_hdlr,
1881
  imm_idx12_x_hdlr, ext_idx12_x_hdlr, srt_hdlr,      tny_hdlr,
1882
  dirdir_hdlr,    immdir_hdlr
1883
}; /* handler function pointers */
1884
1885
/* Disasemble one instruction at address and store in str_buff */
1886
static unsigned int m680x_disassemble(MCInst *MI, m680x_info *info,
1887
              uint16_t address)
1888
384k
{
1889
384k
  cs_m680x *m680x = &info->m680x;
1890
384k
  cs_detail *detail = MI->flat_insn->detail;
1891
384k
  uint16_t base_address = address;
1892
384k
  insn_desc insn_description;
1893
384k
  e_access_mode access_mode;
1894
1895
384k
  if (detail != NULL) {
1896
384k
    memset(detail, 0,
1897
384k
           offsetof(cs_detail, m680x) + sizeof(cs_m680x));
1898
384k
  }
1899
1900
384k
  memset(&insn_description, 0, sizeof(insn_description));
1901
384k
  memset(m680x, 0, sizeof(*m680x));
1902
384k
  info->insn_size = 1;
1903
1904
384k
  if (decode_insn(info, address, &insn_description)) {
1905
343k
    m680x_reg reg;
1906
1907
343k
    if (insn_description.opcode > 0xff)
1908
17.4k
      address += 2; // 8-bit opcode + page prefix
1909
325k
    else
1910
325k
      address++; // 8-bit opcode only
1911
1912
343k
    info->insn = insn_description.insn;
1913
1914
343k
    MCInst_setOpcode(MI, insn_description.opcode);
1915
1916
343k
    reg = g_insn_props[info->insn].reg0;
1917
1918
343k
    if (reg != M680X_REG_INVALID) {
1919
182k
      if (reg == M680X_REG_HX &&
1920
1.52k
          (!info->cpu->reg_byte_size[reg]))
1921
531
        reg = M680X_REG_X;
1922
1923
182k
      add_reg_operand(info, reg);
1924
      // First (or second) operand is a register which is
1925
      // part of the mnemonic
1926
182k
      m680x->flags |= M680X_FIRST_OP_IN_MNEM;
1927
182k
      reg = g_insn_props[info->insn].reg1;
1928
1929
182k
      if (reg != M680X_REG_INVALID) {
1930
5.17k
        if (reg == M680X_REG_HX &&
1931
968
            (!info->cpu->reg_byte_size[reg]))
1932
596
          reg = M680X_REG_X;
1933
1934
5.17k
        add_reg_operand(info, reg);
1935
5.17k
        m680x->flags |= M680X_SECOND_OP_IN_MNEM;
1936
5.17k
      }
1937
182k
    }
1938
1939
    // Call addressing mode specific instruction handler
1940
343k
    (g_insn_handler[insn_description.hid[0]])(MI, info, &address);
1941
343k
    (g_insn_handler[insn_description.hid[1]])(MI, info, &address);
1942
1943
343k
    add_insn_group(detail, g_insn_props[info->insn].group);
1944
1945
343k
    if (g_insn_props[info->insn].cc_modified &&
1946
219k
        (info->cpu->insn_cc_not_modified[0] != info->insn) &&
1947
218k
        (info->cpu->insn_cc_not_modified[1] != info->insn))
1948
218k
      add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1949
1950
343k
    access_mode = g_insn_props[info->insn].access_mode;
1951
1952
    // Fix for M6805 BSET/BCLR. It has a different operand order
1953
    // in comparison to the M6811
1954
343k
    if ((info->cpu->insn_cc_not_modified[0] == info->insn) ||
1955
342k
        (info->cpu->insn_cc_not_modified[1] == info->insn))
1956
1.71k
      access_mode = rmmm;
1957
1958
343k
    build_regs_read_write_counts(MI, info, access_mode);
1959
343k
    add_operators_access(MI, info, access_mode);
1960
1961
343k
    if (g_insn_props[info->insn].update_reg_access)
1962
35.8k
      set_changed_regs_read_write_counts(MI, info);
1963
1964
343k
    info->insn_size = (uint8_t)insn_description.insn_size;
1965
1966
343k
    return info->insn_size;
1967
343k
  } else
1968
41.0k
    MCInst_setOpcode(MI, insn_description.opcode);
1969
1970
  // Illegal instruction
1971
41.0k
  address = base_address;
1972
41.0k
  illegal_hdlr(MI, info, &address);
1973
41.0k
  return 1;
1974
384k
}
1975
1976
// Tables to get the byte size of a register on the CPU
1977
// based on an enum m680x_reg value defined in m680x.h
1978
// Invalid registers return 0.
1979
static const uint8_t g_m6800_reg_byte_size[23] = {
1980
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
1981
  0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 0, 0, 0
1982
};
1983
1984
static const uint8_t g_m6805_reg_byte_size[23] = {
1985
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
1986
  0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 2, 0, 0, 0
1987
};
1988
1989
static const uint8_t g_m6808_reg_byte_size[23] = {
1990
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
1991
  0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 1, 1, 0, 2, 0, 0, 0, 2, 0, 0, 0
1992
};
1993
1994
static const uint8_t g_m6801_reg_byte_size[23] = {
1995
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
1996
  0, 1, 1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 0, 0, 0
1997
};
1998
1999
static const uint8_t g_m6811_reg_byte_size[23] = {
2000
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
2001
  0, 1, 1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 2, 0, 0, 0
2002
};
2003
2004
static const uint8_t g_cpu12_reg_byte_size[23] = {
2005
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
2006
  0, 1, 1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 2, 0, 2, 2
2007
};
2008
2009
static const uint8_t g_m6809_reg_byte_size[23] = {
2010
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
2011
  0, 1, 1, 0, 0, 0, 2, 0, 1, 1, 0, 0, 0, 2, 2, 2, 2, 0, 0, 2, 0, 0, 0
2012
};
2013
2014
static const uint8_t g_hd6309_reg_byte_size[23] = {
2015
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
2016
  0, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 0, 0, 2, 2, 2, 2, 2, 4, 2, 0, 0, 0
2017
};
2018
2019
static const uint8_t g_rs08_reg_byte_size[23] = {
2020
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
2021
  0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 1, 1, 0, 2, 0, 0, 0, 2, 2, 0, 0
2022
};
2023
2024
static const uint8_t g_hcs12x_reg_byte_size[23] = {
2025
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
2026
  0, 1, 1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 2, 0, 2, 2
2027
};
2028
2029
// Table to check for a valid register nibble on the M6809 CPU
2030
// used for TFR and EXG instruction.
2031
static const bool m6809_tfr_reg_valid[16] = {
2032
  true, true, true, true, true,  true,  false, false,
2033
  true, true, true, true, false, false, false, false,
2034
};
2035
2036
static const cpu_tables g_cpu_tables[] = {
2037
  { // M680X_CPU_TYPE_INVALID
2038
    NULL,
2039
    { NULL, NULL },
2040
    { 0, 0 },
2041
    { 0x00, 0x00, 0x00 },
2042
    { NULL, NULL, NULL },
2043
    { 0, 0, 0 },
2044
    NULL,
2045
    NULL,
2046
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2047
  { // M680X_CPU_TYPE_6301
2048
    &g_m6800_inst_page1_table[0],
2049
    { &g_m6801_inst_overlay_table[0], &g_hd6301_inst_overlay_table[0] },
2050
    { ARR_SIZE(g_m6801_inst_overlay_table),
2051
      ARR_SIZE(g_hd6301_inst_overlay_table) },
2052
    { 0x00, 0x00, 0x00 },
2053
    { NULL, NULL, NULL },
2054
    { 0, 0, 0 },
2055
    &g_m6801_reg_byte_size[0],
2056
    NULL,
2057
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2058
  { // M680X_CPU_TYPE_6309
2059
    &g_m6809_inst_page1_table[0],
2060
    { &g_hd6309_inst_overlay_table[0], NULL },
2061
    { ARR_SIZE(g_hd6309_inst_overlay_table), 0 },
2062
    { 0x10, 0x11, 0x00 },
2063
    { &g_hd6309_inst_page2_table[0], &g_hd6309_inst_page3_table[0],
2064
      NULL },
2065
    { ARR_SIZE(g_hd6309_inst_page2_table),
2066
      ARR_SIZE(g_hd6309_inst_page3_table), 0 },
2067
    &g_hd6309_reg_byte_size[0],
2068
    NULL,
2069
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2070
  { // M680X_CPU_TYPE_6800
2071
    &g_m6800_inst_page1_table[0],
2072
    { NULL, NULL },
2073
    { 0, 0 },
2074
    { 0x00, 0x00, 0x00 },
2075
    { NULL, NULL, NULL },
2076
    { 0, 0, 0 },
2077
    &g_m6800_reg_byte_size[0],
2078
    NULL,
2079
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2080
  { // M680X_CPU_TYPE_6801
2081
    &g_m6800_inst_page1_table[0],
2082
    { &g_m6801_inst_overlay_table[0], NULL },
2083
    { ARR_SIZE(g_m6801_inst_overlay_table), 0 },
2084
    { 0x00, 0x00, 0x00 },
2085
    { NULL, NULL, NULL },
2086
    { 0, 0, 0 },
2087
    &g_m6801_reg_byte_size[0],
2088
    NULL,
2089
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2090
  { // M680X_CPU_TYPE_6805
2091
    &g_m6805_inst_page1_table[0],
2092
    { NULL, NULL },
2093
    { 0, 0 },
2094
    { 0x00, 0x00, 0x00 },
2095
    { NULL, NULL, NULL },
2096
    { 0, 0, 0 },
2097
    &g_m6805_reg_byte_size[0],
2098
    NULL,
2099
    { M680X_INS_BCLR, M680X_INS_BSET } },
2100
  { // M680X_CPU_TYPE_6808
2101
    &g_m6805_inst_page1_table[0],
2102
    { &g_m6808_inst_overlay_table[0], NULL },
2103
    { ARR_SIZE(g_m6808_inst_overlay_table), 0 },
2104
    { 0x9E, 0x00, 0x00 },
2105
    { &g_m6808_inst_page2_table[0], NULL, NULL },
2106
    { ARR_SIZE(g_m6808_inst_page2_table), 0, 0 },
2107
    &g_m6808_reg_byte_size[0],
2108
    NULL,
2109
    { M680X_INS_BCLR, M680X_INS_BSET } },
2110
  { // M680X_CPU_TYPE_6809
2111
    &g_m6809_inst_page1_table[0],
2112
    { NULL, NULL },
2113
    { 0, 0 },
2114
    { 0x10, 0x11, 0x00 },
2115
    { &g_m6809_inst_page2_table[0], &g_m6809_inst_page3_table[0], NULL },
2116
    { ARR_SIZE(g_m6809_inst_page2_table),
2117
      ARR_SIZE(g_m6809_inst_page3_table), 0 },
2118
    &g_m6809_reg_byte_size[0],
2119
    &m6809_tfr_reg_valid[0],
2120
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2121
  { // M680X_CPU_TYPE_6811
2122
    &g_m6800_inst_page1_table[0],
2123
    { &g_m6801_inst_overlay_table[0], &g_m6811_inst_overlay_table[0] },
2124
    { ARR_SIZE(g_m6801_inst_overlay_table),
2125
      ARR_SIZE(g_m6811_inst_overlay_table) },
2126
    { 0x18, 0x1A, 0xCD },
2127
    { &g_m6811_inst_page2_table[0], &g_m6811_inst_page3_table[0],
2128
      &g_m6811_inst_page4_table[0] },
2129
    { ARR_SIZE(g_m6811_inst_page2_table),
2130
      ARR_SIZE(g_m6811_inst_page3_table),
2131
      ARR_SIZE(g_m6811_inst_page4_table) },
2132
    &g_m6811_reg_byte_size[0],
2133
    NULL,
2134
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2135
  { // M680X_CPU_TYPE_CPU12
2136
    &g_cpu12_inst_page1_table[0],
2137
    { NULL, NULL },
2138
    { 0, 0 },
2139
    { 0x18, 0x00, 0x00 },
2140
    { &g_cpu12_inst_page2_table[0], NULL, NULL },
2141
    { ARR_SIZE(g_cpu12_inst_page2_table), 0, 0 },
2142
    &g_cpu12_reg_byte_size[0],
2143
    NULL,
2144
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2145
  { // M680X_CPU_TYPE_HCS08
2146
    &g_m6805_inst_page1_table[0],
2147
    { &g_m6808_inst_overlay_table[0], &g_hcs08_inst_overlay_table[0] },
2148
    { ARR_SIZE(g_m6808_inst_overlay_table),
2149
      ARR_SIZE(g_hcs08_inst_overlay_table) },
2150
    { 0x9E, 0x00, 0x00 },
2151
    { &g_hcs08_inst_page2_table[0], NULL, NULL },
2152
    { ARR_SIZE(g_hcs08_inst_page2_table), 0, 0 },
2153
    &g_m6808_reg_byte_size[0],
2154
    NULL,
2155
    { M680X_INS_BCLR, M680X_INS_BSET } },
2156
  { // M680X_CPU_TYPE_RS08
2157
    &g_rs08_inst_page1_table[0],
2158
    { NULL, NULL },
2159
    { 0, 0 },
2160
    { 0x00, 0x00, 0x00 },
2161
    { NULL, NULL, NULL },
2162
    { 0, 0, 0 },
2163
    &g_rs08_reg_byte_size[0],
2164
    NULL,
2165
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2166
  { // M680X_CPU_TYPE_HCS12X
2167
    &g_cpu12_inst_page1_table[0],
2168
    { NULL, NULL },
2169
    { 0, 0 },
2170
    { 0x18, 0x00, 0x00 },
2171
    { &g_hcs12x_inst_page2_table[0], NULL, NULL },
2172
    { ARR_SIZE(g_hcs12x_inst_page2_table), 0, 0 },
2173
    &g_hcs12x_reg_byte_size[0],
2174
    NULL,
2175
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2176
};
2177
2178
static bool m680x_setup_internals(m680x_info *info, e_cpu_type cpu_type,
2179
          uint16_t address, const uint8_t *code,
2180
          uint16_t code_len)
2181
384k
{
2182
384k
  if (cpu_type == M680X_CPU_TYPE_INVALID) {
2183
0
    return false;
2184
0
  }
2185
2186
384k
  info->code = code;
2187
384k
  info->size = code_len;
2188
384k
  info->offset = address;
2189
384k
  info->cpu_type = cpu_type;
2190
2191
384k
  info->cpu = &g_cpu_tables[info->cpu_type];
2192
2193
384k
  return true;
2194
384k
}
2195
2196
bool M680X_getInstruction(csh ud, const uint8_t *code, size_t code_len,
2197
        MCInst *MI, uint16_t *size, uint64_t address,
2198
        void *inst_info)
2199
141k
{
2200
141k
  unsigned int insn_size = 0;
2201
141k
  e_cpu_type cpu_type = M680X_CPU_TYPE_INVALID; // No default CPU type
2202
141k
  cs_struct *handle = (cs_struct *)ud;
2203
141k
  m680x_info *info = (m680x_info *)handle->printer_info;
2204
2205
141k
  MCInst_clear(MI);
2206
2207
141k
  if (handle->mode & CS_MODE_M680X_6800)
2208
411
    cpu_type = M680X_CPU_TYPE_6800;
2209
2210
141k
  else if (handle->mode & CS_MODE_M680X_6801)
2211
431
    cpu_type = M680X_CPU_TYPE_6801;
2212
2213
140k
  else if (handle->mode & CS_MODE_M680X_6805)
2214
1.11k
    cpu_type = M680X_CPU_TYPE_6805;
2215
2216
139k
  else if (handle->mode & CS_MODE_M680X_6808)
2217
9.36k
    cpu_type = M680X_CPU_TYPE_6808;
2218
2219
130k
  else if (handle->mode & CS_MODE_M680X_HCS08)
2220
3.98k
    cpu_type = M680X_CPU_TYPE_HCS08;
2221
2222
126k
  else if (handle->mode & CS_MODE_M680X_6809)
2223
17.7k
    cpu_type = M680X_CPU_TYPE_6809;
2224
2225
108k
  else if (handle->mode & CS_MODE_M680X_6301)
2226
1.79k
    cpu_type = M680X_CPU_TYPE_6301;
2227
2228
106k
  else if (handle->mode & CS_MODE_M680X_6309)
2229
34.4k
    cpu_type = M680X_CPU_TYPE_6309;
2230
2231
72.3k
  else if (handle->mode & CS_MODE_M680X_6811)
2232
11.2k
    cpu_type = M680X_CPU_TYPE_6811;
2233
2234
61.0k
  else if (handle->mode & CS_MODE_M680X_CPU12)
2235
37.7k
    cpu_type = M680X_CPU_TYPE_CPU12;
2236
2237
23.3k
  else if (handle->mode & CS_MODE_M680X_RS08)
2238
3.16k
    cpu_type = M680X_CPU_TYPE_RS08;
2239
2240
20.1k
  else if (handle->mode & CS_MODE_M680X_HCS12X)
2241
20.1k
    cpu_type = M680X_CPU_TYPE_HCS12X;
2242
2243
141k
  if (cpu_type != M680X_CPU_TYPE_INVALID &&
2244
141k
      m680x_setup_internals(info, cpu_type, (uint16_t)address, code,
2245
141k
          (uint16_t)code_len))
2246
141k
    insn_size = m680x_disassemble(MI, info, (uint16_t)address);
2247
2248
141k
  if (insn_size == 0) {
2249
0
    *size = 1;
2250
0
    return false;
2251
0
  }
2252
2253
  // Make sure we always stay within range
2254
141k
  if (insn_size > code_len) {
2255
6
    *size = (uint16_t)code_len;
2256
6
    return false;
2257
6
  } else
2258
141k
    *size = (uint16_t)insn_size;
2259
2260
141k
  return true;
2261
141k
}
2262
2263
cs_err M680X_disassembler_init(cs_struct *ud)
2264
1.15k
{
2265
1.15k
  if (M680X_REG_ENDING != ARR_SIZE(g_m6800_reg_byte_size)) {
2266
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6800_reg_byte_size));
2267
2268
0
    return CS_ERR_MODE;
2269
0
  }
2270
2271
1.15k
  if (M680X_REG_ENDING != ARR_SIZE(g_m6801_reg_byte_size)) {
2272
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6801_reg_byte_size));
2273
2274
0
    return CS_ERR_MODE;
2275
0
  }
2276
2277
1.15k
  if (M680X_REG_ENDING != ARR_SIZE(g_m6805_reg_byte_size)) {
2278
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6805_reg_byte_size));
2279
2280
0
    return CS_ERR_MODE;
2281
0
  }
2282
2283
1.15k
  if (M680X_REG_ENDING != ARR_SIZE(g_m6808_reg_byte_size)) {
2284
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6808_reg_byte_size));
2285
2286
0
    return CS_ERR_MODE;
2287
0
  }
2288
2289
1.15k
  if (M680X_REG_ENDING != ARR_SIZE(g_m6811_reg_byte_size)) {
2290
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6811_reg_byte_size));
2291
2292
0
    return CS_ERR_MODE;
2293
0
  }
2294
2295
1.15k
  if (M680X_REG_ENDING != ARR_SIZE(g_cpu12_reg_byte_size)) {
2296
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_cpu12_reg_byte_size));
2297
2298
0
    return CS_ERR_MODE;
2299
0
  }
2300
2301
1.15k
  if (M680X_REG_ENDING != ARR_SIZE(g_m6809_reg_byte_size)) {
2302
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6809_reg_byte_size));
2303
2304
0
    return CS_ERR_MODE;
2305
0
  }
2306
2307
1.15k
  if (M680X_REG_ENDING != ARR_SIZE(g_rs08_reg_byte_size)) {
2308
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_rs08_reg_byte_size));
2309
2310
0
    return CS_ERR_MODE;
2311
0
  }
2312
2313
1.15k
  if (M680X_REG_ENDING != ARR_SIZE(g_hcs12x_reg_byte_size)) {
2314
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_hcs12x_reg_byte_size));
2315
2316
0
    return CS_ERR_MODE;
2317
0
  }
2318
2319
1.15k
  if (M680X_INS_ENDING != ARR_SIZE(g_insn_props)) {
2320
0
    CS_ASSERT(M680X_INS_ENDING == ARR_SIZE(g_insn_props));
2321
2322
0
    return CS_ERR_MODE;
2323
0
  }
2324
2325
1.15k
  if (M680X_CPU_TYPE_ENDING != ARR_SIZE(g_cpu_tables)) {
2326
0
    CS_ASSERT(M680X_CPU_TYPE_ENDING == ARR_SIZE(g_cpu_tables));
2327
2328
0
    return CS_ERR_MODE;
2329
0
  }
2330
2331
1.15k
  if (HANDLER_ID_ENDING != ARR_SIZE(g_insn_handler)) {
2332
0
    CS_ASSERT(HANDLER_ID_ENDING == ARR_SIZE(g_insn_handler));
2333
2334
0
    return CS_ERR_MODE;
2335
0
  }
2336
2337
1.15k
  if (ACCESS_MODE_ENDING != MATRIX_SIZE(g_access_mode_to_access)) {
2338
0
    CS_ASSERT(ACCESS_MODE_ENDING ==
2339
0
        MATRIX_SIZE(g_access_mode_to_access));
2340
2341
0
    return CS_ERR_MODE;
2342
0
  }
2343
2344
1.15k
  return CS_ERR_OK;
2345
1.15k
}
2346
2347
#ifndef CAPSTONE_DIET
2348
void M680X_reg_access(const cs_insn *insn, cs_regs regs_read,
2349
          uint8_t *regs_read_count, cs_regs regs_write,
2350
          uint8_t *regs_write_count)
2351
0
{
2352
0
  if (insn->detail == NULL) {
2353
0
    *regs_read_count = 0;
2354
0
    *regs_write_count = 0;
2355
0
  } else {
2356
0
    *regs_read_count = insn->detail->regs_read_count;
2357
0
    *regs_write_count = insn->detail->regs_write_count;
2358
2359
0
    memcpy(regs_read, insn->detail->regs_read,
2360
0
           *regs_read_count * sizeof(insn->detail->regs_read[0]));
2361
0
    memcpy(regs_write, insn->detail->regs_write,
2362
0
           *regs_write_count * sizeof(insn->detail->regs_write[0]));
2363
0
  }
2364
0
}
2365
#endif
2366
2367
#endif