Coverage Report

Created: 2026-11-12 06:22

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