Coverage Report

Created: 2026-04-29 06:06

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
  srt_hid,
75
  tny_hid,
76
  dirdir_hid,
77
  immdir_hid,
78
  HANDLER_ID_ENDING,
79
} insn_hdlr_id;
80
81
// Access modes for the first 4 operands. If there are more than
82
// four operands they use the same access mode as the 4th operand.
83
//
84
// u: unchanged
85
// r: (r)read access
86
// w: (w)write access
87
// m: (m)odify access (= read + write)
88
//
89
typedef enum e_access_mode {
90
91
  uuuu,
92
  rrrr,
93
  wwww,
94
  rwww,
95
  rrrm,
96
  rmmm,
97
  wrrr,
98
  mrrr,
99
  mwww,
100
  mmmm,
101
  mwrr,
102
  mmrr,
103
  wmmm,
104
  rruu,
105
  muuu,
106
  ACCESS_MODE_ENDING,
107
} e_access_mode;
108
109
// Access type values are compatible with enum cs_ac_type:
110
typedef cs_ac_type e_access;
111
0
#define UNCHANGED CS_AC_INVALID
112
449k
#define READ CS_AC_READ
113
569k
#define WRITE CS_AC_WRITE
114
708k
#define MODIFY CS_AC_READ_WRITE
115
116
/* Properties of one instruction in PAGE1 (without prefix) */
117
typedef struct inst_page1 {
118
  unsigned insn : 9; // A value of type m680x_insn
119
  unsigned handler_id1 : 6; // Type insn_hdlr_id, first instr. handler id
120
  unsigned handler_id2 : 6; // Type insn_hdlr_id, second instr. handler id
121
} inst_page1;
122
123
/* Properties of one instruction in any other PAGE X */
124
typedef struct inst_pageX {
125
  unsigned opcode : 8; // The opcode byte
126
  unsigned insn : 9; // A value of type m680x_insn
127
  unsigned handler_id1 : 6; // Type insn_hdlr_id, first instr. handler id
128
  unsigned handler_id2 : 6; // Type insn_hdlr_id, second instr. handler id
129
} inst_pageX;
130
131
typedef struct insn_props {
132
  unsigned group : 4;
133
  unsigned access_mode : 5; // A value of type e_access_mode
134
  unsigned reg0 : 5; // A value of type m680x_reg
135
  unsigned reg1 : 5; // A value of type m680x_reg
136
  bool cc_modified : 1;
137
  bool update_reg_access : 1;
138
} insn_props;
139
140
#include "m6800.inc"
141
#include "m6801.inc"
142
#include "hd6301.inc"
143
#include "m6811.inc"
144
#include "cpu12.inc"
145
#include "m6805.inc"
146
#include "m6808.inc"
147
#include "hcs08.inc"
148
#include "m6809.inc"
149
#include "hd6309.inc"
150
#include "rs08.inc"
151
152
#include "insn_props.inc"
153
154
//////////////////////////////////////////////////////////////////////////////
155
156
// M680X instructions have 1 up to 8 bytes (CPU12: MOVW IDX2,IDX2).
157
// A reader is needed to read a byte or word from a given memory address.
158
// See also X86 reader(...)
159
static bool read_byte(const m680x_info *info, uint8_t *byte, uint16_t address)
160
1.07M
{
161
1.07M
  if (address < info->offset ||
162
1.07M
      (uint32_t)(address - info->offset) >= info->size)
163
    // out of code buffer range
164
1.89k
    return false;
165
166
1.07M
  *byte = info->code[address - info->offset];
167
168
1.07M
  return true;
169
1.07M
}
170
171
static bool read_byte_sign_extended(const m680x_info *info, int16_t *word,
172
            uint16_t address)
173
70.8k
{
174
70.8k
  if (address < info->offset ||
175
70.8k
      (uint32_t)(address - info->offset) >= info->size)
176
    // out of code buffer range
177
0
    return false;
178
179
70.8k
  *word = (int16_t)info->code[address - info->offset];
180
181
70.8k
  if (*word & 0x80)
182
28.7k
    *word |= 0xFF00;
183
184
70.8k
  return true;
185
70.8k
}
186
187
static bool read_word(const m680x_info *info, uint16_t *word, uint16_t address)
188
80.9k
{
189
80.9k
  if (address < info->offset ||
190
80.9k
      (uint32_t)(address + 1 - info->offset) >= info->size)
191
    // out of code buffer range
192
10
    return false;
193
194
80.9k
  *word = (uint16_t)info->code[address - info->offset] << 8;
195
80.9k
  *word |= (uint16_t)info->code[address + 1 - info->offset];
196
197
80.9k
  return true;
198
80.9k
}
199
200
static bool read_sdword(const m680x_info *info, int32_t *sdword,
201
      uint16_t address)
202
450
{
203
450
  if (address < info->offset ||
204
450
      (uint32_t)(address + 3 - info->offset) >= info->size)
205
    // out of code buffer range
206
0
    return false;
207
208
450
  *sdword = (uint32_t)info->code[address - info->offset] << 24;
209
450
  *sdword |= (uint32_t)info->code[address + 1 - info->offset] << 16;
210
450
  *sdword |= (uint32_t)info->code[address + 2 - info->offset] << 8;
211
450
  *sdword |= (uint32_t)info->code[address + 3 - info->offset];
212
213
450
  return true;
214
450
}
215
216
// For PAGE2 and PAGE3 opcodes when using an array of inst_page1 most
217
// entries have M680X_INS_ILLGL. To avoid wasting memory an inst_pageX is
218
// used which contains the opcode. Using a binary search for the right opcode
219
// is much faster (= O(log n) ) in comparison to a linear search ( = O(n) ).
220
static int binary_search(const inst_pageX *const inst_pageX_table,
221
       size_t table_size, unsigned int opcode)
222
149k
{
223
  // As part of the algorithm last may get negative.
224
  // => signed integer has to be used.
225
149k
  int first = 0;
226
149k
  int last = (int)table_size - 1;
227
149k
  int middle = (first + last) / 2;
228
229
755k
  while (first <= last) {
230
696k
    if (inst_pageX_table[middle].opcode < opcode) {
231
227k
      first = middle + 1;
232
468k
    } else if (inst_pageX_table[middle].opcode == opcode) {
233
91.4k
      return middle; /* item found */
234
91.4k
    } else
235
377k
      last = middle - 1;
236
237
605k
    middle = (first + last) / 2;
238
605k
  }
239
240
58.3k
  if (first > last)
241
58.3k
    return -1; /* item not found */
242
243
0
  return -2;
244
58.3k
}
245
246
void M680X_get_insn_id(cs_struct *handle, cs_insn *insn, unsigned int id)
247
452k
{
248
452k
  const m680x_info *const info = (const m680x_info *)handle->printer_info;
249
452k
  const cpu_tables *cpu = info->cpu;
250
452k
  uint8_t insn_prefix = (id >> 8) & 0xff;
251
  // opcode is the first instruction byte without the prefix.
252
452k
  uint8_t opcode = id & 0xff;
253
452k
  int index;
254
452k
  int i;
255
256
452k
  insn->id = M680X_INS_ILLGL;
257
258
1.05M
  for (i = 0; i < ARR_SIZE(cpu->pageX_prefix); ++i) {
259
1.03M
    if (cpu->pageX_table_size[i] == 0 ||
260
639k
        (cpu->inst_pageX_table[i] == NULL))
261
393k
      break;
262
263
639k
    if (cpu->pageX_prefix[i] == insn_prefix) {
264
37.6k
      index = binary_search(cpu->inst_pageX_table[i],
265
37.6k
                cpu->pageX_table_size[i], opcode);
266
37.6k
      insn->id =
267
37.6k
        (index >= 0) ?
268
26.5k
          cpu->inst_pageX_table[i][index].insn :
269
37.6k
          M680X_INS_ILLGL;
270
37.6k
      return;
271
37.6k
    }
272
639k
  }
273
274
414k
  if (insn_prefix != 0)
275
0
    return;
276
277
414k
  insn->id = cpu->inst_page1_table[id].insn;
278
279
414k
  if (insn->id != M680X_INS_ILLGL)
280
377k
    return;
281
282
  // Check if opcode byte is present in an overlay table
283
54.8k
  for (i = 0; i < ARR_SIZE(cpu->overlay_table_size); ++i) {
284
52.4k
    if (cpu->overlay_table_size[i] == 0 ||
285
37.2k
        (cpu->inst_overlay_table[i] == NULL))
286
15.1k
      break;
287
288
37.2k
    if ((index = binary_search(cpu->inst_overlay_table[i],
289
37.2k
             cpu->overlay_table_size[i],
290
37.2k
             opcode)) >= 0) {
291
19.1k
      insn->id = cpu->inst_overlay_table[i][index].insn;
292
19.1k
      return;
293
19.1k
    }
294
37.2k
  }
295
36.8k
}
296
297
static void add_insn_group(cs_detail *detail, m680x_group_type group)
298
446k
{
299
446k
  if (detail != NULL && (group != M680X_GRP_INVALID) &&
300
105k
      (group != M680X_GRP_ENDING))
301
105k
    detail->groups[detail->groups_count++] = (uint8_t)group;
302
446k
}
303
304
static bool exists_reg_list(uint16_t *regs, uint8_t count, m680x_reg reg)
305
1.25M
{
306
1.25M
  uint8_t i;
307
308
2.03M
  for (i = 0; i < count; ++i) {
309
814k
    if (regs[i] == (uint16_t)reg)
310
33.3k
      return true;
311
814k
  }
312
313
1.22M
  return false;
314
1.25M
}
315
316
static void add_reg_to_rw_list(MCInst *MI, m680x_reg reg, e_access access)
317
820k
{
318
820k
  cs_detail *detail = MI->flat_insn->detail;
319
320
820k
  if (detail == NULL || (reg == M680X_REG_INVALID))
321
0
    return;
322
323
820k
  switch (access) {
324
437k
  case MODIFY:
325
437k
    if (!exists_reg_list(detail->regs_read, detail->regs_read_count,
326
437k
             reg))
327
429k
      detail->regs_read[detail->regs_read_count++] =
328
429k
        (uint16_t)reg;
329
330
    // intentionally fall through
331
332
542k
  case WRITE:
333
542k
    if (!exists_reg_list(detail->regs_write,
334
542k
             detail->regs_write_count, reg))
335
533k
      detail->regs_write[detail->regs_write_count++] =
336
533k
        (uint16_t)reg;
337
338
542k
    break;
339
340
278k
  case READ:
341
278k
    if (!exists_reg_list(detail->regs_read, detail->regs_read_count,
342
278k
             reg))
343
261k
      detail->regs_read[detail->regs_read_count++] =
344
261k
        (uint16_t)reg;
345
346
278k
    break;
347
348
0
  case UNCHANGED:
349
0
  default:
350
0
    break;
351
820k
  }
352
820k
}
353
354
static void update_am_reg_list(MCInst *MI, m680x_info *info, cs_m680x_op *op,
355
             e_access access)
356
603k
{
357
603k
  if (MI->flat_insn->detail == NULL)
358
0
    return;
359
360
603k
  switch (op->type) {
361
257k
  case M680X_OP_REGISTER:
362
257k
    add_reg_to_rw_list(MI, op->reg, access);
363
257k
    break;
364
365
112k
  case M680X_OP_INDEXED:
366
112k
    add_reg_to_rw_list(MI, op->idx.base_reg, READ);
367
368
112k
    if (op->idx.base_reg == M680X_REG_X &&
369
53.1k
        info->cpu->reg_byte_size[M680X_REG_H])
370
16.7k
      add_reg_to_rw_list(MI, M680X_REG_H, READ);
371
372
112k
    if (op->idx.offset_reg != M680X_REG_INVALID)
373
10.0k
      add_reg_to_rw_list(MI, op->idx.offset_reg, READ);
374
375
112k
    if (op->idx.inc_dec) {
376
22.0k
      add_reg_to_rw_list(MI, op->idx.base_reg, WRITE);
377
378
22.0k
      if (op->idx.base_reg == M680X_REG_X &&
379
7.74k
          info->cpu->reg_byte_size[M680X_REG_H])
380
2.83k
        add_reg_to_rw_list(MI, M680X_REG_H, WRITE);
381
22.0k
    }
382
383
112k
    break;
384
385
233k
  default:
386
233k
    break;
387
603k
  }
388
603k
}
389
390
static const e_access g_access_mode_to_access[4][15] = {
391
  {
392
    UNCHANGED,
393
    READ,
394
    WRITE,
395
    READ,
396
    READ,
397
    READ,
398
    WRITE,
399
    MODIFY,
400
    MODIFY,
401
    MODIFY,
402
    MODIFY,
403
    MODIFY,
404
    WRITE,
405
    READ,
406
    MODIFY,
407
  },
408
  {
409
    UNCHANGED,
410
    READ,
411
    WRITE,
412
    WRITE,
413
    READ,
414
    MODIFY,
415
    READ,
416
    READ,
417
    WRITE,
418
    MODIFY,
419
    WRITE,
420
    MODIFY,
421
    MODIFY,
422
    READ,
423
    UNCHANGED,
424
  },
425
  {
426
    UNCHANGED,
427
    READ,
428
    WRITE,
429
    WRITE,
430
    READ,
431
    MODIFY,
432
    READ,
433
    READ,
434
    WRITE,
435
    MODIFY,
436
    READ,
437
    READ,
438
    MODIFY,
439
    UNCHANGED,
440
    UNCHANGED,
441
  },
442
  {
443
    UNCHANGED,
444
    READ,
445
    WRITE,
446
    WRITE,
447
    MODIFY,
448
    MODIFY,
449
    READ,
450
    READ,
451
    WRITE,
452
    MODIFY,
453
    READ,
454
    READ,
455
    MODIFY,
456
    UNCHANGED,
457
    UNCHANGED,
458
  },
459
};
460
461
static e_access get_access(int operator_index, e_access_mode access_mode)
462
1.26M
{
463
1.26M
  int idx = (operator_index > 3) ? 3 : operator_index;
464
465
1.26M
  return g_access_mode_to_access[idx][access_mode];
466
1.26M
}
467
468
static void build_regs_read_write_counts(MCInst *MI, m680x_info *info,
469
           e_access_mode access_mode)
470
406k
{
471
406k
  cs_m680x *m680x = &info->m680x;
472
406k
  int i;
473
474
406k
  if (MI->flat_insn->detail == NULL || (!m680x->op_count))
475
50.3k
    return;
476
477
959k
  for (i = 0; i < m680x->op_count; ++i) {
478
603k
    e_access access = get_access(i, access_mode);
479
603k
    update_am_reg_list(MI, info, &m680x->operands[i], access);
480
603k
  }
481
356k
}
482
483
static void add_operators_access(MCInst *MI, m680x_info *info,
484
         e_access_mode access_mode)
485
406k
{
486
406k
  cs_m680x *m680x = &info->m680x;
487
406k
  int offset = 0;
488
406k
  int i;
489
490
406k
  if (MI->flat_insn->detail == NULL || (!m680x->op_count) ||
491
356k
      (access_mode == uuuu))
492
91.2k
    return;
493
494
876k
  for (i = 0; i < m680x->op_count; ++i) {
495
560k
    e_access access;
496
497
    // Ugly fix: MULD has a register operand, an immediate operand
498
    // AND an implicitly changed register W
499
560k
    if (info->insn == M680X_INS_MULD && (i == 1))
500
472
      offset = 1;
501
502
560k
    access = get_access(i + offset, access_mode);
503
560k
    m680x->operands[i].access = access;
504
560k
  }
505
315k
}
506
507
typedef struct insn_to_changed_regs {
508
  m680x_insn insn;
509
  e_access_mode access_mode;
510
  m680x_reg regs[10];
511
} insn_to_changed_regs;
512
513
static void set_changed_regs_read_write_counts(MCInst *MI, m680x_info *info)
514
37.9k
{
515
  //TABLE
516
2.07M
#define EOL M680X_REG_INVALID
517
37.9k
  static const insn_to_changed_regs changed_regs[] = {
518
37.9k
    { M680X_INS_BSR, mmmm, { M680X_REG_S, EOL } },
519
37.9k
    { M680X_INS_CALL, mmmm, { M680X_REG_S, EOL } },
520
37.9k
    {
521
37.9k
      M680X_INS_CWAI,
522
37.9k
      mrrr,
523
37.9k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
524
37.9k
        M680X_REG_X, M680X_REG_DP, M680X_REG_D, M680X_REG_CC,
525
37.9k
        EOL },
526
37.9k
    },
527
37.9k
    { M680X_INS_DAA, mrrr, { M680X_REG_A, EOL } },
528
37.9k
    { M680X_INS_DIV,
529
37.9k
      mmrr,
530
37.9k
      { M680X_REG_A, M680X_REG_H, M680X_REG_X, EOL } },
531
37.9k
    { M680X_INS_EDIV,
532
37.9k
      mmrr,
533
37.9k
      { M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL } },
534
37.9k
    { M680X_INS_EDIVS,
535
37.9k
      mmrr,
536
37.9k
      { M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL } },
537
37.9k
    { M680X_INS_EMACS, mrrr, { M680X_REG_X, M680X_REG_Y, EOL } },
538
37.9k
    { M680X_INS_EMAXM, rrrr, { M680X_REG_D, EOL } },
539
37.9k
    { M680X_INS_EMINM, rrrr, { M680X_REG_D, EOL } },
540
37.9k
    { M680X_INS_EMUL, mmrr, { M680X_REG_D, M680X_REG_Y, EOL } },
541
37.9k
    { M680X_INS_EMULS, mmrr, { M680X_REG_D, M680X_REG_Y, EOL } },
542
37.9k
    { M680X_INS_ETBL, wmmm, { M680X_REG_A, M680X_REG_B, EOL } },
543
37.9k
    { M680X_INS_FDIV, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
544
37.9k
    { M680X_INS_IDIV, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
545
37.9k
    { M680X_INS_IDIVS, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
546
37.9k
    { M680X_INS_JSR, mmmm, { M680X_REG_S, EOL } },
547
37.9k
    { M680X_INS_LBSR, mmmm, { M680X_REG_S, EOL } },
548
37.9k
    { M680X_INS_MAXM, rrrr, { M680X_REG_A, EOL } },
549
37.9k
    { M680X_INS_MINM, rrrr, { M680X_REG_A, EOL } },
550
37.9k
    { M680X_INS_MEM,
551
37.9k
      mmrr,
552
37.9k
      { M680X_REG_X, M680X_REG_Y, M680X_REG_A, EOL } },
553
37.9k
    { M680X_INS_MUL, mmmm, { M680X_REG_A, M680X_REG_B, EOL } },
554
37.9k
    { M680X_INS_MULD, mwrr, { M680X_REG_D, M680X_REG_W, EOL } },
555
37.9k
    { M680X_INS_PSHA, rmmm, { M680X_REG_A, M680X_REG_S, EOL } },
556
37.9k
    { M680X_INS_PSHB, rmmm, { M680X_REG_B, M680X_REG_S, EOL } },
557
37.9k
    { M680X_INS_PSHC, rmmm, { M680X_REG_CC, M680X_REG_S, EOL } },
558
37.9k
    { M680X_INS_PSHD, rmmm, { M680X_REG_D, M680X_REG_S, EOL } },
559
37.9k
    { M680X_INS_PSHH, rmmm, { M680X_REG_H, M680X_REG_S, EOL } },
560
37.9k
    { M680X_INS_PSHX, rmmm, { M680X_REG_X, M680X_REG_S, EOL } },
561
37.9k
    { M680X_INS_PSHY, rmmm, { M680X_REG_Y, M680X_REG_S, EOL } },
562
37.9k
    { M680X_INS_PULA, wmmm, { M680X_REG_A, M680X_REG_S, EOL } },
563
37.9k
    { M680X_INS_PULB, wmmm, { M680X_REG_B, M680X_REG_S, EOL } },
564
37.9k
    { M680X_INS_PULC, wmmm, { M680X_REG_CC, M680X_REG_S, EOL } },
565
37.9k
    { M680X_INS_PULD, wmmm, { M680X_REG_D, M680X_REG_S, EOL } },
566
37.9k
    { M680X_INS_PULH, wmmm, { M680X_REG_H, M680X_REG_S, EOL } },
567
37.9k
    { M680X_INS_PULX, wmmm, { M680X_REG_X, M680X_REG_S, EOL } },
568
37.9k
    { M680X_INS_PULY, wmmm, { M680X_REG_Y, M680X_REG_S, EOL } },
569
37.9k
    { M680X_INS_REV,
570
37.9k
      mmrr,
571
37.9k
      { M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL } },
572
37.9k
    { M680X_INS_REVW,
573
37.9k
      mmmm,
574
37.9k
      { M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL } },
575
37.9k
    { M680X_INS_RTC, mwww, { M680X_REG_S, M680X_REG_PC, EOL } },
576
37.9k
    {
577
37.9k
      M680X_INS_RTI,
578
37.9k
      mwww,
579
37.9k
      { M680X_REG_S, M680X_REG_CC, M680X_REG_B, M680X_REG_A,
580
37.9k
        M680X_REG_DP, M680X_REG_X, M680X_REG_Y, M680X_REG_U,
581
37.9k
        M680X_REG_PC, EOL },
582
37.9k
    },
583
37.9k
    { M680X_INS_RTS, mwww, { M680X_REG_S, M680X_REG_PC, EOL } },
584
37.9k
    { M680X_INS_SEX, wrrr, { M680X_REG_A, M680X_REG_B, EOL } },
585
37.9k
    { M680X_INS_SEXW, rwww, { M680X_REG_W, M680X_REG_D, EOL } },
586
37.9k
    { M680X_INS_SWI,
587
37.9k
      mmrr,
588
37.9k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
589
37.9k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
590
37.9k
        M680X_REG_CC, EOL } },
591
37.9k
    {
592
37.9k
      M680X_INS_SWI2,
593
37.9k
      mmrr,
594
37.9k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
595
37.9k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
596
37.9k
        M680X_REG_CC, EOL },
597
37.9k
    },
598
37.9k
    {
599
37.9k
      M680X_INS_SWI3,
600
37.9k
      mmrr,
601
37.9k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
602
37.9k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
603
37.9k
        M680X_REG_CC, EOL },
604
37.9k
    },
605
37.9k
    { M680X_INS_TBL, wrrr, { M680X_REG_A, M680X_REG_B, EOL } },
606
37.9k
    { M680X_INS_WAI,
607
37.9k
      mrrr,
608
37.9k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_X, M680X_REG_A,
609
37.9k
        M680X_REG_B, M680X_REG_CC, EOL } },
610
37.9k
    { M680X_INS_WAV,
611
37.9k
      rmmm,
612
37.9k
      { M680X_REG_A, M680X_REG_B, M680X_REG_X, M680X_REG_Y, EOL } },
613
37.9k
    { M680X_INS_WAVR,
614
37.9k
      rmmm,
615
37.9k
      { M680X_REG_A, M680X_REG_B, M680X_REG_X, M680X_REG_Y, EOL } },
616
37.9k
  };
617
618
37.9k
  int i, j;
619
620
37.9k
  if (MI->flat_insn->detail == NULL)
621
0
    return;
622
623
1.97M
  for (i = 0; i < ARR_SIZE(changed_regs); ++i) {
624
1.93M
    if (info->insn == changed_regs[i].insn) {
625
37.9k
      e_access_mode access_mode = changed_regs[i].access_mode;
626
627
144k
      for (j = 0; changed_regs[i].regs[j] != EOL; ++j) {
628
106k
        e_access access;
629
630
106k
        m680x_reg reg = changed_regs[i].regs[j];
631
632
106k
        if (!info->cpu->reg_byte_size[reg]) {
633
10.8k
          if (info->insn != M680X_INS_MUL)
634
10.3k
            continue;
635
636
          // Hack for M68HC05: MUL uses reg. A,X
637
508
          reg = M680X_REG_X;
638
508
        }
639
640
96.5k
        access = get_access(j, access_mode);
641
96.5k
        add_reg_to_rw_list(MI, reg, access);
642
96.5k
      }
643
37.9k
    }
644
1.93M
  }
645
646
37.9k
#undef EOL
647
37.9k
}
648
649
typedef struct insn_desc {
650
  uint32_t opcode;
651
  m680x_insn insn;
652
  insn_hdlr_id hid[2];
653
  uint16_t insn_size;
654
} insn_desc;
655
656
// If successful return the additional byte size needed for M6809
657
// indexed addressing mode (including the indexed addressing post_byte).
658
// On error return -1.
659
static int get_indexed09_post_byte_size(const m680x_info *info,
660
          uint16_t address)
661
47.0k
{
662
47.0k
  uint8_t ir = 0;
663
47.0k
  uint8_t post_byte;
664
665
  // Read the indexed addressing post byte.
666
47.0k
  if (!read_byte(info, &post_byte, address))
667
175
    return -1;
668
669
  // Depending on the indexed addressing mode more bytes have to be read.
670
46.8k
  switch (post_byte & 0x9F) {
671
854
  case 0x87:
672
2.30k
  case 0x8A:
673
4.13k
  case 0x8E:
674
5.35k
  case 0x8F:
675
6.07k
  case 0x90:
676
6.94k
  case 0x92:
677
7.53k
  case 0x97:
678
8.47k
  case 0x9A:
679
9.00k
  case 0x9E:
680
9.00k
    return -1; // illegal indexed post bytes
681
682
905
  case 0x88: // n8,R
683
1.96k
  case 0x8C: // n8,PCR
684
2.96k
  case 0x98: // [n8,R]
685
3.45k
  case 0x9C: // [n8,PCR]
686
3.45k
    if (!read_byte(info, &ir, address + 1))
687
23
      return -1;
688
3.43k
    return 2;
689
690
677
  case 0x89: // n16,R
691
2.54k
  case 0x8D: // n16,PCR
692
3.18k
  case 0x99: // [n16,R]
693
3.94k
  case 0x9D: // [n16,PCR]
694
3.94k
    if (!read_byte(info, &ir, address + 2))
695
55
      return -1;
696
3.88k
    return 3;
697
698
2.23k
  case 0x9F: // [n]
699
2.23k
    if ((post_byte & 0x60) != 0 ||
700
1.12k
        !read_byte(info, &ir, address + 2))
701
1.14k
      return -1;
702
1.09k
    return 3;
703
46.8k
  }
704
705
  // Any other indexed post byte is valid and
706
  // no additional bytes have to be read.
707
28.2k
  return 1;
708
46.8k
}
709
710
// If successful return the additional byte size needed for CPU12
711
// indexed addressing mode (including the indexed addressing post_byte).
712
// On error return -1.
713
static int get_indexed12_post_byte_size(const m680x_info *info,
714
          uint16_t address, bool is_subset)
715
44.1k
{
716
44.1k
  uint8_t ir;
717
44.1k
  uint8_t post_byte;
718
719
  // Read the indexed addressing post byte.
720
44.1k
  if (!read_byte(info, &post_byte, address))
721
133
    return -1;
722
723
  // Depending on the indexed addressing mode more bytes have to be read.
724
44.0k
  if (!(post_byte & 0x20)) // n5,R
725
16.0k
    return 1;
726
727
28.0k
  switch (post_byte & 0xe7) {
728
2.96k
  case 0xe0:
729
5.54k
  case 0xe1: // n9,R
730
5.54k
    if (is_subset)
731
560
      return -1;
732
733
4.98k
    if (!read_byte(info, &ir, address))
734
0
      return -1;
735
4.98k
    return 2;
736
737
2.22k
  case 0xe2: // n16,R
738
4.68k
  case 0xe3: // [n16,R]
739
4.68k
    if (is_subset)
740
499
      return -1;
741
742
4.18k
    if (!read_byte(info, &ir, address + 1))
743
25
      return -1;
744
4.15k
    return 3;
745
746
461
  case 0xe4: // A,R
747
1.25k
  case 0xe5: // B,R
748
2.60k
  case 0xe6: // D,R
749
5.88k
  case 0xe7: // [D,R]
750
17.8k
  default: // n,-r n,+r n,r- n,r+
751
17.8k
    break;
752
28.0k
  }
753
754
17.8k
  return 1;
755
28.0k
}
756
757
// Check for M6809/HD6309 TFR/EXG instruction for valid register
758
static bool is_tfr09_reg_valid(const m680x_info *info, uint8_t reg_nibble)
759
6.84k
{
760
6.84k
  if (info->cpu->tfr_reg_valid != NULL)
761
3.02k
    return info->cpu->tfr_reg_valid[reg_nibble];
762
763
3.82k
  return true; // e.g. for the M6309 all registers are valid
764
6.84k
}
765
766
// Check for CPU12 TFR/EXG instruction for valid register
767
static bool is_exg_tfr12_post_byte_valid(const m680x_info *info,
768
           uint8_t post_byte)
769
1.11k
{
770
1.11k
  return !(post_byte & 0x08);
771
1.11k
}
772
773
static bool is_tfm_reg_valid(const m680x_info *info, uint8_t reg_nibble)
774
5.10k
{
775
  // HD6809 TFM instruction: Only register X,Y,U,S,D is allowed
776
5.10k
  return reg_nibble <= 4;
777
5.10k
}
778
779
// If successful return the additional byte size needed for CPU12
780
// loop instructions DBEQ/DBNE/IBEQ/IBNE/TBEQ/TBNE (including the post byte).
781
// On error return -1.
782
static int get_loop_post_byte_size(const m680x_info *info, uint16_t address)
783
3.47k
{
784
3.47k
  uint8_t post_byte;
785
3.47k
  uint8_t rr;
786
787
3.47k
  if (!read_byte(info, &post_byte, address))
788
17
    return -1;
789
790
  // According to documentation bit 3 is don't care and not checked here.
791
3.45k
  if ((post_byte >= 0xc0) || ((post_byte & 0x07) == 2) ||
792
2.51k
      ((post_byte & 0x07) == 3))
793
1.24k
    return -1;
794
795
2.21k
  if (!read_byte(info, &rr, address + 1))
796
9
    return -1;
797
798
2.20k
  return 2;
799
2.21k
}
800
801
// If successful return the additional byte size needed for HD6309
802
// bit move instructions BAND/BEOR/BIAND/BIEOR/BIOR/BOR/LDBT/STBT
803
// (including the post byte).
804
// On error return -1.
805
static int get_bitmv_post_byte_size(const m680x_info *info, uint16_t address)
806
1.79k
{
807
1.79k
  uint8_t post_byte;
808
1.79k
  uint8_t rr;
809
810
1.79k
  if (!read_byte(info, &post_byte, address))
811
7
    return -1;
812
813
1.79k
  if ((post_byte & 0xc0) == 0xc0)
814
265
    return -1; // Invalid register specified
815
1.52k
  else {
816
1.52k
    if (!read_byte(info, &rr, address + 1))
817
5
      return -1;
818
1.52k
  }
819
820
1.52k
  return 2;
821
1.79k
}
822
823
static bool is_sufficient_code_size(const m680x_info *info, uint16_t address,
824
            insn_desc *insn_description)
825
243k
{
826
243k
  int i;
827
243k
  bool retval = true;
828
243k
  uint16_t size = 0;
829
243k
  int sz;
830
831
713k
  for (i = 0; i < 2; i++) {
832
478k
    uint8_t ir = 0;
833
478k
    bool is_subset = false;
834
835
478k
    switch (insn_description->hid[i]) {
836
392
    case imm32_hid:
837
392
      if ((retval = read_byte(info, &ir, address + size + 3)))
838
352
        size += 4;
839
392
      break;
840
841
30.3k
    case ext_hid:
842
33.6k
    case imm16_hid:
843
34.9k
    case rel16_hid:
844
36.6k
    case imm8rel_hid:
845
39.7k
    case opidxdr_hid:
846
41.4k
    case idxX16_hid:
847
41.8k
    case idxS16_hid:
848
42.3k
    case dirdir_hid:
849
42.6k
    case immdir_hid:
850
42.6k
      if ((retval = read_byte(info, &ir, address + size + 1)))
851
42.2k
        size += 2;
852
42.6k
      break;
853
854
14.8k
    case rel8_hid:
855
50.0k
    case dir_hid:
856
52.8k
    case rbits_hid:
857
69.4k
    case imm8_hid:
858
77.8k
    case idxX_hid:
859
78.3k
    case idxXp_hid:
860
79.4k
    case idxY_hid:
861
80.0k
    case idxS_hid:
862
81.1k
    case index_hid:
863
81.1k
      if ((retval = read_byte(info, &ir, address + size)))
864
80.8k
        size++;
865
81.1k
      break;
866
867
0
    case illgl_hid:
868
282k
    case inh_hid:
869
286k
    case idxX0_hid:
870
287k
    case idxX0p_hid:
871
288k
    case opidx_hid:
872
295k
    case srt_hid:
873
297k
    case tny_hid:
874
297k
      retval = true;
875
297k
      break;
876
877
25.2k
    case idx09_hid:
878
25.2k
      sz = get_indexed09_post_byte_size(info, address + size);
879
25.2k
      if (sz >= 0)
880
19.6k
        size += sz;
881
5.53k
      else
882
5.53k
        retval = false;
883
25.2k
      break;
884
885
856
    case idx12s_hid:
886
856
      is_subset = true;
887
888
      // intentionally fall through
889
890
19.3k
    case idx12_hid:
891
19.3k
      sz = get_indexed12_post_byte_size(info, address + size,
892
19.3k
                is_subset);
893
19.3k
      if (sz >= 0)
894
18.7k
        size += sz;
895
635
      else
896
635
        retval = false;
897
19.3k
      break;
898
899
1.50k
    case exti12x_hid:
900
2.78k
    case imm16i12x_hid:
901
2.78k
      sz = get_indexed12_post_byte_size(info, address + size,
902
2.78k
                false);
903
2.78k
      if (sz >= 0) {
904
2.77k
        size += sz;
905
2.77k
        if ((retval = read_byte(info, &ir,
906
2.77k
              address + size + 1)))
907
2.76k
          size += 2;
908
2.77k
      } else
909
8
        retval = false;
910
2.78k
      break;
911
912
2.15k
    case imm8i12x_hid:
913
2.15k
      sz = get_indexed12_post_byte_size(info, address + size,
914
2.15k
                false);
915
2.15k
      if (sz >= 0) {
916
2.15k
        size += sz;
917
2.15k
        if ((retval = read_byte(info, &ir,
918
2.15k
              address + size)))
919
2.13k
          size++;
920
2.15k
      } else
921
5
        retval = false;
922
2.15k
      break;
923
924
648
    case tfm_hid:
925
648
      if ((retval = read_byte(info, &ir, address + size))) {
926
645
        size++;
927
645
        retval = is_tfm_reg_valid(info,
928
645
                (ir >> 4) & 0x0F) &&
929
534
           is_tfm_reg_valid(info, ir & 0x0F);
930
645
      }
931
648
      break;
932
933
2.29k
    case rr09_hid:
934
2.29k
      if ((retval = read_byte(info, &ir, address + size))) {
935
2.29k
        size++;
936
2.29k
        retval = is_tfr09_reg_valid(info,
937
2.29k
                  (ir >> 4) & 0x0F) &&
938
1.96k
           is_tfr09_reg_valid(info, ir & 0x0F);
939
2.29k
      }
940
2.29k
      break;
941
942
493
    case rr12_hid:
943
493
      if ((retval = read_byte(info, &ir, address + size))) {
944
491
        size++;
945
491
        retval = is_exg_tfr12_post_byte_valid(info, ir);
946
491
      }
947
493
      break;
948
949
1.47k
    case bitmv_hid:
950
1.47k
      sz = get_bitmv_post_byte_size(info, address + size);
951
1.47k
      if (sz >= 0)
952
1.36k
        size += sz;
953
114
      else
954
114
        retval = false;
955
1.47k
      break;
956
957
2.42k
    case loop_hid:
958
2.42k
      sz = get_loop_post_byte_size(info, address + size);
959
2.42k
      if (sz >= 0)
960
1.79k
        size += sz;
961
635
      else
962
635
        retval = false;
963
2.42k
      break;
964
965
0
    default:
966
0
      CS_ASSERT(0 && "Unexpected instruction handler id");
967
0
      retval = false;
968
0
      break;
969
478k
    }
970
971
478k
    if (!retval)
972
8.83k
      return false;
973
478k
  }
974
975
234k
  insn_description->insn_size += size;
976
977
234k
  return retval;
978
243k
}
979
980
// Check for a valid M680X instruction AND for enough bytes in the code buffer
981
// Return an instruction description in insn_desc.
982
static bool decode_insn(const m680x_info *info, uint16_t address,
983
      insn_desc *insn_description)
984
452k
{
985
452k
  const inst_pageX *inst_table = NULL;
986
452k
  const cpu_tables *cpu = info->cpu;
987
452k
  size_t table_size = 0;
988
452k
  uint16_t base_address = address;
989
452k
  uint8_t ir; // instruction register
990
452k
  int i;
991
452k
  int index;
992
993
452k
  if (!read_byte(info, &ir, address++))
994
0
    return false;
995
996
452k
  insn_description->insn = M680X_INS_ILLGL;
997
452k
  insn_description->opcode = ir;
998
999
  // Check if a page prefix byte is present
1000
1.05M
  for (i = 0; i < ARR_SIZE(cpu->pageX_table_size); ++i) {
1001
1.03M
    if (cpu->pageX_table_size[i] == 0 ||
1002
639k
        (cpu->inst_pageX_table[i] == NULL))
1003
393k
      break;
1004
1005
639k
    if ((cpu->pageX_prefix[i] == ir)) {
1006
      // Get pageX instruction and handler id.
1007
      // Abort for illegal instr.
1008
37.7k
      inst_table = cpu->inst_pageX_table[i];
1009
37.7k
      table_size = cpu->pageX_table_size[i];
1010
1011
37.7k
      if (!read_byte(info, &ir, address++))
1012
52
        return false;
1013
1014
37.6k
      insn_description->opcode =
1015
37.6k
        (insn_description->opcode << 8) | ir;
1016
1017
37.6k
      if ((index = binary_search(inst_table, table_size,
1018
37.6k
               ir)) < 0)
1019
11.1k
        return false;
1020
1021
26.5k
      insn_description->hid[0] =
1022
26.5k
        inst_table[index].handler_id1;
1023
26.5k
      insn_description->hid[1] =
1024
26.5k
        inst_table[index].handler_id2;
1025
26.5k
      insn_description->insn = inst_table[index].insn;
1026
26.5k
      break;
1027
37.6k
    }
1028
639k
  }
1029
1030
441k
  if (insn_description->insn == M680X_INS_ILLGL) {
1031
    // Get page1 insn description
1032
414k
    insn_description->insn = cpu->inst_page1_table[ir].insn;
1033
414k
    insn_description->hid[0] =
1034
414k
      cpu->inst_page1_table[ir].handler_id1;
1035
414k
    insn_description->hid[1] =
1036
414k
      cpu->inst_page1_table[ir].handler_id2;
1037
414k
  }
1038
1039
441k
  if (insn_description->insn == M680X_INS_ILLGL) {
1040
    // Check if opcode byte is present in an overlay table
1041
54.7k
    for (i = 0; i < ARR_SIZE(cpu->overlay_table_size); ++i) {
1042
52.3k
      if (cpu->overlay_table_size[i] == 0 ||
1043
37.1k
          (cpu->inst_overlay_table[i] == NULL))
1044
15.1k
        break;
1045
1046
37.1k
      inst_table = cpu->inst_overlay_table[i];
1047
37.1k
      table_size = cpu->overlay_table_size[i];
1048
1049
37.1k
      if ((index = binary_search(inst_table, table_size,
1050
37.1k
               ir)) >= 0) {
1051
19.1k
        insn_description->hid[0] =
1052
19.1k
          inst_table[index].handler_id1;
1053
19.1k
        insn_description->hid[1] =
1054
19.1k
          inst_table[index].handler_id2;
1055
19.1k
        insn_description->insn = inst_table[index].insn;
1056
19.1k
        break;
1057
19.1k
      }
1058
37.1k
    }
1059
36.7k
  }
1060
1061
441k
  insn_description->insn_size = address - base_address;
1062
1063
441k
  return (insn_description->insn != M680X_INS_ILLGL) &&
1064
423k
         (insn_description->insn != M680X_INS_INVLD) &&
1065
423k
         is_sufficient_code_size(info, address, insn_description);
1066
452k
}
1067
1068
static void illegal_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1069
45.6k
{
1070
45.6k
  cs_m680x_op *op0 = &info->m680x.operands[info->m680x.op_count++];
1071
45.6k
  uint8_t temp8 = 0;
1072
1073
45.6k
  info->insn = M680X_INS_ILLGL;
1074
45.6k
  read_byte(info, &temp8, (*address)++);
1075
45.6k
  op0->imm = (int32_t)temp8 & 0xff;
1076
45.6k
  op0->type = M680X_OP_IMMEDIATE;
1077
45.6k
  op0->size = 1;
1078
45.6k
}
1079
1080
static void inherent_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1081
487k
{
1082
  // There is nothing to do here :-)
1083
487k
}
1084
1085
static void add_reg_operand(m680x_info *info, m680x_reg reg)
1086
257k
{
1087
257k
  cs_m680x *m680x = &info->m680x;
1088
257k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1089
1090
257k
  op->type = M680X_OP_REGISTER;
1091
257k
  op->reg = reg;
1092
257k
  op->size = info->cpu->reg_byte_size[reg];
1093
257k
}
1094
1095
static void set_operand_size(m680x_info *info, cs_m680x_op *op,
1096
           uint8_t default_size)
1097
285k
{
1098
285k
  cs_m680x *m680x = &info->m680x;
1099
1100
285k
  if (info->insn == M680X_INS_JMP || info->insn == M680X_INS_JSR)
1101
13.8k
    op->size = 0;
1102
271k
  else if (info->insn == M680X_INS_DIVD ||
1103
270k
     ((info->insn == M680X_INS_AIS ||
1104
269k
       info->insn == M680X_INS_AIX) &&
1105
1.38k
      op->type != M680X_OP_REGISTER))
1106
2.66k
    op->size = 1;
1107
268k
  else if (info->insn == M680X_INS_DIVQ || info->insn == M680X_INS_MOVW)
1108
11.2k
    op->size = 2;
1109
257k
  else if (info->insn == M680X_INS_EMACS)
1110
284
    op->size = 4;
1111
257k
  else if ((m680x->op_count > 0) &&
1112
257k
     (m680x->operands[0].type == M680X_OP_REGISTER))
1113
158k
    op->size = m680x->operands[0].size;
1114
98.9k
  else
1115
98.9k
    op->size = default_size;
1116
285k
}
1117
1118
static const m680x_reg reg_s_reg_ids[] = {
1119
  M680X_REG_CC, M680X_REG_A, M680X_REG_B, M680X_REG_DP,
1120
  M680X_REG_X,  M680X_REG_Y, M680X_REG_U, M680X_REG_PC,
1121
};
1122
1123
static const m680x_reg reg_u_reg_ids[] = {
1124
  M680X_REG_CC, M680X_REG_A, M680X_REG_B, M680X_REG_DP,
1125
  M680X_REG_X,  M680X_REG_Y, M680X_REG_S, M680X_REG_PC,
1126
};
1127
1128
static void reg_bits_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1129
2.79k
{
1130
2.79k
  cs_m680x_op *op0 = &info->m680x.operands[0];
1131
2.79k
  uint8_t reg_bits = 0;
1132
2.79k
  uint16_t bit_index;
1133
2.79k
  const m680x_reg *reg_to_reg_ids = NULL;
1134
1135
2.79k
  read_byte(info, &reg_bits, (*address)++);
1136
1137
2.79k
  switch (op0->reg) {
1138
1.54k
  case M680X_REG_U:
1139
1.54k
    reg_to_reg_ids = &reg_u_reg_ids[0];
1140
1.54k
    break;
1141
1142
1.25k
  case M680X_REG_S:
1143
1.25k
    reg_to_reg_ids = &reg_s_reg_ids[0];
1144
1.25k
    break;
1145
1146
0
  default:
1147
0
    CS_ASSERT(0 && "Unexpected operand0 register");
1148
0
    break;
1149
2.79k
  }
1150
1151
2.79k
  if ((info->insn == M680X_INS_PULU || (info->insn == M680X_INS_PULS)) &&
1152
1.58k
      ((reg_bits & 0x80) != 0))
1153
    // PULS xxx,PC or PULU xxx,PC which is like return from
1154
    // subroutine (RTS)
1155
366
    add_insn_group(MI->flat_insn->detail, M680X_GRP_RET);
1156
1157
25.1k
  for (bit_index = 0; bit_index < 8; ++bit_index) {
1158
22.3k
    if (reg_bits & (1 << bit_index) && reg_to_reg_ids)
1159
11.4k
      add_reg_operand(info, reg_to_reg_ids[bit_index]);
1160
22.3k
  }
1161
2.79k
}
1162
1163
static const m680x_reg g_tfr_exg_reg_ids[] = {
1164
  /* 16-bit registers */
1165
  M680X_REG_D,
1166
  M680X_REG_X,
1167
  M680X_REG_Y,
1168
  M680X_REG_U,
1169
  M680X_REG_S,
1170
  M680X_REG_PC,
1171
  M680X_REG_W,
1172
  M680X_REG_V,
1173
  /* 8-bit registers */
1174
  M680X_REG_A,
1175
  M680X_REG_B,
1176
  M680X_REG_CC,
1177
  M680X_REG_DP,
1178
  M680X_REG_0,
1179
  M680X_REG_0,
1180
  M680X_REG_E,
1181
  M680X_REG_F,
1182
};
1183
1184
static void reg_reg09_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1185
2.49k
{
1186
2.49k
  uint8_t regs = 0;
1187
1188
2.49k
  read_byte(info, &regs, (*address)++);
1189
1190
2.49k
  add_reg_operand(info, g_tfr_exg_reg_ids[regs >> 4]);
1191
2.49k
  add_reg_operand(info, g_tfr_exg_reg_ids[regs & 0x0f]);
1192
1193
2.49k
  if ((regs & 0x0f) == 0x05) {
1194
    // EXG xxx,PC or TFR xxx,PC which is like a JMP
1195
435
    add_insn_group(MI->flat_insn->detail, M680X_GRP_JUMP);
1196
435
  }
1197
2.49k
}
1198
1199
static void reg_reg12_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1200
1.01k
{
1201
1.01k
  static const m680x_reg g_tfr_exg12_reg0_ids[] = {
1202
1.01k
    M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP3,
1203
1.01k
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,  M680X_REG_S,
1204
1.01k
  };
1205
1.01k
  static const m680x_reg g_tfr_exg12_reg1_ids[] = {
1206
1.01k
    M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP2,
1207
1.01k
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,  M680X_REG_S,
1208
1.01k
  };
1209
1.01k
  uint8_t regs = 0;
1210
1211
1.01k
  read_byte(info, &regs, (*address)++);
1212
1213
  // The opcode of this instruction depends on
1214
  // the msb of its post byte.
1215
1.01k
  if (regs & 0x80)
1216
622
    info->insn = M680X_INS_EXG;
1217
388
  else
1218
388
    info->insn = M680X_INS_TFR;
1219
1220
1.01k
  add_reg_operand(info, g_tfr_exg12_reg0_ids[(regs >> 4) & 0x07]);
1221
1.01k
  add_reg_operand(info, g_tfr_exg12_reg1_ids[regs & 0x07]);
1222
1.01k
}
1223
1224
static void add_rel_operand(m680x_info *info, int16_t offset, uint16_t address)
1225
36.9k
{
1226
36.9k
  cs_m680x *m680x = &info->m680x;
1227
36.9k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1228
1229
36.9k
  op->type = M680X_OP_RELATIVE;
1230
36.9k
  op->size = 0;
1231
36.9k
  op->rel.offset = offset;
1232
36.9k
  op->rel.address = address;
1233
36.9k
}
1234
1235
static void relative8_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1236
34.6k
{
1237
34.6k
  int16_t offset = 0;
1238
1239
34.6k
  read_byte_sign_extended(info, &offset, (*address)++);
1240
34.6k
  add_rel_operand(info, offset, *address + offset);
1241
34.6k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1242
1243
34.6k
  if ((info->insn != M680X_INS_BRA) && (info->insn != M680X_INS_BSR) &&
1244
30.5k
      (info->insn != M680X_INS_BRN))
1245
29.0k
    add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1246
34.6k
}
1247
1248
static void relative16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1249
2.35k
{
1250
2.35k
  uint16_t offset = 0;
1251
1252
2.35k
  read_word(info, &offset, *address);
1253
2.35k
  *address += 2;
1254
2.35k
  add_rel_operand(info, (int16_t)offset, *address + offset);
1255
2.35k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1256
1257
2.35k
  if ((info->insn != M680X_INS_LBRA) && (info->insn != M680X_INS_LBSR) &&
1258
878
      (info->insn != M680X_INS_LBRN))
1259
756
    add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1260
2.35k
}
1261
1262
static const m680x_reg g_rr5_to_reg_ids[] = {
1263
  M680X_REG_X,
1264
  M680X_REG_Y,
1265
  M680X_REG_U,
1266
  M680X_REG_S,
1267
};
1268
1269
static void add_indexed_operand(m680x_info *info, m680x_reg base_reg,
1270
        bool post_inc_dec, uint8_t inc_dec,
1271
        uint8_t offset_bits, uint16_t offset,
1272
        bool no_comma)
1273
34.4k
{
1274
34.4k
  cs_m680x *m680x = &info->m680x;
1275
34.4k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1276
1277
34.4k
  op->type = M680X_OP_INDEXED;
1278
34.4k
  set_operand_size(info, op, 1);
1279
34.4k
  op->idx.base_reg = base_reg;
1280
34.4k
  op->idx.offset_reg = M680X_REG_INVALID;
1281
34.4k
  op->idx.inc_dec = inc_dec;
1282
1283
34.4k
  if (inc_dec && post_inc_dec)
1284
4.67k
    op->idx.flags |= M680X_IDX_POST_INC_DEC;
1285
1286
34.4k
  if (offset_bits != M680X_OFFSET_NONE) {
1287
20.6k
    op->idx.offset = offset;
1288
20.6k
    op->idx.offset_addr = 0;
1289
20.6k
  }
1290
1291
34.4k
  op->idx.offset_bits = offset_bits;
1292
34.4k
  op->idx.flags |= (no_comma ? M680X_IDX_NO_COMMA : 0);
1293
34.4k
}
1294
1295
// M6800/1/2/3 indexed mode handler
1296
static void indexedX_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1297
13.0k
{
1298
13.0k
  uint8_t offset = 0;
1299
1300
13.0k
  read_byte(info, &offset, (*address)++);
1301
1302
13.0k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_8,
1303
13.0k
          (uint16_t)offset, false);
1304
13.0k
}
1305
1306
static void indexedY_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1307
1.82k
{
1308
1.82k
  uint8_t offset = 0;
1309
1310
1.82k
  read_byte(info, &offset, (*address)++);
1311
1312
1.82k
  add_indexed_operand(info, M680X_REG_Y, false, 0, M680X_OFFSET_BITS_8,
1313
1.82k
          (uint16_t)offset, false);
1314
1.82k
}
1315
1316
// M6809/M6309 indexed mode handler
1317
static void indexed09_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1318
36.6k
{
1319
36.6k
  cs_m680x *m680x = &info->m680x;
1320
36.6k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1321
36.6k
  uint8_t post_byte = 0;
1322
36.6k
  uint16_t offset = 0;
1323
36.6k
  int16_t soffset = 0;
1324
1325
36.6k
  read_byte(info, &post_byte, (*address)++);
1326
1327
36.6k
  op->type = M680X_OP_INDEXED;
1328
36.6k
  set_operand_size(info, op, 1);
1329
36.6k
  op->idx.base_reg = g_rr5_to_reg_ids[(post_byte >> 5) & 0x03];
1330
36.6k
  op->idx.offset_reg = M680X_REG_INVALID;
1331
1332
36.6k
  if (!(post_byte & 0x80)) {
1333
    // n5,R
1334
16.8k
    if ((post_byte & 0x10) == 0x10)
1335
7.30k
      op->idx.offset = post_byte | 0xfff0;
1336
9.57k
    else
1337
9.57k
      op->idx.offset = post_byte & 0x0f;
1338
1339
16.8k
    op->idx.offset_addr = op->idx.offset + *address;
1340
16.8k
    op->idx.offset_bits = M680X_OFFSET_BITS_5;
1341
19.7k
  } else {
1342
19.7k
    if ((post_byte & 0x10) == 0x10)
1343
7.47k
      op->idx.flags |= M680X_IDX_INDIRECT;
1344
1345
    // indexed addressing
1346
19.7k
    switch (post_byte & 0x1f) {
1347
1.01k
    case 0x00: // ,R+
1348
1.01k
      op->idx.inc_dec = 1;
1349
1.01k
      op->idx.flags |= M680X_IDX_POST_INC_DEC;
1350
1.01k
      break;
1351
1352
514
    case 0x11: // [,R++]
1353
1.60k
    case 0x01: // ,R++
1354
1.60k
      op->idx.inc_dec = 2;
1355
1.60k
      op->idx.flags |= M680X_IDX_POST_INC_DEC;
1356
1.60k
      break;
1357
1358
1.09k
    case 0x02: // ,-R
1359
1.09k
      op->idx.inc_dec = -1;
1360
1.09k
      break;
1361
1362
991
    case 0x13: // [,--R]
1363
1.74k
    case 0x03: // ,--R
1364
1.74k
      op->idx.inc_dec = -2;
1365
1.74k
      break;
1366
1367
392
    case 0x14: // [,R]
1368
1.66k
    case 0x04: // ,R
1369
1.66k
      break;
1370
1371
458
    case 0x15: // [B,R]
1372
1.47k
    case 0x05: // B,R
1373
1.47k
      op->idx.offset_reg = M680X_REG_B;
1374
1.47k
      break;
1375
1376
315
    case 0x16: // [A,R]
1377
1.05k
    case 0x06: // A,R
1378
1.05k
      op->idx.offset_reg = M680X_REG_A;
1379
1.05k
      break;
1380
1381
478
    case 0x1c: // [n8,PCR]
1382
1.53k
    case 0x0c: // n8,PCR
1383
1.53k
      op->idx.base_reg = M680X_REG_PC;
1384
1.53k
      read_byte_sign_extended(info, &soffset, (*address)++);
1385
1.53k
      op->idx.offset_addr = offset + *address;
1386
1.53k
      op->idx.offset = soffset;
1387
1.53k
      op->idx.offset_bits = M680X_OFFSET_BITS_8;
1388
1.53k
      break;
1389
1390
995
    case 0x18: // [n8,R]
1391
1.89k
    case 0x08: // n8,R
1392
1.89k
      read_byte_sign_extended(info, &soffset, (*address)++);
1393
1.89k
      op->idx.offset = soffset;
1394
1.89k
      op->idx.offset_bits = M680X_OFFSET_BITS_8;
1395
1.89k
      break;
1396
1397
754
    case 0x1d: // [n16,PCR]
1398
2.60k
    case 0x0d: // n16,PCR
1399
2.60k
      op->idx.base_reg = M680X_REG_PC;
1400
2.60k
      read_word(info, &offset, *address);
1401
2.60k
      *address += 2;
1402
2.60k
      op->idx.offset_addr = offset + *address;
1403
2.60k
      op->idx.offset = (int16_t)offset;
1404
2.60k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1405
2.60k
      break;
1406
1407
624
    case 0x19: // [n16,R]
1408
1.28k
    case 0x09: // n16,R
1409
1.28k
      read_word(info, &offset, *address);
1410
1.28k
      *address += 2;
1411
1.28k
      op->idx.offset = (int16_t)offset;
1412
1.28k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1413
1.28k
      break;
1414
1415
855
    case 0x1b: // [D,R]
1416
1.68k
    case 0x0b: // D,R
1417
1.68k
      op->idx.offset_reg = M680X_REG_D;
1418
1.68k
      break;
1419
1420
1.09k
    case 0x1f: // [n16]
1421
1.09k
      op->type = M680X_OP_EXTENDED;
1422
1.09k
      op->ext.indirect = true;
1423
1.09k
      read_word(info, &op->ext.address, *address);
1424
1.09k
      *address += 2;
1425
1.09k
      break;
1426
1427
0
    default:
1428
0
      op->idx.base_reg = M680X_REG_INVALID;
1429
0
      break;
1430
19.7k
    }
1431
19.7k
  }
1432
1433
36.6k
  if (((info->insn == M680X_INS_LEAU) || (info->insn == M680X_INS_LEAS) ||
1434
34.4k
       (info->insn == M680X_INS_LEAX) ||
1435
32.5k
       (info->insn == M680X_INS_LEAY)) &&
1436
5.23k
      (m680x->operands[0].reg == M680X_REG_X ||
1437
3.26k
       (m680x->operands[0].reg == M680X_REG_Y)))
1438
    // Only LEAX and LEAY modify CC register
1439
3.09k
    add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1440
36.6k
}
1441
1442
static const m680x_reg g_idx12_to_reg_ids[4] = {
1443
  M680X_REG_X,
1444
  M680X_REG_Y,
1445
  M680X_REG_S,
1446
  M680X_REG_PC,
1447
};
1448
1449
static const m680x_reg g_or12_to_reg_ids[3] = { M680X_REG_A, M680X_REG_B,
1450
            M680X_REG_D };
1451
1452
// CPU12 indexed mode handler
1453
static void indexed12_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1454
42.9k
{
1455
42.9k
  cs_m680x *m680x = &info->m680x;
1456
42.9k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1457
42.9k
  uint8_t post_byte = 0;
1458
42.9k
  uint8_t offset8 = 0;
1459
1460
42.9k
  read_byte(info, &post_byte, (*address)++);
1461
1462
42.9k
  op->type = M680X_OP_INDEXED;
1463
42.9k
  set_operand_size(info, op, 1);
1464
42.9k
  op->idx.offset_reg = M680X_REG_INVALID;
1465
1466
42.9k
  if (!(post_byte & 0x20)) {
1467
    // n5,R      n5 is a 5-bit signed offset
1468
15.9k
    op->idx.base_reg = g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1469
1470
15.9k
    if ((post_byte & 0x10) == 0x10)
1471
6.65k
      op->idx.offset = post_byte | 0xfff0;
1472
9.32k
    else
1473
9.32k
      op->idx.offset = post_byte & 0x0f;
1474
1475
15.9k
    op->idx.offset_addr = op->idx.offset + *address;
1476
15.9k
    op->idx.offset_bits = M680X_OFFSET_BITS_5;
1477
26.9k
  } else {
1478
26.9k
    if ((post_byte & 0xe0) == 0xe0)
1479
14.9k
      op->idx.base_reg =
1480
14.9k
        g_idx12_to_reg_ids[(post_byte >> 3) & 0x03];
1481
1482
26.9k
    switch (post_byte & 0xe7) {
1483
2.78k
    case 0xe0:
1484
4.97k
    case 0xe1: // n9,R
1485
4.97k
      read_byte(info, &offset8, (*address)++);
1486
4.97k
      op->idx.offset = offset8;
1487
1488
4.97k
      if (post_byte & 0x01) // sign extension
1489
2.18k
        op->idx.offset |= 0xff00;
1490
1491
4.97k
      op->idx.offset_bits = M680X_OFFSET_BITS_9;
1492
1493
4.97k
      if (op->idx.base_reg == M680X_REG_PC)
1494
1.77k
        op->idx.offset_addr = op->idx.offset + *address;
1495
1496
4.97k
      break;
1497
1498
2.38k
    case 0xe3: // [n16,R]
1499
2.38k
      op->idx.flags |= M680X_IDX_INDIRECT;
1500
1501
    // intentionally fall through
1502
4.14k
    case 0xe2: // n16,R
1503
4.14k
      read_word(info, (uint16_t *)&op->idx.offset, *address);
1504
4.14k
      (*address) += 2;
1505
4.14k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1506
1507
4.14k
      if (op->idx.base_reg == M680X_REG_PC)
1508
473
        op->idx.offset_addr = op->idx.offset + *address;
1509
1510
4.14k
      break;
1511
1512
460
    case 0xe4: // A,R
1513
1.25k
    case 0xe5: // B,R
1514
2.60k
    case 0xe6: // D,R
1515
2.60k
      op->idx.offset_reg =
1516
2.60k
        g_or12_to_reg_ids[post_byte & 0x03];
1517
2.60k
      break;
1518
1519
3.27k
    case 0xe7: // [D,R]
1520
3.27k
      op->idx.offset_reg = M680X_REG_D;
1521
3.27k
      op->idx.flags |= M680X_IDX_INDIRECT;
1522
3.27k
      break;
1523
1524
11.9k
    default: // n,-r n,+r n,r- n,r+
1525
      // PC is not allowed in this mode
1526
11.9k
      op->idx.base_reg =
1527
11.9k
        g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1528
11.9k
      op->idx.inc_dec = post_byte & 0x0f;
1529
1530
11.9k
      if (op->idx.inc_dec & 0x08) // evtl. sign extend value
1531
6.42k
        op->idx.inc_dec |= 0xf0;
1532
1533
11.9k
      if (op->idx.inc_dec >= 0)
1534
5.52k
        op->idx.inc_dec++;
1535
1536
11.9k
      if (post_byte & 0x10)
1537
3.53k
        op->idx.flags |= M680X_IDX_POST_INC_DEC;
1538
1539
11.9k
      break;
1540
26.9k
    }
1541
26.9k
  }
1542
42.9k
}
1543
1544
static void index_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1545
1.38k
{
1546
1.38k
  cs_m680x *m680x = &info->m680x;
1547
1.38k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1548
1549
1.38k
  op->type = M680X_OP_CONSTANT;
1550
1.38k
  read_byte(info, &op->const_val, (*address)++);
1551
1.38k
};
1552
1553
static void direct_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1554
68.2k
{
1555
68.2k
  cs_m680x *m680x = &info->m680x;
1556
68.2k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1557
1558
68.2k
  op->type = M680X_OP_DIRECT;
1559
68.2k
  set_operand_size(info, op, 1);
1560
68.2k
  read_byte(info, &op->direct_addr, (*address)++);
1561
68.2k
};
1562
1563
static void extended_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1564
55.1k
{
1565
55.1k
  cs_m680x *m680x = &info->m680x;
1566
55.1k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1567
1568
55.1k
  op->type = M680X_OP_EXTENDED;
1569
55.1k
  set_operand_size(info, op, 1);
1570
55.1k
  read_word(info, &op->ext.address, *address);
1571
55.1k
  *address += 2;
1572
55.1k
}
1573
1574
static void immediate_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1575
39.1k
{
1576
39.1k
  cs_m680x *m680x = &info->m680x;
1577
39.1k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1578
39.1k
  uint16_t word = 0;
1579
39.1k
  int16_t sword = 0;
1580
1581
39.1k
  op->type = M680X_OP_IMMEDIATE;
1582
39.1k
  set_operand_size(info, op, 1);
1583
1584
39.1k
  switch (op->size) {
1585
32.8k
  case 1:
1586
32.8k
    read_byte_sign_extended(info, &sword, *address);
1587
32.8k
    op->imm = sword;
1588
32.8k
    break;
1589
1590
5.82k
  case 2:
1591
5.82k
    read_word(info, &word, *address);
1592
5.82k
    op->imm = (int16_t)word;
1593
5.82k
    break;
1594
1595
450
  case 4:
1596
450
    read_sdword(info, &op->imm, *address);
1597
450
    break;
1598
1599
0
  default:
1600
0
    op->imm = 0;
1601
0
    CS_ASSERT(0 && "Unexpected immediate byte size");
1602
39.1k
  }
1603
1604
39.1k
  *address += op->size;
1605
39.1k
}
1606
1607
// handler for bit move instructions, e.g: BAND A,5,1,$40  Used by HD6309
1608
static void bit_move_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1609
1.52k
{
1610
1.52k
  static const m680x_reg m680x_reg[] = {
1611
1.52k
    M680X_REG_CC,
1612
1.52k
    M680X_REG_A,
1613
1.52k
    M680X_REG_B,
1614
1.52k
    M680X_REG_INVALID,
1615
1.52k
  };
1616
1617
1.52k
  uint8_t post_byte = 0;
1618
1.52k
  cs_m680x *m680x = &info->m680x;
1619
1.52k
  cs_m680x_op *op;
1620
1621
1.52k
  read_byte(info, &post_byte, *address);
1622
1.52k
  (*address)++;
1623
1624
  // operand[0] = register
1625
1.52k
  add_reg_operand(info, m680x_reg[post_byte >> 6]);
1626
1627
  // operand[1] = bit index in source operand
1628
1.52k
  op = &m680x->operands[m680x->op_count++];
1629
1.52k
  op->type = M680X_OP_CONSTANT;
1630
1.52k
  op->const_val = (post_byte >> 3) & 0x07;
1631
1632
  // operand[2] = bit index in destination operand
1633
1.52k
  op = &m680x->operands[m680x->op_count++];
1634
1.52k
  op->type = M680X_OP_CONSTANT;
1635
1.52k
  op->const_val = post_byte & 0x07;
1636
1637
1.52k
  direct_hdlr(MI, info, address);
1638
1.52k
}
1639
1640
// handler for TFM instruction, e.g: TFM X+,Y+  Used by HD6309
1641
static void tfm_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1642
1.83k
{
1643
1.83k
  static const uint8_t inc_dec_r0[] = {
1644
1.83k
    1,
1645
1.83k
    -1,
1646
1.83k
    1,
1647
1.83k
    0,
1648
1.83k
  };
1649
1.83k
  static const uint8_t inc_dec_r1[] = {
1650
1.83k
    1,
1651
1.83k
    -1,
1652
1.83k
    0,
1653
1.83k
    1,
1654
1.83k
  };
1655
1.83k
  uint8_t regs = 0;
1656
1.83k
  uint8_t index = (MI->Opcode & 0xff) - 0x38;
1657
1658
1.83k
  read_byte(info, &regs, *address);
1659
1660
1.83k
  add_indexed_operand(info, g_tfr_exg_reg_ids[regs >> 4], true,
1661
1.83k
          inc_dec_r0[index], M680X_OFFSET_NONE, 0, true);
1662
1.83k
  add_indexed_operand(info, g_tfr_exg_reg_ids[regs & 0x0f], true,
1663
1.83k
          inc_dec_r1[index], M680X_OFFSET_NONE, 0, true);
1664
1665
1.83k
  add_reg_to_rw_list(MI, M680X_REG_W, READ | WRITE);
1666
1.83k
}
1667
1668
static void opidx_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1669
2.74k
{
1670
2.74k
  cs_m680x *m680x = &info->m680x;
1671
2.74k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1672
1673
  // bit index is coded in Opcode
1674
2.74k
  op->type = M680X_OP_CONSTANT;
1675
2.74k
  op->const_val = (MI->Opcode & 0x0e) >> 1;
1676
2.74k
}
1677
1678
// handler for bit test and branch instruction. Used by M6805.
1679
// The bit index is part of the opcode.
1680
// Example: BRSET 3,<$40,LOOP
1681
static void opidx_dir_rel_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1682
5.18k
{
1683
5.18k
  cs_m680x *m680x = &info->m680x;
1684
5.18k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1685
1686
  // bit index is coded in Opcode
1687
5.18k
  op->type = M680X_OP_CONSTANT;
1688
5.18k
  op->const_val = (MI->Opcode & 0x0e) >> 1;
1689
5.18k
  direct_hdlr(MI, info, address);
1690
5.18k
  relative8_hdlr(MI, info, address);
1691
1692
5.18k
  add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1693
5.18k
}
1694
1695
static void indexedX0_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1696
8.45k
{
1697
8.45k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_NONE, 0,
1698
8.45k
          false);
1699
8.45k
}
1700
1701
static void indexedX16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1702
2.75k
{
1703
2.75k
  uint16_t offset = 0;
1704
1705
2.75k
  read_word(info, &offset, *address);
1706
2.75k
  *address += 2;
1707
2.75k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_16,
1708
2.75k
          offset, false);
1709
2.75k
}
1710
1711
static void imm_rel_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1712
3.14k
{
1713
3.14k
  immediate_hdlr(MI, info, address);
1714
3.14k
  relative8_hdlr(MI, info, address);
1715
3.14k
}
1716
1717
static void indexedS_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1718
1.06k
{
1719
1.06k
  uint8_t offset = 0;
1720
1721
1.06k
  read_byte(info, &offset, (*address)++);
1722
1723
1.06k
  add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_8,
1724
1.06k
          (uint16_t)offset, false);
1725
1.06k
}
1726
1727
static void indexedS16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1728
737
{
1729
737
  uint16_t offset = 0;
1730
1731
737
  read_word(info, &offset, *address);
1732
737
  *address += 2;
1733
1734
737
  add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_16,
1735
737
          offset, false);
1736
737
}
1737
1738
static void indexedX0p_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1739
1.67k
{
1740
1.67k
  add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_NONE, 0,
1741
1.67k
          true);
1742
1.67k
}
1743
1744
static void indexedXp_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1745
1.15k
{
1746
1.15k
  uint8_t offset = 0;
1747
1748
1.15k
  read_byte(info, &offset, (*address)++);
1749
1750
1.15k
  add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_BITS_8,
1751
1.15k
          (uint16_t)offset, false);
1752
1.15k
}
1753
1754
static void imm_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1755
6.23k
{
1756
6.23k
  cs_m680x *m680x = &info->m680x;
1757
6.23k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1758
1759
6.23k
  indexed12_hdlr(MI, info, address);
1760
6.23k
  op->type = M680X_OP_IMMEDIATE;
1761
1762
6.23k
  if (info->insn == M680X_INS_MOVW) {
1763
2.38k
    uint16_t imm16 = 0;
1764
1765
2.38k
    read_word(info, &imm16, *address);
1766
2.38k
    op->imm = (int16_t)imm16;
1767
2.38k
    op->size = 2;
1768
3.84k
  } else {
1769
3.84k
    uint8_t imm8 = 0;
1770
1771
3.84k
    read_byte(info, &imm8, *address);
1772
3.84k
    op->imm = (int8_t)imm8;
1773
3.84k
    op->size = 1;
1774
3.84k
  }
1775
1776
6.23k
  set_operand_size(info, op, 1);
1777
6.23k
}
1778
1779
static void ext_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1780
2.61k
{
1781
2.61k
  cs_m680x *m680x = &info->m680x;
1782
2.61k
  cs_m680x_op *op0 = &m680x->operands[m680x->op_count++];
1783
2.61k
  uint16_t imm16 = 0;
1784
1785
2.61k
  indexed12_hdlr(MI, info, address);
1786
2.61k
  read_word(info, &imm16, *address);
1787
2.61k
  op0->type = M680X_OP_EXTENDED;
1788
2.61k
  op0->ext.address = (int16_t)imm16;
1789
2.61k
  set_operand_size(info, op0, 1);
1790
2.61k
}
1791
1792
// handler for CPU12 DBEQ/DNBE/IBEQ/IBNE/TBEQ/TBNE instructions.
1793
// Example: DBNE X,$1000
1794
static void loop_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1795
2.20k
{
1796
2.20k
  static const m680x_reg index_to_reg_id[] = {
1797
2.20k
    M680X_REG_A, M680X_REG_B, M680X_REG_INVALID, M680X_REG_INVALID,
1798
2.20k
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,       M680X_REG_S,
1799
2.20k
  };
1800
2.20k
  static const m680x_insn index_to_insn_id[] = {
1801
2.20k
    M680X_INS_DBEQ, M680X_INS_DBNE, M680X_INS_TBEQ,  M680X_INS_TBNE,
1802
2.20k
    M680X_INS_IBEQ, M680X_INS_IBNE, M680X_INS_ILLGL, M680X_INS_ILLGL
1803
2.20k
  };
1804
2.20k
  cs_m680x *m680x = &info->m680x;
1805
2.20k
  uint8_t post_byte = 0;
1806
2.20k
  uint8_t rel = 0;
1807
2.20k
  cs_m680x_op *op;
1808
1809
2.20k
  read_byte(info, &post_byte, (*address)++);
1810
1811
2.20k
  info->insn = index_to_insn_id[(post_byte >> 5) & 0x07];
1812
1813
2.20k
  if (info->insn == M680X_INS_ILLGL) {
1814
0
    illegal_hdlr(MI, info, address);
1815
0
  };
1816
1817
2.20k
  read_byte(info, &rel, (*address)++);
1818
1819
2.20k
  add_reg_operand(info, index_to_reg_id[post_byte & 0x07]);
1820
1821
2.20k
  op = &m680x->operands[m680x->op_count++];
1822
1823
2.20k
  op->type = M680X_OP_RELATIVE;
1824
1825
2.20k
  op->rel.offset = (post_byte & 0x10) ? (int16_t)(0xff00 | rel) : rel;
1826
1827
2.20k
  op->rel.address = *address + op->rel.offset;
1828
1829
2.20k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1830
2.20k
}
1831
1832
// handler for RS08 specific TNY instruction
1833
// The operand address is embedded in the the least 4 significant bits of the opcode
1834
static void tny_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1835
2.49k
{
1836
2.49k
  cs_m680x *m680x = &info->m680x;
1837
2.49k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1838
1839
2.49k
  op->type = M680X_OP_DIRECT;
1840
2.49k
  op->direct_addr = (uint8_t)(MI->Opcode & 0x0F);
1841
2.49k
  op->size = 1;
1842
2.49k
}
1843
1844
// handler for RS08 specific SRT instruction
1845
// The operand address is embedded in the the least 5 significant bits of the opcode
1846
static void srt_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1847
6.54k
{
1848
6.54k
  cs_m680x *m680x = &info->m680x;
1849
6.54k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1850
1851
6.54k
  op->type = M680X_OP_DIRECT;
1852
6.54k
  op->direct_addr = (uint8_t)(MI->Opcode & 0x1F);
1853
6.54k
  op->size = 1;
1854
6.54k
}
1855
1856
static void dirdir_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1857
444
{
1858
444
  direct_hdlr(MI, info, address);
1859
444
  direct_hdlr(MI, info, address);
1860
444
}
1861
1862
static void immdir_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1863
331
{
1864
331
  immediate_hdlr(MI, info, address);
1865
331
  direct_hdlr(MI, info, address);
1866
331
}
1867
1868
static void (*const g_insn_handler[])(MCInst *, m680x_info *, uint16_t *) = {
1869
  illegal_hdlr,   relative8_hdlr,   relative16_hdlr,
1870
  immediate_hdlr, // 8-bit
1871
  immediate_hdlr, // 16-bit
1872
  immediate_hdlr, // 32-bit
1873
  direct_hdlr,    extended_hdlr,    indexedX_hdlr,   indexedY_hdlr,
1874
  indexed09_hdlr,   inherent_hdlr,    reg_reg09_hdlr,  reg_bits_hdlr,
1875
  bit_move_hdlr,    tfm_hdlr,     opidx_hdlr,      opidx_dir_rel_hdlr,
1876
  indexedX0_hdlr,   indexedX16_hdlr,  imm_rel_hdlr,    indexedS_hdlr,
1877
  indexedS16_hdlr,  indexedXp_hdlr,   indexedX0p_hdlr, indexed12_hdlr,
1878
  indexed12_hdlr, // subset of indexed12
1879
  reg_reg12_hdlr,   loop_hdlr,      index_hdlr,      imm_idx12_x_hdlr,
1880
  imm_idx12_x_hdlr, ext_idx12_x_hdlr, srt_hdlr,      tny_hdlr,
1881
  dirdir_hdlr,    immdir_hdlr
1882
}; /* handler function pointers */
1883
1884
/* Disasemble one instruction at address and store in str_buff */
1885
static unsigned int m680x_disassemble(MCInst *MI, m680x_info *info,
1886
              uint16_t address)
1887
452k
{
1888
452k
  cs_m680x *m680x = &info->m680x;
1889
452k
  cs_detail *detail = MI->flat_insn->detail;
1890
452k
  uint16_t base_address = address;
1891
452k
  insn_desc insn_description;
1892
452k
  e_access_mode access_mode;
1893
1894
452k
  if (detail != NULL) {
1895
452k
    memset(detail, 0,
1896
452k
           offsetof(cs_detail, m680x) + sizeof(cs_m680x));
1897
452k
  }
1898
1899
452k
  memset(&insn_description, 0, sizeof(insn_description));
1900
452k
  memset(m680x, 0, sizeof(*m680x));
1901
452k
  info->insn_size = 1;
1902
1903
452k
  if (decode_insn(info, address, &insn_description)) {
1904
406k
    m680x_reg reg;
1905
1906
406k
    if (insn_description.opcode > 0xff)
1907
23.9k
      address += 2; // 8-bit opcode + page prefix
1908
382k
    else
1909
382k
      address++; // 8-bit opcode only
1910
1911
406k
    info->insn = insn_description.insn;
1912
1913
406k
    MCInst_setOpcode(MI, insn_description.opcode);
1914
1915
406k
    reg = g_insn_props[info->insn].reg0;
1916
1917
406k
    if (reg != M680X_REG_INVALID) {
1918
220k
      if (reg == M680X_REG_HX &&
1919
1.91k
          (!info->cpu->reg_byte_size[reg]))
1920
529
        reg = M680X_REG_X;
1921
1922
220k
      add_reg_operand(info, reg);
1923
      // First (or second) operand is a register which is
1924
      // part of the mnemonic
1925
220k
      m680x->flags |= M680X_FIRST_OP_IN_MNEM;
1926
220k
      reg = g_insn_props[info->insn].reg1;
1927
1928
220k
      if (reg != M680X_REG_INVALID) {
1929
7.01k
        if (reg == M680X_REG_HX &&
1930
1.01k
            (!info->cpu->reg_byte_size[reg]))
1931
536
          reg = M680X_REG_X;
1932
1933
7.01k
        add_reg_operand(info, reg);
1934
7.01k
        m680x->flags |= M680X_SECOND_OP_IN_MNEM;
1935
7.01k
      }
1936
220k
    }
1937
1938
    // Call addressing mode specific instruction handler
1939
406k
    (g_insn_handler[insn_description.hid[0]])(MI, info, &address);
1940
406k
    (g_insn_handler[insn_description.hid[1]])(MI, info, &address);
1941
1942
406k
    add_insn_group(detail, g_insn_props[info->insn].group);
1943
1944
406k
    if (g_insn_props[info->insn].cc_modified &&
1945
265k
        (info->cpu->insn_cc_not_modified[0] != info->insn) &&
1946
264k
        (info->cpu->insn_cc_not_modified[1] != info->insn))
1947
262k
      add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1948
1949
406k
    access_mode = g_insn_props[info->insn].access_mode;
1950
1951
    // Fix for M6805 BSET/BCLR. It has a different operand order
1952
    // in comparison to the M6811
1953
406k
    if ((info->cpu->insn_cc_not_modified[0] == info->insn) ||
1954
405k
        (info->cpu->insn_cc_not_modified[1] == info->insn))
1955
2.74k
      access_mode = rmmm;
1956
1957
406k
    build_regs_read_write_counts(MI, info, access_mode);
1958
406k
    add_operators_access(MI, info, access_mode);
1959
1960
406k
    if (g_insn_props[info->insn].update_reg_access)
1961
37.9k
      set_changed_regs_read_write_counts(MI, info);
1962
1963
406k
    info->insn_size = (uint8_t)insn_description.insn_size;
1964
1965
406k
    return info->insn_size;
1966
406k
  } else
1967
45.6k
    MCInst_setOpcode(MI, insn_description.opcode);
1968
1969
  // Illegal instruction
1970
45.6k
  address = base_address;
1971
45.6k
  illegal_hdlr(MI, info, &address);
1972
45.6k
  return 1;
1973
452k
}
1974
1975
// Tables to get the byte size of a register on the CPU
1976
// based on an enum m680x_reg value defined in m680x.h
1977
// Invalid registers return 0.
1978
static const uint8_t g_m6800_reg_byte_size[23] = {
1979
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
1980
  0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 0, 0, 0
1981
};
1982
1983
static const uint8_t g_m6805_reg_byte_size[23] = {
1984
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
1985
  0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 2, 0, 0, 0
1986
};
1987
1988
static const uint8_t g_m6808_reg_byte_size[23] = {
1989
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
1990
  0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 1, 1, 0, 2, 0, 0, 0, 2, 0, 0, 0
1991
};
1992
1993
static const uint8_t g_m6801_reg_byte_size[23] = {
1994
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
1995
  0, 1, 1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 0, 0, 0
1996
};
1997
1998
static const uint8_t g_m6811_reg_byte_size[23] = {
1999
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
2000
  0, 1, 1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 2, 0, 0, 0
2001
};
2002
2003
static const uint8_t g_cpu12_reg_byte_size[23] = {
2004
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
2005
  0, 1, 1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 2, 0, 2, 2
2006
};
2007
2008
static const uint8_t g_m6809_reg_byte_size[23] = {
2009
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
2010
  0, 1, 1, 0, 0, 0, 2, 0, 1, 1, 0, 0, 0, 2, 2, 2, 2, 0, 0, 2, 0, 0, 0
2011
};
2012
2013
static const uint8_t g_hd6309_reg_byte_size[23] = {
2014
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
2015
  0, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 0, 0, 2, 2, 2, 2, 2, 4, 2, 0, 0, 0
2016
};
2017
2018
static const uint8_t g_rs08_reg_byte_size[23] = {
2019
  // A  B  E  F  0  D  W  CC DP MD HX H  X  Y  S  U  V  Q  PC SPC T2 T3
2020
  0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 1, 1, 0, 2, 0, 0, 0, 2, 2, 0, 0
2021
};
2022
2023
// Table to check for a valid register nibble on the M6809 CPU
2024
// used for TFR and EXG instruction.
2025
static const bool m6809_tfr_reg_valid[16] = {
2026
  true, true, true, true, true,  true,  false, false,
2027
  true, true, true, true, false, false, false, false,
2028
};
2029
2030
static const cpu_tables g_cpu_tables[] = {
2031
  { // M680X_CPU_TYPE_INVALID
2032
    NULL,
2033
    { NULL, NULL },
2034
    { 0, 0 },
2035
    { 0x00, 0x00, 0x00 },
2036
    { NULL, NULL, NULL },
2037
    { 0, 0, 0 },
2038
    NULL,
2039
    NULL,
2040
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2041
  { // M680X_CPU_TYPE_6301
2042
    &g_m6800_inst_page1_table[0],
2043
    { &g_m6801_inst_overlay_table[0], &g_hd6301_inst_overlay_table[0] },
2044
    { ARR_SIZE(g_m6801_inst_overlay_table),
2045
      ARR_SIZE(g_hd6301_inst_overlay_table) },
2046
    { 0x00, 0x00, 0x00 },
2047
    { NULL, NULL, NULL },
2048
    { 0, 0, 0 },
2049
    &g_m6801_reg_byte_size[0],
2050
    NULL,
2051
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2052
  { // M680X_CPU_TYPE_6309
2053
    &g_m6809_inst_page1_table[0],
2054
    { &g_hd6309_inst_overlay_table[0], NULL },
2055
    { ARR_SIZE(g_hd6309_inst_overlay_table), 0 },
2056
    { 0x10, 0x11, 0x00 },
2057
    { &g_hd6309_inst_page2_table[0], &g_hd6309_inst_page3_table[0],
2058
      NULL },
2059
    { ARR_SIZE(g_hd6309_inst_page2_table),
2060
      ARR_SIZE(g_hd6309_inst_page3_table), 0 },
2061
    &g_hd6309_reg_byte_size[0],
2062
    NULL,
2063
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2064
  { // M680X_CPU_TYPE_6800
2065
    &g_m6800_inst_page1_table[0],
2066
    { NULL, NULL },
2067
    { 0, 0 },
2068
    { 0x00, 0x00, 0x00 },
2069
    { NULL, NULL, NULL },
2070
    { 0, 0, 0 },
2071
    &g_m6800_reg_byte_size[0],
2072
    NULL,
2073
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2074
  { // M680X_CPU_TYPE_6801
2075
    &g_m6800_inst_page1_table[0],
2076
    { &g_m6801_inst_overlay_table[0], NULL },
2077
    { ARR_SIZE(g_m6801_inst_overlay_table), 0 },
2078
    { 0x00, 0x00, 0x00 },
2079
    { NULL, NULL, NULL },
2080
    { 0, 0, 0 },
2081
    &g_m6801_reg_byte_size[0],
2082
    NULL,
2083
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2084
  { // M680X_CPU_TYPE_6805
2085
    &g_m6805_inst_page1_table[0],
2086
    { NULL, NULL },
2087
    { 0, 0 },
2088
    { 0x00, 0x00, 0x00 },
2089
    { NULL, NULL, NULL },
2090
    { 0, 0, 0 },
2091
    &g_m6805_reg_byte_size[0],
2092
    NULL,
2093
    { M680X_INS_BCLR, M680X_INS_BSET } },
2094
  { // M680X_CPU_TYPE_6808
2095
    &g_m6805_inst_page1_table[0],
2096
    { &g_m6808_inst_overlay_table[0], NULL },
2097
    { ARR_SIZE(g_m6808_inst_overlay_table), 0 },
2098
    { 0x9E, 0x00, 0x00 },
2099
    { &g_m6808_inst_page2_table[0], NULL, NULL },
2100
    { ARR_SIZE(g_m6808_inst_page2_table), 0, 0 },
2101
    &g_m6808_reg_byte_size[0],
2102
    NULL,
2103
    { M680X_INS_BCLR, M680X_INS_BSET } },
2104
  { // M680X_CPU_TYPE_6809
2105
    &g_m6809_inst_page1_table[0],
2106
    { NULL, NULL },
2107
    { 0, 0 },
2108
    { 0x10, 0x11, 0x00 },
2109
    { &g_m6809_inst_page2_table[0], &g_m6809_inst_page3_table[0], NULL },
2110
    { ARR_SIZE(g_m6809_inst_page2_table),
2111
      ARR_SIZE(g_m6809_inst_page3_table), 0 },
2112
    &g_m6809_reg_byte_size[0],
2113
    &m6809_tfr_reg_valid[0],
2114
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2115
  { // M680X_CPU_TYPE_6811
2116
    &g_m6800_inst_page1_table[0],
2117
    { &g_m6801_inst_overlay_table[0], &g_m6811_inst_overlay_table[0] },
2118
    { ARR_SIZE(g_m6801_inst_overlay_table),
2119
      ARR_SIZE(g_m6811_inst_overlay_table) },
2120
    { 0x18, 0x1A, 0xCD },
2121
    { &g_m6811_inst_page2_table[0], &g_m6811_inst_page3_table[0],
2122
      &g_m6811_inst_page4_table[0] },
2123
    { ARR_SIZE(g_m6811_inst_page2_table),
2124
      ARR_SIZE(g_m6811_inst_page3_table),
2125
      ARR_SIZE(g_m6811_inst_page4_table) },
2126
    &g_m6811_reg_byte_size[0],
2127
    NULL,
2128
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2129
  { // M680X_CPU_TYPE_CPU12
2130
    &g_cpu12_inst_page1_table[0],
2131
    { NULL, NULL },
2132
    { 0, 0 },
2133
    { 0x18, 0x00, 0x00 },
2134
    { &g_cpu12_inst_page2_table[0], NULL, NULL },
2135
    { ARR_SIZE(g_cpu12_inst_page2_table), 0, 0 },
2136
    &g_cpu12_reg_byte_size[0],
2137
    NULL,
2138
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2139
  { // M680X_CPU_TYPE_HCS08
2140
    &g_m6805_inst_page1_table[0],
2141
    { &g_m6808_inst_overlay_table[0], &g_hcs08_inst_overlay_table[0] },
2142
    { ARR_SIZE(g_m6808_inst_overlay_table),
2143
      ARR_SIZE(g_hcs08_inst_overlay_table) },
2144
    { 0x9E, 0x00, 0x00 },
2145
    { &g_hcs08_inst_page2_table[0], NULL, NULL },
2146
    { ARR_SIZE(g_hcs08_inst_page2_table), 0, 0 },
2147
    &g_m6808_reg_byte_size[0],
2148
    NULL,
2149
    { M680X_INS_BCLR, M680X_INS_BSET } },
2150
  { // M680X_CPU_TYPE_RS08
2151
    &g_rs08_inst_page1_table[0],
2152
    { NULL, NULL },
2153
    { 0, 0 },
2154
    { 0x00, 0x00, 0x00 },
2155
    { NULL, NULL, NULL },
2156
    { 0, 0, 0 },
2157
    &g_rs08_reg_byte_size[0],
2158
    NULL,
2159
    { M680X_INS_INVLD, M680X_INS_INVLD } },
2160
};
2161
2162
static bool m680x_setup_internals(m680x_info *info, e_cpu_type cpu_type,
2163
          uint16_t address, const uint8_t *code,
2164
          uint16_t code_len)
2165
452k
{
2166
452k
  if (cpu_type == M680X_CPU_TYPE_INVALID) {
2167
0
    return false;
2168
0
  }
2169
2170
452k
  info->code = code;
2171
452k
  info->size = code_len;
2172
452k
  info->offset = address;
2173
452k
  info->cpu_type = cpu_type;
2174
2175
452k
  info->cpu = &g_cpu_tables[info->cpu_type];
2176
2177
452k
  return true;
2178
452k
}
2179
2180
bool M680X_getInstruction(csh ud, const uint8_t *code, size_t code_len,
2181
        MCInst *MI, uint16_t *size, uint64_t address,
2182
        void *inst_info)
2183
261k
{
2184
261k
  unsigned int insn_size = 0;
2185
261k
  e_cpu_type cpu_type = M680X_CPU_TYPE_INVALID; // No default CPU type
2186
261k
  cs_struct *handle = (cs_struct *)ud;
2187
261k
  m680x_info *info = (m680x_info *)handle->printer_info;
2188
2189
261k
  MCInst_clear(MI);
2190
2191
261k
  if (handle->mode & CS_MODE_M680X_6800)
2192
1.40k
    cpu_type = M680X_CPU_TYPE_6800;
2193
2194
260k
  else if (handle->mode & CS_MODE_M680X_6801)
2195
4.05k
    cpu_type = M680X_CPU_TYPE_6801;
2196
2197
256k
  else if (handle->mode & CS_MODE_M680X_6805)
2198
4.08k
    cpu_type = M680X_CPU_TYPE_6805;
2199
2200
252k
  else if (handle->mode & CS_MODE_M680X_6808)
2201
11.6k
    cpu_type = M680X_CPU_TYPE_6808;
2202
2203
240k
  else if (handle->mode & CS_MODE_M680X_HCS08)
2204
11.6k
    cpu_type = M680X_CPU_TYPE_HCS08;
2205
2206
228k
  else if (handle->mode & CS_MODE_M680X_6809)
2207
23.9k
    cpu_type = M680X_CPU_TYPE_6809;
2208
2209
204k
  else if (handle->mode & CS_MODE_M680X_6301)
2210
3.90k
    cpu_type = M680X_CPU_TYPE_6301;
2211
2212
201k
  else if (handle->mode & CS_MODE_M680X_6309)
2213
77.5k
    cpu_type = M680X_CPU_TYPE_6309;
2214
2215
123k
  else if (handle->mode & CS_MODE_M680X_6811)
2216
11.4k
    cpu_type = M680X_CPU_TYPE_6811;
2217
2218
112k
  else if (handle->mode & CS_MODE_M680X_CPU12)
2219
91.5k
    cpu_type = M680X_CPU_TYPE_CPU12;
2220
2221
20.4k
  else if (handle->mode & CS_MODE_M680X_RS08)
2222
20.4k
    cpu_type = M680X_CPU_TYPE_RS08;
2223
2224
261k
  if (cpu_type != M680X_CPU_TYPE_INVALID &&
2225
261k
      m680x_setup_internals(info, cpu_type, (uint16_t)address, code,
2226
261k
          (uint16_t)code_len))
2227
261k
    insn_size = m680x_disassemble(MI, info, (uint16_t)address);
2228
2229
261k
  if (insn_size == 0) {
2230
0
    *size = 1;
2231
0
    return false;
2232
0
  }
2233
2234
  // Make sure we always stay within range
2235
261k
  if (insn_size > code_len) {
2236
14
    *size = (uint16_t)code_len;
2237
14
    return false;
2238
14
  } else
2239
261k
    *size = (uint16_t)insn_size;
2240
2241
261k
  return true;
2242
261k
}
2243
2244
cs_err M680X_disassembler_init(cs_struct *ud)
2245
1.82k
{
2246
1.82k
  if (M680X_REG_ENDING != ARR_SIZE(g_m6800_reg_byte_size)) {
2247
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6800_reg_byte_size));
2248
2249
0
    return CS_ERR_MODE;
2250
0
  }
2251
2252
1.82k
  if (M680X_REG_ENDING != ARR_SIZE(g_m6801_reg_byte_size)) {
2253
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6801_reg_byte_size));
2254
2255
0
    return CS_ERR_MODE;
2256
0
  }
2257
2258
1.82k
  if (M680X_REG_ENDING != ARR_SIZE(g_m6805_reg_byte_size)) {
2259
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6805_reg_byte_size));
2260
2261
0
    return CS_ERR_MODE;
2262
0
  }
2263
2264
1.82k
  if (M680X_REG_ENDING != ARR_SIZE(g_m6808_reg_byte_size)) {
2265
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6808_reg_byte_size));
2266
2267
0
    return CS_ERR_MODE;
2268
0
  }
2269
2270
1.82k
  if (M680X_REG_ENDING != ARR_SIZE(g_m6811_reg_byte_size)) {
2271
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6811_reg_byte_size));
2272
2273
0
    return CS_ERR_MODE;
2274
0
  }
2275
2276
1.82k
  if (M680X_REG_ENDING != ARR_SIZE(g_cpu12_reg_byte_size)) {
2277
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_cpu12_reg_byte_size));
2278
2279
0
    return CS_ERR_MODE;
2280
0
  }
2281
2282
1.82k
  if (M680X_REG_ENDING != ARR_SIZE(g_m6809_reg_byte_size)) {
2283
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_m6809_reg_byte_size));
2284
2285
0
    return CS_ERR_MODE;
2286
0
  }
2287
2288
1.82k
  if (M680X_REG_ENDING != ARR_SIZE(g_rs08_reg_byte_size)) {
2289
0
    CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(g_rs08_reg_byte_size));
2290
2291
0
    return CS_ERR_MODE;
2292
0
  }
2293
2294
1.82k
  if (M680X_INS_ENDING != ARR_SIZE(g_insn_props)) {
2295
0
    CS_ASSERT(M680X_INS_ENDING == ARR_SIZE(g_insn_props));
2296
2297
0
    return CS_ERR_MODE;
2298
0
  }
2299
2300
1.82k
  if (M680X_CPU_TYPE_ENDING != ARR_SIZE(g_cpu_tables)) {
2301
0
    CS_ASSERT(M680X_CPU_TYPE_ENDING == ARR_SIZE(g_cpu_tables));
2302
2303
0
    return CS_ERR_MODE;
2304
0
  }
2305
2306
1.82k
  if (HANDLER_ID_ENDING != ARR_SIZE(g_insn_handler)) {
2307
0
    CS_ASSERT(HANDLER_ID_ENDING == ARR_SIZE(g_insn_handler));
2308
2309
0
    return CS_ERR_MODE;
2310
0
  }
2311
2312
1.82k
  if (ACCESS_MODE_ENDING != MATRIX_SIZE(g_access_mode_to_access)) {
2313
0
    CS_ASSERT(ACCESS_MODE_ENDING ==
2314
0
        MATRIX_SIZE(g_access_mode_to_access));
2315
2316
0
    return CS_ERR_MODE;
2317
0
  }
2318
2319
1.82k
  return CS_ERR_OK;
2320
1.82k
}
2321
2322
#ifndef CAPSTONE_DIET
2323
void M680X_reg_access(const cs_insn *insn, cs_regs regs_read,
2324
          uint8_t *regs_read_count, cs_regs regs_write,
2325
          uint8_t *regs_write_count)
2326
0
{
2327
0
  if (insn->detail == NULL) {
2328
0
    *regs_read_count = 0;
2329
0
    *regs_write_count = 0;
2330
0
  } else {
2331
0
    *regs_read_count = insn->detail->regs_read_count;
2332
0
    *regs_write_count = insn->detail->regs_write_count;
2333
2334
0
    memcpy(regs_read, insn->detail->regs_read,
2335
0
           *regs_read_count * sizeof(insn->detail->regs_read[0]));
2336
0
    memcpy(regs_write, insn->detail->regs_write,
2337
0
           *regs_write_count * sizeof(insn->detail->regs_write[0]));
2338
0
  }
2339
0
}
2340
#endif
2341
2342
#endif