Coverage Report

Created: 2026-11-12 06:22

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