Coverage Report

Created: 2025-12-14 06:36

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