Coverage Report

Created: 2026-03-13 06:50

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