Coverage Report

Created: 2026-07-16 06:55

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