Coverage Report

Created: 2026-03-03 06:14

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