Coverage Report

Created: 2026-10-17 07:17

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
199k
#define READ CS_AC_READ
113
289k
#define WRITE CS_AC_WRITE
114
325k
#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
510k
{
162
510k
  if (address < info->offset ||
163
510k
      (uint32_t)(address - info->offset) >= info->size)
164
    // out of code buffer range
165
1.12k
    return false;
166
167
509k
  *byte = info->code[address - info->offset];
168
169
509k
  return true;
170
510k
}
171
172
static bool read_byte_sign_extended(const m680x_info *info, int16_t *word,
173
            uint16_t address)
174
30.8k
{
175
30.8k
  if (address < info->offset ||
176
30.8k
      (uint32_t)(address - info->offset) >= info->size)
177
    // out of code buffer range
178
0
    return false;
179
180
30.8k
  *word = (int16_t)info->code[address - info->offset];
181
182
30.8k
  if (*word & 0x80)
183
14.1k
    *word |= 0xFF00;
184
185
30.8k
  return true;
186
30.8k
}
187
188
static bool read_word(const m680x_info *info, uint16_t *word, uint16_t address)
189
36.7k
{
190
36.7k
  if (address < info->offset ||
191
36.7k
      (uint32_t)(address + 1 - info->offset) >= info->size)
192
    // out of code buffer range
193
9
    return false;
194
195
36.7k
  *word = (uint16_t)info->code[address - info->offset] << 8;
196
36.7k
  *word |= (uint16_t)info->code[address + 1 - info->offset];
197
198
36.7k
  return true;
199
36.7k
}
200
201
static bool read_sdword(const m680x_info *info, int32_t *sdword,
202
      uint16_t address)
203
336
{
204
336
  if (address < info->offset ||
205
336
      (uint32_t)(address + 3 - info->offset) >= info->size)
206
    // out of code buffer range
207
0
    return false;
208
209
336
  *sdword = (uint32_t)info->code[address - info->offset] << 24;
210
336
  *sdword |= (uint32_t)info->code[address + 1 - info->offset] << 16;
211
336
  *sdword |= (uint32_t)info->code[address + 2 - info->offset] << 8;
212
336
  *sdword |= (uint32_t)info->code[address + 3 - info->offset];
213
214
336
  return true;
215
336
}
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
70.8k
{
224
  // As part of the algorithm last may get negative.
225
  // => signed integer has to be used.
226
70.8k
  int first = 0;
227
70.8k
  int last = (int)table_size - 1;
228
70.8k
  int middle = (first + last) / 2;
229
230
377k
  while (first <= last) {
231
348k
    if (inst_pageX_table[middle].opcode < opcode) {
232
106k
      first = middle + 1;
233
241k
    } else if (inst_pageX_table[middle].opcode == opcode) {
234
42.3k
      return middle; /* item found */
235
42.3k
    } else
236
199k
      last = middle - 1;
237
238
306k
    middle = (first + last) / 2;
239
306k
  }
240
241
28.4k
  if (first > last)
242
28.4k
    return -1; /* item not found */
243
244
0
  return -2;
245
28.4k
}
246
247
void M680X_get_insn_id(cs_struct *handle, cs_insn *insn, unsigned int id)
248
212k
{
249
212k
  const m680x_info *const info = (const m680x_info *)handle->printer_info;
250
212k
  const cpu_tables *cpu = info->cpu;
251
212k
  uint8_t insn_prefix = (id >> 8) & 0xff;
252
  // opcode is the first instruction byte without the prefix.
253
212k
  uint8_t opcode = id & 0xff;
254
212k
  int index;
255
212k
  int i;
256
257
212k
  insn->id = M680X_INS_ILLGL;
258
259
483k
  for (i = 0; i < ARR_SIZE(cpu->pageX_prefix); ++i) {
260
478k
    if (cpu->pageX_table_size[i] == 0 ||
261
290k
        (cpu->inst_pageX_table[i] == NULL))
262
188k
      break;
263
264
290k
    if (cpu->pageX_prefix[i] == insn_prefix) {
265
18.6k
      index = binary_search(cpu->inst_pageX_table[i],
266
18.6k
                cpu->pageX_table_size[i], opcode);
267
18.6k
      insn->id =
268
18.6k
        (index >= 0) ?
269
13.5k
          cpu->inst_pageX_table[i][index].insn :
270
18.6k
          M680X_INS_ILLGL;
271
18.6k
      return;
272
18.6k
    }
273
290k
  }
274
275
193k
  if (insn_prefix != 0)
276
0
    return;
277
278
193k
  insn->id = cpu->inst_page1_table[id].insn;
279
280
193k
  if (insn->id != M680X_INS_ILLGL)
281
175k
    return;
282
283
  // Check if opcode byte is present in an overlay table
284
27.0k
  for (i = 0; i < ARR_SIZE(cpu->overlay_table_size); ++i) {
285
26.2k
    if (cpu->overlay_table_size[i] == 0 ||
286
16.7k
        (cpu->inst_overlay_table[i] == NULL))
287
9.53k
      break;
288
289
16.7k
    if ((index = binary_search(cpu->inst_overlay_table[i],
290
16.7k
             cpu->overlay_table_size[i],
291
16.7k
             opcode)) >= 0) {
292
7.68k
      insn->id = cpu->inst_overlay_table[i][index].insn;
293
7.68k
      return;
294
7.68k
    }
295
16.7k
  }
296
18.0k
}
297
298
static void add_insn_group(cs_detail *detail, m680x_group_type group)
299
201k
{
300
201k
  if (detail != NULL && (group != M680X_GRP_INVALID) &&
301
43.5k
      (group != M680X_GRP_ENDING))
302
43.5k
    detail->groups[detail->groups_count++] = (uint8_t)group;
303
201k
}
304
305
static bool exists_reg_list(uint16_t *regs, uint8_t count, m680x_reg reg)
306
603k
{
307
603k
  uint8_t i;
308
309
1.05M
  for (i = 0; i < count; ++i) {
310
468k
    if (regs[i] == (uint16_t)reg)
311
14.8k
      return true;
312
468k
  }
313
314
588k
  return false;
315
603k
}
316
317
static void add_reg_to_rw_list(MCInst *MI, m680x_reg reg, e_access access)
318
400k
{
319
400k
  cs_detail *detail = MI->flat_insn->detail;
320
321
400k
  if (detail == NULL || (reg == M680X_REG_INVALID))
322
0
    return;
323
324
400k
  switch (access) {
325
203k
  case MODIFY:
326
203k
    if (!exists_reg_list(detail->regs_read, detail->regs_read_count,
327
203k
             reg))
328
200k
      detail->regs_read[detail->regs_read_count++] =
329
200k
        (uint16_t)reg;
330
331
    // intentionally fall through
332
333
276k
  case WRITE:
334
276k
    if (!exists_reg_list(detail->regs_write,
335
276k
             detail->regs_write_count, reg))
336
271k
      detail->regs_write[detail->regs_write_count++] =
337
271k
        (uint16_t)reg;
338
339
276k
    break;
340
341
124k
  case READ:
342
124k
    if (!exists_reg_list(detail->regs_read, detail->regs_read_count,
343
124k
             reg))
344
117k
      detail->regs_read[detail->regs_read_count++] =
345
117k
        (uint16_t)reg;
346
347
124k
    break;
348
349
0
  case UNCHANGED:
350
0
  default:
351
0
    break;
352
400k
  }
353
400k
}
354
355
static void update_am_reg_list(MCInst *MI, m680x_info *info, cs_m680x_op *op,
356
             e_access access)
357
284k
{
358
284k
  if (MI->flat_insn->detail == NULL)
359
0
    return;
360
361
284k
  switch (op->type) {
362
130k
  case M680X_OP_REGISTER:
363
130k
    add_reg_to_rw_list(MI, op->reg, access);
364
130k
    break;
365
366
53.5k
  case M680X_OP_INDEXED:
367
53.5k
    add_reg_to_rw_list(MI, op->idx.base_reg, READ);
368
369
53.5k
    if (op->idx.base_reg == M680X_REG_X &&
370
19.9k
        info->cpu->reg_byte_size[M680X_REG_H])
371
4.27k
      add_reg_to_rw_list(MI, M680X_REG_H, READ);
372
373
53.5k
    if (op->idx.offset_reg != M680X_REG_INVALID)
374
5.51k
      add_reg_to_rw_list(MI, op->idx.offset_reg, READ);
375
376
53.5k
    if (op->idx.inc_dec) {
377
11.7k
      add_reg_to_rw_list(MI, op->idx.base_reg, WRITE);
378
379
11.7k
      if (op->idx.base_reg == M680X_REG_X &&
380
3.34k
          info->cpu->reg_byte_size[M680X_REG_H])
381
785
        add_reg_to_rw_list(MI, M680X_REG_H, WRITE);
382
11.7k
    }
383
384
53.5k
    break;
385
386
100k
  default:
387
100k
    break;
388
284k
  }
389
284k
}
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
610k
{
464
610k
  int idx = (operator_index > 3) ? 3 : operator_index;
465
466
610k
  return g_access_mode_to_access[idx][access_mode];
467
610k
}
468
469
static void build_regs_read_write_counts(MCInst *MI, m680x_info *info,
470
           e_access_mode access_mode)
471
186k
{
472
186k
  cs_m680x *m680x = &info->m680x;
473
186k
  int i;
474
475
186k
  if (MI->flat_insn->detail == NULL || (!m680x->op_count))
476
23.2k
    return;
477
478
447k
  for (i = 0; i < m680x->op_count; ++i) {
479
284k
    e_access access = get_access(i, access_mode);
480
284k
    update_am_reg_list(MI, info, &m680x->operands[i], access);
481
284k
  }
482
162k
}
483
484
static void add_operators_access(MCInst *MI, m680x_info *info,
485
         e_access_mode access_mode)
486
186k
{
487
186k
  cs_m680x *m680x = &info->m680x;
488
186k
  int offset = 0;
489
186k
  int i;
490
491
186k
  if (MI->flat_insn->detail == NULL || (!m680x->op_count) ||
492
162k
      (access_mode == uuuu))
493
41.0k
    return;
494
495
411k
  for (i = 0; i < m680x->op_count; ++i) {
496
266k
    e_access access;
497
498
    // Ugly fix: MULD has a register operand, an immediate operand
499
    // AND an implicitly changed register W
500
266k
    if (info->insn == M680X_INS_MULD && (i == 1))
501
230
      offset = 1;
502
503
266k
    access = get_access(i + offset, access_mode);
504
266k
    m680x->operands[i].access = access;
505
266k
  }
506
145k
}
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
18.8k
{
516
  //TABLE
517
1.04M
#define EOL M680X_REG_INVALID
518
18.8k
  static const insn_to_changed_regs changed_regs[] = {
519
18.8k
    { M680X_INS_BSR, mmmm, { M680X_REG_S, EOL } },
520
18.8k
    { M680X_INS_CALL, mmmm, { M680X_REG_S, EOL } },
521
18.8k
    {
522
18.8k
      M680X_INS_CWAI,
523
18.8k
      mrrr,
524
18.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
525
18.8k
        M680X_REG_X, M680X_REG_DP, M680X_REG_D, M680X_REG_CC,
526
18.8k
        EOL },
527
18.8k
    },
528
18.8k
    { M680X_INS_DAA, mrrr, { M680X_REG_A, EOL } },
529
18.8k
    { M680X_INS_DIV,
530
18.8k
      mmrr,
531
18.8k
      { M680X_REG_A, M680X_REG_H, M680X_REG_X, EOL } },
532
18.8k
    { M680X_INS_EDIV,
533
18.8k
      mmrr,
534
18.8k
      { M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL } },
535
18.8k
    { M680X_INS_EDIVS,
536
18.8k
      mmrr,
537
18.8k
      { M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL } },
538
18.8k
    { M680X_INS_EMACS, mrrr, { M680X_REG_X, M680X_REG_Y, EOL } },
539
18.8k
    { M680X_INS_EMAXM, rrrr, { M680X_REG_D, EOL } },
540
18.8k
    { M680X_INS_EMINM, rrrr, { M680X_REG_D, EOL } },
541
18.8k
    { M680X_INS_EMUL, mmrr, { M680X_REG_D, M680X_REG_Y, EOL } },
542
18.8k
    { M680X_INS_EMULS, mmrr, { M680X_REG_D, M680X_REG_Y, EOL } },
543
18.8k
    { M680X_INS_ETBL, wmmm, { M680X_REG_A, M680X_REG_B, EOL } },
544
18.8k
    { M680X_INS_FDIV, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
545
18.8k
    { M680X_INS_IDIV, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
546
18.8k
    { M680X_INS_IDIVS, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
547
18.8k
    { M680X_INS_JSR, mmmm, { M680X_REG_S, EOL } },
548
18.8k
    { M680X_INS_LBSR, mmmm, { M680X_REG_S, EOL } },
549
18.8k
    { M680X_INS_MAXM, rrrr, { M680X_REG_A, EOL } },
550
18.8k
    { M680X_INS_MINM, rrrr, { M680X_REG_A, EOL } },
551
18.8k
    { M680X_INS_MEM,
552
18.8k
      mmrr,
553
18.8k
      { M680X_REG_X, M680X_REG_Y, M680X_REG_A, EOL } },
554
18.8k
    { M680X_INS_MUL, mmmm, { M680X_REG_A, M680X_REG_B, EOL } },
555
18.8k
    { M680X_INS_MULD, mwrr, { M680X_REG_D, M680X_REG_W, EOL } },
556
18.8k
    { M680X_INS_PSHA, rmmm, { M680X_REG_A, M680X_REG_S, EOL } },
557
18.8k
    { M680X_INS_PSHB, rmmm, { M680X_REG_B, M680X_REG_S, EOL } },
558
18.8k
    { M680X_INS_PSHC, rmmm, { M680X_REG_CC, M680X_REG_S, EOL } },
559
18.8k
    { M680X_INS_PSHD, rmmm, { M680X_REG_D, M680X_REG_S, EOL } },
560
18.8k
    { M680X_INS_PSHH, rmmm, { M680X_REG_H, M680X_REG_S, EOL } },
561
18.8k
    { M680X_INS_PSHX, rmmm, { M680X_REG_X, M680X_REG_S, EOL } },
562
18.8k
    { M680X_INS_PSHY, rmmm, { M680X_REG_Y, M680X_REG_S, EOL } },
563
18.8k
    { M680X_INS_PULA, wmmm, { M680X_REG_A, M680X_REG_S, EOL } },
564
18.8k
    { M680X_INS_PULB, wmmm, { M680X_REG_B, M680X_REG_S, EOL } },
565
18.8k
    { M680X_INS_PULC, wmmm, { M680X_REG_CC, M680X_REG_S, EOL } },
566
18.8k
    { M680X_INS_PULD, wmmm, { M680X_REG_D, M680X_REG_S, EOL } },
567
18.8k
    { M680X_INS_PULH, wmmm, { M680X_REG_H, M680X_REG_S, EOL } },
568
18.8k
    { M680X_INS_PULX, wmmm, { M680X_REG_X, M680X_REG_S, EOL } },
569
18.8k
    { M680X_INS_PULY, wmmm, { M680X_REG_Y, M680X_REG_S, EOL } },
570
18.8k
    { M680X_INS_REV,
571
18.8k
      mmrr,
572
18.8k
      { M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL } },
573
18.8k
    { M680X_INS_REVW,
574
18.8k
      mmmm,
575
18.8k
      { M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL } },
576
18.8k
    { M680X_INS_RTC, mwww, { M680X_REG_S, M680X_REG_PC, EOL } },
577
18.8k
    {
578
18.8k
      M680X_INS_RTI,
579
18.8k
      mwww,
580
18.8k
      { M680X_REG_S, M680X_REG_CC, M680X_REG_B, M680X_REG_A,
581
18.8k
        M680X_REG_DP, M680X_REG_X, M680X_REG_Y, M680X_REG_U,
582
18.8k
        M680X_REG_PC, EOL },
583
18.8k
    },
584
18.8k
    { M680X_INS_RTS, mwww, { M680X_REG_S, M680X_REG_PC, EOL } },
585
18.8k
    { M680X_INS_SEX, wrrr, { M680X_REG_A, M680X_REG_B, EOL } },
586
18.8k
    { M680X_INS_SEXW, rwww, { M680X_REG_W, M680X_REG_D, EOL } },
587
18.8k
    { M680X_INS_SWI,
588
18.8k
      mmrr,
589
18.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
590
18.8k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
591
18.8k
        M680X_REG_CC, EOL } },
592
18.8k
    {
593
18.8k
      M680X_INS_SWI2,
594
18.8k
      mmrr,
595
18.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
596
18.8k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
597
18.8k
        M680X_REG_CC, EOL },
598
18.8k
    },
599
18.8k
    {
600
18.8k
      M680X_INS_SWI3,
601
18.8k
      mmrr,
602
18.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
603
18.8k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
604
18.8k
        M680X_REG_CC, EOL },
605
18.8k
    },
606
18.8k
    { M680X_INS_TBL, wrrr, { M680X_REG_A, M680X_REG_B, EOL } },
607
18.8k
    { M680X_INS_WAI,
608
18.8k
      mrrr,
609
18.8k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_X, M680X_REG_A,
610
18.8k
        M680X_REG_B, M680X_REG_CC, EOL } },
611
18.8k
    { M680X_INS_WAV,
612
18.8k
      rmmm,
613
18.8k
      { M680X_REG_A, M680X_REG_B, M680X_REG_X, M680X_REG_Y, EOL } },
614
18.8k
    { M680X_INS_WAVR,
615
18.8k
      rmmm,
616
18.8k
      { M680X_REG_A, M680X_REG_B, M680X_REG_X, M680X_REG_Y, EOL } },
617
18.8k
  };
618
619
18.8k
  int i, j;
620
621
18.8k
  if (MI->flat_insn->detail == NULL)
622
0
    return;
623
624
979k
  for (i = 0; i < ARR_SIZE(changed_regs); ++i) {
625
960k
    if (info->insn == changed_regs[i].insn) {
626
18.8k
      e_access_mode access_mode = changed_regs[i].access_mode;
627
628
81.4k
      for (j = 0; changed_regs[i].regs[j] != EOL; ++j) {
629
62.5k
        e_access access;
630
631
62.5k
        m680x_reg reg = changed_regs[i].regs[j];
632
633
62.5k
        if (!info->cpu->reg_byte_size[reg]) {
634
3.00k
          if (info->insn != M680X_INS_MUL)
635
2.80k
            continue;
636
637
          // Hack for M68HC05: MUL uses reg. A,X
638
196
          reg = M680X_REG_X;
639
196
        }
640
641
59.7k
        access = get_access(j, access_mode);
642
59.7k
        add_reg_to_rw_list(MI, reg, access);
643
59.7k
      }
644
18.8k
    }
645
960k
  }
646
647
18.8k
#undef EOL
648
18.8k
}
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
25.4k
{
663
25.4k
  uint8_t ir = 0;
664
25.4k
  uint8_t post_byte;
665
666
  // Read the indexed addressing post byte.
667
25.4k
  if (!read_byte(info, &post_byte, address))
668
112
    return -1;
669
670
  // Depending on the indexed addressing mode more bytes have to be read.
671
25.3k
  switch (post_byte & 0x9F) {
672
309
  case 0x87:
673
968
  case 0x8A:
674
1.53k
  case 0x8E:
675
2.96k
  case 0x8F:
676
3.22k
  case 0x90:
677
3.65k
  case 0x92:
678
3.90k
  case 0x97:
679
4.12k
  case 0x9A:
680
4.45k
  case 0x9E:
681
4.45k
    return -1; // illegal indexed post bytes
682
683
1.19k
  case 0x88: // n8,R
684
1.72k
  case 0x8C: // n8,PCR
685
2.01k
  case 0x98: // [n8,R]
686
2.56k
  case 0x9C: // [n8,PCR]
687
2.56k
    if (!read_byte(info, &ir, address + 1))
688
21
      return -1;
689
2.54k
    return 2;
690
691
468
  case 0x89: // n16,R
692
1.10k
  case 0x8D: // n16,PCR
693
2.22k
  case 0x99: // [n16,R]
694
2.72k
  case 0x9D: // [n16,PCR]
695
2.72k
    if (!read_byte(info, &ir, address + 2))
696
33
      return -1;
697
2.69k
    return 3;
698
699
629
  case 0x9F: // [n]
700
629
    if ((post_byte & 0x60) != 0 ||
701
242
        !read_byte(info, &ir, address + 2))
702
394
      return -1;
703
235
    return 3;
704
25.3k
  }
705
706
  // Any other indexed post byte is valid and
707
  // no additional bytes have to be read.
708
15.0k
  return 1;
709
25.3k
}
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
22.3k
{
717
22.3k
  uint8_t ir;
718
22.3k
  uint8_t post_byte;
719
720
  // Read the indexed addressing post byte.
721
22.3k
  if (!read_byte(info, &post_byte, address))
722
94
    return -1;
723
724
  // Depending on the indexed addressing mode more bytes have to be read.
725
22.2k
  if (!(post_byte & 0x20)) // n5,R
726
7.20k
    return 1;
727
728
15.0k
  switch (post_byte & 0xe7) {
729
1.18k
  case 0xe0:
730
2.76k
  case 0xe1: // n9,R
731
2.76k
    if (is_subset)
732
250
      return -1;
733
734
2.51k
    if (!read_byte(info, &ir, address))
735
0
      return -1;
736
2.51k
    return 2;
737
738
851
  case 0xe2: // n16,R
739
2.35k
  case 0xe3: // [n16,R]
740
2.35k
    if (is_subset)
741
341
      return -1;
742
743
2.01k
    if (!read_byte(info, &ir, address + 1))
744
25
      return -1;
745
1.99k
    return 3;
746
747
1.49k
  case 0xe4: // A,R
748
2.12k
  case 0xe5: // B,R
749
2.51k
  case 0xe6: // D,R
750
3.13k
  case 0xe7: // [D,R]
751
9.95k
  default: // n,-r n,+r n,r- n,r+
752
9.95k
    break;
753
15.0k
  }
754
755
9.95k
  return 1;
756
15.0k
}
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
3.69k
{
761
3.69k
  if (info->cpu->tfr_reg_valid != NULL)
762
2.14k
    return info->cpu->tfr_reg_valid[reg_nibble];
763
764
1.54k
  return true; // e.g. for the M6309 all registers are valid
765
3.69k
}
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
960
{
771
960
  return !(post_byte & 0x08);
772
960
}
773
774
static bool is_tfm_reg_valid(const m680x_info *info, uint8_t reg_nibble)
775
3.96k
{
776
  // HD6809 TFM instruction: Only register X,Y,U,S,D is allowed
777
3.96k
  return reg_nibble <= 4;
778
3.96k
}
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
2.25k
{
785
2.25k
  uint8_t post_byte;
786
2.25k
  uint8_t rr;
787
788
2.25k
  if (!read_byte(info, &post_byte, address))
789
11
    return -1;
790
791
  // According to documentation bit 3 is don't care and not checked here.
792
2.24k
  if ((post_byte >= 0xc0) || ((post_byte & 0x07) == 2) ||
793
1.00k
      ((post_byte & 0x07) == 3))
794
1.44k
    return -1;
795
796
801
  if (!read_byte(info, &rr, address + 1))
797
8
    return -1;
798
799
793
  return 2;
800
801
}
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
604
{
808
604
  uint8_t post_byte;
809
604
  uint8_t rr;
810
811
604
  if (!read_byte(info, &post_byte, address))
812
3
    return -1;
813
814
601
  if ((post_byte & 0xc0) == 0xc0)
815
225
    return -1; // Invalid register specified
816
376
  else {
817
376
    if (!read_byte(info, &rr, address + 1))
818
4
      return -1;
819
376
  }
820
821
372
  return 2;
822
601
}
823
824
static bool is_sufficient_code_size(const m680x_info *info, uint16_t address,
825
            insn_desc *insn_description)
826
196k
{
827
196k
  int i;
828
196k
  bool retval = true;
829
196k
  uint16_t size = 0;
830
196k
  int sz;
831
832
569k
  for (i = 0; i < 2; i++) {
833
383k
    uint8_t ir = 0;
834
383k
    bool is_subset = false;
835
836
383k
    switch (insn_description->hid[i]) {
837
352
    case imm32_hid:
838
352
      if ((retval = read_byte(info, &ir, address + size + 3)))
839
336
        size += 4;
840
352
      break;
841
842
26.1k
    case ext_hid:
843
28.2k
    case imm16_hid:
844
29.2k
    case rel16_hid:
845
30.3k
    case imm8rel_hid:
846
31.6k
    case opidxdr_hid:
847
32.5k
    case idxX16_hid:
848
32.7k
    case idxS16_hid:
849
33.0k
    case dirdir_hid:
850
33.3k
    case immdir_hid:
851
33.3k
      if ((retval = read_byte(info, &ir, address + size + 1)))
852
32.9k
        size += 2;
853
33.3k
      break;
854
855
10.7k
    case rel8_hid:
856
35.1k
    case dir_hid:
857
40.2k
    case rbits_hid:
858
54.5k
    case imm8_hid:
859
57.3k
    case idxX_hid:
860
57.6k
    case idxXp_hid:
861
58.5k
    case idxY_hid:
862
59.0k
    case idxS_hid:
863
59.5k
    case index_hid:
864
59.5k
      if ((retval = read_byte(info, &ir, address + size)))
865
59.2k
        size++;
866
59.5k
      break;
867
868
0
    case illgl_hid:
869
222k
    case inh_hid:
870
225k
    case idxX0_hid:
871
225k
    case idxX0p_hid:
872
226k
    case opidx_hid:
873
231k
    case srt_hid:
874
233k
    case tny_hid:
875
233k
      retval = true;
876
233k
      break;
877
878
25.4k
    case idx09_hid:
879
25.4k
      sz = get_indexed09_post_byte_size(info, address + size);
880
25.4k
      if (sz >= 0)
881
20.4k
        size += sz;
882
5.01k
      else
883
5.01k
        retval = false;
884
25.4k
      break;
885
886
753
    case idx12s_hid:
887
753
      is_subset = true;
888
889
      // intentionally fall through
890
891
18.2k
    case idx12_hid:
892
18.2k
      sz = get_indexed12_post_byte_size(info, address + size,
893
18.2k
                is_subset);
894
18.2k
      if (sz >= 0)
895
17.5k
        size += sz;
896
695
      else
897
695
        retval = false;
898
18.2k
      break;
899
900
1.10k
    case exti12x_hid:
901
1.85k
    case imm16i12x_hid:
902
1.85k
      sz = get_indexed12_post_byte_size(info, address + size,
903
1.85k
                false);
904
1.85k
      if (sz >= 0) {
905
1.84k
        size += sz;
906
1.84k
        if ((retval = read_byte(info, &ir,
907
1.84k
              address + size + 1)))
908
1.82k
          size += 2;
909
1.84k
      } else
910
11
        retval = false;
911
1.85k
      break;
912
913
2.25k
    case imm8i12x_hid:
914
2.25k
      sz = get_indexed12_post_byte_size(info, address + size,
915
2.25k
                false);
916
2.25k
      if (sz >= 0) {
917
2.25k
        size += sz;
918
2.25k
        if ((retval = read_byte(info, &ir,
919
2.25k
              address + size)))
920
2.22k
          size++;
921
2.25k
      } else
922
4
        retval = false;
923
2.25k
      break;
924
925
2.54k
    case tfm_hid:
926
2.54k
      if ((retval = read_byte(info, &ir, address + size))) {
927
2.53k
        size++;
928
2.53k
        retval = is_tfm_reg_valid(info,
929
2.53k
                (ir >> 4) & 0x0F) &&
930
1.43k
           is_tfm_reg_valid(info, ir & 0x0F);
931
2.53k
      }
932
2.54k
      break;
933
934
1.97k
    case rr09_hid:
935
1.97k
      if ((retval = read_byte(info, &ir, address + size))) {
936
1.96k
        size++;
937
1.96k
        retval = is_tfr09_reg_valid(info,
938
1.96k
                  (ir >> 4) & 0x0F) &&
939
1.73k
           is_tfr09_reg_valid(info, ir & 0x0F);
940
1.96k
      }
941
1.97k
      break;
942
943
964
    case rr12_hid:
944
964
      if ((retval = read_byte(info, &ir, address + size))) {
945
960
        size++;
946
960
        retval = is_exg_tfr12_post_byte_valid(info, ir);
947
960
      }
948
964
      break;
949
950
604
    case bitmv_hid:
951
604
      sz = get_bitmv_post_byte_size(info, address + size);
952
604
      if (sz >= 0)
953
372
        size += sz;
954
232
      else
955
232
        retval = false;
956
604
      break;
957
958
2.25k
    case loop_hid:
959
2.25k
      sz = get_loop_post_byte_size(info, address + size);
960
2.25k
      if (sz >= 0)
961
793
        size += sz;
962
1.46k
      else
963
1.46k
        retval = false;
964
2.25k
      break;
965
966
0
    default:
967
0
      CS_ASSERT(0 && "Unexpected instruction handler id");
968
0
      retval = false;
969
0
      break;
970
383k
    }
971
972
383k
    if (!retval)
973
10.5k
      return false;
974
383k
  }
975
976
186k
  insn_description->insn_size += size;
977
978
186k
  return retval;
979
196k
}
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
212k
{
986
212k
  const inst_pageX *inst_table = NULL;
987
212k
  const cpu_tables *cpu = info->cpu;
988
212k
  size_t table_size = 0;
989
212k
  uint16_t base_address = address;
990
212k
  uint8_t ir; // instruction register
991
212k
  int i;
992
212k
  int index;
993
994
212k
  if (!read_byte(info, &ir, address++))
995
0
    return false;
996
997
212k
  insn_description->insn = M680X_INS_ILLGL;
998
212k
  insn_description->opcode = ir;
999
1000
  // Check if a page prefix byte is present
1001
483k
  for (i = 0; i < ARR_SIZE(cpu->pageX_table_size); ++i) {
1002
478k
    if (cpu->pageX_table_size[i] == 0 ||
1003
290k
        (cpu->inst_pageX_table[i] == NULL))
1004
188k
      break;
1005
1006
290k
    if ((cpu->pageX_prefix[i] == ir)) {
1007
      // Get pageX instruction and handler id.
1008
      // Abort for illegal instr.
1009
18.7k
      inst_table = cpu->inst_pageX_table[i];
1010
18.7k
      table_size = cpu->pageX_table_size[i];
1011
1012
18.7k
      if (!read_byte(info, &ir, address++))
1013
36
        return false;
1014
1015
18.6k
      insn_description->opcode =
1016
18.6k
        (insn_description->opcode << 8) | ir;
1017
1018
18.6k
      if ((index = binary_search(inst_table, table_size,
1019
18.6k
               ir)) < 0)
1020
5.18k
        return false;
1021
1022
13.5k
      insn_description->hid[0] =
1023
13.5k
        inst_table[index].handler_id1;
1024
13.5k
      insn_description->hid[1] =
1025
13.5k
        inst_table[index].handler_id2;
1026
13.5k
      insn_description->insn = inst_table[index].insn;
1027
13.5k
      break;
1028
18.6k
    }
1029
290k
  }
1030
1031
207k
  if (insn_description->insn == M680X_INS_ILLGL) {
1032
    // Get page1 insn description
1033
193k
    insn_description->insn = cpu->inst_page1_table[ir].insn;
1034
193k
    insn_description->hid[0] =
1035
193k
      cpu->inst_page1_table[ir].handler_id1;
1036
193k
    insn_description->hid[1] =
1037
193k
      cpu->inst_page1_table[ir].handler_id2;
1038
193k
  }
1039
1040
207k
  if (insn_description->insn == M680X_INS_ILLGL) {
1041
    // Check if opcode byte is present in an overlay table
1042
26.9k
    for (i = 0; i < ARR_SIZE(cpu->overlay_table_size); ++i) {
1043
26.2k
      if (cpu->overlay_table_size[i] == 0 ||
1044
16.7k
          (cpu->inst_overlay_table[i] == NULL))
1045
9.50k
        break;
1046
1047
16.7k
      inst_table = cpu->inst_overlay_table[i];
1048
16.7k
      table_size = cpu->overlay_table_size[i];
1049
1050
16.7k
      if ((index = binary_search(inst_table, table_size,
1051
16.7k
               ir)) >= 0) {
1052
7.68k
        insn_description->hid[0] =
1053
7.68k
          inst_table[index].handler_id1;
1054
7.68k
        insn_description->hid[1] =
1055
7.68k
          inst_table[index].handler_id2;
1056
7.68k
        insn_description->insn = inst_table[index].insn;
1057
7.68k
        break;
1058
7.68k
      }
1059
16.7k
    }
1060
17.9k
  }
1061
1062
207k
  insn_description->insn_size = address - base_address;
1063
1064
207k
  return (insn_description->insn != M680X_INS_ILLGL) &&
1065
196k
         (insn_description->insn != M680X_INS_INVLD) &&
1066
196k
         is_sufficient_code_size(info, address, insn_description);
1067
212k
}
1068
1069
static void illegal_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1070
26.0k
{
1071
26.0k
  cs_m680x_op *op0 = &info->m680x.operands[info->m680x.op_count++];
1072
26.0k
  uint8_t temp8 = 0;
1073
1074
26.0k
  info->insn = M680X_INS_ILLGL;
1075
26.0k
  read_byte(info, &temp8, (*address)++);
1076
26.0k
  op0->imm = (int32_t)temp8 & 0xff;
1077
26.0k
  op0->type = M680X_OP_IMMEDIATE;
1078
26.0k
  op0->size = 1;
1079
26.0k
}
1080
1081
static void inherent_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1082
222k
{
1083
  // There is nothing to do here :-)
1084
222k
}
1085
1086
static void add_reg_operand(m680x_info *info, m680x_reg reg)
1087
130k
{
1088
130k
  cs_m680x *m680x = &info->m680x;
1089
130k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1090
1091
130k
  op->type = M680X_OP_REGISTER;
1092
130k
  op->reg = reg;
1093
130k
  op->size = info->cpu->reg_byte_size[reg];
1094
130k
}
1095
1096
static void set_operand_size(m680x_info *info, cs_m680x_op *op,
1097
           uint8_t default_size)
1098
128k
{
1099
128k
  cs_m680x *m680x = &info->m680x;
1100
1101
128k
  if (info->insn == M680X_INS_JMP || info->insn == M680X_INS_JSR)
1102
6.27k
    op->size = 0;
1103
121k
  else if (info->insn == M680X_INS_DIVD ||
1104
120k
     ((info->insn == M680X_INS_AIS ||
1105
120k
       info->insn == M680X_INS_AIX) &&
1106
480
      op->type != M680X_OP_REGISTER))
1107
1.56k
    op->size = 1;
1108
120k
  else if (info->insn == M680X_INS_DIVQ || info->insn == M680X_INS_MOVW)
1109
3.99k
    op->size = 2;
1110
116k
  else if (info->insn == M680X_INS_EMACS)
1111
200
    op->size = 4;
1112
116k
  else if ((m680x->op_count > 0) &&
1113
116k
     (m680x->operands[0].type == M680X_OP_REGISTER))
1114
71.5k
    op->size = m680x->operands[0].size;
1115
44.6k
  else
1116
44.6k
    op->size = default_size;
1117
128k
}
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
5.04k
{
1131
5.04k
  cs_m680x_op *op0 = &info->m680x.operands[0];
1132
5.04k
  uint8_t reg_bits = 0;
1133
5.04k
  uint16_t bit_index;
1134
5.04k
  const m680x_reg *reg_to_reg_ids = NULL;
1135
1136
5.04k
  read_byte(info, &reg_bits, (*address)++);
1137
1138
5.04k
  switch (op0->reg) {
1139
2.63k
  case M680X_REG_U:
1140
2.63k
    reg_to_reg_ids = &reg_u_reg_ids[0];
1141
2.63k
    break;
1142
1143
2.41k
  case M680X_REG_S:
1144
2.41k
    reg_to_reg_ids = &reg_s_reg_ids[0];
1145
2.41k
    break;
1146
1147
0
  default:
1148
0
    CS_ASSERT(0 && "Unexpected operand0 register");
1149
0
    break;
1150
5.04k
  }
1151
1152
5.04k
  if ((info->insn == M680X_INS_PULU || (info->insn == M680X_INS_PULS)) &&
1153
2.26k
      ((reg_bits & 0x80) != 0))
1154
    // PULS xxx,PC or PULU xxx,PC which is like return from
1155
    // subroutine (RTS)
1156
330
    add_insn_group(MI->flat_insn->detail, M680X_GRP_RET);
1157
1158
45.3k
  for (bit_index = 0; bit_index < 8; ++bit_index) {
1159
40.3k
    if (reg_bits & (1 << bit_index) && reg_to_reg_ids)
1160
20.1k
      add_reg_operand(info, reg_to_reg_ids[bit_index]);
1161
40.3k
  }
1162
5.04k
}
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
1.02k
{
1187
1.02k
  uint8_t regs = 0;
1188
1189
1.02k
  read_byte(info, &regs, (*address)++);
1190
1191
1.02k
  add_reg_operand(info, g_tfr_exg_reg_ids[regs >> 4]);
1192
1.02k
  add_reg_operand(info, g_tfr_exg_reg_ids[regs & 0x0f]);
1193
1194
1.02k
  if ((regs & 0x0f) == 0x05) {
1195
    // EXG xxx,PC or TFR xxx,PC which is like a JMP
1196
378
    add_insn_group(MI->flat_insn->detail, M680X_GRP_JUMP);
1197
378
  }
1198
1.02k
}
1199
1200
static void reg_reg12_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1201
872
{
1202
872
  static const m680x_reg g_tfr_exg12_reg0_ids[] = {
1203
872
    M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP3,
1204
872
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,  M680X_REG_S,
1205
872
  };
1206
872
  static const m680x_reg g_tfr_exg12_reg1_ids[] = {
1207
872
    M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP2,
1208
872
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,  M680X_REG_S,
1209
872
  };
1210
872
  uint8_t regs = 0;
1211
1212
872
  read_byte(info, &regs, (*address)++);
1213
1214
  // The opcode of this instruction depends on
1215
  // the msb of its post byte.
1216
872
  if (regs & 0x80)
1217
614
    info->insn = M680X_INS_EXG;
1218
258
  else
1219
258
    info->insn = M680X_INS_TFR;
1220
1221
872
  add_reg_operand(info, g_tfr_exg12_reg0_ids[(regs >> 4) & 0x07]);
1222
872
  add_reg_operand(info, g_tfr_exg12_reg1_ids[regs & 0x07]);
1223
872
}
1224
1225
static void add_rel_operand(m680x_info *info, int16_t offset, uint16_t address)
1226
14.0k
{
1227
14.0k
  cs_m680x *m680x = &info->m680x;
1228
14.0k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1229
1230
14.0k
  op->type = M680X_OP_RELATIVE;
1231
14.0k
  op->size = 0;
1232
14.0k
  op->rel.offset = offset;
1233
14.0k
  op->rel.address = address;
1234
14.0k
}
1235
1236
static void relative8_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1237
13.0k
{
1238
13.0k
  int16_t offset = 0;
1239
1240
13.0k
  read_byte_sign_extended(info, &offset, (*address)++);
1241
13.0k
  add_rel_operand(info, offset, *address + offset);
1242
13.0k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1243
1244
13.0k
  if ((info->insn != M680X_INS_BRA) && (info->insn != M680X_INS_BSR) &&
1245
10.8k
      (info->insn != M680X_INS_BRN))
1246
10.4k
    add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1247
13.0k
}
1248
1249
static void relative16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1250
1.00k
{
1251
1.00k
  uint16_t offset = 0;
1252
1253
1.00k
  read_word(info, &offset, *address);
1254
1.00k
  *address += 2;
1255
1.00k
  add_rel_operand(info, (int16_t)offset, *address + offset);
1256
1.00k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1257
1258
1.00k
  if ((info->insn != M680X_INS_LBRA) && (info->insn != M680X_INS_LBSR) &&
1259
473
      (info->insn != M680X_INS_LBRN))
1260
264
    add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1261
1.00k
}
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
11.6k
{
1275
11.6k
  cs_m680x *m680x = &info->m680x;
1276
11.6k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1277
1278
11.6k
  op->type = M680X_OP_INDEXED;
1279
11.6k
  set_operand_size(info, op, 1);
1280
11.6k
  op->idx.base_reg = base_reg;
1281
11.6k
  op->idx.offset_reg = M680X_REG_INVALID;
1282
11.6k
  op->idx.inc_dec = inc_dec;
1283
1284
11.6k
  if (inc_dec && post_inc_dec)
1285
2.00k
    op->idx.flags |= M680X_IDX_POST_INC_DEC;
1286
1287
11.6k
  if (offset_bits != M680X_OFFSET_NONE) {
1288
5.52k
    op->idx.offset = offset;
1289
5.52k
    op->idx.offset_addr = 0;
1290
5.52k
  }
1291
1292
11.6k
  op->idx.offset_bits = offset_bits;
1293
11.6k
  op->idx.flags |= (no_comma ? M680X_IDX_NO_COMMA : 0);
1294
11.6k
}
1295
1296
// M6800/1/2/3 indexed mode handler
1297
static void indexedX_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1298
2.78k
{
1299
2.78k
  uint8_t offset = 0;
1300
1301
2.78k
  read_byte(info, &offset, (*address)++);
1302
1303
2.78k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_8,
1304
2.78k
          (uint16_t)offset, false);
1305
2.78k
}
1306
1307
static void indexedY_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1308
895
{
1309
895
  uint8_t offset = 0;
1310
1311
895
  read_byte(info, &offset, (*address)++);
1312
1313
895
  add_indexed_operand(info, M680X_REG_Y, false, 0, M680X_OFFSET_BITS_8,
1314
895
          (uint16_t)offset, false);
1315
895
}
1316
1317
// M6809/M6309 indexed mode handler
1318
static void indexed09_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1319
20.4k
{
1320
20.4k
  cs_m680x *m680x = &info->m680x;
1321
20.4k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1322
20.4k
  uint8_t post_byte = 0;
1323
20.4k
  uint16_t offset = 0;
1324
20.4k
  int16_t soffset = 0;
1325
1326
20.4k
  read_byte(info, &post_byte, (*address)++);
1327
1328
20.4k
  op->type = M680X_OP_INDEXED;
1329
20.4k
  set_operand_size(info, op, 1);
1330
20.4k
  op->idx.base_reg = g_rr5_to_reg_ids[(post_byte >> 5) & 0x03];
1331
20.4k
  op->idx.offset_reg = M680X_REG_INVALID;
1332
1333
20.4k
  if (!(post_byte & 0x80)) {
1334
    // n5,R
1335
9.14k
    if ((post_byte & 0x10) == 0x10)
1336
5.09k
      op->idx.offset = post_byte | 0xfff0;
1337
4.04k
    else
1338
4.04k
      op->idx.offset = post_byte & 0x0f;
1339
1340
9.14k
    op->idx.offset_addr = op->idx.offset + *address;
1341
9.14k
    op->idx.offset_bits = M680X_OFFSET_BITS_5;
1342
11.3k
  } else {
1343
11.3k
    if ((post_byte & 0x10) == 0x10)
1344
4.77k
      op->idx.flags |= M680X_IDX_INDIRECT;
1345
1346
    // indexed addressing
1347
11.3k
    switch (post_byte & 0x1f) {
1348
417
    case 0x00: // ,R+
1349
417
      op->idx.inc_dec = 1;
1350
417
      op->idx.flags |= M680X_IDX_POST_INC_DEC;
1351
417
      break;
1352
1353
241
    case 0x11: // [,R++]
1354
941
    case 0x01: // ,R++
1355
941
      op->idx.inc_dec = 2;
1356
941
      op->idx.flags |= M680X_IDX_POST_INC_DEC;
1357
941
      break;
1358
1359
321
    case 0x02: // ,-R
1360
321
      op->idx.inc_dec = -1;
1361
321
      break;
1362
1363
857
    case 0x13: // [,--R]
1364
1.21k
    case 0x03: // ,--R
1365
1.21k
      op->idx.inc_dec = -2;
1366
1.21k
      break;
1367
1368
256
    case 0x14: // [,R]
1369
586
    case 0x04: // ,R
1370
586
      break;
1371
1372
263
    case 0x15: // [B,R]
1373
799
    case 0x05: // B,R
1374
799
      op->idx.offset_reg = M680X_REG_B;
1375
799
      break;
1376
1377
342
    case 0x16: // [A,R]
1378
758
    case 0x06: // A,R
1379
758
      op->idx.offset_reg = M680X_REG_A;
1380
758
      break;
1381
1382
549
    case 0x1c: // [n8,PCR]
1383
1.07k
    case 0x0c: // n8,PCR
1384
1.07k
      op->idx.base_reg = M680X_REG_PC;
1385
1.07k
      read_byte_sign_extended(info, &soffset, (*address)++);
1386
1.07k
      op->idx.offset_addr = offset + *address;
1387
1.07k
      op->idx.offset = soffset;
1388
1.07k
      op->idx.offset_bits = M680X_OFFSET_BITS_8;
1389
1.07k
      break;
1390
1391
283
    case 0x18: // [n8,R]
1392
1.47k
    case 0x08: // n8,R
1393
1.47k
      read_byte_sign_extended(info, &soffset, (*address)++);
1394
1.47k
      op->idx.offset = soffset;
1395
1.47k
      op->idx.offset_bits = M680X_OFFSET_BITS_8;
1396
1.47k
      break;
1397
1398
498
    case 0x1d: // [n16,PCR]
1399
1.11k
    case 0x0d: // n16,PCR
1400
1.11k
      op->idx.base_reg = M680X_REG_PC;
1401
1.11k
      read_word(info, &offset, *address);
1402
1.11k
      *address += 2;
1403
1.11k
      op->idx.offset_addr = offset + *address;
1404
1.11k
      op->idx.offset = (int16_t)offset;
1405
1.11k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1406
1.11k
      break;
1407
1408
1.11k
    case 0x19: // [n16,R]
1409
1.57k
    case 0x09: // n16,R
1410
1.57k
      read_word(info, &offset, *address);
1411
1.57k
      *address += 2;
1412
1.57k
      op->idx.offset = (int16_t)offset;
1413
1.57k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1414
1.57k
      break;
1415
1416
134
    case 0x1b: // [D,R]
1417
825
    case 0x0b: // D,R
1418
825
      op->idx.offset_reg = M680X_REG_D;
1419
825
      break;
1420
1421
235
    case 0x1f: // [n16]
1422
235
      op->type = M680X_OP_EXTENDED;
1423
235
      op->ext.indirect = true;
1424
235
      read_word(info, &op->ext.address, *address);
1425
235
      *address += 2;
1426
235
      break;
1427
1428
0
    default:
1429
0
      op->idx.base_reg = M680X_REG_INVALID;
1430
0
      break;
1431
11.3k
    }
1432
11.3k
  }
1433
1434
20.4k
  if (((info->insn == M680X_INS_LEAU) || (info->insn == M680X_INS_LEAS) ||
1435
18.6k
       (info->insn == M680X_INS_LEAX) ||
1436
17.5k
       (info->insn == M680X_INS_LEAY)) &&
1437
3.72k
      (m680x->operands[0].reg == M680X_REG_X ||
1438
2.67k
       (m680x->operands[0].reg == M680X_REG_Y)))
1439
    // Only LEAX and LEAY modify CC register
1440
1.87k
    add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1441
20.4k
}
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
21.6k
{
1456
21.6k
  cs_m680x *m680x = &info->m680x;
1457
21.6k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1458
21.6k
  uint8_t post_byte = 0;
1459
21.6k
  uint8_t offset8 = 0;
1460
1461
21.6k
  read_byte(info, &post_byte, (*address)++);
1462
1463
21.6k
  op->type = M680X_OP_INDEXED;
1464
21.6k
  set_operand_size(info, op, 1);
1465
21.6k
  op->idx.offset_reg = M680X_REG_INVALID;
1466
1467
21.6k
  if (!(post_byte & 0x20)) {
1468
    // n5,R      n5 is a 5-bit signed offset
1469
7.19k
    op->idx.base_reg = g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1470
1471
7.19k
    if ((post_byte & 0x10) == 0x10)
1472
1.76k
      op->idx.offset = post_byte | 0xfff0;
1473
5.42k
    else
1474
5.42k
      op->idx.offset = post_byte & 0x0f;
1475
1476
7.19k
    op->idx.offset_addr = op->idx.offset + *address;
1477
7.19k
    op->idx.offset_bits = M680X_OFFSET_BITS_5;
1478
14.4k
  } else {
1479
14.4k
    if ((post_byte & 0xe0) == 0xe0)
1480
7.60k
      op->idx.base_reg =
1481
7.60k
        g_idx12_to_reg_ids[(post_byte >> 3) & 0x03];
1482
1483
14.4k
    switch (post_byte & 0xe7) {
1484
1.06k
    case 0xe0:
1485
2.49k
    case 0xe1: // n9,R
1486
2.49k
      read_byte(info, &offset8, (*address)++);
1487
2.49k
      op->idx.offset = offset8;
1488
1489
2.49k
      if (post_byte & 0x01) // sign extension
1490
1.42k
        op->idx.offset |= 0xff00;
1491
1492
2.49k
      op->idx.offset_bits = M680X_OFFSET_BITS_9;
1493
1494
2.49k
      if (op->idx.base_reg == M680X_REG_PC)
1495
535
        op->idx.offset_addr = op->idx.offset + *address;
1496
1497
2.49k
      break;
1498
1499
1.20k
    case 0xe3: // [n16,R]
1500
1.20k
      op->idx.flags |= M680X_IDX_INDIRECT;
1501
1502
    // intentionally fall through
1503
1.97k
    case 0xe2: // n16,R
1504
1.97k
      read_word(info, (uint16_t *)&op->idx.offset, *address);
1505
1.97k
      (*address) += 2;
1506
1.97k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1507
1508
1.97k
      if (op->idx.base_reg == M680X_REG_PC)
1509
248
        op->idx.offset_addr = op->idx.offset + *address;
1510
1511
1.97k
      break;
1512
1513
1.49k
    case 0xe4: // A,R
1514
2.12k
    case 0xe5: // B,R
1515
2.51k
    case 0xe6: // D,R
1516
2.51k
      op->idx.offset_reg =
1517
2.51k
        g_or12_to_reg_ids[post_byte & 0x03];
1518
2.51k
      break;
1519
1520
617
    case 0xe7: // [D,R]
1521
617
      op->idx.offset_reg = M680X_REG_D;
1522
617
      op->idx.flags |= M680X_IDX_INDIRECT;
1523
617
      break;
1524
1525
6.80k
    default: // n,-r n,+r n,r- n,r+
1526
      // PC is not allowed in this mode
1527
6.80k
      op->idx.base_reg =
1528
6.80k
        g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1529
6.80k
      op->idx.inc_dec = post_byte & 0x0f;
1530
1531
6.80k
      if (op->idx.inc_dec & 0x08) // evtl. sign extend value
1532
3.34k
        op->idx.inc_dec |= 0xf0;
1533
1534
6.80k
      if (op->idx.inc_dec >= 0)
1535
3.45k
        op->idx.inc_dec++;
1536
1537
6.80k
      if (post_byte & 0x10)
1538
1.93k
        op->idx.flags |= M680X_IDX_POST_INC_DEC;
1539
1540
6.80k
      break;
1541
14.4k
    }
1542
14.4k
  }
1543
21.6k
}
1544
1545
static void index_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1546
524
{
1547
524
  cs_m680x *m680x = &info->m680x;
1548
524
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1549
1550
524
  op->type = M680X_OP_CONSTANT;
1551
524
  read_byte(info, &op->const_val, (*address)++);
1552
524
};
1553
1554
static void direct_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1555
26.8k
{
1556
26.8k
  cs_m680x *m680x = &info->m680x;
1557
26.8k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1558
1559
26.8k
  op->type = M680X_OP_DIRECT;
1560
26.8k
  set_operand_size(info, op, 1);
1561
26.8k
  read_byte(info, &op->direct_addr, (*address)++);
1562
26.8k
};
1563
1564
static void extended_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1565
25.9k
{
1566
25.9k
  cs_m680x *m680x = &info->m680x;
1567
25.9k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1568
1569
25.9k
  op->type = M680X_OP_EXTENDED;
1570
25.9k
  set_operand_size(info, op, 1);
1571
25.9k
  read_word(info, &op->ext.address, *address);
1572
25.9k
  *address += 2;
1573
25.9k
}
1574
1575
static void immediate_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1576
17.6k
{
1577
17.6k
  cs_m680x *m680x = &info->m680x;
1578
17.6k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1579
17.6k
  uint16_t word = 0;
1580
17.6k
  int16_t sword = 0;
1581
1582
17.6k
  op->type = M680X_OP_IMMEDIATE;
1583
17.6k
  set_operand_size(info, op, 1);
1584
1585
17.6k
  switch (op->size) {
1586
15.2k
  case 1:
1587
15.2k
    read_byte_sign_extended(info, &sword, *address);
1588
15.2k
    op->imm = sword;
1589
15.2k
    break;
1590
1591
2.04k
  case 2:
1592
2.04k
    read_word(info, &word, *address);
1593
2.04k
    op->imm = (int16_t)word;
1594
2.04k
    break;
1595
1596
336
  case 4:
1597
336
    read_sdword(info, &op->imm, *address);
1598
336
    break;
1599
1600
0
  default:
1601
0
    op->imm = 0;
1602
0
    CS_ASSERT(0 && "Unexpected immediate byte size");
1603
17.6k
  }
1604
1605
17.6k
  *address += op->size;
1606
17.6k
}
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
372
{
1611
372
  static const m680x_reg m680x_reg[] = {
1612
372
    M680X_REG_CC,
1613
372
    M680X_REG_A,
1614
372
    M680X_REG_B,
1615
372
    M680X_REG_INVALID,
1616
372
  };
1617
1618
372
  uint8_t post_byte = 0;
1619
372
  cs_m680x *m680x = &info->m680x;
1620
372
  cs_m680x_op *op;
1621
1622
372
  read_byte(info, &post_byte, *address);
1623
372
  (*address)++;
1624
1625
  // operand[0] = register
1626
372
  add_reg_operand(info, m680x_reg[post_byte >> 6]);
1627
1628
  // operand[1] = bit index in source operand
1629
372
  op = &m680x->operands[m680x->op_count++];
1630
372
  op->type = M680X_OP_CONSTANT;
1631
372
  op->const_val = (post_byte >> 3) & 0x07;
1632
1633
  // operand[2] = bit index in destination operand
1634
372
  op = &m680x->operands[m680x->op_count++];
1635
372
  op->type = M680X_OP_CONSTANT;
1636
372
  op->const_val = post_byte & 0x07;
1637
1638
372
  direct_hdlr(MI, info, address);
1639
372
}
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
1.21k
{
1644
1.21k
  static const uint8_t inc_dec_r0[] = {
1645
1.21k
    1,
1646
1.21k
    -1,
1647
1.21k
    1,
1648
1.21k
    0,
1649
1.21k
  };
1650
1.21k
  static const uint8_t inc_dec_r1[] = {
1651
1.21k
    1,
1652
1.21k
    -1,
1653
1.21k
    0,
1654
1.21k
    1,
1655
1.21k
  };
1656
1.21k
  uint8_t regs = 0;
1657
1.21k
  uint8_t index = (MI->Opcode & 0xff) - 0x38;
1658
1659
1.21k
  read_byte(info, &regs, *address);
1660
1661
1.21k
  add_indexed_operand(info, g_tfr_exg_reg_ids[regs >> 4], true,
1662
1.21k
          inc_dec_r0[index], M680X_OFFSET_NONE, 0, true);
1663
1.21k
  add_indexed_operand(info, g_tfr_exg_reg_ids[regs & 0x0f], true,
1664
1.21k
          inc_dec_r1[index], M680X_OFFSET_NONE, 0, true);
1665
1666
1.21k
  add_reg_to_rw_list(MI, M680X_REG_W, READ | WRITE);
1667
1.21k
}
1668
1669
static void opidx_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1670
921
{
1671
921
  cs_m680x *m680x = &info->m680x;
1672
921
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1673
1674
  // bit index is coded in Opcode
1675
921
  op->type = M680X_OP_CONSTANT;
1676
921
  op->const_val = (MI->Opcode & 0x0e) >> 1;
1677
921
}
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
1.27k
{
1684
1.27k
  cs_m680x *m680x = &info->m680x;
1685
1.27k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1686
1687
  // bit index is coded in Opcode
1688
1.27k
  op->type = M680X_OP_CONSTANT;
1689
1.27k
  op->const_val = (MI->Opcode & 0x0e) >> 1;
1690
1.27k
  direct_hdlr(MI, info, address);
1691
1.27k
  relative8_hdlr(MI, info, address);
1692
1693
1.27k
  add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1694
1.27k
}
1695
1696
static void indexedX0_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1697
3.26k
{
1698
3.26k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_NONE, 0,
1699
3.26k
          false);
1700
3.26k
}
1701
1702
static void indexedX16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1703
871
{
1704
871
  uint16_t offset = 0;
1705
1706
871
  read_word(info, &offset, *address);
1707
871
  *address += 2;
1708
871
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_16,
1709
871
          offset, false);
1710
871
}
1711
1712
static void imm_rel_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1713
1.10k
{
1714
1.10k
  immediate_hdlr(MI, info, address);
1715
1.10k
  relative8_hdlr(MI, info, address);
1716
1.10k
}
1717
1718
static void indexedS_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1719
427
{
1720
427
  uint8_t offset = 0;
1721
1722
427
  read_byte(info, &offset, (*address)++);
1723
1724
427
  add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_8,
1725
427
          (uint16_t)offset, false);
1726
427
}
1727
1728
static void indexedS16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1729
207
{
1730
207
  uint16_t offset = 0;
1731
1732
207
  read_word(info, &offset, *address);
1733
207
  *address += 2;
1734
1735
207
  add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_16,
1736
207
          offset, false);
1737
207
}
1738
1739
static void indexedX0p_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1740
443
{
1741
443
  add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_NONE, 0,
1742
443
          true);
1743
443
}
1744
1745
static void indexedXp_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1746
342
{
1747
342
  uint8_t offset = 0;
1748
1749
342
  read_byte(info, &offset, (*address)++);
1750
1751
342
  add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_BITS_8,
1752
342
          (uint16_t)offset, false);
1753
342
}
1754
1755
static void imm_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1756
2.95k
{
1757
2.95k
  cs_m680x *m680x = &info->m680x;
1758
2.95k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1759
1760
2.95k
  indexed12_hdlr(MI, info, address);
1761
2.95k
  op->type = M680X_OP_IMMEDIATE;
1762
1763
2.95k
  if (info->insn == M680X_INS_MOVW) {
1764
733
    uint16_t imm16 = 0;
1765
1766
733
    read_word(info, &imm16, *address);
1767
733
    op->imm = (int16_t)imm16;
1768
733
    op->size = 2;
1769
2.22k
  } else {
1770
2.22k
    uint8_t imm8 = 0;
1771
1772
2.22k
    read_byte(info, &imm8, *address);
1773
2.22k
    op->imm = (int8_t)imm8;
1774
2.22k
    op->size = 1;
1775
2.22k
  }
1776
1777
2.95k
  set_operand_size(info, op, 1);
1778
2.95k
}
1779
1780
static void ext_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1781
1.08k
{
1782
1.08k
  cs_m680x *m680x = &info->m680x;
1783
1.08k
  cs_m680x_op *op0 = &m680x->operands[m680x->op_count++];
1784
1.08k
  uint16_t imm16 = 0;
1785
1786
1.08k
  indexed12_hdlr(MI, info, address);
1787
1.08k
  read_word(info, &imm16, *address);
1788
1.08k
  op0->type = M680X_OP_EXTENDED;
1789
1.08k
  op0->ext.address = (int16_t)imm16;
1790
1.08k
  set_operand_size(info, op0, 1);
1791
1.08k
}
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
793
{
1797
793
  static const m680x_reg index_to_reg_id[] = {
1798
793
    M680X_REG_A, M680X_REG_B, M680X_REG_INVALID, M680X_REG_INVALID,
1799
793
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,       M680X_REG_S,
1800
793
  };
1801
793
  static const m680x_insn index_to_insn_id[] = {
1802
793
    M680X_INS_DBEQ, M680X_INS_DBNE, M680X_INS_TBEQ,  M680X_INS_TBNE,
1803
793
    M680X_INS_IBEQ, M680X_INS_IBNE, M680X_INS_ILLGL, M680X_INS_ILLGL
1804
793
  };
1805
793
  cs_m680x *m680x = &info->m680x;
1806
793
  uint8_t post_byte = 0;
1807
793
  uint8_t rel = 0;
1808
793
  cs_m680x_op *op;
1809
1810
793
  read_byte(info, &post_byte, (*address)++);
1811
1812
793
  info->insn = index_to_insn_id[(post_byte >> 5) & 0x07];
1813
1814
793
  if (info->insn == M680X_INS_ILLGL) {
1815
0
    illegal_hdlr(MI, info, address);
1816
0
  };
1817
1818
793
  read_byte(info, &rel, (*address)++);
1819
1820
793
  add_reg_operand(info, index_to_reg_id[post_byte & 0x07]);
1821
1822
793
  op = &m680x->operands[m680x->op_count++];
1823
1824
793
  op->type = M680X_OP_RELATIVE;
1825
1826
793
  op->rel.offset = (post_byte & 0x10) ? (int16_t)(0xff00 | rel) : rel;
1827
1828
793
  op->rel.address = *address + op->rel.offset;
1829
1830
793
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1831
793
}
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
2.50k
{
1837
2.50k
  cs_m680x *m680x = &info->m680x;
1838
2.50k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1839
1840
2.50k
  op->type = M680X_OP_DIRECT;
1841
2.50k
  op->direct_addr = (uint8_t)(MI->Opcode & 0x0F);
1842
2.50k
  op->size = 1;
1843
2.50k
}
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
4.76k
{
1849
4.76k
  cs_m680x *m680x = &info->m680x;
1850
4.76k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1851
1852
4.76k
  op->type = M680X_OP_DIRECT;
1853
4.76k
  op->direct_addr = (uint8_t)(MI->Opcode & 0x1F);
1854
4.76k
  op->size = 1;
1855
4.76k
}
1856
1857
static void dirdir_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1858
295
{
1859
295
  direct_hdlr(MI, info, address);
1860
295
  direct_hdlr(MI, info, address);
1861
295
}
1862
1863
static void immdir_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1864
267
{
1865
267
  immediate_hdlr(MI, info, address);
1866
267
  direct_hdlr(MI, info, address);
1867
267
}
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
212k
{
1889
212k
  cs_m680x *m680x = &info->m680x;
1890
212k
  cs_detail *detail = MI->flat_insn->detail;
1891
212k
  uint16_t base_address = address;
1892
212k
  insn_desc insn_description;
1893
212k
  e_access_mode access_mode;
1894
1895
212k
  if (detail != NULL) {
1896
212k
    memset(detail, 0,
1897
212k
           offsetof(cs_detail, m680x) + sizeof(cs_m680x));
1898
212k
  }
1899
1900
212k
  memset(&insn_description, 0, sizeof(insn_description));
1901
212k
  memset(m680x, 0, sizeof(*m680x));
1902
212k
  info->insn_size = 1;
1903
1904
212k
  if (decode_insn(info, address, &insn_description)) {
1905
186k
    m680x_reg reg;
1906
1907
186k
    if (insn_description.opcode > 0xff)
1908
11.1k
      address += 2; // 8-bit opcode + page prefix
1909
175k
    else
1910
175k
      address++; // 8-bit opcode only
1911
1912
186k
    info->insn = insn_description.insn;
1913
1914
186k
    MCInst_setOpcode(MI, insn_description.opcode);
1915
1916
186k
    reg = g_insn_props[info->insn].reg0;
1917
1918
186k
    if (reg != M680X_REG_INVALID) {
1919
103k
      if (reg == M680X_REG_HX &&
1920
1.04k
          (!info->cpu->reg_byte_size[reg]))
1921
265
        reg = M680X_REG_X;
1922
1923
103k
      add_reg_operand(info, reg);
1924
      // First (or second) operand is a register which is
1925
      // part of the mnemonic
1926
103k
      m680x->flags |= M680X_FIRST_OP_IN_MNEM;
1927
103k
      reg = g_insn_props[info->insn].reg1;
1928
1929
103k
      if (reg != M680X_REG_INVALID) {
1930
2.00k
        if (reg == M680X_REG_HX &&
1931
414
            (!info->cpu->reg_byte_size[reg]))
1932
215
          reg = M680X_REG_X;
1933
1934
2.00k
        add_reg_operand(info, reg);
1935
2.00k
        m680x->flags |= M680X_SECOND_OP_IN_MNEM;
1936
2.00k
      }
1937
103k
    }
1938
1939
    // Call addressing mode specific instruction handler
1940
186k
    (g_insn_handler[insn_description.hid[0]])(MI, info, &address);
1941
186k
    (g_insn_handler[insn_description.hid[1]])(MI, info, &address);
1942
1943
186k
    add_insn_group(detail, g_insn_props[info->insn].group);
1944
1945
186k
    if (g_insn_props[info->insn].cc_modified &&
1946
120k
        (info->cpu->insn_cc_not_modified[0] != info->insn) &&
1947
119k
        (info->cpu->insn_cc_not_modified[1] != info->insn))
1948
119k
      add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1949
1950
186k
    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
186k
    if ((info->cpu->insn_cc_not_modified[0] == info->insn) ||
1955
185k
        (info->cpu->insn_cc_not_modified[1] == info->insn))
1956
921
      access_mode = rmmm;
1957
1958
186k
    build_regs_read_write_counts(MI, info, access_mode);
1959
186k
    add_operators_access(MI, info, access_mode);
1960
1961
186k
    if (g_insn_props[info->insn].update_reg_access)
1962
18.8k
      set_changed_regs_read_write_counts(MI, info);
1963
1964
186k
    info->insn_size = (uint8_t)insn_description.insn_size;
1965
1966
186k
    return info->insn_size;
1967
186k
  } else
1968
26.0k
    MCInst_setOpcode(MI, insn_description.opcode);
1969
1970
  // Illegal instruction
1971
26.0k
  address = base_address;
1972
26.0k
  illegal_hdlr(MI, info, &address);
1973
26.0k
  return 1;
1974
212k
}
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
212k
{
2182
212k
  if (cpu_type == M680X_CPU_TYPE_INVALID) {
2183
0
    return false;
2184
0
  }
2185
2186
212k
  info->code = code;
2187
212k
  info->size = code_len;
2188
212k
  info->offset = address;
2189
212k
  info->cpu_type = cpu_type;
2190
2191
212k
  info->cpu = &g_cpu_tables[info->cpu_type];
2192
2193
212k
  return true;
2194
212k
}
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
212k
{
2200
212k
  unsigned int insn_size = 0;
2201
212k
  e_cpu_type cpu_type = M680X_CPU_TYPE_INVALID; // No default CPU type
2202
212k
  cs_struct *handle = (cs_struct *)ud;
2203
212k
  m680x_info *info = (m680x_info *)handle->printer_info;
2204
2205
212k
  MCInst_clear(MI);
2206
2207
212k
  if (handle->mode & CS_MODE_M680X_6800)
2208
923
    cpu_type = M680X_CPU_TYPE_6800;
2209
2210
211k
  else if (handle->mode & CS_MODE_M680X_6801)
2211
5.15k
    cpu_type = M680X_CPU_TYPE_6801;
2212
2213
206k
  else if (handle->mode & CS_MODE_M680X_6805)
2214
5.29k
    cpu_type = M680X_CPU_TYPE_6805;
2215
2216
200k
  else if (handle->mode & CS_MODE_M680X_6808)
2217
4.67k
    cpu_type = M680X_CPU_TYPE_6808;
2218
2219
196k
  else if (handle->mode & CS_MODE_M680X_HCS08)
2220
5.89k
    cpu_type = M680X_CPU_TYPE_HCS08;
2221
2222
190k
  else if (handle->mode & CS_MODE_M680X_6809)
2223
18.3k
    cpu_type = M680X_CPU_TYPE_6809;
2224
2225
172k
  else if (handle->mode & CS_MODE_M680X_6301)
2226
1.02k
    cpu_type = M680X_CPU_TYPE_6301;
2227
2228
170k
  else if (handle->mode & CS_MODE_M680X_6309)
2229
74.0k
    cpu_type = M680X_CPU_TYPE_6309;
2230
2231
96.8k
  else if (handle->mode & CS_MODE_M680X_6811)
2232
6.75k
    cpu_type = M680X_CPU_TYPE_6811;
2233
2234
90.1k
  else if (handle->mode & CS_MODE_M680X_CPU12)
2235
37.4k
    cpu_type = M680X_CPU_TYPE_CPU12;
2236
2237
52.6k
  else if (handle->mode & CS_MODE_M680X_RS08)
2238
11.4k
    cpu_type = M680X_CPU_TYPE_RS08;
2239
2240
41.2k
  else if (handle->mode & CS_MODE_M680X_HCS12X)
2241
41.2k
    cpu_type = M680X_CPU_TYPE_HCS12X;
2242
2243
212k
  if (cpu_type != M680X_CPU_TYPE_INVALID &&
2244
212k
      m680x_setup_internals(info, cpu_type, (uint16_t)address, code,
2245
212k
          (uint16_t)code_len))
2246
212k
    insn_size = m680x_disassemble(MI, info, (uint16_t)address);
2247
2248
212k
  if (insn_size == 0) {
2249
0
    *size = 1;
2250
0
    return false;
2251
0
  }
2252
2253
  // Make sure we always stay within range
2254
212k
  if (insn_size > code_len) {
2255
24
    *size = (uint16_t)code_len;
2256
24
    return false;
2257
24
  } else
2258
212k
    *size = (uint16_t)insn_size;
2259
2260
212k
  return true;
2261
212k
}
2262
2263
cs_err M680X_disassembler_init(cs_struct *ud)
2264
2.17k
{
2265
2.17k
  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.17k
  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.17k
  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.17k
  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.17k
  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.17k
  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.17k
  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.17k
  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.17k
  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.17k
  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.17k
  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.17k
  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.17k
  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.17k
  return CS_ERR_OK;
2345
2.17k
}
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