Coverage Report

Created: 2025-12-05 06:11

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