Coverage Report

Created: 2026-01-10 06:34

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
455k
#define READ CS_AC_READ
109
572k
#define WRITE CS_AC_WRITE
110
663k
#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.05M
{
156
1.05M
  if (address < info->offset ||
157
1.05M
      (uint32_t)(address - info->offset) >= info->size)
158
    // out of code buffer range
159
2.03k
    return false;
160
161
1.05M
  *byte = info->code[address - info->offset];
162
163
1.05M
  return true;
164
1.05M
}
165
166
static bool read_byte_sign_extended(const m680x_info *info, int16_t *word,
167
            uint16_t address)
168
65.0k
{
169
65.0k
  if (address < info->offset ||
170
65.0k
      (uint32_t)(address - info->offset) >= info->size)
171
    // out of code buffer range
172
0
    return false;
173
174
65.0k
  *word = (int16_t)info->code[address - info->offset];
175
176
65.0k
  if (*word & 0x80)
177
23.4k
    *word |= 0xFF00;
178
179
65.0k
  return true;
180
65.0k
}
181
182
static bool read_word(const m680x_info *info, uint16_t *word, uint16_t address)
183
80.2k
{
184
80.2k
  if (address < info->offset ||
185
80.2k
      (uint32_t)(address + 1 - info->offset) >= info->size)
186
    // out of code buffer range
187
13
    return false;
188
189
80.2k
  *word = (uint16_t)info->code[address - info->offset] << 8;
190
80.2k
  *word |= (uint16_t)info->code[address + 1 - info->offset];
191
192
80.2k
  return true;
193
80.2k
}
194
195
static bool read_sdword(const m680x_info *info, int32_t *sdword,
196
      uint16_t address)
197
919
{
198
919
  if (address < info->offset ||
199
919
      (uint32_t)(address + 3 - info->offset) >= info->size)
200
    // out of code buffer range
201
0
    return false;
202
203
919
  *sdword = (uint32_t)info->code[address - info->offset] << 24;
204
919
  *sdword |= (uint32_t)info->code[address + 1 - info->offset] << 16;
205
919
  *sdword |= (uint32_t)info->code[address + 2 - info->offset] << 8;
206
919
  *sdword |= (uint32_t)info->code[address + 3 - info->offset];
207
208
919
  return true;
209
919
}
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
143k
{
218
  // As part of the algorithm last may get negative.
219
  // => signed integer has to be used.
220
143k
  int first = 0;
221
143k
  int last = (int)table_size - 1;
222
143k
  int middle = (first + last) / 2;
223
224
712k
  while (first <= last) {
225
664k
    if (inst_pageX_table[middle].opcode < opcode) {
226
225k
      first = middle + 1;
227
438k
    } else if (inst_pageX_table[middle].opcode == opcode) {
228
94.7k
      return middle; /* item found */
229
94.7k
    } else
230
344k
      last = middle - 1;
231
232
569k
    middle = (first + last) / 2;
233
569k
  }
234
235
48.5k
  if (first > last)
236
48.5k
    return -1; /* item not found */
237
238
0
  return -2;
239
48.5k
}
240
241
void M680X_get_insn_id(cs_struct *handle, cs_insn *insn, unsigned int id)
242
424k
{
243
424k
  const m680x_info *const info = (const m680x_info *)handle->printer_info;
244
424k
  const cpu_tables *cpu = info->cpu;
245
424k
  uint8_t insn_prefix = (id >> 8) & 0xff;
246
  // opcode is the first instruction byte without the prefix.
247
424k
  uint8_t opcode = id & 0xff;
248
424k
  int index;
249
424k
  int i;
250
251
424k
  insn->id = M680X_INS_ILLGL;
252
253
1.02M
  for (i = 0; i < ARR_SIZE(cpu->pageX_prefix); ++i) {
254
1.00M
    if (cpu->pageX_table_size[i] == 0 ||
255
636k
        (cpu->inst_pageX_table[i] == NULL))
256
373k
      break;
257
258
636k
    if (cpu->pageX_prefix[i] == insn_prefix) {
259
37.5k
      index = binary_search(cpu->inst_pageX_table[i],
260
37.5k
                cpu->pageX_table_size[i], opcode);
261
37.5k
      insn->id =
262
37.5k
        (index >= 0) ?
263
27.3k
          cpu->inst_pageX_table[i][index].insn :
264
37.5k
          M680X_INS_ILLGL;
265
37.5k
      return;
266
37.5k
    }
267
636k
  }
268
269
386k
  if (insn_prefix != 0)
270
0
    return;
271
272
386k
  insn->id = cpu->inst_page1_table[id].insn;
273
274
386k
  if (insn->id != M680X_INS_ILLGL)
275
352k
    return;
276
277
  // Check if opcode byte is present in an overlay table
278
48.3k
  for (i = 0; i < ARR_SIZE(cpu->overlay_table_size); ++i) {
279
46.2k
    if (cpu->overlay_table_size[i] == 0 ||
280
34.1k
        (cpu->inst_overlay_table[i] == NULL))
281
12.0k
      break;
282
283
34.1k
    if ((index = binary_search(cpu->inst_overlay_table[i],
284
34.1k
             cpu->overlay_table_size[i],
285
34.1k
             opcode)) >= 0) {
286
20.0k
      insn->id = cpu->inst_overlay_table[i][index].insn;
287
20.0k
      return;
288
20.0k
    }
289
34.1k
  }
290
34.2k
}
291
292
static void add_insn_group(cs_detail *detail, m680x_group_type group)
293
422k
{
294
422k
  if (detail != NULL && (group != M680X_GRP_INVALID) &&
295
102k
      (group != M680X_GRP_ENDING))
296
102k
    detail->groups[detail->groups_count++] = (uint8_t)group;
297
422k
}
298
299
static bool exists_reg_list(uint16_t *regs, uint8_t count, m680x_reg reg)
300
1.23M
{
301
1.23M
  uint8_t i;
302
303
2.13M
  for (i = 0; i < count; ++i) {
304
936k
    if (regs[i] == (uint16_t)reg)
305
34.3k
      return true;
306
936k
  }
307
308
1.19M
  return false;
309
1.23M
}
310
311
static void add_reg_to_rw_list(MCInst *MI, m680x_reg reg, e_access access)
312
821k
{
313
821k
  cs_detail *detail = MI->flat_insn->detail;
314
315
821k
  if (detail == NULL || (reg == M680X_REG_INVALID))
316
0
    return;
317
318
821k
  switch (access) {
319
411k
  case MODIFY:
320
411k
    if (!exists_reg_list(detail->regs_read, detail->regs_read_count,
321
411k
             reg))
322
403k
      detail->regs_read[detail->regs_read_count++] =
323
403k
        (uint16_t)reg;
324
325
    // intentionally fall through
326
327
539k
  case WRITE:
328
539k
    if (!exists_reg_list(detail->regs_write,
329
539k
             detail->regs_write_count, reg))
330
531k
      detail->regs_write[detail->regs_write_count++] =
331
531k
        (uint16_t)reg;
332
333
539k
    break;
334
335
281k
  case READ:
336
281k
    if (!exists_reg_list(detail->regs_read, detail->regs_read_count,
337
281k
             reg))
338
263k
      detail->regs_read[detail->regs_read_count++] =
339
263k
        (uint16_t)reg;
340
341
281k
    break;
342
343
0
  case UNCHANGED:
344
0
  default:
345
0
    break;
346
821k
  }
347
821k
}
348
349
static void update_am_reg_list(MCInst *MI, m680x_info *info, cs_m680x_op *op,
350
             e_access access)
351
582k
{
352
582k
  if (MI->flat_insn->detail == NULL)
353
0
    return;
354
355
582k
  switch (op->type) {
356
253k
  case M680X_OP_REGISTER:
357
253k
    add_reg_to_rw_list(MI, op->reg, access);
358
253k
    break;
359
360
117k
  case M680X_OP_INDEXED:
361
117k
    add_reg_to_rw_list(MI, op->idx.base_reg, READ);
362
363
117k
    if (op->idx.base_reg == M680X_REG_X &&
364
50.1k
        info->cpu->reg_byte_size[M680X_REG_H])
365
16.1k
      add_reg_to_rw_list(MI, M680X_REG_H, READ);
366
367
117k
    if (op->idx.offset_reg != M680X_REG_INVALID)
368
11.1k
      add_reg_to_rw_list(MI, op->idx.offset_reg, READ);
369
370
117k
    if (op->idx.inc_dec) {
371
26.6k
      add_reg_to_rw_list(MI, op->idx.base_reg, WRITE);
372
373
26.6k
      if (op->idx.base_reg == M680X_REG_X &&
374
9.11k
          info->cpu->reg_byte_size[M680X_REG_H])
375
4.25k
        add_reg_to_rw_list(MI, M680X_REG_H, WRITE);
376
26.6k
    }
377
378
117k
    break;
379
380
211k
  default:
381
211k
    break;
382
582k
  }
383
582k
}
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.23M
{
458
1.23M
  int idx = (operator_index > 3) ? 3 : operator_index;
459
460
1.23M
  return g_access_mode_to_access[idx][access_mode];
461
1.23M
}
462
463
static void build_regs_read_write_counts(MCInst *MI, m680x_info *info,
464
           e_access_mode access_mode)
465
381k
{
466
381k
  cs_m680x *m680x = &info->m680x;
467
381k
  int i;
468
469
381k
  if (MI->flat_insn->detail == NULL || (!m680x->op_count))
470
48.1k
    return;
471
472
916k
  for (i = 0; i < m680x->op_count; ++i) {
473
582k
    e_access access = get_access(i, access_mode);
474
582k
    update_am_reg_list(MI, info, &m680x->operands[i], access);
475
582k
  }
476
333k
}
477
478
static void add_operators_access(MCInst *MI, m680x_info *info,
479
         e_access_mode access_mode)
480
381k
{
481
381k
  cs_m680x *m680x = &info->m680x;
482
381k
  int offset = 0;
483
381k
  int i;
484
485
381k
  if (MI->flat_insn->detail == NULL || (!m680x->op_count) ||
486
333k
      (access_mode == uuuu))
487
86.0k
    return;
488
489
839k
  for (i = 0; i < m680x->op_count; ++i) {
490
543k
    e_access access;
491
492
    // Ugly fix: MULD has a register operand, an immediate operand
493
    // AND an implicitly changed register W
494
543k
    if (info->insn == M680X_INS_MULD && (i == 1))
495
828
      offset = 1;
496
497
543k
    access = get_access(i + offset, access_mode);
498
543k
    m680x->operands[i].access = access;
499
543k
  }
500
295k
}
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
36.1k
{
510
  //TABLE
511
1.99M
#define EOL M680X_REG_INVALID
512
36.1k
  static const insn_to_changed_regs changed_regs[] = {
513
36.1k
    { M680X_INS_BSR, mmmm, { M680X_REG_S, EOL } },
514
36.1k
    { M680X_INS_CALL, mmmm, { M680X_REG_S, EOL } },
515
36.1k
    {
516
36.1k
      M680X_INS_CWAI,
517
36.1k
      mrrr,
518
36.1k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
519
36.1k
        M680X_REG_X, M680X_REG_DP, M680X_REG_D, M680X_REG_CC,
520
36.1k
        EOL },
521
36.1k
    },
522
36.1k
    { M680X_INS_DAA, mrrr, { M680X_REG_A, EOL } },
523
36.1k
    { M680X_INS_DIV,
524
36.1k
      mmrr,
525
36.1k
      { M680X_REG_A, M680X_REG_H, M680X_REG_X, EOL } },
526
36.1k
    { M680X_INS_EDIV,
527
36.1k
      mmrr,
528
36.1k
      { M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL } },
529
36.1k
    { M680X_INS_EDIVS,
530
36.1k
      mmrr,
531
36.1k
      { M680X_REG_D, M680X_REG_Y, M680X_REG_X, EOL } },
532
36.1k
    { M680X_INS_EMACS, mrrr, { M680X_REG_X, M680X_REG_Y, EOL } },
533
36.1k
    { M680X_INS_EMAXM, rrrr, { M680X_REG_D, EOL } },
534
36.1k
    { M680X_INS_EMINM, rrrr, { M680X_REG_D, EOL } },
535
36.1k
    { M680X_INS_EMUL, mmrr, { M680X_REG_D, M680X_REG_Y, EOL } },
536
36.1k
    { M680X_INS_EMULS, mmrr, { M680X_REG_D, M680X_REG_Y, EOL } },
537
36.1k
    { M680X_INS_ETBL, wmmm, { M680X_REG_A, M680X_REG_B, EOL } },
538
36.1k
    { M680X_INS_FDIV, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
539
36.1k
    { M680X_INS_IDIV, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
540
36.1k
    { M680X_INS_IDIVS, mmmm, { M680X_REG_D, M680X_REG_X, EOL } },
541
36.1k
    { M680X_INS_JSR, mmmm, { M680X_REG_S, EOL } },
542
36.1k
    { M680X_INS_LBSR, mmmm, { M680X_REG_S, EOL } },
543
36.1k
    { M680X_INS_MAXM, rrrr, { M680X_REG_A, EOL } },
544
36.1k
    { M680X_INS_MINM, rrrr, { M680X_REG_A, EOL } },
545
36.1k
    { M680X_INS_MEM,
546
36.1k
      mmrr,
547
36.1k
      { M680X_REG_X, M680X_REG_Y, M680X_REG_A, EOL } },
548
36.1k
    { M680X_INS_MUL, mmmm, { M680X_REG_A, M680X_REG_B, EOL } },
549
36.1k
    { M680X_INS_MULD, mwrr, { M680X_REG_D, M680X_REG_W, EOL } },
550
36.1k
    { M680X_INS_PSHA, rmmm, { M680X_REG_A, M680X_REG_S, EOL } },
551
36.1k
    { M680X_INS_PSHB, rmmm, { M680X_REG_B, M680X_REG_S, EOL } },
552
36.1k
    { M680X_INS_PSHC, rmmm, { M680X_REG_CC, M680X_REG_S, EOL } },
553
36.1k
    { M680X_INS_PSHD, rmmm, { M680X_REG_D, M680X_REG_S, EOL } },
554
36.1k
    { M680X_INS_PSHH, rmmm, { M680X_REG_H, M680X_REG_S, EOL } },
555
36.1k
    { M680X_INS_PSHX, rmmm, { M680X_REG_X, M680X_REG_S, EOL } },
556
36.1k
    { M680X_INS_PSHY, rmmm, { M680X_REG_Y, M680X_REG_S, EOL } },
557
36.1k
    { M680X_INS_PULA, wmmm, { M680X_REG_A, M680X_REG_S, EOL } },
558
36.1k
    { M680X_INS_PULB, wmmm, { M680X_REG_B, M680X_REG_S, EOL } },
559
36.1k
    { M680X_INS_PULC, wmmm, { M680X_REG_CC, M680X_REG_S, EOL } },
560
36.1k
    { M680X_INS_PULD, wmmm, { M680X_REG_D, M680X_REG_S, EOL } },
561
36.1k
    { M680X_INS_PULH, wmmm, { M680X_REG_H, M680X_REG_S, EOL } },
562
36.1k
    { M680X_INS_PULX, wmmm, { M680X_REG_X, M680X_REG_S, EOL } },
563
36.1k
    { M680X_INS_PULY, wmmm, { M680X_REG_Y, M680X_REG_S, EOL } },
564
36.1k
    { M680X_INS_REV,
565
36.1k
      mmrr,
566
36.1k
      { M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL } },
567
36.1k
    { M680X_INS_REVW,
568
36.1k
      mmmm,
569
36.1k
      { M680X_REG_A, M680X_REG_X, M680X_REG_Y, EOL } },
570
36.1k
    { M680X_INS_RTC, mwww, { M680X_REG_S, M680X_REG_PC, EOL } },
571
36.1k
    {
572
36.1k
      M680X_INS_RTI,
573
36.1k
      mwww,
574
36.1k
      { M680X_REG_S, M680X_REG_CC, M680X_REG_B, M680X_REG_A,
575
36.1k
        M680X_REG_DP, M680X_REG_X, M680X_REG_Y, M680X_REG_U,
576
36.1k
        M680X_REG_PC, EOL },
577
36.1k
    },
578
36.1k
    { M680X_INS_RTS, mwww, { M680X_REG_S, M680X_REG_PC, EOL } },
579
36.1k
    { M680X_INS_SEX, wrrr, { M680X_REG_A, M680X_REG_B, EOL } },
580
36.1k
    { M680X_INS_SEXW, rwww, { M680X_REG_W, M680X_REG_D, EOL } },
581
36.1k
    { M680X_INS_SWI,
582
36.1k
      mmrr,
583
36.1k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
584
36.1k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
585
36.1k
        M680X_REG_CC, EOL } },
586
36.1k
    {
587
36.1k
      M680X_INS_SWI2,
588
36.1k
      mmrr,
589
36.1k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
590
36.1k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
591
36.1k
        M680X_REG_CC, EOL },
592
36.1k
    },
593
36.1k
    {
594
36.1k
      M680X_INS_SWI3,
595
36.1k
      mmrr,
596
36.1k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_U, M680X_REG_Y,
597
36.1k
        M680X_REG_X, M680X_REG_DP, M680X_REG_A, M680X_REG_B,
598
36.1k
        M680X_REG_CC, EOL },
599
36.1k
    },
600
36.1k
    { M680X_INS_TBL, wrrr, { M680X_REG_A, M680X_REG_B, EOL } },
601
36.1k
    { M680X_INS_WAI,
602
36.1k
      mrrr,
603
36.1k
      { M680X_REG_S, M680X_REG_PC, M680X_REG_X, M680X_REG_A,
604
36.1k
        M680X_REG_B, M680X_REG_CC, EOL } },
605
36.1k
    { M680X_INS_WAV,
606
36.1k
      rmmm,
607
36.1k
      { M680X_REG_A, M680X_REG_B, M680X_REG_X, M680X_REG_Y, EOL } },
608
36.1k
    { M680X_INS_WAVR,
609
36.1k
      rmmm,
610
36.1k
      { M680X_REG_A, M680X_REG_B, M680X_REG_X, M680X_REG_Y, EOL } },
611
36.1k
  };
612
613
36.1k
  int i, j;
614
615
36.1k
  if (MI->flat_insn->detail == NULL)
616
0
    return;
617
618
1.87M
  for (i = 0; i < ARR_SIZE(changed_regs); ++i) {
619
1.84M
    if (info->insn == changed_regs[i].insn) {
620
36.1k
      e_access_mode access_mode = changed_regs[i].access_mode;
621
622
155k
      for (j = 0; changed_regs[i].regs[j] != EOL; ++j) {
623
119k
        e_access access;
624
625
119k
        m680x_reg reg = changed_regs[i].regs[j];
626
627
119k
        if (!info->cpu->reg_byte_size[reg]) {
628
9.32k
          if (info->insn != M680X_INS_MUL)
629
8.87k
            continue;
630
631
          // Hack for M68HC05: MUL uses reg. A,X
632
449
          reg = M680X_REG_X;
633
449
        }
634
635
110k
        access = get_access(j, access_mode);
636
110k
        add_reg_to_rw_list(MI, reg, access);
637
110k
      }
638
36.1k
    }
639
1.84M
  }
640
641
36.1k
#undef EOL
642
36.1k
}
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
50.6k
{
657
50.6k
  uint8_t ir = 0;
658
50.6k
  uint8_t post_byte;
659
660
  // Read the indexed addressing post byte.
661
50.6k
  if (!read_byte(info, &post_byte, address))
662
206
    return -1;
663
664
  // Depending on the indexed addressing mode more bytes have to be read.
665
50.4k
  switch (post_byte & 0x9F) {
666
1.61k
  case 0x87:
667
2.86k
  case 0x8A:
668
3.88k
  case 0x8E:
669
5.13k
  case 0x8F:
670
5.74k
  case 0x90:
671
6.30k
  case 0x92:
672
6.86k
  case 0x97:
673
7.37k
  case 0x9A:
674
7.88k
  case 0x9E:
675
7.88k
    return -1; // illegal indexed post bytes
676
677
2.46k
  case 0x88: // n8,R
678
3.58k
  case 0x8C: // n8,PCR
679
3.99k
  case 0x98: // [n8,R]
680
4.57k
  case 0x9C: // [n8,PCR]
681
4.57k
    if (!read_byte(info, &ir, address + 1))
682
30
      return -1;
683
4.54k
    return 2;
684
685
1.16k
  case 0x89: // n16,R
686
2.32k
  case 0x8D: // n16,PCR
687
3.03k
  case 0x99: // [n16,R]
688
3.81k
  case 0x9D: // [n16,PCR]
689
3.81k
    if (!read_byte(info, &ir, address + 2))
690
52
      return -1;
691
3.75k
    return 3;
692
693
1.48k
  case 0x9F: // [n]
694
1.48k
    if ((post_byte & 0x60) != 0 ||
695
606
        !read_byte(info, &ir, address + 2))
696
887
      return -1;
697
600
    return 3;
698
50.4k
  }
699
700
  // Any other indexed post byte is valid and
701
  // no additional bytes have to be read.
702
32.7k
  return 1;
703
50.4k
}
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
50.2k
{
711
50.2k
  uint8_t ir;
712
50.2k
  uint8_t post_byte;
713
714
  // Read the indexed addressing post byte.
715
50.2k
  if (!read_byte(info, &post_byte, address))
716
166
    return -1;
717
718
  // Depending on the indexed addressing mode more bytes have to be read.
719
50.0k
  if (!(post_byte & 0x20)) // n5,R
720
17.1k
    return 1;
721
722
32.9k
  switch (post_byte & 0xe7) {
723
4.09k
  case 0xe0:
724
8.05k
  case 0xe1: // n9,R
725
8.05k
    if (is_subset)
726
575
      return -1;
727
728
7.48k
    if (!read_byte(info, &ir, address))
729
0
      return -1;
730
7.48k
    return 2;
731
732
3.05k
  case 0xe2: // n16,R
733
5.83k
  case 0xe3: // [n16,R]
734
5.83k
    if (is_subset)
735
329
      return -1;
736
737
5.50k
    if (!read_byte(info, &ir, address + 1))
738
42
      return -1;
739
5.46k
    return 3;
740
741
1.44k
  case 0xe4: // A,R
742
2.73k
  case 0xe5: // B,R
743
4.03k
  case 0xe6: // D,R
744
5.36k
  case 0xe7: // [D,R]
745
19.0k
  default: // n,-r n,+r n,r- n,r+
746
19.0k
    break;
747
32.9k
  }
748
749
19.0k
  return 1;
750
32.9k
}
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.26k
{
755
6.26k
  if (info->cpu->tfr_reg_valid != NULL)
756
2.83k
    return info->cpu->tfr_reg_valid[reg_nibble];
757
758
3.42k
  return true; // e.g. for the M6309 all registers are valid
759
6.26k
}
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.46k
{
765
2.46k
  return !(post_byte & 0x08);
766
2.46k
}
767
768
static bool is_tfm_reg_valid(const m680x_info *info, uint8_t reg_nibble)
769
5.71k
{
770
  // HD6809 TFM instruction: Only register X,Y,U,S,D is allowed
771
5.71k
  return reg_nibble <= 4;
772
5.71k
}
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
5.30k
{
779
5.30k
  uint8_t post_byte;
780
5.30k
  uint8_t rr;
781
782
5.30k
  if (!read_byte(info, &post_byte, address))
783
12
    return -1;
784
785
  // According to documentation bit 3 is don't care and not checked here.
786
5.29k
  if ((post_byte >= 0xc0) || ((post_byte & 0x07) == 2) ||
787
3.87k
      ((post_byte & 0x07) == 3))
788
2.94k
    return -1;
789
790
2.34k
  if (!read_byte(info, &rr, address + 1))
791
14
    return -1;
792
793
2.33k
  return 2;
794
2.34k
}
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.69k
{
802
1.69k
  uint8_t post_byte;
803
1.69k
  uint8_t rr;
804
805
1.69k
  if (!read_byte(info, &post_byte, address))
806
13
    return -1;
807
808
1.67k
  if ((post_byte & 0xc0) == 0xc0)
809
893
    return -1; // Invalid register specified
810
784
  else {
811
784
    if (!read_byte(info, &rr, address + 1))
812
6
      return -1;
813
784
  }
814
815
778
  return 2;
816
1.67k
}
817
818
static bool is_sufficient_code_size(const m680x_info *info, uint16_t address,
819
            insn_desc *insn_description)
820
400k
{
821
400k
  int i;
822
400k
  bool retval = true;
823
400k
  uint16_t size = 0;
824
400k
  int sz;
825
826
1.16M
  for (i = 0; i < 2; i++) {
827
782k
    uint8_t ir = 0;
828
782k
    bool is_subset = false;
829
830
782k
    switch (insn_description->hid[i]) {
831
954
    case imm32_hid:
832
954
      if ((retval = read_byte(info, &ir, address + size + 3)))
833
919
        size += 4;
834
954
      break;
835
836
53.8k
    case ext_hid:
837
60.3k
    case imm16_hid:
838
63.4k
    case rel16_hid:
839
66.6k
    case imm8rel_hid:
840
71.5k
    case opidxdr_hid:
841
73.4k
    case idxX16_hid:
842
73.5k
    case idxS16_hid:
843
73.5k
      if ((retval = read_byte(info, &ir, address + size + 1)))
844
72.8k
        size += 2;
845
73.5k
      break;
846
847
25.6k
    case rel8_hid:
848
84.6k
    case dir_hid:
849
92.0k
    case rbits_hid:
850
116k
    case imm8_hid:
851
123k
    case idxX_hid:
852
124k
    case idxXp_hid:
853
126k
    case idxY_hid:
854
127k
    case idxS_hid:
855
128k
    case index_hid:
856
128k
      if ((retval = read_byte(info, &ir, address + size)))
857
128k
        size++;
858
128k
      break;
859
860
0
    case illgl_hid:
861
449k
    case inh_hid:
862
458k
    case idxX0_hid:
863
460k
    case idxX0p_hid:
864
462k
    case opidx_hid:
865
462k
      retval = true;
866
462k
      break;
867
868
50.6k
    case idx09_hid:
869
50.6k
      sz = get_indexed09_post_byte_size(info, address + size);
870
50.6k
      if (sz >= 0)
871
41.6k
        size += sz;
872
9.05k
      else
873
9.05k
        retval = false;
874
50.6k
      break;
875
876
1.12k
    case idx12s_hid:
877
1.12k
      is_subset = true;
878
879
      // intentionally fall through
880
881
39.8k
    case idx12_hid:
882
39.8k
      sz = get_indexed12_post_byte_size(info, address + size,
883
39.8k
                is_subset);
884
39.8k
      if (sz >= 0)
885
38.7k
        size += sz;
886
1.08k
      else
887
1.08k
        retval = false;
888
39.8k
      break;
889
890
2.92k
    case exti12x_hid:
891
5.59k
    case imm16i12x_hid:
892
5.59k
      sz = get_indexed12_post_byte_size(info, address + size,
893
5.59k
                false);
894
5.59k
      if (sz >= 0) {
895
5.58k
        size += sz;
896
5.58k
        if ((retval = read_byte(info, &ir,
897
5.58k
              address + size + 1)))
898
5.54k
          size += 2;
899
5.58k
      } else
900
13
        retval = false;
901
5.59k
      break;
902
903
4.74k
    case imm8i12x_hid:
904
4.74k
      sz = get_indexed12_post_byte_size(info, address + size,
905
4.74k
                false);
906
4.74k
      if (sz >= 0) {
907
4.72k
        size += sz;
908
4.72k
        if ((retval = read_byte(info, &ir,
909
4.72k
              address + size)))
910
4.69k
          size++;
911
4.72k
      } else
912
19
        retval = false;
913
4.74k
      break;
914
915
3.02k
    case tfm_hid:
916
3.02k
      if ((retval = read_byte(info, &ir, address + size))) {
917
3.01k
        size++;
918
3.01k
        retval = is_tfm_reg_valid(info,
919
3.01k
                (ir >> 4) & 0x0F) &&
920
2.70k
           is_tfm_reg_valid(info, ir & 0x0F);
921
3.01k
      }
922
3.02k
      break;
923
924
3.36k
    case rr09_hid:
925
3.36k
      if ((retval = read_byte(info, &ir, address + size))) {
926
3.35k
        size++;
927
3.35k
        retval = is_tfr09_reg_valid(info,
928
3.35k
                  (ir >> 4) & 0x0F) &&
929
2.90k
           is_tfr09_reg_valid(info, ir & 0x0F);
930
3.35k
      }
931
3.36k
      break;
932
933
2.47k
    case rr12_hid:
934
2.47k
      if ((retval = read_byte(info, &ir, address + size))) {
935
2.46k
        size++;
936
2.46k
        retval = is_exg_tfr12_post_byte_valid(info, ir);
937
2.46k
      }
938
2.47k
      break;
939
940
1.69k
    case bitmv_hid:
941
1.69k
      sz = get_bitmv_post_byte_size(info, address + size);
942
1.69k
      if (sz >= 0)
943
778
        size += sz;
944
912
      else
945
912
        retval = false;
946
1.69k
      break;
947
948
5.30k
    case loop_hid:
949
5.30k
      sz = get_loop_post_byte_size(info, address + size);
950
5.30k
      if (sz >= 0)
951
2.33k
        size += sz;
952
2.97k
      else
953
2.97k
        retval = false;
954
5.30k
      break;
955
956
0
    default:
957
0
      CS_ASSERT(0 && "Unexpected instruction handler id");
958
0
      retval = false;
959
0
      break;
960
782k
    }
961
962
782k
    if (!retval)
963
18.1k
      return false;
964
782k
  }
965
966
381k
  insn_description->insn_size += size;
967
968
381k
  return retval;
969
400k
}
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
424k
{
976
424k
  const inst_pageX *inst_table = NULL;
977
424k
  const cpu_tables *cpu = info->cpu;
978
424k
  size_t table_size = 0;
979
424k
  uint16_t base_address = address;
980
424k
  uint8_t ir; // instruction register
981
424k
  int i;
982
424k
  int index;
983
984
424k
  if (!read_byte(info, &ir, address++))
985
0
    return false;
986
987
424k
  insn_description->insn = M680X_INS_ILLGL;
988
424k
  insn_description->opcode = ir;
989
990
  // Check if a page prefix byte is present
991
1.02M
  for (i = 0; i < ARR_SIZE(cpu->pageX_table_size); ++i) {
992
1.00M
    if (cpu->pageX_table_size[i] == 0 ||
993
636k
        (cpu->inst_pageX_table[i] == NULL))
994
373k
      break;
995
996
636k
    if ((cpu->pageX_prefix[i] == ir)) {
997
      // Get pageX instruction and handler id.
998
      // Abort for illegal instr.
999
37.6k
      inst_table = cpu->inst_pageX_table[i];
1000
37.6k
      table_size = cpu->pageX_table_size[i];
1001
1002
37.6k
      if (!read_byte(info, &ir, address++))
1003
57
        return false;
1004
1005
37.5k
      insn_description->opcode =
1006
37.5k
        (insn_description->opcode << 8) | ir;
1007
1008
37.5k
      if ((index = binary_search(inst_table, table_size,
1009
37.5k
               ir)) < 0)
1010
10.2k
        return false;
1011
1012
27.3k
      insn_description->hid[0] =
1013
27.3k
        inst_table[index].handler_id1;
1014
27.3k
      insn_description->hid[1] =
1015
27.3k
        inst_table[index].handler_id2;
1016
27.3k
      insn_description->insn = inst_table[index].insn;
1017
27.3k
      break;
1018
37.5k
    }
1019
636k
  }
1020
1021
414k
  if (insn_description->insn == M680X_INS_ILLGL) {
1022
    // Get page1 insn description
1023
386k
    insn_description->insn = cpu->inst_page1_table[ir].insn;
1024
386k
    insn_description->hid[0] =
1025
386k
      cpu->inst_page1_table[ir].handler_id1;
1026
386k
    insn_description->hid[1] =
1027
386k
      cpu->inst_page1_table[ir].handler_id2;
1028
386k
  }
1029
1030
414k
  if (insn_description->insn == M680X_INS_ILLGL) {
1031
    // Check if opcode byte is present in an overlay table
1032
48.2k
    for (i = 0; i < ARR_SIZE(cpu->overlay_table_size); ++i) {
1033
46.0k
      if (cpu->overlay_table_size[i] == 0 ||
1034
34.0k
          (cpu->inst_overlay_table[i] == NULL))
1035
12.0k
        break;
1036
1037
34.0k
      inst_table = cpu->inst_overlay_table[i];
1038
34.0k
      table_size = cpu->overlay_table_size[i];
1039
1040
34.0k
      if ((index = binary_search(inst_table, table_size,
1041
34.0k
               ir)) >= 0) {
1042
20.0k
        insn_description->hid[0] =
1043
20.0k
          inst_table[index].handler_id1;
1044
20.0k
        insn_description->hid[1] =
1045
20.0k
          inst_table[index].handler_id2;
1046
20.0k
        insn_description->insn = inst_table[index].insn;
1047
20.0k
        break;
1048
20.0k
      }
1049
34.0k
    }
1050
34.2k
  }
1051
1052
414k
  insn_description->insn_size = address - base_address;
1053
1054
414k
  return (insn_description->insn != M680X_INS_ILLGL) &&
1055
400k
         (insn_description->insn != M680X_INS_INVLD) &&
1056
400k
         is_sufficient_code_size(info, address, insn_description);
1057
424k
}
1058
1059
static void illegal_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1060
42.5k
{
1061
42.5k
  cs_m680x_op *op0 = &info->m680x.operands[info->m680x.op_count++];
1062
42.5k
  uint8_t temp8 = 0;
1063
1064
42.5k
  info->insn = M680X_INS_ILLGL;
1065
42.5k
  read_byte(info, &temp8, (*address)++);
1066
42.5k
  op0->imm = (int32_t)temp8 & 0xff;
1067
42.5k
  op0->type = M680X_OP_IMMEDIATE;
1068
42.5k
  op0->size = 1;
1069
42.5k
}
1070
1071
static void inherent_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1072
449k
{
1073
  // There is nothing to do here :-)
1074
449k
}
1075
1076
static void add_reg_operand(m680x_info *info, m680x_reg reg)
1077
253k
{
1078
253k
  cs_m680x *m680x = &info->m680x;
1079
253k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1080
1081
253k
  op->type = M680X_OP_REGISTER;
1082
253k
  op->reg = reg;
1083
253k
  op->size = info->cpu->reg_byte_size[reg];
1084
253k
}
1085
1086
static void set_operand_size(m680x_info *info, cs_m680x_op *op,
1087
           uint8_t default_size)
1088
280k
{
1089
280k
  cs_m680x *m680x = &info->m680x;
1090
1091
280k
  if (info->insn == M680X_INS_JMP || info->insn == M680X_INS_JSR)
1092
12.2k
    op->size = 0;
1093
268k
  else if (info->insn == M680X_INS_DIVD ||
1094
266k
     ((info->insn == M680X_INS_AIS ||
1095
266k
       info->insn == M680X_INS_AIX) &&
1096
952
      op->type != M680X_OP_REGISTER))
1097
3.01k
    op->size = 1;
1098
265k
  else if (info->insn == M680X_INS_DIVQ || info->insn == M680X_INS_MOVW)
1099
9.59k
    op->size = 2;
1100
255k
  else if (info->insn == M680X_INS_EMACS)
1101
229
    op->size = 4;
1102
255k
  else if ((m680x->op_count > 0) &&
1103
255k
     (m680x->operands[0].type == M680X_OP_REGISTER))
1104
156k
    op->size = m680x->operands[0].size;
1105
99.6k
  else
1106
99.6k
    op->size = default_size;
1107
280k
}
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
3.38k
{
1121
3.38k
  cs_m680x_op *op0 = &info->m680x.operands[0];
1122
3.38k
  uint8_t reg_bits = 0;
1123
3.38k
  uint16_t bit_index;
1124
3.38k
  const m680x_reg *reg_to_reg_ids = NULL;
1125
1126
3.38k
  read_byte(info, &reg_bits, (*address)++);
1127
1128
3.38k
  switch (op0->reg) {
1129
2.26k
  case M680X_REG_U:
1130
2.26k
    reg_to_reg_ids = &reg_u_reg_ids[0];
1131
2.26k
    break;
1132
1133
1.12k
  case M680X_REG_S:
1134
1.12k
    reg_to_reg_ids = &reg_s_reg_ids[0];
1135
1.12k
    break;
1136
1137
0
  default:
1138
0
    CS_ASSERT(0 && "Unexpected operand0 register");
1139
0
    break;
1140
3.38k
  }
1141
1142
3.38k
  if ((info->insn == M680X_INS_PULU || (info->insn == M680X_INS_PULS)) &&
1143
2.12k
      ((reg_bits & 0x80) != 0))
1144
    // PULS xxx,PC or PULU xxx,PC which is like return from
1145
    // subroutine (RTS)
1146
746
    add_insn_group(MI->flat_insn->detail, M680X_GRP_RET);
1147
1148
30.4k
  for (bit_index = 0; bit_index < 8; ++bit_index) {
1149
27.0k
    if (reg_bits & (1 << bit_index) && reg_to_reg_ids)
1150
13.7k
      add_reg_operand(info, reg_to_reg_ids[bit_index]);
1151
27.0k
  }
1152
3.38k
}
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
1.82k
{
1177
1.82k
  uint8_t regs = 0;
1178
1179
1.82k
  read_byte(info, &regs, (*address)++);
1180
1181
1.82k
  add_reg_operand(info, g_tfr_exg_reg_ids[regs >> 4]);
1182
1.82k
  add_reg_operand(info, g_tfr_exg_reg_ids[regs & 0x0f]);
1183
1184
1.82k
  if ((regs & 0x0f) == 0x05) {
1185
    // EXG xxx,PC or TFR xxx,PC which is like a JMP
1186
371
    add_insn_group(MI->flat_insn->detail, M680X_GRP_JUMP);
1187
371
  }
1188
1.82k
}
1189
1190
static void reg_reg12_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1191
2.29k
{
1192
2.29k
  static const m680x_reg g_tfr_exg12_reg0_ids[] = {
1193
2.29k
    M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP3,
1194
2.29k
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,  M680X_REG_S,
1195
2.29k
  };
1196
2.29k
  static const m680x_reg g_tfr_exg12_reg1_ids[] = {
1197
2.29k
    M680X_REG_A, M680X_REG_B, M680X_REG_CC, M680X_REG_TMP2,
1198
2.29k
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,  M680X_REG_S,
1199
2.29k
  };
1200
2.29k
  uint8_t regs = 0;
1201
1202
2.29k
  read_byte(info, &regs, (*address)++);
1203
1204
  // The opcode of this instruction depends on
1205
  // the msb of its post byte.
1206
2.29k
  if (regs & 0x80)
1207
1.60k
    info->insn = M680X_INS_EXG;
1208
691
  else
1209
691
    info->insn = M680X_INS_TFR;
1210
1211
2.29k
  add_reg_operand(info, g_tfr_exg12_reg0_ids[(regs >> 4) & 0x07]);
1212
2.29k
  add_reg_operand(info, g_tfr_exg12_reg1_ids[regs & 0x07]);
1213
2.29k
}
1214
1215
static void add_rel_operand(m680x_info *info, int16_t offset, uint16_t address)
1216
36.5k
{
1217
36.5k
  cs_m680x *m680x = &info->m680x;
1218
36.5k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1219
1220
36.5k
  op->type = M680X_OP_RELATIVE;
1221
36.5k
  op->size = 0;
1222
36.5k
  op->rel.offset = offset;
1223
36.5k
  op->rel.address = address;
1224
36.5k
}
1225
1226
static void relative8_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1227
33.4k
{
1228
33.4k
  int16_t offset = 0;
1229
1230
33.4k
  read_byte_sign_extended(info, &offset, (*address)++);
1231
33.4k
  add_rel_operand(info, offset, *address + offset);
1232
33.4k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1233
1234
33.4k
  if ((info->insn != M680X_INS_BRA) && (info->insn != M680X_INS_BSR) &&
1235
27.8k
      (info->insn != M680X_INS_BRN))
1236
26.1k
    add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1237
33.4k
}
1238
1239
static void relative16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1240
3.06k
{
1241
3.06k
  uint16_t offset = 0;
1242
1243
3.06k
  read_word(info, &offset, *address);
1244
3.06k
  *address += 2;
1245
3.06k
  add_rel_operand(info, (int16_t)offset, *address + offset);
1246
3.06k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1247
1248
3.06k
  if ((info->insn != M680X_INS_LBRA) && (info->insn != M680X_INS_LBSR) &&
1249
1.12k
      (info->insn != M680X_INS_LBRN))
1250
519
    add_reg_to_rw_list(MI, M680X_REG_CC, READ);
1251
3.06k
}
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
27.8k
{
1265
27.8k
  cs_m680x *m680x = &info->m680x;
1266
27.8k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1267
1268
27.8k
  op->type = M680X_OP_INDEXED;
1269
27.8k
  set_operand_size(info, op, 1);
1270
27.8k
  op->idx.base_reg = base_reg;
1271
27.8k
  op->idx.offset_reg = M680X_REG_INVALID;
1272
27.8k
  op->idx.inc_dec = inc_dec;
1273
1274
27.8k
  if (inc_dec && post_inc_dec)
1275
6.51k
    op->idx.flags |= M680X_IDX_POST_INC_DEC;
1276
1277
27.8k
  if (offset_bits != M680X_OFFSET_NONE) {
1278
12.9k
    op->idx.offset = offset;
1279
12.9k
    op->idx.offset_addr = 0;
1280
12.9k
  }
1281
1282
27.8k
  op->idx.offset_bits = offset_bits;
1283
27.8k
  op->idx.flags |= (no_comma ? M680X_IDX_NO_COMMA : 0);
1284
27.8k
}
1285
1286
// M6800/1/2/3 indexed mode handler
1287
static void indexedX_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1288
6.74k
{
1289
6.74k
  uint8_t offset = 0;
1290
1291
6.74k
  read_byte(info, &offset, (*address)++);
1292
1293
6.74k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_8,
1294
6.74k
          (uint16_t)offset, false);
1295
6.74k
}
1296
1297
static void indexedY_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1298
1.34k
{
1299
1.34k
  uint8_t offset = 0;
1300
1301
1.34k
  read_byte(info, &offset, (*address)++);
1302
1303
1.34k
  add_indexed_operand(info, M680X_REG_Y, false, 0, M680X_OFFSET_BITS_8,
1304
1.34k
          (uint16_t)offset, false);
1305
1.34k
}
1306
1307
// M6809/M6309 indexed mode handler
1308
static void indexed09_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1309
41.6k
{
1310
41.6k
  cs_m680x *m680x = &info->m680x;
1311
41.6k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1312
41.6k
  uint8_t post_byte = 0;
1313
41.6k
  uint16_t offset = 0;
1314
41.6k
  int16_t soffset = 0;
1315
1316
41.6k
  read_byte(info, &post_byte, (*address)++);
1317
1318
41.6k
  op->type = M680X_OP_INDEXED;
1319
41.6k
  set_operand_size(info, op, 1);
1320
41.6k
  op->idx.base_reg = g_rr5_to_reg_ids[(post_byte >> 5) & 0x03];
1321
41.6k
  op->idx.offset_reg = M680X_REG_INVALID;
1322
1323
41.6k
  if (!(post_byte & 0x80)) {
1324
    // n5,R
1325
18.8k
    if ((post_byte & 0x10) == 0x10)
1326
9.22k
      op->idx.offset = post_byte | 0xfff0;
1327
9.66k
    else
1328
9.66k
      op->idx.offset = post_byte & 0x0f;
1329
1330
18.8k
    op->idx.offset_addr = op->idx.offset + *address;
1331
18.8k
    op->idx.offset_bits = M680X_OFFSET_BITS_5;
1332
22.7k
  } else {
1333
22.7k
    if ((post_byte & 0x10) == 0x10)
1334
6.92k
      op->idx.flags |= M680X_IDX_INDIRECT;
1335
1336
    // indexed addressing
1337
22.7k
    switch (post_byte & 0x1f) {
1338
1.44k
    case 0x00: // ,R+
1339
1.44k
      op->idx.inc_dec = 1;
1340
1.44k
      op->idx.flags |= M680X_IDX_POST_INC_DEC;
1341
1.44k
      break;
1342
1343
391
    case 0x11: // [,R++]
1344
1.99k
    case 0x01: // ,R++
1345
1.99k
      op->idx.inc_dec = 2;
1346
1.99k
      op->idx.flags |= M680X_IDX_POST_INC_DEC;
1347
1.99k
      break;
1348
1349
922
    case 0x02: // ,-R
1350
922
      op->idx.inc_dec = -1;
1351
922
      break;
1352
1353
1.13k
    case 0x13: // [,--R]
1354
2.14k
    case 0x03: // ,--R
1355
2.14k
      op->idx.inc_dec = -2;
1356
2.14k
      break;
1357
1358
544
    case 0x14: // [,R]
1359
1.56k
    case 0x04: // ,R
1360
1.56k
      break;
1361
1362
544
    case 0x15: // [B,R]
1363
2.86k
    case 0x05: // B,R
1364
2.86k
      op->idx.offset_reg = M680X_REG_B;
1365
2.86k
      break;
1366
1367
812
    case 0x16: // [A,R]
1368
1.55k
    case 0x06: // A,R
1369
1.55k
      op->idx.offset_reg = M680X_REG_A;
1370
1.55k
      break;
1371
1372
583
    case 0x1c: // [n8,PCR]
1373
1.69k
    case 0x0c: // n8,PCR
1374
1.69k
      op->idx.base_reg = M680X_REG_PC;
1375
1.69k
      read_byte_sign_extended(info, &soffset, (*address)++);
1376
1.69k
      op->idx.offset_addr = offset + *address;
1377
1.69k
      op->idx.offset = soffset;
1378
1.69k
      op->idx.offset_bits = M680X_OFFSET_BITS_8;
1379
1.69k
      break;
1380
1381
402
    case 0x18: // [n8,R]
1382
2.85k
    case 0x08: // n8,R
1383
2.85k
      read_byte_sign_extended(info, &soffset, (*address)++);
1384
2.85k
      op->idx.offset = soffset;
1385
2.85k
      op->idx.offset_bits = M680X_OFFSET_BITS_8;
1386
2.85k
      break;
1387
1388
773
    case 0x1d: // [n16,PCR]
1389
1.90k
    case 0x0d: // n16,PCR
1390
1.90k
      op->idx.base_reg = M680X_REG_PC;
1391
1.90k
      read_word(info, &offset, *address);
1392
1.90k
      *address += 2;
1393
1.90k
      op->idx.offset_addr = offset + *address;
1394
1.90k
      op->idx.offset = (int16_t)offset;
1395
1.90k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1396
1.90k
      break;
1397
1398
697
    case 0x19: // [n16,R]
1399
1.85k
    case 0x09: // n16,R
1400
1.85k
      read_word(info, &offset, *address);
1401
1.85k
      *address += 2;
1402
1.85k
      op->idx.offset = (int16_t)offset;
1403
1.85k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1404
1.85k
      break;
1405
1406
436
    case 0x1b: // [D,R]
1407
1.33k
    case 0x0b: // D,R
1408
1.33k
      op->idx.offset_reg = M680X_REG_D;
1409
1.33k
      break;
1410
1411
600
    case 0x1f: // [n16]
1412
600
      op->type = M680X_OP_EXTENDED;
1413
600
      op->ext.indirect = true;
1414
600
      read_word(info, &op->ext.address, *address);
1415
600
      *address += 2;
1416
600
      break;
1417
1418
0
    default:
1419
0
      op->idx.base_reg = M680X_REG_INVALID;
1420
0
      break;
1421
22.7k
    }
1422
22.7k
  }
1423
1424
41.6k
  if (((info->insn == M680X_INS_LEAU) || (info->insn == M680X_INS_LEAS) ||
1425
39.0k
       (info->insn == M680X_INS_LEAX) ||
1426
36.7k
       (info->insn == M680X_INS_LEAY)) &&
1427
6.38k
      (m680x->operands[0].reg == M680X_REG_X ||
1428
4.11k
       (m680x->operands[0].reg == M680X_REG_Y)))
1429
    // Only LEAX and LEAY modify CC register
1430
3.76k
    add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1431
41.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
48.9k
{
1446
48.9k
  cs_m680x *m680x = &info->m680x;
1447
48.9k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1448
48.9k
  uint8_t post_byte = 0;
1449
48.9k
  uint8_t offset8 = 0;
1450
1451
48.9k
  read_byte(info, &post_byte, (*address)++);
1452
1453
48.9k
  op->type = M680X_OP_INDEXED;
1454
48.9k
  set_operand_size(info, op, 1);
1455
48.9k
  op->idx.offset_reg = M680X_REG_INVALID;
1456
1457
48.9k
  if (!(post_byte & 0x20)) {
1458
    // n5,R      n5 is a 5-bit signed offset
1459
17.1k
    op->idx.base_reg = g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1460
1461
17.1k
    if ((post_byte & 0x10) == 0x10)
1462
7.46k
      op->idx.offset = post_byte | 0xfff0;
1463
9.64k
    else
1464
9.64k
      op->idx.offset = post_byte & 0x0f;
1465
1466
17.1k
    op->idx.offset_addr = op->idx.offset + *address;
1467
17.1k
    op->idx.offset_bits = M680X_OFFSET_BITS_5;
1468
31.8k
  } else {
1469
31.8k
    if ((post_byte & 0xe0) == 0xe0)
1470
18.2k
      op->idx.base_reg =
1471
18.2k
        g_idx12_to_reg_ids[(post_byte >> 3) & 0x03];
1472
1473
31.8k
    switch (post_byte & 0xe7) {
1474
4.07k
    case 0xe0:
1475
7.45k
    case 0xe1: // n9,R
1476
7.45k
      read_byte(info, &offset8, (*address)++);
1477
7.45k
      op->idx.offset = offset8;
1478
1479
7.45k
      if (post_byte & 0x01) // sign extension
1480
3.37k
        op->idx.offset |= 0xff00;
1481
1482
7.45k
      op->idx.offset_bits = M680X_OFFSET_BITS_9;
1483
1484
7.45k
      if (op->idx.base_reg == M680X_REG_PC)
1485
1.72k
        op->idx.offset_addr = op->idx.offset + *address;
1486
1487
7.45k
      break;
1488
1489
2.53k
    case 0xe3: // [n16,R]
1490
2.53k
      op->idx.flags |= M680X_IDX_INDIRECT;
1491
1492
    // intentionally fall through
1493
5.44k
    case 0xe2: // n16,R
1494
5.44k
      read_word(info, (uint16_t *)&op->idx.offset, *address);
1495
5.44k
      (*address) += 2;
1496
5.44k
      op->idx.offset_bits = M680X_OFFSET_BITS_16;
1497
1498
5.44k
      if (op->idx.base_reg == M680X_REG_PC)
1499
655
        op->idx.offset_addr = op->idx.offset + *address;
1500
1501
5.44k
      break;
1502
1503
1.44k
    case 0xe4: // A,R
1504
2.73k
    case 0xe5: // B,R
1505
4.03k
    case 0xe6: // D,R
1506
4.03k
      op->idx.offset_reg =
1507
4.03k
        g_or12_to_reg_ids[post_byte & 0x03];
1508
4.03k
      break;
1509
1510
1.32k
    case 0xe7: // [D,R]
1511
1.32k
      op->idx.offset_reg = M680X_REG_D;
1512
1.32k
      op->idx.flags |= M680X_IDX_INDIRECT;
1513
1.32k
      break;
1514
1515
13.6k
    default: // n,-r n,+r n,r- n,r+
1516
      // PC is not allowed in this mode
1517
13.6k
      op->idx.base_reg =
1518
13.6k
        g_idx12_to_reg_ids[(post_byte >> 6) & 0x03];
1519
13.6k
      op->idx.inc_dec = post_byte & 0x0f;
1520
1521
13.6k
      if (op->idx.inc_dec & 0x08) // evtl. sign extend value
1522
6.10k
        op->idx.inc_dec |= 0xf0;
1523
1524
13.6k
      if (op->idx.inc_dec >= 0)
1525
7.52k
        op->idx.inc_dec++;
1526
1527
13.6k
      if (post_byte & 0x10)
1528
3.93k
        op->idx.flags |= M680X_IDX_POST_INC_DEC;
1529
1530
13.6k
      break;
1531
31.8k
    }
1532
31.8k
  }
1533
48.9k
}
1534
1535
static void index_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1536
1.17k
{
1537
1.17k
  cs_m680x *m680x = &info->m680x;
1538
1.17k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1539
1540
1.17k
  op->type = M680X_OP_CONSTANT;
1541
1.17k
  read_byte(info, &op->const_val, (*address)++);
1542
1.17k
};
1543
1544
static void direct_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1545
64.3k
{
1546
64.3k
  cs_m680x *m680x = &info->m680x;
1547
64.3k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1548
1549
64.3k
  op->type = M680X_OP_DIRECT;
1550
64.3k
  set_operand_size(info, op, 1);
1551
64.3k
  read_byte(info, &op->direct_addr, (*address)++);
1552
64.3k
};
1553
1554
static void extended_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1555
53.3k
{
1556
53.3k
  cs_m680x *m680x = &info->m680x;
1557
53.3k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1558
1559
53.3k
  op->type = M680X_OP_EXTENDED;
1560
53.3k
  set_operand_size(info, op, 1);
1561
53.3k
  read_word(info, &op->ext.address, *address);
1562
53.3k
  *address += 2;
1563
53.3k
}
1564
1565
static void immediate_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1566
34.4k
{
1567
34.4k
  cs_m680x *m680x = &info->m680x;
1568
34.4k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1569
34.4k
  uint16_t word = 0;
1570
34.4k
  int16_t sword = 0;
1571
1572
34.4k
  op->type = M680X_OP_IMMEDIATE;
1573
34.4k
  set_operand_size(info, op, 1);
1574
1575
34.4k
  switch (op->size) {
1576
27.0k
  case 1:
1577
27.0k
    read_byte_sign_extended(info, &sword, *address);
1578
27.0k
    op->imm = sword;
1579
27.0k
    break;
1580
1581
6.46k
  case 2:
1582
6.46k
    read_word(info, &word, *address);
1583
6.46k
    op->imm = (int16_t)word;
1584
6.46k
    break;
1585
1586
919
  case 4:
1587
919
    read_sdword(info, &op->imm, *address);
1588
919
    break;
1589
1590
0
  default:
1591
0
    op->imm = 0;
1592
0
    CS_ASSERT(0 && "Unexpected immediate byte size");
1593
34.4k
  }
1594
1595
34.4k
  *address += op->size;
1596
34.4k
}
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
778
{
1601
778
  static const m680x_reg m680x_reg[] = {
1602
778
    M680X_REG_CC,
1603
778
    M680X_REG_A,
1604
778
    M680X_REG_B,
1605
778
    M680X_REG_INVALID,
1606
778
  };
1607
1608
778
  uint8_t post_byte = 0;
1609
778
  cs_m680x *m680x = &info->m680x;
1610
778
  cs_m680x_op *op;
1611
1612
778
  read_byte(info, &post_byte, *address);
1613
778
  (*address)++;
1614
1615
  // operand[0] = register
1616
778
  add_reg_operand(info, m680x_reg[post_byte >> 6]);
1617
1618
  // operand[1] = bit index in source operand
1619
778
  op = &m680x->operands[m680x->op_count++];
1620
778
  op->type = M680X_OP_CONSTANT;
1621
778
  op->const_val = (post_byte >> 3) & 0x07;
1622
1623
  // operand[2] = bit index in destination operand
1624
778
  op = &m680x->operands[m680x->op_count++];
1625
778
  op->type = M680X_OP_CONSTANT;
1626
778
  op->const_val = post_byte & 0x07;
1627
1628
778
  direct_hdlr(MI, info, address);
1629
778
}
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
2.07k
{
1634
2.07k
  static const uint8_t inc_dec_r0[] = {
1635
2.07k
    1,
1636
2.07k
    -1,
1637
2.07k
    1,
1638
2.07k
    0,
1639
2.07k
  };
1640
2.07k
  static const uint8_t inc_dec_r1[] = {
1641
2.07k
    1,
1642
2.07k
    -1,
1643
2.07k
    0,
1644
2.07k
    1,
1645
2.07k
  };
1646
2.07k
  uint8_t regs = 0;
1647
2.07k
  uint8_t index = (MI->Opcode & 0xff) - 0x38;
1648
1649
2.07k
  read_byte(info, &regs, *address);
1650
1651
2.07k
  add_indexed_operand(info, g_tfr_exg_reg_ids[regs >> 4], true,
1652
2.07k
          inc_dec_r0[index], M680X_OFFSET_NONE, 0, true);
1653
2.07k
  add_indexed_operand(info, g_tfr_exg_reg_ids[regs & 0x0f], true,
1654
2.07k
          inc_dec_r1[index], M680X_OFFSET_NONE, 0, true);
1655
1656
2.07k
  add_reg_to_rw_list(MI, M680X_REG_W, READ | WRITE);
1657
2.07k
}
1658
1659
static void opidx_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1660
1.78k
{
1661
1.78k
  cs_m680x *m680x = &info->m680x;
1662
1.78k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1663
1664
  // bit index is coded in Opcode
1665
1.78k
  op->type = M680X_OP_CONSTANT;
1666
1.78k
  op->const_val = (MI->Opcode & 0x0e) >> 1;
1667
1.78k
}
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
4.80k
{
1674
4.80k
  cs_m680x *m680x = &info->m680x;
1675
4.80k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1676
1677
  // bit index is coded in Opcode
1678
4.80k
  op->type = M680X_OP_CONSTANT;
1679
4.80k
  op->const_val = (MI->Opcode & 0x0e) >> 1;
1680
4.80k
  direct_hdlr(MI, info, address);
1681
4.80k
  relative8_hdlr(MI, info, address);
1682
1683
4.80k
  add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1684
4.80k
}
1685
1686
static void indexedX0_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1687
8.32k
{
1688
8.32k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_NONE, 0,
1689
8.32k
          false);
1690
8.32k
}
1691
1692
static void indexedX16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1693
1.82k
{
1694
1.82k
  uint16_t offset = 0;
1695
1696
1.82k
  read_word(info, &offset, *address);
1697
1.82k
  *address += 2;
1698
1.82k
  add_indexed_operand(info, M680X_REG_X, false, 0, M680X_OFFSET_BITS_16,
1699
1.82k
          offset, false);
1700
1.82k
}
1701
1702
static void imm_rel_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1703
3.17k
{
1704
3.17k
  immediate_hdlr(MI, info, address);
1705
3.17k
  relative8_hdlr(MI, info, address);
1706
3.17k
}
1707
1708
static void indexedS_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1709
1.05k
{
1710
1.05k
  uint8_t offset = 0;
1711
1712
1.05k
  read_byte(info, &offset, (*address)++);
1713
1714
1.05k
  add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_8,
1715
1.05k
          (uint16_t)offset, false);
1716
1.05k
}
1717
1718
static void indexedS16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1719
127
{
1720
127
  uint16_t offset = 0;
1721
1722
127
  read_word(info, &offset, *address);
1723
127
  *address += 2;
1724
1725
127
  add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_16,
1726
127
          offset, false);
1727
127
}
1728
1729
static void indexedX0p_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1730
2.44k
{
1731
2.44k
  add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_NONE, 0,
1732
2.44k
          true);
1733
2.44k
}
1734
1735
static void indexedXp_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1736
1.81k
{
1737
1.81k
  uint8_t offset = 0;
1738
1739
1.81k
  read_byte(info, &offset, (*address)++);
1740
1741
1.81k
  add_indexed_operand(info, M680X_REG_X, true, 1, M680X_OFFSET_BITS_8,
1742
1.81k
          (uint16_t)offset, false);
1743
1.81k
}
1744
1745
static void imm_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1746
7.34k
{
1747
7.34k
  cs_m680x *m680x = &info->m680x;
1748
7.34k
  cs_m680x_op *op = &m680x->operands[m680x->op_count++];
1749
1750
7.34k
  indexed12_hdlr(MI, info, address);
1751
7.34k
  op->type = M680X_OP_IMMEDIATE;
1752
1753
7.34k
  if (info->insn == M680X_INS_MOVW) {
1754
2.65k
    uint16_t imm16 = 0;
1755
1756
2.65k
    read_word(info, &imm16, *address);
1757
2.65k
    op->imm = (int16_t)imm16;
1758
2.65k
    op->size = 2;
1759
4.69k
  } else {
1760
4.69k
    uint8_t imm8 = 0;
1761
1762
4.69k
    read_byte(info, &imm8, *address);
1763
4.69k
    op->imm = (int8_t)imm8;
1764
4.69k
    op->size = 1;
1765
4.69k
  }
1766
1767
7.34k
  set_operand_size(info, op, 1);
1768
7.34k
}
1769
1770
static void ext_idx12_x_hdlr(MCInst *MI, m680x_info *info, uint16_t *address)
1771
2.88k
{
1772
2.88k
  cs_m680x *m680x = &info->m680x;
1773
2.88k
  cs_m680x_op *op0 = &m680x->operands[m680x->op_count++];
1774
2.88k
  uint16_t imm16 = 0;
1775
1776
2.88k
  indexed12_hdlr(MI, info, address);
1777
2.88k
  read_word(info, &imm16, *address);
1778
2.88k
  op0->type = M680X_OP_EXTENDED;
1779
2.88k
  op0->ext.address = (int16_t)imm16;
1780
2.88k
  set_operand_size(info, op0, 1);
1781
2.88k
}
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
2.33k
{
1787
2.33k
  static const m680x_reg index_to_reg_id[] = {
1788
2.33k
    M680X_REG_A, M680X_REG_B, M680X_REG_INVALID, M680X_REG_INVALID,
1789
2.33k
    M680X_REG_D, M680X_REG_X, M680X_REG_Y,       M680X_REG_S,
1790
2.33k
  };
1791
2.33k
  static const m680x_insn index_to_insn_id[] = {
1792
2.33k
    M680X_INS_DBEQ, M680X_INS_DBNE, M680X_INS_TBEQ,  M680X_INS_TBNE,
1793
2.33k
    M680X_INS_IBEQ, M680X_INS_IBNE, M680X_INS_ILLGL, M680X_INS_ILLGL
1794
2.33k
  };
1795
2.33k
  cs_m680x *m680x = &info->m680x;
1796
2.33k
  uint8_t post_byte = 0;
1797
2.33k
  uint8_t rel = 0;
1798
2.33k
  cs_m680x_op *op;
1799
1800
2.33k
  read_byte(info, &post_byte, (*address)++);
1801
1802
2.33k
  info->insn = index_to_insn_id[(post_byte >> 5) & 0x07];
1803
1804
2.33k
  if (info->insn == M680X_INS_ILLGL) {
1805
0
    illegal_hdlr(MI, info, address);
1806
0
  };
1807
1808
2.33k
  read_byte(info, &rel, (*address)++);
1809
1810
2.33k
  add_reg_operand(info, index_to_reg_id[post_byte & 0x07]);
1811
1812
2.33k
  op = &m680x->operands[m680x->op_count++];
1813
1814
2.33k
  op->type = M680X_OP_RELATIVE;
1815
1816
2.33k
  op->rel.offset = (post_byte & 0x10) ? (int16_t)(0xff00 | rel) : rel;
1817
1818
2.33k
  op->rel.address = *address + op->rel.offset;
1819
1820
2.33k
  add_insn_group(MI->flat_insn->detail, M680X_GRP_BRAREL);
1821
2.33k
}
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
424k
{
1842
424k
  cs_m680x *m680x = &info->m680x;
1843
424k
  cs_detail *detail = MI->flat_insn->detail;
1844
424k
  uint16_t base_address = address;
1845
424k
  insn_desc insn_description;
1846
424k
  e_access_mode access_mode;
1847
1848
424k
  if (detail != NULL) {
1849
424k
    memset(detail, 0,
1850
424k
           offsetof(cs_detail, m680x) + sizeof(cs_m680x));
1851
424k
  }
1852
1853
424k
  memset(&insn_description, 0, sizeof(insn_description));
1854
424k
  memset(m680x, 0, sizeof(*m680x));
1855
424k
  info->insn_size = 1;
1856
1857
424k
  if (decode_insn(info, address, &insn_description)) {
1858
381k
    m680x_reg reg;
1859
1860
381k
    if (insn_description.opcode > 0xff)
1861
24.3k
      address += 2; // 8-bit opcode + page prefix
1862
357k
    else
1863
357k
      address++; // 8-bit opcode only
1864
1865
381k
    info->insn = insn_description.insn;
1866
1867
381k
    MCInst_setOpcode(MI, insn_description.opcode);
1868
1869
381k
    reg = g_insn_props[info->insn].reg0;
1870
1871
381k
    if (reg != M680X_REG_INVALID) {
1872
205k
      if (reg == M680X_REG_HX &&
1873
1.95k
          (!info->cpu->reg_byte_size[reg]))
1874
448
        reg = M680X_REG_X;
1875
1876
205k
      add_reg_operand(info, reg);
1877
      // First (or second) operand is a register which is
1878
      // part of the mnemonic
1879
205k
      m680x->flags |= M680X_FIRST_OP_IN_MNEM;
1880
205k
      reg = g_insn_props[info->insn].reg1;
1881
1882
205k
      if (reg != M680X_REG_INVALID) {
1883
4.35k
        if (reg == M680X_REG_HX &&
1884
975
            (!info->cpu->reg_byte_size[reg]))
1885
550
          reg = M680X_REG_X;
1886
1887
4.35k
        add_reg_operand(info, reg);
1888
4.35k
        m680x->flags |= M680X_SECOND_OP_IN_MNEM;
1889
4.35k
      }
1890
205k
    }
1891
1892
    // Call addressing mode specific instruction handler
1893
381k
    (g_insn_handler[insn_description.hid[0]])(MI, info, &address);
1894
381k
    (g_insn_handler[insn_description.hid[1]])(MI, info, &address);
1895
1896
381k
    add_insn_group(detail, g_insn_props[info->insn].group);
1897
1898
381k
    if (g_insn_props[info->insn].cc_modified &&
1899
245k
        (info->cpu->insn_cc_not_modified[0] != info->insn) &&
1900
244k
        (info->cpu->insn_cc_not_modified[1] != info->insn))
1901
243k
      add_reg_to_rw_list(MI, M680X_REG_CC, MODIFY);
1902
1903
381k
    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
381k
    if ((info->cpu->insn_cc_not_modified[0] == info->insn) ||
1908
380k
        (info->cpu->insn_cc_not_modified[1] == info->insn))
1909
1.78k
      access_mode = rmmm;
1910
1911
381k
    build_regs_read_write_counts(MI, info, access_mode);
1912
381k
    add_operators_access(MI, info, access_mode);
1913
1914
381k
    if (g_insn_props[info->insn].update_reg_access)
1915
36.1k
      set_changed_regs_read_write_counts(MI, info);
1916
1917
381k
    info->insn_size = (uint8_t)insn_description.insn_size;
1918
1919
381k
    return info->insn_size;
1920
381k
  } else
1921
42.5k
    MCInst_setOpcode(MI, insn_description.opcode);
1922
1923
  // Illegal instruction
1924
42.5k
  address = base_address;
1925
42.5k
  illegal_hdlr(MI, info, &address);
1926
42.5k
  return 1;
1927
424k
}
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
424k
{
2105
424k
  if (cpu_type == M680X_CPU_TYPE_INVALID) {
2106
0
    return false;
2107
0
  }
2108
2109
424k
  info->code = code;
2110
424k
  info->size = code_len;
2111
424k
  info->offset = address;
2112
424k
  info->cpu_type = cpu_type;
2113
2114
424k
  info->cpu = &g_cpu_tables[info->cpu_type];
2115
2116
424k
  return true;
2117
424k
}
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
424k
{
2123
424k
  unsigned int insn_size = 0;
2124
424k
  e_cpu_type cpu_type = M680X_CPU_TYPE_INVALID; // No default CPU type
2125
424k
  cs_struct *handle = (cs_struct *)ud;
2126
424k
  m680x_info *info = (m680x_info *)handle->printer_info;
2127
2128
424k
  MCInst_clear(MI);
2129
2130
424k
  if (handle->mode & CS_MODE_M680X_6800)
2131
2.07k
    cpu_type = M680X_CPU_TYPE_6800;
2132
2133
422k
  else if (handle->mode & CS_MODE_M680X_6801)
2134
1.55k
    cpu_type = M680X_CPU_TYPE_6801;
2135
2136
420k
  else if (handle->mode & CS_MODE_M680X_6805)
2137
4.68k
    cpu_type = M680X_CPU_TYPE_6805;
2138
2139
416k
  else if (handle->mode & CS_MODE_M680X_6808)
2140
19.3k
    cpu_type = M680X_CPU_TYPE_6808;
2141
2142
396k
  else if (handle->mode & CS_MODE_M680X_HCS08)
2143
17.0k
    cpu_type = M680X_CPU_TYPE_HCS08;
2144
2145
379k
  else if (handle->mode & CS_MODE_M680X_6809)
2146
37.5k
    cpu_type = M680X_CPU_TYPE_6809;
2147
2148
342k
  else if (handle->mode & CS_MODE_M680X_6301)
2149
3.12k
    cpu_type = M680X_CPU_TYPE_6301;
2150
2151
339k
  else if (handle->mode & CS_MODE_M680X_6309)
2152
161k
    cpu_type = M680X_CPU_TYPE_6309;
2153
2154
178k
  else if (handle->mode & CS_MODE_M680X_6811)
2155
15.6k
    cpu_type = M680X_CPU_TYPE_6811;
2156
2157
162k
  else if (handle->mode & CS_MODE_M680X_CPU12)
2158
162k
    cpu_type = M680X_CPU_TYPE_CPU12;
2159
2160
424k
  if (cpu_type != M680X_CPU_TYPE_INVALID &&
2161
424k
      m680x_setup_internals(info, cpu_type, (uint16_t)address, code,
2162
424k
          (uint16_t)code_len))
2163
424k
    insn_size = m680x_disassemble(MI, info, (uint16_t)address);
2164
2165
424k
  if (insn_size == 0) {
2166
0
    *size = 1;
2167
0
    return false;
2168
0
  }
2169
2170
  // Make sure we always stay within range
2171
424k
  if (insn_size > code_len) {
2172
39
    *size = (uint16_t)code_len;
2173
39
    return false;
2174
39
  } else
2175
424k
    *size = (uint16_t)insn_size;
2176
2177
424k
  return true;
2178
424k
}
2179
2180
cs_err M680X_disassembler_init(cs_struct *ud)
2181
3.82k
{
2182
3.82k
  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
3.82k
  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
3.82k
  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
3.82k
  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
3.82k
  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
3.82k
  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
3.82k
  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
3.82k
  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
3.82k
  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
3.82k
  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
3.82k
  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
3.82k
  return CS_ERR_OK;
2250
3.82k
}
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