Coverage Report

Created: 2025-10-14 06:42

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