Coverage Report

Created: 2025-11-11 06:33

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
245k
#define READ CS_AC_READ
109
306k
#define WRITE CS_AC_WRITE
110
376k
#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
596k
{
156
596k
  if (address < info->offset ||
157
596k
      (uint32_t)(address - info->offset) >= info->size)
158
    // out of code buffer range
159
879
    return false;
160
161
595k
  *byte = info->code[address - info->offset];
162
163
595k
  return true;
164
596k
}
165
166
static bool read_byte_sign_extended(const m680x_info *info, int16_t *word,
167
            uint16_t address)
168
40.4k
{
169
40.4k
  if (address < info->offset ||
170
40.4k
      (uint32_t)(address - info->offset) >= info->size)
171
    // out of code buffer range
172
0
    return false;
173
174
40.4k
  *word = (int16_t)info->code[address - info->offset];
175
176
40.4k
  if (*word & 0x80)
177
14.4k
    *word |= 0xFF00;
178
179
40.4k
  return true;
180
40.4k
}
181
182
static bool read_word(const m680x_info *info, uint16_t *word, uint16_t address)
183
41.1k
{
184
41.1k
  if (address < info->offset ||
185
41.1k
      (uint32_t)(address + 1 - info->offset) >= info->size)
186
    // out of code buffer range
187
7
    return false;
188
189
41.1k
  *word = (uint16_t)info->code[address - info->offset] << 8;
190
41.1k
  *word |= (uint16_t)info->code[address + 1 - info->offset];
191
192
41.1k
  return true;
193
41.1k
}
194
195
static bool read_sdword(const m680x_info *info, int32_t *sdword,
196
      uint16_t address)
197
826
{
198
826
  if (address < info->offset ||
199
826
      (uint32_t)(address + 3 - info->offset) >= info->size)
200
    // out of code buffer range
201
0
    return false;
202
203
826
  *sdword = (uint32_t)info->code[address - info->offset] << 24;
204
826
  *sdword |= (uint32_t)info->code[address + 1 - info->offset] << 16;
205
826
  *sdword |= (uint32_t)info->code[address + 2 - info->offset] << 8;
206
826
  *sdword |= (uint32_t)info->code[address + 3 - info->offset];
207
208
826
  return true;
209
826
}
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
87.3k
{
218
  // As part of the algorithm last may get negative.
219
  // => signed integer has to be used.
220
87.3k
  int first = 0;
221
87.3k
  int last = (int)table_size - 1;
222
87.3k
  int middle = (first + last) / 2;
223
224
429k
  while (first <= last) {
225
395k
    if (inst_pageX_table[middle].opcode < opcode) {
226
118k
      first = middle + 1;
227
276k
    } else if (inst_pageX_table[middle].opcode == opcode) {
228
52.5k
      return middle; /* item found */
229
52.5k
    } else
230
223k
      last = middle - 1;
231
232
342k
    middle = (first + last) / 2;
233
342k
  }
234
235
34.7k
  if (first > last)
236
34.7k
    return -1; /* item not found */
237
238
0
  return -2;
239
34.7k
}
240
241
void M680X_get_insn_id(cs_struct *handle, cs_insn *insn, unsigned int id)
242
247k
{
243
247k
  const m680x_info *const info = (const m680x_info *)handle->printer_info;
244
247k
  const cpu_tables *cpu = info->cpu;
245
247k
  uint8_t insn_prefix = (id >> 8) & 0xff;
246
  // opcode is the first instruction byte without the prefix.
247
247k
  uint8_t opcode = id & 0xff;
248
247k
  int index;
249
247k
  int i;
250
251
247k
  insn->id = M680X_INS_ILLGL;
252
253
597k
  for (i = 0; i < ARR_SIZE(cpu->pageX_prefix); ++i) {
254
586k
    if (cpu->pageX_table_size[i] == 0 ||
255
372k
        (cpu->inst_pageX_table[i] == NULL))
256
213k
      break;
257
258
372k
    if (cpu->pageX_prefix[i] == insn_prefix) {
259
22.4k
      index = binary_search(cpu->inst_pageX_table[i],
260
22.4k
                cpu->pageX_table_size[i], opcode);
261
22.4k
      insn->id =
262
22.4k
        (index >= 0) ?
263
14.6k
          cpu->inst_pageX_table[i][index].insn :
264
22.4k
          M680X_INS_ILLGL;
265
22.4k
      return;
266
22.4k
    }
267
372k
  }
268
269
224k
  if (insn_prefix != 0)
270
0
    return;
271
272
224k
  insn->id = cpu->inst_page1_table[id].insn;
273
274
224k
  if (insn->id != M680X_INS_ILLGL)
275
203k
    return;
276
277
  // Check if opcode byte is present in an overlay table
278
31.1k
  for (i = 0; i < ARR_SIZE(cpu->overlay_table_size); ++i) {
279
29.1k
    if (cpu->overlay_table_size[i] == 0 ||
280
21.1k
        (cpu->inst_overlay_table[i] == NULL))
281
7.97k
      break;
282
283
21.1k
    if ((index = binary_search(cpu->inst_overlay_table[i],
284
21.1k
             cpu->overlay_table_size[i],
285
21.1k
             opcode)) >= 0) {
286
11.6k
      insn->id = cpu->inst_overlay_table[i][index].insn;
287
11.6k
      return;
288
11.6k
    }
289
21.1k
  }
290
21.5k
}
291
292
static void add_insn_group(cs_detail *detail, m680x_group_type group)
293
242k
{
294
242k
  if (detail != NULL && (group != M680X_GRP_INVALID) &&
295
61.3k
      (group != M680X_GRP_ENDING))
296
61.3k
    detail->groups[detail->groups_count++] = (uint8_t)group;
297
242k
}
298
299
static bool exists_reg_list(uint16_t *regs, uint8_t count, m680x_reg reg)
300
675k
{
301
675k
  uint8_t i;
302
303
1.10M
  for (i = 0; i < count; ++i) {
304
453k
    if (regs[i] == (uint16_t)reg)
305
19.7k
      return true;
306
453k
  }
307
308
656k
  return false;
309
675k
}
310
311
static void add_reg_to_rw_list(MCInst *MI, m680x_reg reg, e_access access)
312
443k
{
313
443k
  cs_detail *detail = MI->flat_insn->detail;
314
315
443k
  if (detail == NULL || (reg == M680X_REG_INVALID))
316
0
    return;
317
318
443k
  switch (access) {
319
232k
  case MODIFY:
320
232k
    if (!exists_reg_list(detail->regs_read, detail->regs_read_count,
321
232k
             reg))
322
226k
      detail->regs_read[detail->regs_read_count++] =
323
226k
        (uint16_t)reg;
324
325
    // intentionally fall through
326
327
292k
  case WRITE:
328
292k
    if (!exists_reg_list(detail->regs_write,
329
292k
             detail->regs_write_count, reg))
330
286k
      detail->regs_write[detail->regs_write_count++] =
331
286k
        (uint16_t)reg;
332
333
292k
    break;
334
335
151k
  case READ:
336
151k
    if (!exists_reg_list(detail->regs_read, detail->regs_read_count,
337
151k
             reg))
338
142k
      detail->regs_read[detail->regs_read_count++] =
339
142k
        (uint16_t)reg;
340
341
151k
    break;
342
343
0
  case UNCHANGED:
344
0
  default:
345
0
    break;
346
443k
  }
347
443k
}
348
349
static void update_am_reg_list(MCInst *MI, m680x_info *info, cs_m680x_op *op,
350
             e_access access)
351
318k
{
352
318k
  if (MI->flat_insn->detail == NULL)
353
0
    return;
354
355
318k
  switch (op->type) {
356
136k
  case M680X_OP_REGISTER:
357
136k
    add_reg_to_rw_list(MI, op->reg, access);
358
136k
    break;
359
360
60.5k
  case M680X_OP_INDEXED:
361
60.5k
    add_reg_to_rw_list(MI, op->idx.base_reg, READ);
362
363
60.5k
    if (op->idx.base_reg == M680X_REG_X &&
364
26.5k
        info->cpu->reg_byte_size[M680X_REG_H])
365
10.2k
      add_reg_to_rw_list(MI, M680X_REG_H, READ);
366
367
60.5k
    if (op->idx.offset_reg != M680X_REG_INVALID)
368
4.44k
      add_reg_to_rw_list(MI, op->idx.offset_reg, READ);
369
370
60.5k
    if (op->idx.inc_dec) {
371
12.2k
      add_reg_to_rw_list(MI, op->idx.base_reg, WRITE);
372
373
12.2k
      if (op->idx.base_reg == M680X_REG_X &&
374
3.92k
          info->cpu->reg_byte_size[M680X_REG_H])
375
1.37k
        add_reg_to_rw_list(MI, M680X_REG_H, WRITE);
376
12.2k
    }
377
378
60.5k
    break;
379
380
121k
  default:
381
121k
    break;
382
318k
  }
383
318k
}
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
666k
{
458
666k
  int idx = (operator_index > 3) ? 3 : operator_index;
459
460
666k
  return g_access_mode_to_access[idx][access_mode];
461
666k
}
462
463
static void build_regs_read_write_counts(MCInst *MI, m680x_info *info,
464
           e_access_mode access_mode)
465
217k
{
466
217k
  cs_m680x *m680x = &info->m680x;
467
217k
  int i;
468
469
217k
  if (MI->flat_insn->detail == NULL || (!m680x->op_count))
470
27.4k
    return;
471
472
508k
  for (i = 0; i < m680x->op_count; ++i) {
473
318k
    e_access access = get_access(i, access_mode);
474
318k
    update_am_reg_list(MI, info, &m680x->operands[i], access);
475
318k
  }
476
189k
}
477
478
static void add_operators_access(MCInst *MI, m680x_info *info,
479
         e_access_mode access_mode)
480
217k
{
481
217k
  cs_m680x *m680x = &info->m680x;
482
217k
  int offset = 0;
483
217k
  int i;
484
485
217k
  if (MI->flat_insn->detail == NULL || (!m680x->op_count) ||
486
189k
      (access_mode == uuuu))
487
51.8k
    return;
488
489
459k
  for (i = 0; i < m680x->op_count; ++i) {
490
293k
    e_access access;
491
492
    // Ugly fix: MULD has a register operand, an immediate operand
493
    // AND an implicitly changed register W
494
293k
    if (info->insn == M680X_INS_MULD && (i == 1))
495
203
      offset = 1;
496
497
293k
    access = get_access(i + offset, access_mode);
498
293k
    m680x->operands[i].access = access;
499
293k
  }
500
165k
}
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
19.8k
{
510
  //TABLE
511
1.09M
#define EOL M680X_REG_INVALID
512
19.8k
  static const insn_to_changed_regs changed_regs[] = {
513
19.8k
    { M680X_INS_BSR, mmmm, { M680X_REG_S, EOL } },
514
19.8k
    { M680X_INS_CALL, mmmm, { M680X_REG_S, EOL } },
515
19.8k
    {
516
19.8k
      M680X_INS_CWAI,
517
19.8k
      mrrr,
518
19.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
519
19.8k
        M680X_REG_X, M680X_REG_DP, M680X_REG_D, M680X_REG_CC,
520
19.8k
        EOL },
521
19.8k
    },
522
19.8k
    { M680X_INS_DAA, mrrr, { M680X_REG_A, EOL } },
523
19.8k
    { M680X_INS_DIV,
524
19.8k
      mmrr,
525
19.8k
      { M680X_REG_A, M680X_REG_H, M680X_REG_X, EOL } },
526
19.8k
    { M680X_INS_EDIV,
527
19.8k
      mmrr,
528
19.8k
      { M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL } },
529
19.8k
    { M680X_INS_EDIVS,
530
19.8k
      mmrr,
531
19.8k
      { M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL } },
532
19.8k
    { M680X_INS_EMACS, mrrr, { M680X_REG_X, M680X_REG_Y, EOL } },
533
19.8k
    { M680X_INS_EMAXM, rrrr, { M680X_REG_D, EOL } },
534
19.8k
    { M680X_INS_EMINM, rrrr, { M680X_REG_D, EOL } },
535
19.8k
    { M680X_INS_EMUL, mmrr, { M680X_REG_D, M680X_REG_Y, EOL } },
536
19.8k
    { M680X_INS_EMULS, mmrr, { M680X_REG_D, M680X_REG_Y, EOL } },
537
19.8k
    { M680X_INS_ETBL, wmmm, { M680X_REG_A, M680X_REG_B, EOL } },
538
19.8k
    { M680X_INS_FDIV, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
539
19.8k
    { M680X_INS_IDIV, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
540
19.8k
    { M680X_INS_IDIVS, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
541
19.8k
    { M680X_INS_JSR, mmmm, { M680X_REG_S, EOL } },
542
19.8k
    { M680X_INS_LBSR, mmmm, { M680X_REG_S, EOL } },
543
19.8k
    { M680X_INS_MAXM, rrrr, { M680X_REG_A, EOL } },
544
19.8k
    { M680X_INS_MINM, rrrr, { M680X_REG_A, EOL } },
545
19.8k
    { M680X_INS_MEM,
546
19.8k
      mmrr,
547
19.8k
      { M680X_REG_X, M680X_REG_Y, M680X_REG_A, EOL } },
548
19.8k
    { M680X_INS_MUL, mmmm, { M680X_REG_A, M680X_REG_B, EOL } },
549
19.8k
    { M680X_INS_MULD, mwrr, { M680X_REG_D, M680X_REG_W, EOL } },
550
19.8k
    { M680X_INS_PSHA, rmmm, { M680X_REG_A, M680X_REG_S, EOL } },
551
19.8k
    { M680X_INS_PSHB, rmmm, { M680X_REG_B, M680X_REG_S, EOL } },
552
19.8k
    { M680X_INS_PSHC, rmmm, { M680X_REG_CC, M680X_REG_S, EOL } },
553
19.8k
    { M680X_INS_PSHD, rmmm, { M680X_REG_D, M680X_REG_S, EOL } },
554
19.8k
    { M680X_INS_PSHH, rmmm, { M680X_REG_H, M680X_REG_S, EOL } },
555
19.8k
    { M680X_INS_PSHX, rmmm, { M680X_REG_X, M680X_REG_S, EOL } },
556
19.8k
    { M680X_INS_PSHY, rmmm, { M680X_REG_Y, M680X_REG_S, EOL } },
557
19.8k
    { M680X_INS_PULA, wmmm, { M680X_REG_A, M680X_REG_S, EOL } },
558
19.8k
    { M680X_INS_PULB, wmmm, { M680X_REG_B, M680X_REG_S, EOL } },
559
19.8k
    { M680X_INS_PULC, wmmm, { M680X_REG_CC, M680X_REG_S, EOL } },
560
19.8k
    { M680X_INS_PULD, wmmm, { M680X_REG_D, M680X_REG_S, EOL } },
561
19.8k
    { M680X_INS_PULH, wmmm, { M680X_REG_H, M680X_REG_S, EOL } },
562
19.8k
    { M680X_INS_PULX, wmmm, { M680X_REG_X, M680X_REG_S, EOL } },
563
19.8k
    { M680X_INS_PULY, wmmm, { M680X_REG_Y, M680X_REG_S, EOL } },
564
19.8k
    { M680X_INS_REV,
565
19.8k
      mmrr,
566
19.8k
      { M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL } },
567
19.8k
    { M680X_INS_REVW,
568
19.8k
      mmmm,
569
19.8k
      { M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL } },
570
19.8k
    { M680X_INS_RTC, mwww, { M680X_REG_S, M680X_REG_PC, EOL } },
571
19.8k
    {
572
19.8k
      M680X_INS_RTI,
573
19.8k
      mwww,
574
19.8k
      { M680X_REG_S, M680X_REG_CC, M680X_REG_B, M680X_REG_A,
575
19.8k
        M680X_REG_DP, M680X_REG_X, M680X_REG_Y, M680X_REG_U,
576
19.8k
        M680X_REG_PC, EOL },
577
19.8k
    },
578
19.8k
    { M680X_INS_RTS, mwww, { M680X_REG_S, M680X_REG_PC, EOL } },
579
19.8k
    { M680X_INS_SEX, wrrr, { M680X_REG_A, M680X_REG_B, EOL } },
580
19.8k
    { M680X_INS_SEXW, rwww, { M680X_REG_W, M680X_REG_D, EOL } },
581
19.8k
    { M680X_INS_SWI,
582
19.8k
      mmrr,
583
19.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
584
19.8k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
585
19.8k
        M680X_REG_CC, EOL } },
586
19.8k
    {
587
19.8k
      M680X_INS_SWI2,
588
19.8k
      mmrr,
589
19.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
590
19.8k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
591
19.8k
        M680X_REG_CC, EOL },
592
19.8k
    },
593
19.8k
    {
594
19.8k
      M680X_INS_SWI3,
595
19.8k
      mmrr,
596
19.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
597
19.8k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
598
19.8k
        M680X_REG_CC, EOL },
599
19.8k
    },
600
19.8k
    { M680X_INS_TBL, wrrr, { M680X_REG_A, M680X_REG_B, EOL } },
601
19.8k
    { M680X_INS_WAI,
602
19.8k
      mrrr,
603
19.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_X, M680X_REG_A,
604
19.8k
        M680X_REG_B, M680X_REG_CC, EOL } },
605
19.8k
    { M680X_INS_WAV,
606
19.8k
      rmmm,
607
19.8k
      { M680X_REG_A, M680X_REG_B, M680X_REG_X, M680X_REG_Y, EOL } },
608
19.8k
    { M680X_INS_WAVR,
609
19.8k
      rmmm,
610
19.8k
      { M680X_REG_A, M680X_REG_B, M680X_REG_X, M680X_REG_Y, EOL } },
611
19.8k
  };
612
613
19.8k
  int i, j;
614
615
19.8k
  if (MI->flat_insn->detail == NULL)
616
0
    return;
617
618
1.03M
  for (i = 0; i < ARR_SIZE(changed_regs); ++i) {
619
1.01M
    if (info->insn == changed_regs[i].insn) {
620
19.8k
      e_access_mode access_mode = changed_regs[i].access_mode;
621
622
79.4k
      for (j = 0; changed_regs[i].regs[j] != EOL; ++j) {
623
59.6k
        e_access access;
624
625
59.6k
        m680x_reg reg = changed_regs[i].regs[j];
626
627
59.6k
        if (!info->cpu->reg_byte_size[reg]) {
628
5.31k
          if (info->insn != M680X_INS_MUL)
629
4.98k
            continue;
630
631
          // Hack for M68HC05: MUL uses reg. A,X
632
330
          reg = M680X_REG_X;
633
330
        }
634
635
54.6k
        access = get_access(j, access_mode);
636
54.6k
        add_reg_to_rw_list(MI, reg, access);
637
54.6k
      }
638
19.8k
    }
639
1.01M
  }
640
641
19.8k
#undef EOL
642
19.8k
}
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
29.9k
{
657
29.9k
  uint8_t ir = 0;
658
29.9k
  uint8_t post_byte;
659
660
  // Read the indexed addressing post byte.
661
29.9k
  if (!read_byte(info, &post_byte, address))
662
70
    return -1;
663
664
  // Depending on the indexed addressing mode more bytes have to be read.
665
29.8k
  switch (post_byte & 0x9F) {
666
1.39k
  case 0x87:
667
2.09k
  case 0x8A:
668
4.67k
  case 0x8E:
669
5.36k
  case 0x8F:
670
5.71k
  case 0x90:
671
6.08k
  case 0x92:
672
6.37k
  case 0x97:
673
6.67k
  case 0x9A:
674
7.03k
  case 0x9E:
675
7.03k
    return -1; // illegal indexed post bytes
676
677
1.02k
  case 0x88: // n8,R
678
1.76k
  case 0x8C: // n8,PCR
679
2.06k
  case 0x98: // [n8,R]
680
2.53k
  case 0x9C: // [n8,PCR]
681
2.53k
    if (!read_byte(info, &ir, address + 1))
682
8
      return -1;
683
2.52k
    return 2;
684
685
463
  case 0x89: // n16,R
686
1.04k
  case 0x8D: // n16,PCR
687
1.42k
  case 0x99: // [n16,R]
688
1.85k
  case 0x9D: // [n16,PCR]
689
1.85k
    if (!read_byte(info, &ir, address + 2))
690
33
      return -1;
691
1.82k
    return 3;
692
693
863
  case 0x9F: // [n]
694
863
    if ((post_byte & 0x60) != 0 ||
695
382
        !read_byte(info, &ir, address + 2))
696
486
      return -1;
697
377
    return 3;
698
29.8k
  }
699
700
  // Any other indexed post byte is valid and
701
  // no additional bytes have to be read.
702
17.5k
  return 1;
703
29.8k
}
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
22.9k
{
711
22.9k
  uint8_t ir;
712
22.9k
  uint8_t post_byte;
713
714
  // Read the indexed addressing post byte.
715
22.9k
  if (!read_byte(info, &post_byte, address))
716
61
    return -1;
717
718
  // Depending on the indexed addressing mode more bytes have to be read.
719
22.8k
  if (!(post_byte & 0x20)) // n5,R
720
8.12k
    return 1;
721
722
14.7k
  switch (post_byte & 0xe7) {
723
2.29k
  case 0xe0:
724
3.77k
  case 0xe1: // n9,R
725
3.77k
    if (is_subset)
726
400
      return -1;
727
728
3.37k
    if (!read_byte(info, &ir, address))
729
0
      return -1;
730
3.37k
    return 2;
731
732
1.36k
  case 0xe2: // n16,R
733
2.74k
  case 0xe3: // [n16,R]
734
2.74k
    if (is_subset)
735
240
      return -1;
736
737
2.50k
    if (!read_byte(info, &ir, address + 1))
738
17
      return -1;
739
2.48k
    return 3;
740
741
403
  case 0xe4: // A,R
742
839
  case 0xe5: // B,R
743
1.30k
  case 0xe6: // D,R
744
2.31k
  case 0xe7: // [D,R]
745
8.19k
  default: // n,-r n,+r n,r- n,r+
746
8.19k
    break;
747
14.7k
  }
748
749
8.19k
  return 1;
750
14.7k
}
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.36k
{
755
4.36k
  if (info->cpu->tfr_reg_valid != NULL)
756
2.44k
    return info->cpu->tfr_reg_valid[reg_nibble];
757
758
1.92k
  return true; // e.g. for the M6309 all registers are valid
759
4.36k
}
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
1.22k
{
765
1.22k
  return !(post_byte & 0x08);
766
1.22k
}
767
768
static bool is_tfm_reg_valid(const m680x_info *info, uint8_t reg_nibble)
769
2.66k
{
770
  // HD6809 TFM instruction: Only register X,Y,U,S,D is allowed
771
2.66k
  return reg_nibble <= 4;
772
2.66k
}
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
2.26k
{
779
2.26k
  uint8_t post_byte;
780
2.26k
  uint8_t rr;
781
782
2.26k
  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
2.26k
  if ((post_byte >= 0xc0) || ((post_byte & 0x07) == 2) ||
787
1.77k
      ((post_byte & 0x07) == 3))
788
758
    return -1;
789
790
1.50k
  if (!read_byte(info, &rr, address + 1))
791
8
    return -1;
792
793
1.49k
  return 2;
794
1.50k
}
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
376
{
802
376
  uint8_t post_byte;
803
376
  uint8_t rr;
804
805
376
  if (!read_byte(info, &post_byte, address))
806
3
    return -1;
807
808
373
  if ((post_byte & 0xc0) == 0xc0)
809
205
    return -1; // Invalid register specified
810
168
  else {
811
168
    if (!read_byte(info, &rr, address + 1))
812
6
      return -1;
813
168
  }
814
815
162
  return 2;
816
373
}
817
818
static bool is_sufficient_code_size(const m680x_info *info, uint16_t address,
819
            insn_desc *insn_description)
820
229k
{
821
229k
  int i;
822
229k
  bool retval = true;
823
229k
  uint16_t size = 0;
824
229k
  int sz;
825
826
663k
  for (i = 0; i < 2; i++) {
827
446k
    uint8_t ir = 0;
828
446k
    bool is_subset = false;
829
830
446k
    switch (insn_description->hid[i]) {
831
848
    case imm32_hid:
832
848
      if ((retval = read_byte(info, &ir, address + size + 3)))
833
826
        size += 4;
834
848
      break;
835
836
26.8k
    case ext_hid:
837
29.4k
    case imm16_hid:
838
30.8k
    case rel16_hid:
839
32.3k
    case imm8rel_hid:
840
36.2k
    case opidxdr_hid:
841
38.0k
    case idxX16_hid:
842
38.4k
    case idxS16_hid:
843
38.4k
      if ((retval = read_byte(info, &ir, address + size + 1)))
844
38.1k
        size += 2;
845
38.4k
      break;
846
847
16.4k
    case rel8_hid:
848
50.5k
    case dir_hid:
849
53.1k
    case rbits_hid:
850
68.2k
    case imm8_hid:
851
72.6k
    case idxX_hid:
852
73.1k
    case idxXp_hid:
853
73.7k
    case idxY_hid:
854
74.1k
    case idxS_hid:
855
74.6k
    case index_hid:
856
74.6k
      if ((retval = read_byte(info, &ir, address + size)))
857
74.3k
        size++;
858
74.6k
      break;
859
860
0
    case illgl_hid:
861
263k
    case inh_hid:
862
269k
    case idxX0_hid:
863
270k
    case idxX0p_hid:
864
271k
    case opidx_hid:
865
271k
      retval = true;
866
271k
      break;
867
868
29.9k
    case idx09_hid:
869
29.9k
      sz = get_indexed09_post_byte_size(info, address + size);
870
29.9k
      if (sz >= 0)
871
22.3k
        size += sz;
872
7.63k
      else
873
7.63k
        retval = false;
874
29.9k
      break;
875
876
805
    case idx12s_hid:
877
805
      is_subset = true;
878
879
      // intentionally fall through
880
881
16.6k
    case idx12_hid:
882
16.6k
      sz = get_indexed12_post_byte_size(info, address + size,
883
16.6k
                is_subset);
884
16.6k
      if (sz >= 0)
885
15.9k
        size += sz;
886
703
      else
887
703
        retval = false;
888
16.6k
      break;
889
890
990
    case exti12x_hid:
891
3.55k
    case imm16i12x_hid:
892
3.55k
      sz = get_indexed12_post_byte_size(info, address + size,
893
3.55k
                false);
894
3.55k
      if (sz >= 0) {
895
3.54k
        size += sz;
896
3.54k
        if ((retval = read_byte(info, &ir,
897
3.54k
              address + size + 1)))
898
3.52k
          size += 2;
899
3.54k
      } else
900
6
        retval = false;
901
3.55k
      break;
902
903
2.65k
    case imm8i12x_hid:
904
2.65k
      sz = get_indexed12_post_byte_size(info, address + size,
905
2.65k
                false);
906
2.65k
      if (sz >= 0) {
907
2.64k
        size += sz;
908
2.64k
        if ((retval = read_byte(info, &ir,
909
2.64k
              address + size)))
910
2.64k
          size++;
911
2.64k
      } else
912
9
        retval = false;
913
2.65k
      break;
914
915
1.83k
    case tfm_hid:
916
1.83k
      if ((retval = read_byte(info, &ir, address + size))) {
917
1.83k
        size++;
918
1.83k
        retval = is_tfm_reg_valid(info,
919
1.83k
                (ir >> 4) & 0x0F) &&
920
833
           is_tfm_reg_valid(info, ir & 0x0F);
921
1.83k
      }
922
1.83k
      break;
923
924
2.32k
    case rr09_hid:
925
2.32k
      if ((retval = read_byte(info, &ir, address + size))) {
926
2.31k
        size++;
927
2.31k
        retval = is_tfr09_reg_valid(info,
928
2.31k
                  (ir >> 4) & 0x0F) &&
929
2.05k
           is_tfr09_reg_valid(info, ir & 0x0F);
930
2.31k
      }
931
2.32k
      break;
932
933
1.22k
    case rr12_hid:
934
1.22k
      if ((retval = read_byte(info, &ir, address + size))) {
935
1.22k
        size++;
936
1.22k
        retval = is_exg_tfr12_post_byte_valid(info, ir);
937
1.22k
      }
938
1.22k
      break;
939
940
376
    case bitmv_hid:
941
376
      sz = get_bitmv_post_byte_size(info, address + size);
942
376
      if (sz >= 0)
943
162
        size += sz;
944
214
      else
945
214
        retval = false;
946
376
      break;
947
948
2.26k
    case loop_hid:
949
2.26k
      sz = get_loop_post_byte_size(info, address + size);
950
2.26k
      if (sz >= 0)
951
1.49k
        size += sz;
952
769
      else
953
769
        retval = false;
954
2.26k
      break;
955
956
0
    default:
957
0
      CS_ASSERT(0 && "Unexpected instruction handler id");
958
0
      retval = false;
959
0
      break;
960
446k
    }
961
962
446k
    if (!retval)
963
12.1k
      return false;
964
446k
  }
965
966
217k
  insn_description->insn_size += size;
967
968
217k
  return retval;
969
229k
}
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
247k
{
976
247k
  const inst_pageX *inst_table = NULL;
977
247k
  const cpu_tables *cpu = info->cpu;
978
247k
  size_t table_size = 0;
979
247k
  uint16_t base_address = address;
980
247k
  uint8_t ir; // instruction register
981
247k
  int i;
982
247k
  int index;
983
984
247k
  if (!read_byte(info, &ir, address++))
985
0
    return false;
986
987
247k
  insn_description->insn = M680X_INS_ILLGL;
988
247k
  insn_description->opcode = ir;
989
990
  // Check if a page prefix byte is present
991
597k
  for (i = 0; i < ARR_SIZE(cpu->pageX_table_size); ++i) {
992
586k
    if (cpu->pageX_table_size[i] == 0 ||
993
372k
        (cpu->inst_pageX_table[i] == NULL))
994
213k
      break;
995
996
372k
    if ((cpu->pageX_prefix[i] == ir)) {
997
      // Get pageX instruction and handler id.
998
      // Abort for illegal instr.
999
22.5k
      inst_table = cpu->inst_pageX_table[i];
1000
22.5k
      table_size = cpu->pageX_table_size[i];
1001
1002
22.5k
      if (!read_byte(info, &ir, address++))
1003
20
        return false;
1004
1005
22.4k
      insn_description->opcode =
1006
22.4k
        (insn_description->opcode << 8) | ir;
1007
1008
22.4k
      if ((index = binary_search(inst_table, table_size,
1009
22.4k
               ir)) < 0)
1010
7.82k
        return false;
1011
1012
14.6k
      insn_description->hid[0] =
1013
14.6k
        inst_table[index].handler_id1;
1014
14.6k
      insn_description->hid[1] =
1015
14.6k
        inst_table[index].handler_id2;
1016
14.6k
      insn_description->insn = inst_table[index].insn;
1017
14.6k
      break;
1018
22.4k
    }
1019
372k
  }
1020
1021
239k
  if (insn_description->insn == M680X_INS_ILLGL) {
1022
    // Get page1 insn description
1023
224k
    insn_description->insn = cpu->inst_page1_table[ir].insn;
1024
224k
    insn_description->hid[0] =
1025
224k
      cpu->inst_page1_table[ir].handler_id1;
1026
224k
    insn_description->hid[1] =
1027
224k
      cpu->inst_page1_table[ir].handler_id2;
1028
224k
  }
1029
1030
239k
  if (insn_description->insn == M680X_INS_ILLGL) {
1031
    // Check if opcode byte is present in an overlay table
1032
31.0k
    for (i = 0; i < ARR_SIZE(cpu->overlay_table_size); ++i) {
1033
29.1k
      if (cpu->overlay_table_size[i] == 0 ||
1034
21.1k
          (cpu->inst_overlay_table[i] == NULL))
1035
7.95k
        break;
1036
1037
21.1k
      inst_table = cpu->inst_overlay_table[i];
1038
21.1k
      table_size = cpu->overlay_table_size[i];
1039
1040
21.1k
      if ((index = binary_search(inst_table, table_size,
1041
21.1k
               ir)) >= 0) {
1042
11.6k
        insn_description->hid[0] =
1043
11.6k
          inst_table[index].handler_id1;
1044
11.6k
        insn_description->hid[1] =
1045
11.6k
          inst_table[index].handler_id2;
1046
11.6k
        insn_description->insn = inst_table[index].insn;
1047
11.6k
        break;
1048
11.6k
      }
1049
21.1k
    }
1050
21.5k
  }
1051
1052
239k
  insn_description->insn_size = address - base_address;
1053
1054
239k
  return (insn_description->insn != M680X_INS_ILLGL) &&
1055
229k
         (insn_description->insn != M680X_INS_INVLD) &&
1056
229k
         is_sufficient_code_size(info, address, insn_description);
1057
247k
}
1058
1059
static void illegal_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1060
29.8k
{
1061
29.8k
  cs_m680x_op *op0 = &info->m680x.operands[info->m680x.op_count++];
1062
29.8k
  uint8_t temp8 = 0;
1063
1064
29.8k
  info->insn = M680X_INS_ILLGL;
1065
29.8k
  read_byte(info, &temp8, (*address)++);
1066
29.8k
  op0->imm = (int32_t)temp8 & 0xff;
1067
29.8k
  op0->type = M680X_OP_IMMEDIATE;
1068
29.8k
  op0->size = 1;
1069
29.8k
}
1070
1071
static void inherent_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1072
263k
{
1073
  // There is nothing to do here :-)
1074
263k
}
1075
1076
static void add_reg_operand(m680x_info *info, m680x_reg reg)
1077
136k
{
1078
136k
  cs_m680x *m680x = &info->m680x;
1079
136k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1080
1081
136k
  op->type = M680X_OP_REGISTER;
1082
136k
  op->reg = reg;
1083
136k
  op->size = info->cpu->reg_byte_size[reg];
1084
136k
}
1085
1086
static void set_operand_size(m680x_info *info, cs_m680x_op *op,
1087
           uint8_t default_size)
1088
151k
{
1089
151k
  cs_m680x *m680x = &info->m680x;
1090
1091
151k
  if (info->insn == M680X_INS_JMP || info->insn == M680X_INS_JSR)
1092
7.32k
    op->size = 0;
1093
144k
  else if (info->insn == M680X_INS_DIVD ||
1094
143k
     ((info->insn == M680X_INS_AIS ||
1095
142k
       info->insn == M680X_INS_AIX) &&
1096
510
      op->type != M680X_OP_REGISTER))
1097
1.43k
    op->size = 1;
1098
142k
  else if (info->insn == M680X_INS_DIVQ || info->insn == M680X_INS_MOVW)
1099
6.74k
    op->size = 2;
1100
135k
  else if (info->insn == M680X_INS_EMACS)
1101
108
    op->size = 4;
1102
135k
  else if ((m680x->op_count > 0) &&
1103
135k
     (m680x->operands[0].type == M680X_OP_REGISTER))
1104
83.1k
    op->size = m680x->operands[0].size;
1105
52.7k
  else
1106
52.7k
    op->size = default_size;
1107
151k
}
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
2.56k
{
1121
2.56k
  cs_m680x_op *op0 = &info->m680x.operands[0];
1122
2.56k
  uint8_t reg_bits = 0;
1123
2.56k
  uint16_t bit_index;
1124
2.56k
  const m680x_reg *reg_to_reg_ids = NULL;
1125
1126
2.56k
  read_byte(info, &reg_bits, (*address)++);
1127
1128
2.56k
  switch (op0->reg) {
1129
1.30k
  case M680X_REG_U:
1130
1.30k
    reg_to_reg_ids = &reg_u_reg_ids[0];
1131
1.30k
    break;
1132
1133
1.26k
  case M680X_REG_S:
1134
1.26k
    reg_to_reg_ids = &reg_s_reg_ids[0];
1135
1.26k
    break;
1136
1137
0
  default:
1138
0
    CS_ASSERT(0 && "Unexpected operand0 register");
1139
0
    break;
1140
2.56k
  }
1141
1142
2.56k
  if ((info->insn == M680X_INS_PULU || (info->insn == M680X_INS_PULS)) &&
1143
1.56k
      ((reg_bits & 0x80) != 0))
1144
    // PULS xxx,PC or PULU xxx,PC which is like return from
1145
    // subroutine (RTS)
1146
226
    add_insn_group(MI->flat_insn->detail, M680X_GRP_RET);
1147
1148
23.1k
  for (bit_index = 0; bit_index < 8; ++bit_index) {
1149
20.5k
    if (reg_bits & (1 << bit_index) && reg_to_reg_ids)
1150
10.5k
      add_reg_operand(info, reg_to_reg_ids[bit_index]);
1151
20.5k
  }
1152
2.56k
}
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.33k
{
1177
1.33k
  uint8_t regs = 0;
1178
1179
1.33k
  read_byte(info, &regs, (*address)++);
1180
1181
1.33k
  add_reg_operand(info, g_tfr_exg_reg_ids[regs >> 4]);
1182
1.33k
  add_reg_operand(info, g_tfr_exg_reg_ids[regs & 0x0f]);
1183
1184
1.33k
  if ((regs & 0x0f) == 0x05) {
1185
    // EXG xxx,PC or TFR xxx,PC which is like a JMP
1186
267
    add_insn_group(MI->flat_insn->detail, M680X_GRP_JUMP);
1187
267
  }
1188
1.33k
}
1189
1190
static void reg_reg12_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1191
1.10k
{
1192
1.10k
  static const m680x_reg g_tfr_exg12_reg0_ids[] = {
1193
1.10k
    M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP3,
1194
1.10k
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,  M680X_REG_S,
1195
1.10k
  };
1196
1.10k
  static const m680x_reg g_tfr_exg12_reg1_ids[] = {
1197
1.10k
    M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP2,
1198
1.10k
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,  M680X_REG_S,
1199
1.10k
  };
1200
1.10k
  uint8_t regs = 0;
1201
1202
1.10k
  read_byte(info, &regs, (*address)++);
1203
1204
  // The opcode of this instruction depends on
1205
  // the msb of its post byte.
1206
1.10k
  if (regs & 0x80)
1207
722
    info->insn = M680X_INS_EXG;
1208
386
  else
1209
386
    info->insn = M680X_INS_TFR;
1210
1211
1.10k
  add_reg_operand(info, g_tfr_exg12_reg0_ids[(regs >> 4) & 0x07]);
1212
1.10k
  add_reg_operand(info, g_tfr_exg12_reg1_ids[regs & 0x07]);
1213
1.10k
}
1214
1215
static void add_rel_operand(m680x_info *info, int16_t offset, uint16_t address)
1216
23.0k
{
1217
23.0k
  cs_m680x *m680x = &info->m680x;
1218
23.0k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1219
1220
23.0k
  op->type = M680X_OP_RELATIVE;
1221
23.0k
  op->size = 0;
1222
23.0k
  op->rel.offset = offset;
1223
23.0k
  op->rel.address = address;
1224
23.0k
}
1225
1226
static void relative8_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1227
21.6k
{
1228
21.6k
  int16_t offset = 0;
1229
1230
21.6k
  read_byte_sign_extended(info, &offset, (*address)++);
1231
21.6k
  add_rel_operand(info, offset, *address + offset);
1232
21.6k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1233
1234
21.6k
  if ((info->insn != M680X_INS_BRA) && (info->insn != M680X_INS_BSR) &&
1235
19.3k
      (info->insn != M680X_INS_BRN))
1236
18.3k
    add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1237
21.6k
}
1238
1239
static void relative16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1240
1.42k
{
1241
1.42k
  uint16_t offset = 0;
1242
1243
1.42k
  read_word(info, &offset, *address);
1244
1.42k
  *address += 2;
1245
1.42k
  add_rel_operand(info, (int16_t)offset, *address + offset);
1246
1.42k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1247
1248
1.42k
  if ((info->insn != M680X_INS_LBRA) && (info->insn != M680X_INS_LBSR) &&
1249
460
      (info->insn != M680X_INS_LBRN))
1250
367
    add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1251
1.42k
}
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
16.4k
{
1265
16.4k
  cs_m680x *m680x = &info->m680x;
1266
16.4k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1267
1268
16.4k
  op->type = M680X_OP_INDEXED;
1269
16.4k
  set_operand_size(info, op, 1);
1270
16.4k
  op->idx.base_reg = base_reg;
1271
16.4k
  op->idx.offset_reg = M680X_REG_INVALID;
1272
16.4k
  op->idx.inc_dec = inc_dec;
1273
1274
16.4k
  if (inc_dec && post_inc_dec)
1275
2.17k
    op->idx.flags |= M680X_IDX_POST_INC_DEC;
1276
1277
16.4k
  if (offset_bits != M680X_OFFSET_NONE) {
1278
8.00k
    op->idx.offset = offset;
1279
8.00k
    op->idx.offset_addr = 0;
1280
8.00k
  }
1281
1282
16.4k
  op->idx.offset_bits = offset_bits;
1283
16.4k
  op->idx.flags |= (no_comma ? M680X_IDX_NO_COMMA : 0);
1284
16.4k
}
1285
1286
// M6800/1/2/3 indexed mode handler
1287
static void indexedX_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1288
4.29k
{
1289
4.29k
  uint8_t offset = 0;
1290
1291
4.29k
  read_byte(info, &offset, (*address)++);
1292
1293
4.29k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_8,
1294
4.29k
          (uint16_t)offset, false);
1295
4.29k
}
1296
1297
static void indexedY_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1298
670
{
1299
670
  uint8_t offset = 0;
1300
1301
670
  read_byte(info, &offset, (*address)++);
1302
1303
670
  add_indexed_operand(info, M680X_REG_Y, false, 0, M680X_OFFSET_BITS_8,
1304
670
          (uint16_t)offset, false);
1305
670
}
1306
1307
// M6809/M6309 indexed mode handler
1308
static void indexed09_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1309
22.3k
{
1310
22.3k
  cs_m680x *m680x = &info->m680x;
1311
22.3k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1312
22.3k
  uint8_t post_byte = 0;
1313
22.3k
  uint16_t offset = 0;
1314
22.3k
  int16_t soffset = 0;
1315
1316
22.3k
  read_byte(info, &post_byte, (*address)++);
1317
1318
22.3k
  op->type = M680X_OP_INDEXED;
1319
22.3k
  set_operand_size(info, op, 1);
1320
22.3k
  op->idx.base_reg = g_rr5_to_reg_ids[(post_byte >> 5) & 0x03];
1321
22.3k
  op->idx.offset_reg = M680X_REG_INVALID;
1322
1323
22.3k
  if (!(post_byte & 0x80)) {
1324
    // n5,R
1325
10.5k
    if ((post_byte & 0x10) == 0x10)
1326
5.30k
      op->idx.offset = post_byte | 0xfff0;
1327
5.26k
    else
1328
5.26k
      op->idx.offset = post_byte & 0x0f;
1329
1330
10.5k
    op->idx.offset_addr = op->idx.offset + *address;
1331
10.5k
    op->idx.offset_bits = M680X_OFFSET_BITS_5;
1332
11.7k
  } else {
1333
11.7k
    if ((post_byte & 0x10) == 0x10)
1334
4.05k
      op->idx.flags |= M680X_IDX_INDIRECT;
1335
1336
    // indexed addressing
1337
11.7k
    switch (post_byte & 0x1f) {
1338
867
    case 0x00: // ,R+
1339
867
      op->idx.inc_dec = 1;
1340
867
      op->idx.flags |= M680X_IDX_POST_INC_DEC;
1341
867
      break;
1342
1343
433
    case 0x11: // [,R++]
1344
1.65k
    case 0x01: // ,R++
1345
1.65k
      op->idx.inc_dec = 2;
1346
1.65k
      op->idx.flags |= M680X_IDX_POST_INC_DEC;
1347
1.65k
      break;
1348
1349
783
    case 0x02: // ,-R
1350
783
      op->idx.inc_dec = -1;
1351
783
      break;
1352
1353
534
    case 0x13: // [,--R]
1354
883
    case 0x03: // ,--R
1355
883
      op->idx.inc_dec = -2;
1356
883
      break;
1357
1358
327
    case 0x14: // [,R]
1359
702
    case 0x04: // ,R
1360
702
      break;
1361
1362
353
    case 0x15: // [B,R]
1363
970
    case 0x05: // B,R
1364
970
      op->idx.offset_reg = M680X_REG_B;
1365
970
      break;
1366
1367
151
    case 0x16: // [A,R]
1368
517
    case 0x06: // A,R
1369
517
      op->idx.offset_reg = M680X_REG_A;
1370
517
      break;
1371
1372
460
    case 0x1c: // [n8,PCR]
1373
1.20k
    case 0x0c: // n8,PCR
1374
1.20k
      op->idx.base_reg = M680X_REG_PC;
1375
1.20k
      read_byte_sign_extended(info, &soffset, (*address)++);
1376
1.20k
      op->idx.offset_addr = offset + *address;
1377
1.20k
      op->idx.offset = soffset;
1378
1.20k
      op->idx.offset_bits = M680X_OFFSET_BITS_8;
1379
1.20k
      break;
1380
1381
303
    case 0x18: // [n8,R]
1382
1.32k
    case 0x08: // n8,R
1383
1.32k
      read_byte_sign_extended(info, &soffset, (*address)++);
1384
1.32k
      op->idx.offset = soffset;
1385
1.32k
      op->idx.offset_bits = M680X_OFFSET_BITS_8;
1386
1.32k
      break;
1387
1388
425
    case 0x1d: // [n16,PCR]
1389
1.00k
    case 0x0d: // n16,PCR
1390
1.00k
      op->idx.base_reg = M680X_REG_PC;
1391
1.00k
      read_word(info, &offset, *address);
1392
1.00k
      *address += 2;
1393
1.00k
      op->idx.offset_addr = offset + *address;
1394
1.00k
      op->idx.offset = (int16_t)offset;
1395
1.00k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1396
1.00k
      break;
1397
1398
374
    case 0x19: // [n16,R]
1399
820
    case 0x09: // n16,R
1400
820
      read_word(info, &offset, *address);
1401
820
      *address += 2;
1402
820
      op->idx.offset = (int16_t)offset;
1403
820
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1404
820
      break;
1405
1406
322
    case 0x1b: // [D,R]
1407
643
    case 0x0b: // D,R
1408
643
      op->idx.offset_reg = M680X_REG_D;
1409
643
      break;
1410
1411
377
    case 0x1f: // [n16]
1412
377
      op->type = M680X_OP_EXTENDED;
1413
377
      op->ext.indirect = true;
1414
377
      read_word(info, &op->ext.address, *address);
1415
377
      *address += 2;
1416
377
      break;
1417
1418
0
    default:
1419
0
      op->idx.base_reg = M680X_REG_INVALID;
1420
0
      break;
1421
11.7k
    }
1422
11.7k
  }
1423
1424
22.3k
  if (((info->insn == M680X_INS_LEAU) || (info->insn == M680X_INS_LEAS) ||
1425
21.0k
       (info->insn == M680X_INS_LEAX) ||
1426
19.9k
       (info->insn == M680X_INS_LEAY)) &&
1427
3.07k
      (m680x->operands[0].reg == M680X_REG_X ||
1428
1.97k
       (m680x->operands[0].reg == M680X_REG_Y)))
1429
    // Only LEAX and LEAY modify CC register
1430
1.81k
    add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1431
22.3k
}
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.1k
{
1446
22.1k
  cs_m680x *m680x = &info->m680x;
1447
22.1k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1448
22.1k
  uint8_t post_byte = 0;
1449
22.1k
  uint8_t offset8 = 0;
1450
1451
22.1k
  read_byte(info, &post_byte, (*address)++);
1452
1453
22.1k
  op->type = M680X_OP_INDEXED;
1454
22.1k
  set_operand_size(info, op, 1);
1455
22.1k
  op->idx.offset_reg = M680X_REG_INVALID;
1456
1457
22.1k
  if (!(post_byte & 0x20)) {
1458
    // n5,R      n5 is a 5-bit signed offset
1459
8.11k
    op->idx.base_reg = g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1460
1461
8.11k
    if ((post_byte & 0x10) == 0x10)
1462
3.24k
      op->idx.offset = post_byte | 0xfff0;
1463
4.86k
    else
1464
4.86k
      op->idx.offset = post_byte & 0x0f;
1465
1466
8.11k
    op->idx.offset_addr = op->idx.offset + *address;
1467
8.11k
    op->idx.offset_bits = M680X_OFFSET_BITS_5;
1468
14.0k
  } else {
1469
14.0k
    if ((post_byte & 0xe0) == 0xe0)
1470
8.16k
      op->idx.base_reg =
1471
8.16k
        g_idx12_to_reg_ids[(post_byte >> 3) & 0x03];
1472
1473
14.0k
    switch (post_byte & 0xe7) {
1474
2.27k
    case 0xe0:
1475
3.37k
    case 0xe1: // n9,R
1476
3.37k
      read_byte(info, &offset8, (*address)++);
1477
3.37k
      op->idx.offset = offset8;
1478
1479
3.37k
      if (post_byte & 0x01) // sign extension
1480
1.10k
        op->idx.offset |= 0xff00;
1481
1482
3.37k
      op->idx.offset_bits = M680X_OFFSET_BITS_9;
1483
1484
3.37k
      if (op->idx.base_reg == M680X_REG_PC)
1485
874
        op->idx.offset_addr = op->idx.offset + *address;
1486
1487
3.37k
      break;
1488
1489
1.24k
    case 0xe3: // [n16,R]
1490
1.24k
      op->idx.flags |= M680X_IDX_INDIRECT;
1491
1492
    // intentionally fall through
1493
2.48k
    case 0xe2: // n16,R
1494
2.48k
      read_word(info, (uint16_t *)&op->idx.offset, *address);
1495
2.48k
      (*address) += 2;
1496
2.48k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1497
1498
2.48k
      if (op->idx.base_reg == M680X_REG_PC)
1499
334
        op->idx.offset_addr = op->idx.offset + *address;
1500
1501
2.48k
      break;
1502
1503
403
    case 0xe4: // A,R
1504
838
    case 0xe5: // B,R
1505
1.30k
    case 0xe6: // D,R
1506
1.30k
      op->idx.offset_reg =
1507
1.30k
        g_or12_to_reg_ids[post_byte & 0x03];
1508
1.30k
      break;
1509
1510
1.01k
    case 0xe7: // [D,R]
1511
1.01k
      op->idx.offset_reg = M680X_REG_D;
1512
1.01k
      op->idx.flags |= M680X_IDX_INDIRECT;
1513
1.01k
      break;
1514
1515
5.86k
    default: // n,-r n,+r n,r- n,r+
1516
      // PC is not allowed in this mode
1517
5.86k
      op->idx.base_reg =
1518
5.86k
        g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1519
5.86k
      op->idx.inc_dec = post_byte & 0x0f;
1520
1521
5.86k
      if (op->idx.inc_dec & 0x08) // evtl. sign extend value
1522
2.50k
        op->idx.inc_dec |= 0xf0;
1523
1524
5.86k
      if (op->idx.inc_dec >= 0)
1525
3.36k
        op->idx.inc_dec++;
1526
1527
5.86k
      if (post_byte & 0x10)
1528
2.22k
        op->idx.flags |= M680X_IDX_POST_INC_DEC;
1529
1530
5.86k
      break;
1531
14.0k
    }
1532
14.0k
  }
1533
22.1k
}
1534
1535
static void index_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1536
522
{
1537
522
  cs_m680x *m680x = &info->m680x;
1538
522
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1539
1540
522
  op->type = M680X_OP_CONSTANT;
1541
522
  read_byte(info, &op->const_val, (*address)++);
1542
522
};
1543
1544
static void direct_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1545
38.0k
{
1546
38.0k
  cs_m680x *m680x = &info->m680x;
1547
38.0k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1548
1549
38.0k
  op->type = M680X_OP_DIRECT;
1550
38.0k
  set_operand_size(info, op, 1);
1551
38.0k
  read_byte(info, &op->direct_addr, (*address)++);
1552
38.0k
};
1553
1554
static void extended_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1555
26.6k
{
1556
26.6k
  cs_m680x *m680x = &info->m680x;
1557
26.6k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1558
1559
26.6k
  op->type = M680X_OP_EXTENDED;
1560
26.6k
  set_operand_size(info, op, 1);
1561
26.6k
  read_word(info, &op->ext.address, *address);
1562
26.6k
  *address += 2;
1563
26.6k
}
1564
1565
static void immediate_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1566
19.6k
{
1567
19.6k
  cs_m680x *m680x = &info->m680x;
1568
19.6k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1569
19.6k
  uint16_t word = 0;
1570
19.6k
  int16_t sword = 0;
1571
1572
19.6k
  op->type = M680X_OP_IMMEDIATE;
1573
19.6k
  set_operand_size(info, op, 1);
1574
1575
19.6k
  switch (op->size) {
1576
16.3k
  case 1:
1577
16.3k
    read_byte_sign_extended(info, &sword, *address);
1578
16.3k
    op->imm = sword;
1579
16.3k
    break;
1580
1581
2.55k
  case 2:
1582
2.55k
    read_word(info, &word, *address);
1583
2.55k
    op->imm = (int16_t)word;
1584
2.55k
    break;
1585
1586
826
  case 4:
1587
826
    read_sdword(info, &op->imm, *address);
1588
826
    break;
1589
1590
0
  default:
1591
0
    op->imm = 0;
1592
0
    CS_ASSERT(0 && "Unexpected immediate byte size");
1593
19.6k
  }
1594
1595
19.6k
  *address += op->size;
1596
19.6k
}
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
162
{
1601
162
  static const m680x_reg m680x_reg[] = {
1602
162
    M680X_REG_CC,
1603
162
    M680X_REG_A,
1604
162
    M680X_REG_B,
1605
162
    M680X_REG_INVALID,
1606
162
  };
1607
1608
162
  uint8_t post_byte = 0;
1609
162
  cs_m680x *m680x = &info->m680x;
1610
162
  cs_m680x_op *op;
1611
1612
162
  read_byte(info, &post_byte, *address);
1613
162
  (*address)++;
1614
1615
  // operand[0] = register
1616
162
  add_reg_operand(info, m680x_reg[post_byte >> 6]);
1617
1618
  // operand[1] = bit index in source operand
1619
162
  op = &m680x->operands[m680x->op_count++];
1620
162
  op->type = M680X_OP_CONSTANT;
1621
162
  op->const_val = (post_byte >> 3) & 0x07;
1622
1623
  // operand[2] = bit index in destination operand
1624
162
  op = &m680x->operands[m680x->op_count++];
1625
162
  op->type = M680X_OP_CONSTANT;
1626
162
  op->const_val = post_byte & 0x07;
1627
1628
162
  direct_hdlr(MI, info, address);
1629
162
}
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
774
{
1634
774
  static const uint8_t inc_dec_r0[] = {
1635
774
    1,
1636
774
    -1,
1637
774
    1,
1638
774
    0,
1639
774
  };
1640
774
  static const uint8_t inc_dec_r1[] = {
1641
774
    1,
1642
774
    -1,
1643
774
    0,
1644
774
    1,
1645
774
  };
1646
774
  uint8_t regs = 0;
1647
774
  uint8_t index = (MI->Opcode & 0xff) - 0x38;
1648
1649
774
  read_byte(info, &regs, *address);
1650
1651
774
  add_indexed_operand(info, g_tfr_exg_reg_ids[regs >> 4], true,
1652
774
          inc_dec_r0[index], M680X_OFFSET_NONE, 0, true);
1653
774
  add_indexed_operand(info, g_tfr_exg_reg_ids[regs & 0x0f], true,
1654
774
          inc_dec_r1[index], M680X_OFFSET_NONE, 0, true);
1655
1656
774
  add_reg_to_rw_list(MI, M680X_REG_W, READ | WRITE);
1657
774
}
1658
1659
static void opidx_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1660
1.44k
{
1661
1.44k
  cs_m680x *m680x = &info->m680x;
1662
1.44k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1663
1664
  // bit index is coded in Opcode
1665
1.44k
  op->type = M680X_OP_CONSTANT;
1666
1.44k
  op->const_val = (MI->Opcode & 0x0e) >> 1;
1667
1.44k
}
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
3.82k
{
1674
3.82k
  cs_m680x *m680x = &info->m680x;
1675
3.82k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1676
1677
  // bit index is coded in Opcode
1678
3.82k
  op->type = M680X_OP_CONSTANT;
1679
3.82k
  op->const_val = (MI->Opcode & 0x0e) >> 1;
1680
3.82k
  direct_hdlr(MI, info, address);
1681
3.82k
  relative8_hdlr(MI, info, address);
1682
1683
3.82k
  add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1684
3.82k
}
1685
1686
static void indexedX0_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1687
6.01k
{
1688
6.01k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_NONE, 0,
1689
6.01k
          false);
1690
6.01k
}
1691
1692
static void indexedX16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1693
1.76k
{
1694
1.76k
  uint16_t offset = 0;
1695
1696
1.76k
  read_word(info, &offset, *address);
1697
1.76k
  *address += 2;
1698
1.76k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_16,
1699
1.76k
          offset, false);
1700
1.76k
}
1701
1702
static void imm_rel_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1703
1.44k
{
1704
1.44k
  immediate_hdlr(MI, info, address);
1705
1.44k
  relative8_hdlr(MI, info, address);
1706
1.44k
}
1707
1708
static void indexedS_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1709
330
{
1710
330
  uint8_t offset = 0;
1711
1712
330
  read_byte(info, &offset, (*address)++);
1713
1714
330
  add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_8,
1715
330
          (uint16_t)offset, false);
1716
330
}
1717
1718
static void indexedS16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1719
466
{
1720
466
  uint16_t offset = 0;
1721
1722
466
  read_word(info, &offset, *address);
1723
466
  *address += 2;
1724
1725
466
  add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_16,
1726
466
          offset, false);
1727
466
}
1728
1729
static void indexedX0p_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1730
891
{
1731
891
  add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_NONE, 0,
1732
891
          true);
1733
891
}
1734
1735
static void indexedXp_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1736
483
{
1737
483
  uint8_t offset = 0;
1738
1739
483
  read_byte(info, &offset, (*address)++);
1740
1741
483
  add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_BITS_8,
1742
483
          (uint16_t)offset, false);
1743
483
}
1744
1745
static void imm_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1746
5.18k
{
1747
5.18k
  cs_m680x *m680x = &info->m680x;
1748
5.18k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1749
1750
5.18k
  indexed12_hdlr(MI, info, address);
1751
5.18k
  op->type = M680X_OP_IMMEDIATE;
1752
1753
5.18k
  if (info->insn == M680X_INS_MOVW) {
1754
2.54k
    uint16_t imm16 = 0;
1755
1756
2.54k
    read_word(info, &imm16, *address);
1757
2.54k
    op->imm = (int16_t)imm16;
1758
2.54k
    op->size = 2;
1759
2.64k
  } else {
1760
2.64k
    uint8_t imm8 = 0;
1761
1762
2.64k
    read_byte(info, &imm8, *address);
1763
2.64k
    op->imm = (int8_t)imm8;
1764
2.64k
    op->size = 1;
1765
2.64k
  }
1766
1767
5.18k
  set_operand_size(info, op, 1);
1768
5.18k
}
1769
1770
static void ext_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1771
983
{
1772
983
  cs_m680x *m680x = &info->m680x;
1773
983
  cs_m680x_op *op0 = &m680x->operands[m680x->op_count++];
1774
983
  uint16_t imm16 = 0;
1775
1776
983
  indexed12_hdlr(MI, info, address);
1777
983
  read_word(info, &imm16, *address);
1778
983
  op0->type = M680X_OP_EXTENDED;
1779
983
  op0->ext.address = (int16_t)imm16;
1780
983
  set_operand_size(info, op0, 1);
1781
983
}
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.49k
{
1787
1.49k
  static const m680x_reg index_to_reg_id[] = {
1788
1.49k
    M680X_REG_A, M680X_REG_B, M680X_REG_INVALID, M680X_REG_INVALID,
1789
1.49k
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,       M680X_REG_S,
1790
1.49k
  };
1791
1.49k
  static const m680x_insn index_to_insn_id[] = {
1792
1.49k
    M680X_INS_DBEQ, M680X_INS_DBNE, M680X_INS_TBEQ,  M680X_INS_TBNE,
1793
1.49k
    M680X_INS_IBEQ, M680X_INS_IBNE, M680X_INS_ILLGL, M680X_INS_ILLGL
1794
1.49k
  };
1795
1.49k
  cs_m680x *m680x = &info->m680x;
1796
1.49k
  uint8_t post_byte = 0;
1797
1.49k
  uint8_t rel = 0;
1798
1.49k
  cs_m680x_op *op;
1799
1800
1.49k
  read_byte(info, &post_byte, (*address)++);
1801
1802
1.49k
  info->insn = index_to_insn_id[(post_byte >> 5) & 0x07];
1803
1804
1.49k
  if (info->insn == M680X_INS_ILLGL) {
1805
0
    illegal_hdlr(MI, info, address);
1806
0
  };
1807
1808
1.49k
  read_byte(info, &rel, (*address)++);
1809
1810
1.49k
  add_reg_operand(info, index_to_reg_id[post_byte & 0x07]);
1811
1812
1.49k
  op = &m680x->operands[m680x->op_count++];
1813
1814
1.49k
  op->type = M680X_OP_RELATIVE;
1815
1816
1.49k
  op->rel.offset = (post_byte & 0x10) ? (int16_t)(0xff00 | rel) : rel;
1817
1818
1.49k
  op->rel.address = *address + op->rel.offset;
1819
1820
1.49k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1821
1.49k
}
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
247k
{
1842
247k
  cs_m680x *m680x = &info->m680x;
1843
247k
  cs_detail *detail = MI->flat_insn->detail;
1844
247k
  uint16_t base_address = address;
1845
247k
  insn_desc insn_description;
1846
247k
  e_access_mode access_mode;
1847
1848
247k
  if (detail != NULL) {
1849
247k
    memset(detail, 0,
1850
247k
           offsetof(cs_detail, m680x) + sizeof(cs_m680x));
1851
247k
  }
1852
1853
247k
  memset(&insn_description, 0, sizeof(insn_description));
1854
247k
  memset(m680x, 0, sizeof(*m680x));
1855
247k
  info->insn_size = 1;
1856
1857
247k
  if (decode_insn(info, address, &insn_description)) {
1858
217k
    m680x_reg reg;
1859
1860
217k
    if (insn_description.opcode > 0xff)
1861
12.6k
      address += 2; // 8-bit opcode + page prefix
1862
204k
    else
1863
204k
      address++; // 8-bit opcode only
1864
1865
217k
    info->insn = insn_description.insn;
1866
1867
217k
    MCInst_setOpcode(MI, insn_description.opcode);
1868
1869
217k
    reg = g_insn_props[info->insn].reg0;
1870
1871
217k
    if (reg != M680X_REG_INVALID) {
1872
115k
      if (reg == M680X_REG_HX &&
1873
1.04k
          (!info->cpu->reg_byte_size[reg]))
1874
280
        reg = M680X_REG_X;
1875
1876
115k
      add_reg_operand(info, reg);
1877
      // First (or second) operand is a register which is
1878
      // part of the mnemonic
1879
115k
      m680x->flags |= M680X_FIRST_OP_IN_MNEM;
1880
115k
      reg = g_insn_props[info->insn].reg1;
1881
1882
115k
      if (reg != M680X_REG_INVALID) {
1883
3.71k
        if (reg == M680X_REG_HX &&
1884
466
            (!info->cpu->reg_byte_size[reg]))
1885
252
          reg = M680X_REG_X;
1886
1887
3.71k
        add_reg_operand(info, reg);
1888
3.71k
        m680x->flags |= M680X_SECOND_OP_IN_MNEM;
1889
3.71k
      }
1890
115k
    }
1891
1892
    // Call addressing mode specific instruction handler
1893
217k
    (g_insn_handler[insn_description.hid[0]])(MI, info, &address);
1894
217k
    (g_insn_handler[insn_description.hid[1]])(MI, info, &address);
1895
1896
217k
    add_insn_group(detail, g_insn_props[info->insn].group);
1897
1898
217k
    if (g_insn_props[info->insn].cc_modified &&
1899
140k
        (info->cpu->insn_cc_not_modified[0] != info->insn) &&
1900
139k
        (info->cpu->insn_cc_not_modified[1] != info->insn))
1901
138k
      add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1902
1903
217k
    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
217k
    if ((info->cpu->insn_cc_not_modified[0] == info->insn) ||
1908
216k
        (info->cpu->insn_cc_not_modified[1] == info->insn))
1909
1.44k
      access_mode = rmmm;
1910
1911
217k
    build_regs_read_write_counts(MI, info, access_mode);
1912
217k
    add_operators_access(MI, info, access_mode);
1913
1914
217k
    if (g_insn_props[info->insn].update_reg_access)
1915
19.8k
      set_changed_regs_read_write_counts(MI, info);
1916
1917
217k
    info->insn_size = (uint8_t)insn_description.insn_size;
1918
1919
217k
    return info->insn_size;
1920
217k
  } else
1921
29.8k
    MCInst_setOpcode(MI, insn_description.opcode);
1922
1923
  // Illegal instruction
1924
29.8k
  address = base_address;
1925
29.8k
  illegal_hdlr(MI, info, &address);
1926
29.8k
  return 1;
1927
247k
}
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
247k
{
2105
247k
  if (cpu_type == M680X_CPU_TYPE_INVALID) {
2106
0
    return false;
2107
0
  }
2108
2109
247k
  info->code = code;
2110
247k
  info->size = code_len;
2111
247k
  info->offset = address;
2112
247k
  info->cpu_type = cpu_type;
2113
2114
247k
  info->cpu = &g_cpu_tables[info->cpu_type];
2115
2116
247k
  return true;
2117
247k
}
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
247k
{
2123
247k
  unsigned int insn_size = 0;
2124
247k
  e_cpu_type cpu_type = M680X_CPU_TYPE_INVALID; // No default CPU type
2125
247k
  cs_struct *handle = (cs_struct *)ud;
2126
247k
  m680x_info *info = (m680x_info *)handle->printer_info;
2127
2128
247k
  MCInst_clear(MI);
2129
2130
247k
  if (handle->mode & CS_MODE_M680X_6800)
2131
830
    cpu_type = M680X_CPU_TYPE_6800;
2132
2133
246k
  else if (handle->mode & CS_MODE_M680X_6801)
2134
1.34k
    cpu_type = M680X_CPU_TYPE_6801;
2135
2136
244k
  else if (handle->mode & CS_MODE_M680X_6805)
2137
4.11k
    cpu_type = M680X_CPU_TYPE_6805;
2138
2139
240k
  else if (handle->mode & CS_MODE_M680X_6808)
2140
14.4k
    cpu_type = M680X_CPU_TYPE_6808;
2141
2142
226k
  else if (handle->mode & CS_MODE_M680X_HCS08)
2143
10.7k
    cpu_type = M680X_CPU_TYPE_HCS08;
2144
2145
215k
  else if (handle->mode & CS_MODE_M680X_6809)
2146
27.7k
    cpu_type = M680X_CPU_TYPE_6809;
2147
2148
187k
  else if (handle->mode & CS_MODE_M680X_6301)
2149
4.92k
    cpu_type = M680X_CPU_TYPE_6301;
2150
2151
182k
  else if (handle->mode & CS_MODE_M680X_6309)
2152
86.1k
    cpu_type = M680X_CPU_TYPE_6309;
2153
2154
96.7k
  else if (handle->mode & CS_MODE_M680X_6811)
2155
12.8k
    cpu_type = M680X_CPU_TYPE_6811;
2156
2157
83.8k
  else if (handle->mode & CS_MODE_M680X_CPU12)
2158
83.8k
    cpu_type = M680X_CPU_TYPE_CPU12;
2159
2160
247k
  if (cpu_type != M680X_CPU_TYPE_INVALID &&
2161
247k
      m680x_setup_internals(info, cpu_type, (uint16_t)address, code,
2162
247k
          (uint16_t)code_len))
2163
247k
    insn_size = m680x_disassemble(MI, info, (uint16_t)address);
2164
2165
247k
  if (insn_size == 0) {
2166
0
    *size = 1;
2167
0
    return false;
2168
0
  }
2169
2170
  // Make sure we always stay within range
2171
247k
  if (insn_size > code_len) {
2172
15
    *size = (uint16_t)code_len;
2173
15
    return false;
2174
15
  } else
2175
247k
    *size = (uint16_t)insn_size;
2176
2177
247k
  return true;
2178
247k
}
2179
2180
cs_err M680X_disassembler_init(cs_struct *ud)
2181
1.55k
{
2182
1.55k
  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.55k
  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.55k
  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.55k
  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.55k
  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.55k
  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.55k
  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.55k
  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.55k
  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.55k
  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.55k
  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.55k
  return CS_ERR_OK;
2250
1.55k
}
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