Coverage Report

Created: 2026-03-03 06:15

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