Coverage Report

Created: 2026-09-28 06:34

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