Coverage Report

Created: 2025-10-28 07:02

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