Coverage Report

Created: 2025-11-09 07:00

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