Coverage Report

Created: 2026-09-03 07:09

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