Coverage Report

Created: 2026-08-31 06:58

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
507k
#define READ CS_AC_READ
113
686k
#define WRITE CS_AC_WRITE
114
833k
#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
1.25M
{
162
1.25M
  if (address < info->offset ||
163
1.25M
      (uint32_t)(address - info->offset) >= info->size)
164
    // out of code buffer range
165
2.13k
    return false;
166
167
1.25M
  *byte = info->code[address - info->offset];
168
169
1.25M
  return true;
170
1.25M
}
171
172
static bool read_byte_sign_extended(const m680x_info *info, int16_t *word,
173
            uint16_t address)
174
73.4k
{
175
73.4k
  if (address < info->offset ||
176
73.4k
      (uint32_t)(address - info->offset) >= info->size)
177
    // out of code buffer range
178
0
    return false;
179
180
73.4k
  *word = (int16_t)info->code[address - info->offset];
181
182
73.4k
  if (*word & 0x80)
183
30.8k
    *word |= 0xFF00;
184
185
73.4k
  return true;
186
73.4k
}
187
188
static bool read_word(const m680x_info *info, uint16_t *word, uint16_t address)
189
98.4k
{
190
98.4k
  if (address < info->offset ||
191
98.4k
      (uint32_t)(address + 1 - info->offset) >= info->size)
192
    // out of code buffer range
193
15
    return false;
194
195
98.4k
  *word = (uint16_t)info->code[address - info->offset] << 8;
196
98.4k
  *word |= (uint16_t)info->code[address + 1 - info->offset];
197
198
98.4k
  return true;
199
98.4k
}
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
171k
{
224
  // As part of the algorithm last may get negative.
225
  // => signed integer has to be used.
226
171k
  int first = 0;
227
171k
  int last = (int)table_size - 1;
228
171k
  int middle = (first + last) / 2;
229
230
882k
  while (first <= last) {
231
816k
    if (inst_pageX_table[middle].opcode < opcode) {
232
250k
      first = middle + 1;
233
565k
    } else if (inst_pageX_table[middle].opcode == opcode) {
234
105k
      return middle; /* item found */
235
105k
    } else
236
459k
      last = middle - 1;
237
238
710k
    middle = (first + last) / 2;
239
710k
  }
240
241
65.3k
  if (first > last)
242
65.3k
    return -1; /* item not found */
243
244
0
  return -2;
245
65.3k
}
246
247
void M680X_get_insn_id(cs_struct *handle, cs_insn *insn, unsigned int id)
248
532k
{
249
532k
  const m680x_info *const info = (const m680x_info *)handle->printer_info;
250
532k
  const cpu_tables *cpu = info->cpu;
251
532k
  uint8_t insn_prefix = (id >> 8) & 0xff;
252
  // opcode is the first instruction byte without the prefix.
253
532k
  uint8_t opcode = id & 0xff;
254
532k
  int index;
255
532k
  int i;
256
257
532k
  insn->id = M680X_INS_ILLGL;
258
259
1.23M
  for (i = 0; i < ARR_SIZE(cpu->pageX_prefix); ++i) {
260
1.21M
    if (cpu->pageX_table_size[i] == 0 ||
261
749k
        (cpu->inst_pageX_table[i] == NULL))
262
468k
      break;
263
264
749k
    if (cpu->pageX_prefix[i] == insn_prefix) {
265
46.2k
      index = binary_search(cpu->inst_pageX_table[i],
266
46.2k
                cpu->pageX_table_size[i], opcode);
267
46.2k
      insn->id =
268
46.2k
        (index >= 0) ?
269
29.5k
          cpu->inst_pageX_table[i][index].insn :
270
46.2k
          M680X_INS_ILLGL;
271
46.2k
      return;
272
46.2k
    }
273
749k
  }
274
275
485k
  if (insn_prefix != 0)
276
0
    return;
277
278
485k
  insn->id = cpu->inst_page1_table[id].insn;
279
280
485k
  if (insn->id != M680X_INS_ILLGL)
281
445k
    return;
282
283
  // Check if opcode byte is present in an overlay table
284
56.3k
  for (i = 0; i < ARR_SIZE(cpu->overlay_table_size); ++i) {
285
54.7k
    if (cpu->overlay_table_size[i] == 0 ||
286
39.4k
        (cpu->inst_overlay_table[i] == NULL))
287
15.2k
      break;
288
289
39.4k
    if ((index = binary_search(cpu->inst_overlay_table[i],
290
39.4k
             cpu->overlay_table_size[i],
291
39.4k
             opcode)) >= 0) {
292
23.4k
      insn->id = cpu->inst_overlay_table[i][index].insn;
293
23.4k
      return;
294
23.4k
    }
295
39.4k
  }
296
40.3k
}
297
298
static void add_insn_group(cs_detail *detail, m680x_group_type group)
299
521k
{
300
521k
  if (detail != NULL && (group != M680X_GRP_INVALID) &&
301
115k
      (group != M680X_GRP_ENDING))
302
115k
    detail->groups[detail->groups_count++] = (uint8_t)group;
303
521k
}
304
305
static bool exists_reg_list(uint16_t *regs, uint8_t count, m680x_reg reg)
306
1.48M
{
307
1.48M
  uint8_t i;
308
309
2.44M
  for (i = 0; i < count; ++i) {
310
997k
    if (regs[i] == (uint16_t)reg)
311
38.8k
      return true;
312
997k
  }
313
314
1.44M
  return false;
315
1.48M
}
316
317
static void add_reg_to_rw_list(MCInst *MI, m680x_reg reg, e_access access)
318
966k
{
319
966k
  cs_detail *detail = MI->flat_insn->detail;
320
321
966k
  if (detail == NULL || (reg == M680X_REG_INVALID))
322
0
    return;
323
324
966k
  switch (access) {
325
515k
  case MODIFY:
326
515k
    if (!exists_reg_list(detail->regs_read, detail->regs_read_count,
327
515k
             reg))
328
505k
      detail->regs_read[detail->regs_read_count++] =
329
505k
        (uint16_t)reg;
330
331
    // intentionally fall through
332
333
654k
  case WRITE:
334
654k
    if (!exists_reg_list(detail->regs_write,
335
654k
             detail->regs_write_count, reg))
336
643k
      detail->regs_write[detail->regs_write_count++] =
337
643k
        (uint16_t)reg;
338
339
654k
    break;
340
341
312k
  case READ:
342
312k
    if (!exists_reg_list(detail->regs_read, detail->regs_read_count,
343
312k
             reg))
344
293k
      detail->regs_read[detail->regs_read_count++] =
345
293k
        (uint16_t)reg;
346
347
312k
    break;
348
349
0
  case UNCHANGED:
350
0
  default:
351
0
    break;
352
966k
  }
353
966k
}
354
355
static void update_am_reg_list(MCInst *MI, m680x_info *info, cs_m680x_op *op,
356
             e_access access)
357
689k
{
358
689k
  if (MI->flat_insn->detail == NULL)
359
0
    return;
360
361
689k
  switch (op->type) {
362
300k
  case M680X_OP_REGISTER:
363
300k
    add_reg_to_rw_list(MI, op->reg, access);
364
300k
    break;
365
366
130k
  case M680X_OP_INDEXED:
367
130k
    add_reg_to_rw_list(MI, op->idx.base_reg, READ);
368
369
130k
    if (op->idx.base_reg == M680X_REG_X &&
370
56.9k
        info->cpu->reg_byte_size[M680X_REG_H])
371
17.2k
      add_reg_to_rw_list(MI, M680X_REG_H, READ);
372
373
130k
    if (op->idx.offset_reg != M680X_REG_INVALID)
374
14.4k
      add_reg_to_rw_list(MI, op->idx.offset_reg, READ);
375
376
130k
    if (op->idx.inc_dec) {
377
28.8k
      add_reg_to_rw_list(MI, op->idx.base_reg, WRITE);
378
379
28.8k
      if (op->idx.base_reg == M680X_REG_X &&
380
9.55k
          info->cpu->reg_byte_size[M680X_REG_H])
381
2.52k
        add_reg_to_rw_list(MI, M680X_REG_H, WRITE);
382
28.8k
    }
383
384
130k
    break;
385
386
259k
  default:
387
259k
    break;
388
689k
  }
389
689k
}
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.45M
{
464
1.45M
  int idx = (operator_index > 3) ? 3 : operator_index;
465
466
1.45M
  return g_access_mode_to_access[idx][access_mode];
467
1.45M
}
468
469
static void build_regs_read_write_counts(MCInst *MI, m680x_info *info,
470
           e_access_mode access_mode)
471
478k
{
472
478k
  cs_m680x *m680x = &info->m680x;
473
478k
  int i;
474
475
478k
  if (MI->flat_insn->detail == NULL || (!m680x->op_count))
476
66.6k
    return;
477
478
1.10M
  for (i = 0; i < m680x->op_count; ++i) {
479
689k
    e_access access = get_access(i, access_mode);
480
689k
    update_am_reg_list(MI, info, &m680x->operands[i], access);
481
689k
  }
482
411k
}
483
484
static void add_operators_access(MCInst *MI, m680x_info *info,
485
         e_access_mode access_mode)
486
478k
{
487
478k
  cs_m680x *m680x = &info->m680x;
488
478k
  int offset = 0;
489
478k
  int i;
490
491
478k
  if (MI->flat_insn->detail == NULL || (!m680x->op_count) ||
492
411k
      (access_mode == uuuu))
493
112k
    return;
494
495
1.00M
  for (i = 0; i < m680x->op_count; ++i) {
496
642k
    e_access access;
497
498
    // Ugly fix: MULD has a register operand, an immediate operand
499
    // AND an implicitly changed register W
500
642k
    if (info->insn == M680X_INS_MULD && (i == 1))
501
636
      offset = 1;
502
503
642k
    access = get_access(i + offset, access_mode);
504
642k
    m680x->operands[i].access = access;
505
642k
  }
506
365k
}
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
44.8k
{
516
  //TABLE
517
2.46M
#define EOL M680X_REG_INVALID
518
44.8k
  static const insn_to_changed_regs changed_regs[] = {
519
44.8k
    { M680X_INS_BSR, mmmm, { M680X_REG_S, EOL } },
520
44.8k
    { M680X_INS_CALL, mmmm, { M680X_REG_S, EOL } },
521
44.8k
    {
522
44.8k
      M680X_INS_CWAI,
523
44.8k
      mrrr,
524
44.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
525
44.8k
        M680X_REG_X, M680X_REG_DP, M680X_REG_D, M680X_REG_CC,
526
44.8k
        EOL },
527
44.8k
    },
528
44.8k
    { M680X_INS_DAA, mrrr, { M680X_REG_A, EOL } },
529
44.8k
    { M680X_INS_DIV,
530
44.8k
      mmrr,
531
44.8k
      { M680X_REG_A, M680X_REG_H, M680X_REG_X, EOL } },
532
44.8k
    { M680X_INS_EDIV,
533
44.8k
      mmrr,
534
44.8k
      { M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL } },
535
44.8k
    { M680X_INS_EDIVS,
536
44.8k
      mmrr,
537
44.8k
      { M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL } },
538
44.8k
    { M680X_INS_EMACS, mrrr, { M680X_REG_X, M680X_REG_Y, EOL } },
539
44.8k
    { M680X_INS_EMAXM, rrrr, { M680X_REG_D, EOL } },
540
44.8k
    { M680X_INS_EMINM, rrrr, { M680X_REG_D, EOL } },
541
44.8k
    { M680X_INS_EMUL, mmrr, { M680X_REG_D, M680X_REG_Y, EOL } },
542
44.8k
    { M680X_INS_EMULS, mmrr, { M680X_REG_D, M680X_REG_Y, EOL } },
543
44.8k
    { M680X_INS_ETBL, wmmm, { M680X_REG_A, M680X_REG_B, EOL } },
544
44.8k
    { M680X_INS_FDIV, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
545
44.8k
    { M680X_INS_IDIV, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
546
44.8k
    { M680X_INS_IDIVS, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
547
44.8k
    { M680X_INS_JSR, mmmm, { M680X_REG_S, EOL } },
548
44.8k
    { M680X_INS_LBSR, mmmm, { M680X_REG_S, EOL } },
549
44.8k
    { M680X_INS_MAXM, rrrr, { M680X_REG_A, EOL } },
550
44.8k
    { M680X_INS_MINM, rrrr, { M680X_REG_A, EOL } },
551
44.8k
    { M680X_INS_MEM,
552
44.8k
      mmrr,
553
44.8k
      { M680X_REG_X, M680X_REG_Y, M680X_REG_A, EOL } },
554
44.8k
    { M680X_INS_MUL, mmmm, { M680X_REG_A, M680X_REG_B, EOL } },
555
44.8k
    { M680X_INS_MULD, mwrr, { M680X_REG_D, M680X_REG_W, EOL } },
556
44.8k
    { M680X_INS_PSHA, rmmm, { M680X_REG_A, M680X_REG_S, EOL } },
557
44.8k
    { M680X_INS_PSHB, rmmm, { M680X_REG_B, M680X_REG_S, EOL } },
558
44.8k
    { M680X_INS_PSHC, rmmm, { M680X_REG_CC, M680X_REG_S, EOL } },
559
44.8k
    { M680X_INS_PSHD, rmmm, { M680X_REG_D, M680X_REG_S, EOL } },
560
44.8k
    { M680X_INS_PSHH, rmmm, { M680X_REG_H, M680X_REG_S, EOL } },
561
44.8k
    { M680X_INS_PSHX, rmmm, { M680X_REG_X, M680X_REG_S, EOL } },
562
44.8k
    { M680X_INS_PSHY, rmmm, { M680X_REG_Y, M680X_REG_S, EOL } },
563
44.8k
    { M680X_INS_PULA, wmmm, { M680X_REG_A, M680X_REG_S, EOL } },
564
44.8k
    { M680X_INS_PULB, wmmm, { M680X_REG_B, M680X_REG_S, EOL } },
565
44.8k
    { M680X_INS_PULC, wmmm, { M680X_REG_CC, M680X_REG_S, EOL } },
566
44.8k
    { M680X_INS_PULD, wmmm, { M680X_REG_D, M680X_REG_S, EOL } },
567
44.8k
    { M680X_INS_PULH, wmmm, { M680X_REG_H, M680X_REG_S, EOL } },
568
44.8k
    { M680X_INS_PULX, wmmm, { M680X_REG_X, M680X_REG_S, EOL } },
569
44.8k
    { M680X_INS_PULY, wmmm, { M680X_REG_Y, M680X_REG_S, EOL } },
570
44.8k
    { M680X_INS_REV,
571
44.8k
      mmrr,
572
44.8k
      { M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL } },
573
44.8k
    { M680X_INS_REVW,
574
44.8k
      mmmm,
575
44.8k
      { M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL } },
576
44.8k
    { M680X_INS_RTC, mwww, { M680X_REG_S, M680X_REG_PC, EOL } },
577
44.8k
    {
578
44.8k
      M680X_INS_RTI,
579
44.8k
      mwww,
580
44.8k
      { M680X_REG_S, M680X_REG_CC, M680X_REG_B, M680X_REG_A,
581
44.8k
        M680X_REG_DP, M680X_REG_X, M680X_REG_Y, M680X_REG_U,
582
44.8k
        M680X_REG_PC, EOL },
583
44.8k
    },
584
44.8k
    { M680X_INS_RTS, mwww, { M680X_REG_S, M680X_REG_PC, EOL } },
585
44.8k
    { M680X_INS_SEX, wrrr, { M680X_REG_A, M680X_REG_B, EOL } },
586
44.8k
    { M680X_INS_SEXW, rwww, { M680X_REG_W, M680X_REG_D, EOL } },
587
44.8k
    { M680X_INS_SWI,
588
44.8k
      mmrr,
589
44.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
590
44.8k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
591
44.8k
        M680X_REG_CC, EOL } },
592
44.8k
    {
593
44.8k
      M680X_INS_SWI2,
594
44.8k
      mmrr,
595
44.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
596
44.8k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
597
44.8k
        M680X_REG_CC, EOL },
598
44.8k
    },
599
44.8k
    {
600
44.8k
      M680X_INS_SWI3,
601
44.8k
      mmrr,
602
44.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
603
44.8k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
604
44.8k
        M680X_REG_CC, EOL },
605
44.8k
    },
606
44.8k
    { M680X_INS_TBL, wrrr, { M680X_REG_A, M680X_REG_B, EOL } },
607
44.8k
    { M680X_INS_WAI,
608
44.8k
      mrrr,
609
44.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_X, M680X_REG_A,
610
44.8k
        M680X_REG_B, M680X_REG_CC, EOL } },
611
44.8k
    { M680X_INS_WAV,
612
44.8k
      rmmm,
613
44.8k
      { M680X_REG_A, M680X_REG_B, M680X_REG_X, M680X_REG_Y, EOL } },
614
44.8k
    { M680X_INS_WAVR,
615
44.8k
      rmmm,
616
44.8k
      { M680X_REG_A, M680X_REG_B, M680X_REG_X, M680X_REG_Y, EOL } },
617
44.8k
  };
618
619
44.8k
  int i, j;
620
621
44.8k
  if (MI->flat_insn->detail == NULL)
622
0
    return;
623
624
2.33M
  for (i = 0; i < ARR_SIZE(changed_regs); ++i) {
625
2.28M
    if (info->insn == changed_regs[i].insn) {
626
44.7k
      e_access_mode access_mode = changed_regs[i].access_mode;
627
628
173k
      for (j = 0; changed_regs[i].regs[j] != EOL; ++j) {
629
128k
        e_access access;
630
631
128k
        m680x_reg reg = changed_regs[i].regs[j];
632
633
128k
        if (!info->cpu->reg_byte_size[reg]) {
634
7.09k
          if (info->insn != M680X_INS_MUL)
635
6.44k
            continue;
636
637
          // Hack for M68HC05: MUL uses reg. A,X
638
651
          reg = M680X_REG_X;
639
651
        }
640
641
122k
        access = get_access(j, access_mode);
642
122k
        add_reg_to_rw_list(MI, reg, access);
643
122k
      }
644
44.7k
    }
645
2.28M
  }
646
647
44.8k
#undef EOL
648
44.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
56.6k
{
663
56.6k
  uint8_t ir = 0;
664
56.6k
  uint8_t post_byte;
665
666
  // Read the indexed addressing post byte.
667
56.6k
  if (!read_byte(info, &post_byte, address))
668
222
    return -1;
669
670
  // Depending on the indexed addressing mode more bytes have to be read.
671
56.4k
  switch (post_byte & 0x9F) {
672
1.84k
  case 0x87:
673
3.09k
  case 0x8A:
674
4.32k
  case 0x8E:
675
5.44k
  case 0x8F:
676
6.76k
  case 0x90:
677
7.57k
  case 0x92:
678
8.23k
  case 0x97:
679
8.80k
  case 0x9A:
680
9.69k
  case 0x9E:
681
9.69k
    return -1; // illegal indexed post bytes
682
683
1.34k
  case 0x88: // n8,R
684
2.73k
  case 0x8C: // n8,PCR
685
3.69k
  case 0x98: // [n8,R]
686
4.30k
  case 0x9C: // [n8,PCR]
687
4.30k
    if (!read_byte(info, &ir, address + 1))
688
26
      return -1;
689
4.27k
    return 2;
690
691
1.90k
  case 0x89: // n16,R
692
4.36k
  case 0x8D: // n16,PCR
693
5.03k
  case 0x99: // [n16,R]
694
5.89k
  case 0x9D: // [n16,PCR]
695
5.89k
    if (!read_byte(info, &ir, address + 2))
696
38
      return -1;
697
5.85k
    return 3;
698
699
2.11k
  case 0x9F: // [n]
700
2.11k
    if ((post_byte & 0x60) != 0 ||
701
895
        !read_byte(info, &ir, address + 2))
702
1.23k
      return -1;
703
885
    return 3;
704
56.4k
  }
705
706
  // Any other indexed post byte is valid and
707
  // no additional bytes have to be read.
708
34.4k
  return 1;
709
56.4k
}
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
56.7k
{
717
56.7k
  uint8_t ir;
718
56.7k
  uint8_t post_byte;
719
720
  // Read the indexed addressing post byte.
721
56.7k
  if (!read_byte(info, &post_byte, address))
722
165
    return -1;
723
724
  // Depending on the indexed addressing mode more bytes have to be read.
725
56.5k
  if (!(post_byte & 0x20)) // n5,R
726
16.2k
    return 1;
727
728
40.3k
  switch (post_byte & 0xe7) {
729
3.21k
  case 0xe0:
730
5.86k
  case 0xe1: // n9,R
731
5.86k
    if (is_subset)
732
441
      return -1;
733
734
5.42k
    if (!read_byte(info, &ir, address))
735
0
      return -1;
736
5.42k
    return 2;
737
738
2.92k
  case 0xe2: // n16,R
739
6.98k
  case 0xe3: // [n16,R]
740
6.98k
    if (is_subset)
741
1.00k
      return -1;
742
743
5.98k
    if (!read_byte(info, &ir, address + 1))
744
21
      return -1;
745
5.96k
    return 3;
746
747
1.46k
  case 0xe4: // A,R
748
3.03k
  case 0xe5: // B,R
749
5.50k
  case 0xe6: // D,R
750
8.90k
  case 0xe7: // [D,R]
751
27.4k
  default: // n,-r n,+r n,r- n,r+
752
27.4k
    break;
753
40.3k
  }
754
755
27.4k
  return 1;
756
40.3k
}
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
11.8k
{
761
11.8k
  if (info->cpu->tfr_reg_valid != NULL)
762
2.66k
    return info->cpu->tfr_reg_valid[reg_nibble];
763
764
9.23k
  return true; // e.g. for the M6309 all registers are valid
765
11.8k
}
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
2.65k
{
771
2.65k
  return !(post_byte & 0x08);
772
2.65k
}
773
774
static bool is_tfm_reg_valid(const m680x_info *info, uint8_t reg_nibble)
775
5.06k
{
776
  // HD6809 TFM instruction: Only register X,Y,U,S,D is allowed
777
5.06k
  return reg_nibble <= 4;
778
5.06k
}
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.13k
{
785
4.13k
  uint8_t post_byte;
786
4.13k
  uint8_t rr;
787
788
4.13k
  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.11k
  if ((post_byte >= 0xc0) || ((post_byte & 0x07) == 2) ||
793
2.58k
      ((post_byte & 0x07) == 3))
794
1.70k
    return -1;
795
796
2.41k
  if (!read_byte(info, &rr, address + 1))
797
14
    return -1;
798
799
2.40k
  return 2;
800
2.41k
}
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.14k
{
808
1.14k
  uint8_t post_byte;
809
1.14k
  uint8_t rr;
810
811
1.14k
  if (!read_byte(info, &post_byte, address))
812
4
    return -1;
813
814
1.13k
  if ((post_byte & 0xc0) == 0xc0)
815
300
    return -1; // Invalid register specified
816
837
  else {
817
837
    if (!read_byte(info, &rr, address + 1))
818
3
      return -1;
819
837
  }
820
821
834
  return 2;
822
1.13k
}
823
824
static bool is_sufficient_code_size(const m680x_info *info, uint16_t address,
825
            insn_desc *insn_description)
826
249k
{
827
249k
  int i;
828
249k
  bool retval = true;
829
249k
  uint16_t size = 0;
830
249k
  int sz;
831
832
731k
  for (i = 0; i < 2; i++) {
833
490k
    uint8_t ir = 0;
834
490k
    bool is_subset = false;
835
836
490k
    switch (insn_description->hid[i]) {
837
581
    case imm32_hid:
838
581
      if ((retval = read_byte(info, &ir, address + size + 3)))
839
561
        size += 4;
840
581
      break;
841
842
33.8k
    case ext_hid:
843
36.9k
    case imm16_hid:
844
38.6k
    case rel16_hid:
845
39.9k
    case imm8rel_hid:
846
42.4k
    case opidxdr_hid:
847
43.4k
    case idxX16_hid:
848
43.5k
    case idxS16_hid:
849
44.1k
    case dirdir_hid:
850
44.4k
    case immdir_hid:
851
44.4k
      if ((retval = read_byte(info, &ir, address + size + 1)))
852
44.0k
        size += 2;
853
44.4k
      break;
854
855
15.0k
    case rel8_hid:
856
50.8k
    case dir_hid:
857
53.5k
    case rbits_hid:
858
68.9k
    case imm8_hid:
859
71.4k
    case idxX_hid:
860
71.7k
    case idxXp_hid:
861
72.6k
    case idxY_hid:
862
73.0k
    case idxS_hid:
863
73.9k
    case index_hid:
864
73.9k
      if ((retval = read_byte(info, &ir, address + size)))
865
73.5k
        size++;
866
73.9k
      break;
867
868
0
    case illgl_hid:
869
291k
    case inh_hid:
870
295k
    case idxX0_hid:
871
296k
    case idxX0p_hid:
872
297k
    case opidx_hid:
873
303k
    case srt_hid:
874
305k
    case tny_hid:
875
305k
      retval = true;
876
305k
      break;
877
878
29.5k
    case idx09_hid:
879
29.5k
      sz = get_indexed09_post_byte_size(info, address + size);
880
29.5k
      if (sz >= 0)
881
24.2k
        size += sz;
882
5.36k
      else
883
5.36k
        retval = false;
884
29.5k
      break;
885
886
1.47k
    case idx12s_hid:
887
1.47k
      is_subset = true;
888
889
      // intentionally fall through
890
891
24.5k
    case idx12_hid:
892
24.5k
      sz = get_indexed12_post_byte_size(info, address + size,
893
24.5k
                is_subset);
894
24.5k
      if (sz >= 0)
895
23.7k
        size += sz;
896
842
      else
897
842
        retval = false;
898
24.5k
      break;
899
900
1.39k
    case exti12x_hid:
901
2.19k
    case imm16i12x_hid:
902
2.19k
      sz = get_indexed12_post_byte_size(info, address + size,
903
2.19k
                false);
904
2.19k
      if (sz >= 0) {
905
2.19k
        size += sz;
906
2.19k
        if ((retval = read_byte(info, &ir,
907
2.19k
              address + size + 1)))
908
2.17k
          size += 2;
909
2.19k
      } else
910
9
        retval = false;
911
2.19k
      break;
912
913
2.47k
    case imm8i12x_hid:
914
2.47k
      sz = get_indexed12_post_byte_size(info, address + size,
915
2.47k
                false);
916
2.47k
      if (sz >= 0) {
917
2.46k
        size += sz;
918
2.46k
        if ((retval = read_byte(info, &ir,
919
2.46k
              address + size)))
920
2.45k
          size++;
921
2.46k
      } else
922
3
        retval = false;
923
2.47k
      break;
924
925
1.39k
    case tfm_hid:
926
1.39k
      if ((retval = read_byte(info, &ir, address + size))) {
927
1.38k
        size++;
928
1.38k
        retval = is_tfm_reg_valid(info,
929
1.38k
                (ir >> 4) & 0x0F) &&
930
1.15k
           is_tfm_reg_valid(info, ir & 0x0F);
931
1.38k
      }
932
1.39k
      break;
933
934
2.47k
    case rr09_hid:
935
2.47k
      if ((retval = read_byte(info, &ir, address + size))) {
936
2.47k
        size++;
937
2.47k
        retval = is_tfr09_reg_valid(info,
938
2.47k
                  (ir >> 4) & 0x0F) &&
939
1.95k
           is_tfr09_reg_valid(info, ir & 0x0F);
940
2.47k
      }
941
2.47k
      break;
942
943
730
    case rr12_hid:
944
730
      if ((retval = read_byte(info, &ir, address + size))) {
945
727
        size++;
946
727
        retval = is_exg_tfr12_post_byte_valid(info, ir);
947
727
      }
948
730
      break;
949
950
542
    case bitmv_hid:
951
542
      sz = get_bitmv_post_byte_size(info, address + size);
952
542
      if (sz >= 0)
953
405
        size += sz;
954
137
      else
955
137
        retval = false;
956
542
      break;
957
958
2.15k
    case loop_hid:
959
2.15k
      sz = get_loop_post_byte_size(info, address + size);
960
2.15k
      if (sz >= 0)
961
1.39k
        size += sz;
962
758
      else
963
758
        retval = false;
964
2.15k
      break;
965
966
0
    default:
967
0
      CS_ASSERT(0 && "Unexpected instruction handler id");
968
0
      retval = false;
969
0
      break;
970
490k
    }
971
972
490k
    if (!retval)
973
9.70k
      return false;
974
490k
  }
975
976
240k
  insn_description->insn_size += size;
977
978
240k
  return retval;
979
249k
}
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
532k
{
986
532k
  const inst_pageX *inst_table = NULL;
987
532k
  const cpu_tables *cpu = info->cpu;
988
532k
  size_t table_size = 0;
989
532k
  uint16_t base_address = address;
990
532k
  uint8_t ir; // instruction register
991
532k
  int i;
992
532k
  int index;
993
994
532k
  if (!read_byte(info, &ir, address++))
995
0
    return false;
996
997
532k
  insn_description->insn = M680X_INS_ILLGL;
998
532k
  insn_description->opcode = ir;
999
1000
  // Check if a page prefix byte is present
1001
1.23M
  for (i = 0; i < ARR_SIZE(cpu->pageX_table_size); ++i) {
1002
1.21M
    if (cpu->pageX_table_size[i] == 0 ||
1003
749k
        (cpu->inst_pageX_table[i] == NULL))
1004
468k
      break;
1005
1006
749k
    if ((cpu->pageX_prefix[i] == ir)) {
1007
      // Get pageX instruction and handler id.
1008
      // Abort for illegal instr.
1009
46.3k
      inst_table = cpu->inst_pageX_table[i];
1010
46.3k
      table_size = cpu->pageX_table_size[i];
1011
1012
46.3k
      if (!read_byte(info, &ir, address++))
1013
71
        return false;
1014
1015
46.2k
      insn_description->opcode =
1016
46.2k
        (insn_description->opcode << 8) | ir;
1017
1018
46.2k
      if ((index = binary_search(inst_table, table_size,
1019
46.2k
               ir)) < 0)
1020
16.7k
        return false;
1021
1022
29.5k
      insn_description->hid[0] =
1023
29.5k
        inst_table[index].handler_id1;
1024
29.5k
      insn_description->hid[1] =
1025
29.5k
        inst_table[index].handler_id2;
1026
29.5k
      insn_description->insn = inst_table[index].insn;
1027
29.5k
      break;
1028
46.2k
    }
1029
749k
  }
1030
1031
515k
  if (insn_description->insn == M680X_INS_ILLGL) {
1032
    // Get page1 insn description
1033
485k
    insn_description->insn = cpu->inst_page1_table[ir].insn;
1034
485k
    insn_description->hid[0] =
1035
485k
      cpu->inst_page1_table[ir].handler_id1;
1036
485k
    insn_description->hid[1] =
1037
485k
      cpu->inst_page1_table[ir].handler_id2;
1038
485k
  }
1039
1040
515k
  if (insn_description->insn == M680X_INS_ILLGL) {
1041
    // Check if opcode byte is present in an overlay table
1042
56.2k
    for (i = 0; i < ARR_SIZE(cpu->overlay_table_size); ++i) {
1043
54.6k
      if (cpu->overlay_table_size[i] == 0 ||
1044
39.3k
          (cpu->inst_overlay_table[i] == NULL))
1045
15.2k
        break;
1046
1047
39.3k
      inst_table = cpu->inst_overlay_table[i];
1048
39.3k
      table_size = cpu->overlay_table_size[i];
1049
1050
39.3k
      if ((index = binary_search(inst_table, table_size,
1051
39.3k
               ir)) >= 0) {
1052
23.4k
        insn_description->hid[0] =
1053
23.4k
          inst_table[index].handler_id1;
1054
23.4k
        insn_description->hid[1] =
1055
23.4k
          inst_table[index].handler_id2;
1056
23.4k
        insn_description->insn = inst_table[index].insn;
1057
23.4k
        break;
1058
23.4k
      }
1059
39.3k
    }
1060
40.2k
  }
1061
1062
515k
  insn_description->insn_size = address - base_address;
1063
1064
515k
  return (insn_description->insn != M680X_INS_ILLGL) &&
1065
498k
         (insn_description->insn != M680X_INS_INVLD) &&
1066
498k
         is_sufficient_code_size(info, address, insn_description);
1067
532k
}
1068
1069
static void illegal_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1070
53.9k
{
1071
53.9k
  cs_m680x_op *op0 = &info->m680x.operands[info->m680x.op_count++];
1072
53.9k
  uint8_t temp8 = 0;
1073
1074
53.9k
  info->insn = M680X_INS_ILLGL;
1075
53.9k
  read_byte(info, &temp8, (*address)++);
1076
53.9k
  op0->imm = (int32_t)temp8 & 0xff;
1077
53.9k
  op0->type = M680X_OP_IMMEDIATE;
1078
53.9k
  op0->size = 1;
1079
53.9k
}
1080
1081
static void inherent_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1082
585k
{
1083
  // There is nothing to do here :-)
1084
585k
}
1085
1086
static void add_reg_operand(m680x_info *info, m680x_reg reg)
1087
300k
{
1088
300k
  cs_m680x *m680x = &info->m680x;
1089
300k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1090
1091
300k
  op->type = M680X_OP_REGISTER;
1092
300k
  op->reg = reg;
1093
300k
  op->size = info->cpu->reg_byte_size[reg];
1094
300k
}
1095
1096
static void set_operand_size(m680x_info *info, cs_m680x_op *op,
1097
           uint8_t default_size)
1098
325k
{
1099
325k
  cs_m680x *m680x = &info->m680x;
1100
1101
325k
  if (info->insn == M680X_INS_JMP || info->insn == M680X_INS_JSR)
1102
16.4k
    op->size = 0;
1103
309k
  else if (info->insn == M680X_INS_DIVD ||
1104
307k
     ((info->insn == M680X_INS_AIS ||
1105
306k
       info->insn == M680X_INS_AIX) &&
1106
1.03k
      op->type != M680X_OP_REGISTER))
1107
3.08k
    op->size = 1;
1108
306k
  else if (info->insn == M680X_INS_DIVQ || info->insn == M680X_INS_MOVW)
1109
11.1k
    op->size = 2;
1110
295k
  else if (info->insn == M680X_INS_EMACS)
1111
433
    op->size = 4;
1112
294k
  else if ((m680x->op_count > 0) &&
1113
294k
     (m680x->operands[0].type == M680X_OP_REGISTER))
1114
182k
    op->size = m680x->operands[0].size;
1115
112k
  else
1116
112k
    op->size = default_size;
1117
325k
}
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
2.70k
{
1131
2.70k
  cs_m680x_op *op0 = &info->m680x.operands[0];
1132
2.70k
  uint8_t reg_bits = 0;
1133
2.70k
  uint16_t bit_index;
1134
2.70k
  const m680x_reg *reg_to_reg_ids = NULL;
1135
1136
2.70k
  read_byte(info, &reg_bits, (*address)++);
1137
1138
2.70k
  switch (op0->reg) {
1139
1.19k
  case M680X_REG_U:
1140
1.19k
    reg_to_reg_ids = &reg_u_reg_ids[0];
1141
1.19k
    break;
1142
1143
1.51k
  case M680X_REG_S:
1144
1.51k
    reg_to_reg_ids = &reg_s_reg_ids[0];
1145
1.51k
    break;
1146
1147
0
  default:
1148
0
    CS_ASSERT(0 && "Unexpected operand0 register");
1149
0
    break;
1150
2.70k
  }
1151
1152
2.70k
  if ((info->insn == M680X_INS_PULU || (info->insn == M680X_INS_PULS)) &&
1153
1.47k
      ((reg_bits & 0x80) != 0))
1154
    // PULS xxx,PC or PULU xxx,PC which is like return from
1155
    // subroutine (RTS)
1156
327
    add_insn_group(MI->flat_insn->detail, M680X_GRP_RET);
1157
1158
24.3k
  for (bit_index = 0; bit_index < 8; ++bit_index) {
1159
21.6k
    if (reg_bits & (1 << bit_index) && reg_to_reg_ids)
1160
10.3k
      add_reg_operand(info, reg_to_reg_ids[bit_index]);
1161
21.6k
  }
1162
2.70k
}
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
4.73k
{
1187
4.73k
  uint8_t regs = 0;
1188
1189
4.73k
  read_byte(info, &regs, (*address)++);
1190
1191
4.73k
  add_reg_operand(info, g_tfr_exg_reg_ids[regs >> 4]);
1192
4.73k
  add_reg_operand(info, g_tfr_exg_reg_ids[regs & 0x0f]);
1193
1194
4.73k
  if ((regs & 0x0f) == 0x05) {
1195
    // EXG xxx,PC or TFR xxx,PC which is like a JMP
1196
311
    add_insn_group(MI->flat_insn->detail, M680X_GRP_JUMP);
1197
311
  }
1198
4.73k
}
1199
1200
static void reg_reg12_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1201
2.10k
{
1202
2.10k
  static const m680x_reg g_tfr_exg12_reg0_ids[] = {
1203
2.10k
    M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP3,
1204
2.10k
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,  M680X_REG_S,
1205
2.10k
  };
1206
2.10k
  static const m680x_reg g_tfr_exg12_reg1_ids[] = {
1207
2.10k
    M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP2,
1208
2.10k
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,  M680X_REG_S,
1209
2.10k
  };
1210
2.10k
  uint8_t regs = 0;
1211
1212
2.10k
  read_byte(info, &regs, (*address)++);
1213
1214
  // The opcode of this instruction depends on
1215
  // the msb of its post byte.
1216
2.10k
  if (regs & 0x80)
1217
1.52k
    info->insn = M680X_INS_EXG;
1218
582
  else
1219
582
    info->insn = M680X_INS_TFR;
1220
1221
2.10k
  add_reg_operand(info, g_tfr_exg12_reg0_ids[(regs >> 4) & 0x07]);
1222
2.10k
  add_reg_operand(info, g_tfr_exg12_reg1_ids[regs & 0x07]);
1223
2.10k
}
1224
1225
static void add_rel_operand(m680x_info *info, int16_t offset, uint16_t address)
1226
39.9k
{
1227
39.9k
  cs_m680x *m680x = &info->m680x;
1228
39.9k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1229
1230
39.9k
  op->type = M680X_OP_RELATIVE;
1231
39.9k
  op->size = 0;
1232
39.9k
  op->rel.offset = offset;
1233
39.9k
  op->rel.address = address;
1234
39.9k
}
1235
1236
static void relative8_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1237
37.0k
{
1238
37.0k
  int16_t offset = 0;
1239
1240
37.0k
  read_byte_sign_extended(info, &offset, (*address)++);
1241
37.0k
  add_rel_operand(info, offset, *address + offset);
1242
37.0k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1243
1244
37.0k
  if ((info->insn != M680X_INS_BRA) && (info->insn != M680X_INS_BSR) &&
1245
32.1k
      (info->insn != M680X_INS_BRN))
1246
30.3k
    add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1247
37.0k
}
1248
1249
static void relative16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1250
2.90k
{
1251
2.90k
  uint16_t offset = 0;
1252
1253
2.90k
  read_word(info, &offset, *address);
1254
2.90k
  *address += 2;
1255
2.90k
  add_rel_operand(info, (int16_t)offset, *address + offset);
1256
2.90k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1257
1258
2.90k
  if ((info->insn != M680X_INS_LBRA) && (info->insn != M680X_INS_LBSR) &&
1259
1.33k
      (info->insn != M680X_INS_LBRN))
1260
1.16k
    add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1261
2.90k
}
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
30.7k
{
1275
30.7k
  cs_m680x *m680x = &info->m680x;
1276
30.7k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1277
1278
30.7k
  op->type = M680X_OP_INDEXED;
1279
30.7k
  set_operand_size(info, op, 1);
1280
30.7k
  op->idx.base_reg = base_reg;
1281
30.7k
  op->idx.offset_reg = M680X_REG_INVALID;
1282
30.7k
  op->idx.inc_dec = inc_dec;
1283
1284
30.7k
  if (inc_dec && post_inc_dec)
1285
3.88k
    op->idx.flags |= M680X_IDX_POST_INC_DEC;
1286
1287
30.7k
  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
30.7k
  op->idx.offset_bits = offset_bits;
1293
30.7k
  op->idx.flags |= (no_comma ? M680X_IDX_NO_COMMA : 0);
1294
30.7k
}
1295
1296
// M6800/1/2/3 indexed mode handler
1297
static void indexedX_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1298
8.17k
{
1299
8.17k
  uint8_t offset = 0;
1300
1301
8.17k
  read_byte(info, &offset, (*address)++);
1302
1303
8.17k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_8,
1304
8.17k
          (uint16_t)offset, false);
1305
8.17k
}
1306
1307
static void indexedY_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1308
1.91k
{
1309
1.91k
  uint8_t offset = 0;
1310
1311
1.91k
  read_byte(info, &offset, (*address)++);
1312
1313
1.91k
  add_indexed_operand(info, M680X_REG_Y, false, 0, M680X_OFFSET_BITS_8,
1314
1.91k
          (uint16_t)offset, false);
1315
1.91k
}
1316
1317
// M6809/M6309 indexed mode handler
1318
static void indexed09_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1319
45.4k
{
1320
45.4k
  cs_m680x *m680x = &info->m680x;
1321
45.4k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1322
45.4k
  uint8_t post_byte = 0;
1323
45.4k
  uint16_t offset = 0;
1324
45.4k
  int16_t soffset = 0;
1325
1326
45.4k
  read_byte(info, &post_byte, (*address)++);
1327
1328
45.4k
  op->type = M680X_OP_INDEXED;
1329
45.4k
  set_operand_size(info, op, 1);
1330
45.4k
  op->idx.base_reg = g_rr5_to_reg_ids[(post_byte >> 5) & 0x03];
1331
45.4k
  op->idx.offset_reg = M680X_REG_INVALID;
1332
1333
45.4k
  if (!(post_byte & 0x80)) {
1334
    // n5,R
1335
20.5k
    if ((post_byte & 0x10) == 0x10)
1336
10.0k
      op->idx.offset = post_byte | 0xfff0;
1337
10.4k
    else
1338
10.4k
      op->idx.offset = post_byte & 0x0f;
1339
1340
20.5k
    op->idx.offset_addr = op->idx.offset + *address;
1341
20.5k
    op->idx.offset_bits = M680X_OFFSET_BITS_5;
1342
24.9k
  } else {
1343
24.9k
    if ((post_byte & 0x10) == 0x10)
1344
9.17k
      op->idx.flags |= M680X_IDX_INDIRECT;
1345
1346
    // indexed addressing
1347
24.9k
    switch (post_byte & 0x1f) {
1348
1.03k
    case 0x00: // ,R+
1349
1.03k
      op->idx.inc_dec = 1;
1350
1.03k
      op->idx.flags |= M680X_IDX_POST_INC_DEC;
1351
1.03k
      break;
1352
1353
581
    case 0x11: // [,R++]
1354
2.37k
    case 0x01: // ,R++
1355
2.37k
      op->idx.inc_dec = 2;
1356
2.37k
      op->idx.flags |= M680X_IDX_POST_INC_DEC;
1357
2.37k
      break;
1358
1359
843
    case 0x02: // ,-R
1360
843
      op->idx.inc_dec = -1;
1361
843
      break;
1362
1363
1.35k
    case 0x13: // [,--R]
1364
2.14k
    case 0x03: // ,--R
1365
2.14k
      op->idx.inc_dec = -2;
1366
2.14k
      break;
1367
1368
964
    case 0x14: // [,R]
1369
1.95k
    case 0x04: // ,R
1370
1.95k
      break;
1371
1372
638
    case 0x15: // [B,R]
1373
1.43k
    case 0x05: // B,R
1374
1.43k
      op->idx.offset_reg = M680X_REG_B;
1375
1.43k
      break;
1376
1377
1.01k
    case 0x16: // [A,R]
1378
2.42k
    case 0x06: // A,R
1379
2.42k
      op->idx.offset_reg = M680X_REG_A;
1380
2.42k
      break;
1381
1382
599
    case 0x1c: // [n8,PCR]
1383
1.98k
    case 0x0c: // n8,PCR
1384
1.98k
      op->idx.base_reg = M680X_REG_PC;
1385
1.98k
      read_byte_sign_extended(info, &soffset, (*address)++);
1386
1.98k
      op->idx.offset_addr = offset + *address;
1387
1.98k
      op->idx.offset = soffset;
1388
1.98k
      op->idx.offset_bits = M680X_OFFSET_BITS_8;
1389
1.98k
      break;
1390
1391
958
    case 0x18: // [n8,R]
1392
2.29k
    case 0x08: // n8,R
1393
2.29k
      read_byte_sign_extended(info, &soffset, (*address)++);
1394
2.29k
      op->idx.offset = soffset;
1395
2.29k
      op->idx.offset_bits = M680X_OFFSET_BITS_8;
1396
2.29k
      break;
1397
1398
853
    case 0x1d: // [n16,PCR]
1399
3.29k
    case 0x0d: // n16,PCR
1400
3.29k
      op->idx.base_reg = M680X_REG_PC;
1401
3.29k
      read_word(info, &offset, *address);
1402
3.29k
      *address += 2;
1403
3.29k
      op->idx.offset_addr = offset + *address;
1404
3.29k
      op->idx.offset = (int16_t)offset;
1405
3.29k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1406
3.29k
      break;
1407
1408
674
    case 0x19: // [n16,R]
1409
2.56k
    case 0x09: // n16,R
1410
2.56k
      read_word(info, &offset, *address);
1411
2.56k
      *address += 2;
1412
2.56k
      op->idx.offset = (int16_t)offset;
1413
2.56k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1414
2.56k
      break;
1415
1416
644
    case 0x1b: // [D,R]
1417
1.72k
    case 0x0b: // D,R
1418
1.72k
      op->idx.offset_reg = M680X_REG_D;
1419
1.72k
      break;
1420
1421
885
    case 0x1f: // [n16]
1422
885
      op->type = M680X_OP_EXTENDED;
1423
885
      op->ext.indirect = true;
1424
885
      read_word(info, &op->ext.address, *address);
1425
885
      *address += 2;
1426
885
      break;
1427
1428
0
    default:
1429
0
      op->idx.base_reg = M680X_REG_INVALID;
1430
0
      break;
1431
24.9k
    }
1432
24.9k
  }
1433
1434
45.4k
  if (((info->insn == M680X_INS_LEAU) || (info->insn == M680X_INS_LEAS) ||
1435
41.8k
       (info->insn == M680X_INS_LEAX) ||
1436
39.2k
       (info->insn == M680X_INS_LEAY)) &&
1437
7.43k
      (m680x->operands[0].reg == M680X_REG_X ||
1438
4.85k
       (m680x->operands[0].reg == M680X_REG_Y)))
1439
    // Only LEAX and LEAY modify CC register
1440
3.79k
    add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1441
45.4k
}
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
55.0k
{
1456
55.0k
  cs_m680x *m680x = &info->m680x;
1457
55.0k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1458
55.0k
  uint8_t post_byte = 0;
1459
55.0k
  uint8_t offset8 = 0;
1460
1461
55.0k
  read_byte(info, &post_byte, (*address)++);
1462
1463
55.0k
  op->type = M680X_OP_INDEXED;
1464
55.0k
  set_operand_size(info, op, 1);
1465
55.0k
  op->idx.offset_reg = M680X_REG_INVALID;
1466
1467
55.0k
  if (!(post_byte & 0x20)) {
1468
    // n5,R      n5 is a 5-bit signed offset
1469
16.1k
    op->idx.base_reg = g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1470
1471
16.1k
    if ((post_byte & 0x10) == 0x10)
1472
6.76k
      op->idx.offset = post_byte | 0xfff0;
1473
9.43k
    else
1474
9.43k
      op->idx.offset = post_byte & 0x0f;
1475
1476
16.1k
    op->idx.offset_addr = op->idx.offset + *address;
1477
16.1k
    op->idx.offset_bits = M680X_OFFSET_BITS_5;
1478
38.8k
  } else {
1479
38.8k
    if ((post_byte & 0xe0) == 0xe0)
1480
20.2k
      op->idx.base_reg =
1481
20.2k
        g_idx12_to_reg_ids[(post_byte >> 3) & 0x03];
1482
1483
38.8k
    switch (post_byte & 0xe7) {
1484
3.01k
    case 0xe0:
1485
5.40k
    case 0xe1: // n9,R
1486
5.40k
      read_byte(info, &offset8, (*address)++);
1487
5.40k
      op->idx.offset = offset8;
1488
1489
5.40k
      if (post_byte & 0x01) // sign extension
1490
2.39k
        op->idx.offset |= 0xff00;
1491
1492
5.40k
      op->idx.offset_bits = M680X_OFFSET_BITS_9;
1493
1494
5.40k
      if (op->idx.base_reg == M680X_REG_PC)
1495
2.06k
        op->idx.offset_addr = op->idx.offset + *address;
1496
1497
5.40k
      break;
1498
1499
3.63k
    case 0xe3: // [n16,R]
1500
3.63k
      op->idx.flags |= M680X_IDX_INDIRECT;
1501
1502
    // intentionally fall through
1503
5.95k
    case 0xe2: // n16,R
1504
5.95k
      read_word(info, (uint16_t *)&op->idx.offset, *address);
1505
5.95k
      (*address) += 2;
1506
5.95k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1507
1508
5.95k
      if (op->idx.base_reg == M680X_REG_PC)
1509
1.10k
        op->idx.offset_addr = op->idx.offset + *address;
1510
1511
5.95k
      break;
1512
1513
1.46k
    case 0xe4: // A,R
1514
3.03k
    case 0xe5: // B,R
1515
5.50k
    case 0xe6: // D,R
1516
5.50k
      op->idx.offset_reg =
1517
5.50k
        g_or12_to_reg_ids[post_byte & 0x03];
1518
5.50k
      break;
1519
1520
3.39k
    case 0xe7: // [D,R]
1521
3.39k
      op->idx.offset_reg = M680X_REG_D;
1522
3.39k
      op->idx.flags |= M680X_IDX_INDIRECT;
1523
3.39k
      break;
1524
1525
18.5k
    default: // n,-r n,+r n,r- n,r+
1526
      // PC is not allowed in this mode
1527
18.5k
      op->idx.base_reg =
1528
18.5k
        g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1529
18.5k
      op->idx.inc_dec = post_byte & 0x0f;
1530
1531
18.5k
      if (op->idx.inc_dec & 0x08) // evtl. sign extend value
1532
9.72k
        op->idx.inc_dec |= 0xf0;
1533
1534
18.5k
      if (op->idx.inc_dec >= 0)
1535
8.84k
        op->idx.inc_dec++;
1536
1537
18.5k
      if (post_byte & 0x10)
1538
5.77k
        op->idx.flags |= M680X_IDX_POST_INC_DEC;
1539
1540
18.5k
      break;
1541
38.8k
    }
1542
38.8k
  }
1543
55.0k
}
1544
1545
static void index_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1546
1.60k
{
1547
1.60k
  cs_m680x *m680x = &info->m680x;
1548
1.60k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1549
1550
1.60k
  op->type = M680X_OP_CONSTANT;
1551
1.60k
  read_byte(info, &op->const_val, (*address)++);
1552
1.60k
};
1553
1554
static void direct_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1555
76.7k
{
1556
76.7k
  cs_m680x *m680x = &info->m680x;
1557
76.7k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1558
1559
76.7k
  op->type = M680X_OP_DIRECT;
1560
76.7k
  set_operand_size(info, op, 1);
1561
76.7k
  read_byte(info, &op->direct_addr, (*address)++);
1562
76.7k
};
1563
1564
static void extended_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1565
69.2k
{
1566
69.2k
  cs_m680x *m680x = &info->m680x;
1567
69.2k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1568
1569
69.2k
  op->type = M680X_OP_EXTENDED;
1570
69.2k
  set_operand_size(info, op, 1);
1571
69.2k
  read_word(info, &op->ext.address, *address);
1572
69.2k
  *address += 2;
1573
69.2k
}
1574
1575
static void immediate_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1576
38.6k
{
1577
38.6k
  cs_m680x *m680x = &info->m680x;
1578
38.6k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1579
38.6k
  uint16_t word = 0;
1580
38.6k
  int16_t sword = 0;
1581
1582
38.6k
  op->type = M680X_OP_IMMEDIATE;
1583
38.6k
  set_operand_size(info, op, 1);
1584
1585
38.6k
  switch (op->size) {
1586
32.1k
  case 1:
1587
32.1k
    read_byte_sign_extended(info, &sword, *address);
1588
32.1k
    op->imm = sword;
1589
32.1k
    break;
1590
1591
5.54k
  case 2:
1592
5.54k
    read_word(info, &word, *address);
1593
5.54k
    op->imm = (int16_t)word;
1594
5.54k
    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
38.6k
  }
1604
1605
38.6k
  *address += op->size;
1606
38.6k
}
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
834
{
1611
834
  static const m680x_reg m680x_reg[] = {
1612
834
    M680X_REG_CC,
1613
834
    M680X_REG_A,
1614
834
    M680X_REG_B,
1615
834
    M680X_REG_INVALID,
1616
834
  };
1617
1618
834
  uint8_t post_byte = 0;
1619
834
  cs_m680x *m680x = &info->m680x;
1620
834
  cs_m680x_op *op;
1621
1622
834
  read_byte(info, &post_byte, *address);
1623
834
  (*address)++;
1624
1625
  // operand[0] = register
1626
834
  add_reg_operand(info, m680x_reg[post_byte >> 6]);
1627
1628
  // operand[1] = bit index in source operand
1629
834
  op = &m680x->operands[m680x->op_count++];
1630
834
  op->type = M680X_OP_CONSTANT;
1631
834
  op->const_val = (post_byte >> 3) & 0x07;
1632
1633
  // operand[2] = bit index in destination operand
1634
834
  op = &m680x->operands[m680x->op_count++];
1635
834
  op->type = M680X_OP_CONSTANT;
1636
834
  op->const_val = post_byte & 0x07;
1637
1638
834
  direct_hdlr(MI, info, address);
1639
834
}
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
1.20k
{
1644
1.20k
  static const uint8_t inc_dec_r0[] = {
1645
1.20k
    1,
1646
1.20k
    -1,
1647
1.20k
    1,
1648
1.20k
    0,
1649
1.20k
  };
1650
1.20k
  static const uint8_t inc_dec_r1[] = {
1651
1.20k
    1,
1652
1.20k
    -1,
1653
1.20k
    0,
1654
1.20k
    1,
1655
1.20k
  };
1656
1.20k
  uint8_t regs = 0;
1657
1.20k
  uint8_t index = (MI->Opcode & 0xff) - 0x38;
1658
1659
1.20k
  read_byte(info, &regs, *address);
1660
1661
1.20k
  add_indexed_operand(info, g_tfr_exg_reg_ids[regs >> 4], true,
1662
1.20k
          inc_dec_r0[index], M680X_OFFSET_NONE, 0, true);
1663
1.20k
  add_indexed_operand(info, g_tfr_exg_reg_ids[regs & 0x0f], true,
1664
1.20k
          inc_dec_r1[index], M680X_OFFSET_NONE, 0, true);
1665
1666
1.20k
  add_reg_to_rw_list(MI, M680X_REG_W, READ | WRITE);
1667
1.20k
}
1668
1669
static void opidx_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1670
2.68k
{
1671
2.68k
  cs_m680x *m680x = &info->m680x;
1672
2.68k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1673
1674
  // bit index is coded in Opcode
1675
2.68k
  op->type = M680X_OP_CONSTANT;
1676
2.68k
  op->const_val = (MI->Opcode & 0x0e) >> 1;
1677
2.68k
}
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
7.03k
{
1684
7.03k
  cs_m680x *m680x = &info->m680x;
1685
7.03k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1686
1687
  // bit index is coded in Opcode
1688
7.03k
  op->type = M680X_OP_CONSTANT;
1689
7.03k
  op->const_val = (MI->Opcode & 0x0e) >> 1;
1690
7.03k
  direct_hdlr(MI, info, address);
1691
7.03k
  relative8_hdlr(MI, info, address);
1692
1693
7.03k
  add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1694
7.03k
}
1695
1696
static void indexedX0_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1697
11.6k
{
1698
11.6k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_NONE, 0,
1699
11.6k
          false);
1700
11.6k
}
1701
1702
static void indexedX16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1703
2.81k
{
1704
2.81k
  uint16_t offset = 0;
1705
1706
2.81k
  read_word(info, &offset, *address);
1707
2.81k
  *address += 2;
1708
2.81k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_16,
1709
2.81k
          offset, false);
1710
2.81k
}
1711
1712
static void imm_rel_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1713
2.78k
{
1714
2.78k
  immediate_hdlr(MI, info, address);
1715
2.78k
  relative8_hdlr(MI, info, address);
1716
2.78k
}
1717
1718
static void indexedS_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1719
928
{
1720
928
  uint8_t offset = 0;
1721
1722
928
  read_byte(info, &offset, (*address)++);
1723
1724
928
  add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_8,
1725
928
          (uint16_t)offset, false);
1726
928
}
1727
1728
static void indexedS16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1729
332
{
1730
332
  uint16_t offset = 0;
1731
1732
332
  read_word(info, &offset, *address);
1733
332
  *address += 2;
1734
1735
332
  add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_16,
1736
332
          offset, false);
1737
332
}
1738
1739
static void indexedX0p_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1740
1.61k
{
1741
1.61k
  add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_NONE, 0,
1742
1.61k
          true);
1743
1.61k
}
1744
1745
static void indexedXp_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1746
907
{
1747
907
  uint8_t offset = 0;
1748
1749
907
  read_byte(info, &offset, (*address)++);
1750
1751
907
  add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_BITS_8,
1752
907
          (uint16_t)offset, false);
1753
907
}
1754
1755
static void imm_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1756
7.90k
{
1757
7.90k
  cs_m680x *m680x = &info->m680x;
1758
7.90k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1759
1760
7.90k
  indexed12_hdlr(MI, info, address);
1761
7.90k
  op->type = M680X_OP_IMMEDIATE;
1762
1763
7.90k
  if (info->insn == M680X_INS_MOVW) {
1764
2.65k
    uint16_t imm16 = 0;
1765
1766
2.65k
    read_word(info, &imm16, *address);
1767
2.65k
    op->imm = (int16_t)imm16;
1768
2.65k
    op->size = 2;
1769
5.25k
  } else {
1770
5.25k
    uint8_t imm8 = 0;
1771
1772
5.25k
    read_byte(info, &imm8, *address);
1773
5.25k
    op->imm = (int8_t)imm8;
1774
5.25k
    op->size = 1;
1775
5.25k
  }
1776
1777
7.90k
  set_operand_size(info, op, 1);
1778
7.90k
}
1779
1780
static void ext_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1781
2.18k
{
1782
2.18k
  cs_m680x *m680x = &info->m680x;
1783
2.18k
  cs_m680x_op *op0 = &m680x->operands[m680x->op_count++];
1784
2.18k
  uint16_t imm16 = 0;
1785
1786
2.18k
  indexed12_hdlr(MI, info, address);
1787
2.18k
  read_word(info, &imm16, *address);
1788
2.18k
  op0->type = M680X_OP_EXTENDED;
1789
2.18k
  op0->ext.address = (int16_t)imm16;
1790
2.18k
  set_operand_size(info, op0, 1);
1791
2.18k
}
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.40k
{
1797
2.40k
  static const m680x_reg index_to_reg_id[] = {
1798
2.40k
    M680X_REG_A, M680X_REG_B, M680X_REG_INVALID, M680X_REG_INVALID,
1799
2.40k
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,       M680X_REG_S,
1800
2.40k
  };
1801
2.40k
  static const m680x_insn index_to_insn_id[] = {
1802
2.40k
    M680X_INS_DBEQ, M680X_INS_DBNE, M680X_INS_TBEQ,  M680X_INS_TBNE,
1803
2.40k
    M680X_INS_IBEQ, M680X_INS_IBNE, M680X_INS_ILLGL, M680X_INS_ILLGL
1804
2.40k
  };
1805
2.40k
  cs_m680x *m680x = &info->m680x;
1806
2.40k
  uint8_t post_byte = 0;
1807
2.40k
  uint8_t rel = 0;
1808
2.40k
  cs_m680x_op *op;
1809
1810
2.40k
  read_byte(info, &post_byte, (*address)++);
1811
1812
2.40k
  info->insn = index_to_insn_id[(post_byte >> 5) & 0x07];
1813
1814
2.40k
  if (info->insn == M680X_INS_ILLGL) {
1815
0
    illegal_hdlr(MI, info, address);
1816
0
  };
1817
1818
2.40k
  read_byte(info, &rel, (*address)++);
1819
1820
2.40k
  add_reg_operand(info, index_to_reg_id[post_byte & 0x07]);
1821
1822
2.40k
  op = &m680x->operands[m680x->op_count++];
1823
1824
2.40k
  op->type = M680X_OP_RELATIVE;
1825
1826
2.40k
  op->rel.offset = (post_byte & 0x10) ? (int16_t)(0xff00 | rel) : rel;
1827
1828
2.40k
  op->rel.address = *address + op->rel.offset;
1829
1830
2.40k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1831
2.40k
}
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
2.28k
{
1837
2.28k
  cs_m680x *m680x = &info->m680x;
1838
2.28k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1839
1840
2.28k
  op->type = M680X_OP_DIRECT;
1841
2.28k
  op->direct_addr = (uint8_t)(MI->Opcode & 0x0F);
1842
2.28k
  op->size = 1;
1843
2.28k
}
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
5.78k
{
1849
5.78k
  cs_m680x *m680x = &info->m680x;
1850
5.78k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1851
1852
5.78k
  op->type = M680X_OP_DIRECT;
1853
5.78k
  op->direct_addr = (uint8_t)(MI->Opcode & 0x1F);
1854
5.78k
  op->size = 1;
1855
5.78k
}
1856
1857
static void dirdir_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1858
593
{
1859
593
  direct_hdlr(MI, info, address);
1860
593
  direct_hdlr(MI, info, address);
1861
593
}
1862
1863
static void immdir_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1864
294
{
1865
294
  immediate_hdlr(MI, info, address);
1866
294
  direct_hdlr(MI, info, address);
1867
294
}
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
532k
{
1889
532k
  cs_m680x *m680x = &info->m680x;
1890
532k
  cs_detail *detail = MI->flat_insn->detail;
1891
532k
  uint16_t base_address = address;
1892
532k
  insn_desc insn_description;
1893
532k
  e_access_mode access_mode;
1894
1895
532k
  if (detail != NULL) {
1896
532k
    memset(detail, 0,
1897
532k
           offsetof(cs_detail, m680x) + sizeof(cs_m680x));
1898
532k
  }
1899
1900
532k
  memset(&insn_description, 0, sizeof(insn_description));
1901
532k
  memset(m680x, 0, sizeof(*m680x));
1902
532k
  info->insn_size = 1;
1903
1904
532k
  if (decode_insn(info, address, &insn_description)) {
1905
478k
    m680x_reg reg;
1906
1907
478k
    if (insn_description.opcode > 0xff)
1908
25.9k
      address += 2; // 8-bit opcode + page prefix
1909
452k
    else
1910
452k
      address++; // 8-bit opcode only
1911
1912
478k
    info->insn = insn_description.insn;
1913
1914
478k
    MCInst_setOpcode(MI, insn_description.opcode);
1915
1916
478k
    reg = g_insn_props[info->insn].reg0;
1917
1918
478k
    if (reg != M680X_REG_INVALID) {
1919
255k
      if (reg == M680X_REG_HX &&
1920
2.49k
          (!info->cpu->reg_byte_size[reg]))
1921
523
        reg = M680X_REG_X;
1922
1923
255k
      add_reg_operand(info, reg);
1924
      // First (or second) operand is a register which is
1925
      // part of the mnemonic
1926
255k
      m680x->flags |= M680X_FIRST_OP_IN_MNEM;
1927
255k
      reg = g_insn_props[info->insn].reg1;
1928
1929
255k
      if (reg != M680X_REG_INVALID) {
1930
5.71k
        if (reg == M680X_REG_HX &&
1931
1.77k
            (!info->cpu->reg_byte_size[reg]))
1932
575
          reg = M680X_REG_X;
1933
1934
5.71k
        add_reg_operand(info, reg);
1935
5.71k
        m680x->flags |= M680X_SECOND_OP_IN_MNEM;
1936
5.71k
      }
1937
255k
    }
1938
1939
    // Call addressing mode specific instruction handler
1940
478k
    (g_insn_handler[insn_description.hid[0]])(MI, info, &address);
1941
478k
    (g_insn_handler[insn_description.hid[1]])(MI, info, &address);
1942
1943
478k
    add_insn_group(detail, g_insn_props[info->insn].group);
1944
1945
478k
    if (g_insn_props[info->insn].cc_modified &&
1946
309k
        (info->cpu->insn_cc_not_modified[0] != info->insn) &&
1947
308k
        (info->cpu->insn_cc_not_modified[1] != info->insn))
1948
307k
      add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1949
1950
478k
    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
478k
    if ((info->cpu->insn_cc_not_modified[0] == info->insn) ||
1955
476k
        (info->cpu->insn_cc_not_modified[1] == info->insn))
1956
2.68k
      access_mode = rmmm;
1957
1958
478k
    build_regs_read_write_counts(MI, info, access_mode);
1959
478k
    add_operators_access(MI, info, access_mode);
1960
1961
478k
    if (g_insn_props[info->insn].update_reg_access)
1962
44.8k
      set_changed_regs_read_write_counts(MI, info);
1963
1964
478k
    info->insn_size = (uint8_t)insn_description.insn_size;
1965
1966
478k
    return info->insn_size;
1967
478k
  } else
1968
53.9k
    MCInst_setOpcode(MI, insn_description.opcode);
1969
1970
  // Illegal instruction
1971
53.9k
  address = base_address;
1972
53.9k
  illegal_hdlr(MI, info, &address);
1973
53.9k
  return 1;
1974
532k
}
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
532k
{
2182
532k
  if (cpu_type == M680X_CPU_TYPE_INVALID) {
2183
0
    return false;
2184
0
  }
2185
2186
532k
  info->code = code;
2187
532k
  info->size = code_len;
2188
532k
  info->offset = address;
2189
532k
  info->cpu_type = cpu_type;
2190
2191
532k
  info->cpu = &g_cpu_tables[info->cpu_type];
2192
2193
532k
  return true;
2194
532k
}
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
264k
{
2200
264k
  unsigned int insn_size = 0;
2201
264k
  e_cpu_type cpu_type = M680X_CPU_TYPE_INVALID; // No default CPU type
2202
264k
  cs_struct *handle = (cs_struct *)ud;
2203
264k
  m680x_info *info = (m680x_info *)handle->printer_info;
2204
2205
264k
  MCInst_clear(MI);
2206
2207
264k
  if (handle->mode & CS_MODE_M680X_6800)
2208
1.16k
    cpu_type = M680X_CPU_TYPE_6800;
2209
2210
263k
  else if (handle->mode & CS_MODE_M680X_6801)
2211
2.97k
    cpu_type = M680X_CPU_TYPE_6801;
2212
2213
260k
  else if (handle->mode & CS_MODE_M680X_6805)
2214
4.71k
    cpu_type = M680X_CPU_TYPE_6805;
2215
2216
255k
  else if (handle->mode & CS_MODE_M680X_6808)
2217
9.17k
    cpu_type = M680X_CPU_TYPE_6808;
2218
2219
246k
  else if (handle->mode & CS_MODE_M680X_HCS08)
2220
5.52k
    cpu_type = M680X_CPU_TYPE_HCS08;
2221
2222
241k
  else if (handle->mode & CS_MODE_M680X_6809)
2223
22.9k
    cpu_type = M680X_CPU_TYPE_6809;
2224
2225
218k
  else if (handle->mode & CS_MODE_M680X_6301)
2226
917
    cpu_type = M680X_CPU_TYPE_6301;
2227
2228
217k
  else if (handle->mode & CS_MODE_M680X_6309)
2229
84.9k
    cpu_type = M680X_CPU_TYPE_6309;
2230
2231
132k
  else if (handle->mode & CS_MODE_M680X_6811)
2232
9.10k
    cpu_type = M680X_CPU_TYPE_6811;
2233
2234
123k
  else if (handle->mode & CS_MODE_M680X_CPU12)
2235
61.2k
    cpu_type = M680X_CPU_TYPE_CPU12;
2236
2237
61.9k
  else if (handle->mode & CS_MODE_M680X_RS08)
2238
13.0k
    cpu_type = M680X_CPU_TYPE_RS08;
2239
2240
48.8k
  else if (handle->mode & CS_MODE_M680X_HCS12X)
2241
48.8k
    cpu_type = M680X_CPU_TYPE_HCS12X;
2242
2243
264k
  if (cpu_type != M680X_CPU_TYPE_INVALID &&
2244
264k
      m680x_setup_internals(info, cpu_type, (uint16_t)address, code,
2245
264k
          (uint16_t)code_len))
2246
264k
    insn_size = m680x_disassemble(MI, info, (uint16_t)address);
2247
2248
264k
  if (insn_size == 0) {
2249
0
    *size = 1;
2250
0
    return false;
2251
0
  }
2252
2253
  // Make sure we always stay within range
2254
264k
  if (insn_size > code_len) {
2255
8
    *size = (uint16_t)code_len;
2256
8
    return false;
2257
8
  } else
2258
264k
    *size = (uint16_t)insn_size;
2259
2260
264k
  return true;
2261
264k
}
2262
2263
cs_err M680X_disassembler_init(cs_struct *ud)
2264
1.94k
{
2265
1.94k
  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.94k
  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.94k
  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.94k
  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.94k
  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.94k
  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.94k
  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.94k
  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.94k
  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.94k
  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.94k
  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.94k
  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.94k
  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.94k
  return CS_ERR_OK;
2345
1.94k
}
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