Coverage Report

Created: 2025-10-10 06:20

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