Coverage Report

Created: 2026-06-15 06:41

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