Coverage Report

Created: 2026-04-12 06:30

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