Coverage Report

Created: 2025-08-28 06:43

/src/capstonenext/arch/SH/SHDisassembler.c
Line
Count
Source (jump to first uncovered line)
1
/* Capstone Disassembly Engine */
2
/* By Yoshinori Sato, 2022 */
3
4
#include <string.h>
5
#include <stdarg.h>
6
#include "../../cs_priv.h"
7
#include "../../MCInst.h"
8
#include "../../MCDisassembler.h"
9
#include "../../utils.h"
10
#include "SHDisassembler.h"
11
#include "capstone/sh.h"
12
13
#define regs_read(_detail, _reg) \
14
0
  if (_detail) \
15
0
  _detail->regs_read[_detail->regs_read_count++] = _reg
16
#define regs_write(_detail, _reg) \
17
0
  if (_detail) \
18
0
  _detail->regs_write[_detail->regs_write_count++] = _reg
19
20
enum direction { read, write };
21
22
static void regs_rw(cs_detail *detail, enum direction rw, sh_reg reg)
23
0
{
24
0
  switch (rw) {
25
0
  case read:
26
0
    regs_read(detail, reg);
27
0
    break;
28
0
  case write:
29
0
    regs_write(detail, reg);
30
0
    break;
31
0
  }
32
0
}
33
34
static void set_reg_n(sh_info *info, sh_reg reg, int pos, enum direction rw,
35
          cs_detail *detail)
36
0
{
37
0
  info->op.operands[pos].type = SH_OP_REG;
38
0
  info->op.operands[pos].reg = reg;
39
0
  regs_rw(detail, rw, reg);
40
0
}
41
42
static void set_reg(sh_info *info, sh_reg reg, enum direction rw,
43
        cs_detail *detail)
44
0
{
45
0
  set_reg_n(info, reg, info->op.op_count, rw, detail);
46
0
  info->op.op_count++;
47
0
}
48
49
static void set_mem_n(sh_info *info, sh_op_mem_type address, sh_reg reg,
50
          uint32_t disp, int sz, int pos, cs_detail *detail)
51
0
{
52
0
  info->op.operands[pos].type = SH_OP_MEM;
53
0
  info->op.operands[pos].mem.address = address;
54
0
  info->op.operands[pos].mem.reg = reg;
55
0
  info->op.operands[pos].mem.disp = disp;
56
0
  if (sz > 0)
57
0
    info->op.size = sz;
58
0
  switch (address) {
59
0
  case SH_OP_MEM_REG_POST:
60
0
  case SH_OP_MEM_REG_PRE:
61
0
    regs_write(detail, reg);
62
0
    break;
63
0
  case SH_OP_MEM_GBR_R0:
64
0
    regs_read(detail, SH_REG_GBR);
65
0
    regs_read(detail, SH_REG_R0);
66
0
    break;
67
0
  case SH_OP_MEM_REG_R0:
68
0
    regs_read(detail, SH_REG_R0);
69
0
    regs_read(detail, reg);
70
0
    break;
71
0
  case SH_OP_MEM_PCR:
72
0
    break;
73
0
  default:
74
0
    regs_read(detail, reg);
75
0
    break;
76
0
  }
77
0
}
78
79
static void set_mem(sh_info *info, sh_op_mem_type address, sh_reg reg,
80
        uint32_t disp, int sz, cs_detail *detail)
81
0
{
82
0
  set_mem_n(info, address, reg, disp, sz, info->op.op_count, detail);
83
0
  info->op.op_count++;
84
0
}
85
86
static void set_imm(sh_info *info, int sign, uint64_t imm)
87
0
{
88
0
  info->op.operands[info->op.op_count].type = SH_OP_IMM;
89
0
  if (sign && imm >= 128)
90
0
    imm = -256 + imm;
91
0
  info->op.operands[info->op.op_count].imm = imm;
92
0
  info->op.op_count++;
93
0
}
94
95
static void set_groups(cs_detail *detail, int n, ...)
96
0
{
97
0
  va_list g;
98
0
  va_start(g, n);
99
0
  while (n > 0) {
100
0
    sh_insn_group grp;
101
    // NOLINTBEGIN(clang-analyzer-valist.Uninitialized)
102
0
    grp = va_arg(g, sh_insn_group);
103
    // NOLINTEND(clang-analyzer-valist.Uninitialized)
104
0
    if (detail) {
105
0
      detail->groups[detail->groups_count] = grp;
106
0
      detail->groups_count++;
107
0
    }
108
0
    n--;
109
0
  }
110
0
  va_end(g);
111
0
}
112
113
enum {
114
  ISA_ALL = 1,
115
  ISA_SH2 = 2,
116
  ISA_SH2A = 3,
117
  ISA_SH3 = 4,
118
  ISA_SH4 = 5,
119
  ISA_SH4A = 6,
120
  ISA_MAX = 7,
121
};
122
123
static int isalevel(cs_mode mode)
124
0
{
125
0
  int level;
126
0
  mode >>= 1; /* skip endian */
127
0
  for (level = 2; level < ISA_MAX; level++) {
128
0
    if (mode & 1)
129
0
      return level;
130
0
    mode >>= 1;
131
0
  }
132
0
  return ISA_ALL;
133
0
}
134
135
enum co_processor { none, shfpu, shdsp };
136
typedef union reg_insn {
137
  sh_reg reg;
138
  sh_insn insn;
139
} reg_insn;
140
struct ri_list {
141
  int no;
142
  int /* reg_insn */ ri;
143
  int level;
144
  enum co_processor cp;
145
};
146
147
static const struct ri_list ldc_stc_regs[] = {
148
  { 0, SH_REG_SR, ISA_ALL, none },
149
  { 1, SH_REG_GBR, ISA_ALL, none },
150
  { 2, SH_REG_VBR, ISA_ALL, none },
151
  { 3, SH_REG_SSR, ISA_SH3, none },
152
  { 4, SH_REG_SPC, ISA_SH3, none },
153
  { 5, SH_REG_MOD, ISA_ALL, shdsp },
154
  { 6, SH_REG_RS, ISA_ALL, shdsp },
155
  { 7, SH_REG_RE, ISA_ALL, shdsp },
156
  { 8, SH_REG_R0_BANK, ISA_SH3, none },
157
  { 9, SH_REG_R1_BANK, ISA_SH3, none },
158
  { 10, SH_REG_R2_BANK, ISA_SH3, none },
159
  { 11, SH_REG_R3_BANK, ISA_SH3, none },
160
  { 12, SH_REG_R4_BANK, ISA_SH3, none },
161
  { 13, SH_REG_R5_BANK, ISA_SH3, none },
162
  { 14, SH_REG_R6_BANK, ISA_SH3, none },
163
  { 15, SH_REG_R7_BANK, ISA_SH3, none },
164
  { -1, SH_REG_INVALID, ISA_ALL, none },
165
};
166
167
static sh_insn lookup_insn(const struct ri_list *list, int no, cs_mode mode)
168
0
{
169
0
  int level = isalevel(mode);
170
0
  sh_insn error = SH_INS_INVALID;
171
0
  for (; list->no >= 0; list++) {
172
0
    if (no != list->no)
173
0
      continue;
174
0
    if (((level >= 0) && (level < list->level)) ||
175
0
        ((level < 0) && (-(level) != list->level)))
176
0
      continue;
177
0
    if ((list->cp == none) ||
178
0
        ((list->cp == shfpu) && (mode & CS_MODE_SHFPU)) ||
179
0
        ((list->cp == shdsp) && (mode & CS_MODE_SHDSP))) {
180
0
      return list->ri;
181
0
    }
182
0
  }
183
0
  return error;
184
0
}
185
186
static sh_reg lookup_regs(const struct ri_list *list, int no, cs_mode mode)
187
0
{
188
0
  int level = isalevel(mode);
189
0
  sh_reg error = SH_REG_INVALID;
190
0
  for (; list->no >= 0; list++) {
191
0
    if (no != list->no)
192
0
      continue;
193
0
    if (((level >= 0) && (level < list->level)) ||
194
0
        ((level < 0) && (-(level) != list->level)))
195
0
      continue;
196
0
    if ((list->cp == none) ||
197
0
        ((list->cp == shfpu) && (mode & CS_MODE_SHFPU)) ||
198
0
        ((list->cp == shdsp) && (mode & CS_MODE_SHDSP))) {
199
0
      return list->ri;
200
0
    }
201
0
  }
202
0
  return error;
203
0
}
204
205
// #define lookup_regs(list, no, mode) ((reg_insn)(lookup(reg, list, no, mode).reg))
206
// #define lookup_insn(list, no, mode) ((sh_insn)(lookup(insn, list, no, mode).insn))
207
208
static sh_reg opSTCsrc(uint16_t code, MCInst *MI, cs_mode mode, sh_info *info,
209
           cs_detail *detail)
210
0
{
211
0
  int s = (code >> 4) & 0x0f;
212
0
  int d = (code >> 8) & 0x0f;
213
0
  sh_reg sreg;
214
0
  MCInst_setOpcode(MI, SH_INS_STC);
215
0
  sreg = lookup_regs(ldc_stc_regs, s, mode);
216
0
  if (sreg != SH_REG_INVALID) {
217
0
    set_reg(info, sreg, read, detail);
218
0
    return SH_REG_R0 + d;
219
0
  } else {
220
0
    return SH_REG_INVALID;
221
0
  }
222
0
}
223
224
static bool opSTC(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
225
      sh_info *info, cs_detail *detail)
226
0
{
227
0
  sh_reg d;
228
0
  d = opSTCsrc(code, MI, mode, info, detail);
229
0
  if (d != SH_REG_INVALID) {
230
0
    set_reg(info, d, write, detail);
231
0
    return MCDisassembler_Success;
232
0
  } else {
233
0
    return MCDisassembler_Fail;
234
0
  }
235
0
}
236
237
static bool op0xx3(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
238
       sh_info *info, cs_detail *detail)
239
0
{
240
0
  int r = (code >> 8) & 0x0f;
241
0
  int insn_code = (code >> 4) & 0x0f;
242
0
  static const struct ri_list list[] = {
243
0
    { 0, SH_INS_BSRF, ISA_SH2, none },
244
0
    { 2, SH_INS_BRAF, ISA_SH2, none },
245
0
    { 6, SH_INS_MOVLI, ISA_SH4A, none },
246
0
    { 7, SH_INS_MOVCO, ISA_SH4A, none },
247
0
    { 8, SH_INS_PREF, ISA_SH2A, none },
248
0
    { 9, SH_INS_OCBI, ISA_SH4, none },
249
0
    { 10, SH_INS_OCBP, ISA_SH4, none },
250
0
    { 11, SH_INS_OCBWB, ISA_SH4, none },
251
0
    { 12, SH_INS_MOVCA, ISA_SH4, none },
252
0
    { 13, SH_INS_PREFI, ISA_SH4A, none },
253
0
    { 14, SH_INS_ICBI, ISA_SH4A, none },
254
0
    { -1, SH_INS_INVALID, ISA_ALL, none },
255
0
  };
256
0
  sh_insn insn = lookup_insn(list, insn_code, mode);
257
258
0
  if (insn != SH_INS_INVALID) {
259
0
    MCInst_setOpcode(MI, insn);
260
0
    switch (insn_code) {
261
0
    case 0: /// bsrf Rn
262
0
    case 2: /// braf Rn
263
0
      set_reg(info, SH_REG_R0 + r, read, detail);
264
0
      if (detail)
265
0
        set_groups(detail, 2, SH_GRP_JUMP,
266
0
             SH_GRP_BRANCH_RELATIVE);
267
0
      break;
268
0
    case 8: /// pref @Rn
269
0
    case 9: /// ocbi @Rn
270
0
    case 10: /// ocbp @Rn
271
0
    case 11: /// ocbwb @Rn
272
0
    case 13: /// prefi @Rn
273
0
    case 14: /// icbi @Rn
274
0
      set_mem(info, SH_OP_MEM_REG_IND, SH_REG_R0 + r, 0, 0,
275
0
        detail);
276
0
      break;
277
0
    case 6: /// movli @Rn, R0
278
0
      set_mem(info, SH_OP_MEM_REG_IND, SH_REG_R0 + r, 0, 32,
279
0
        detail);
280
0
      set_reg(info, SH_REG_R0, write, detail);
281
0
      break;
282
0
    case 7: /// movco R0,@Rn
283
0
    case 12: /// movca R0,@Rn
284
0
      set_reg(info, SH_REG_R0, read, detail);
285
0
      set_mem(info, SH_OP_MEM_REG_IND, SH_REG_R0 + r, 0, 32,
286
0
        detail);
287
0
      break;
288
0
    }
289
0
    return MCDisassembler_Success;
290
0
  } else {
291
0
    return MCDisassembler_Fail;
292
0
  }
293
0
}
294
295
#define nm(code, dir) \
296
0
  int m, n; \
297
0
  m = (code >> (4 * (dir + 1))) & 0x0f; \
298
0
  n = (code >> (8 - 4 * dir)) & 0x0f
299
300
static bool opMOVx(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
301
       int size, sh_info *info, cs_detail *detail)
302
0
{
303
0
  int ad = ((code >> 10) & 0x3c) | ((code >> 2) & 0x03);
304
0
  enum direction rw;
305
0
  MCInst_setOpcode(MI, SH_INS_MOV);
306
0
  switch (ad) {
307
0
  case 0x01: /// mov.X Rs,@(R0, Rd)
308
0
  case 0x03: /// mov.X @(R0, Rs), Rd
309
0
    rw = (ad >> 1);
310
0
    {
311
0
      nm(code, rw);
312
0
      set_reg_n(info, SH_REG_R0 + m, rw, rw, detail);
313
0
      set_mem_n(info, SH_OP_MEM_REG_R0, SH_REG_R0 + n, 0,
314
0
          size, 1 - rw, detail);
315
0
      info->op.op_count = 2;
316
0
    }
317
0
    break;
318
0
  case 0x20: /// mov.X Rs,@-Rd
319
0
  case 0x60: /// mov.X @Rs+,Rd
320
0
    rw = (ad >> 6) & 1;
321
0
    {
322
0
      nm(code, rw);
323
0
      set_reg_n(info, SH_REG_R0 + m, rw, rw, detail);
324
0
      set_mem_n(info, SH_OP_MEM_REG_PRE, SH_REG_R0 + n, 0,
325
0
          size, 1 - rw, detail);
326
0
    }
327
0
    break;
328
0
  default:
329
0
    return MCDisassembler_Fail;
330
0
  }
331
0
  return MCDisassembler_Success;
332
0
}
333
334
static bool opMOV_B(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
335
        sh_info *info, cs_detail *detail)
336
0
{
337
0
  return opMOVx(code, address, MI, mode, 8, info, detail);
338
0
}
339
340
static bool opMOV_W(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
341
        sh_info *info, cs_detail *detail)
342
0
{
343
0
  return opMOVx(code, address, MI, mode, 16, info, detail);
344
0
}
345
346
static bool opMOV_L(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
347
        sh_info *info, cs_detail *detail)
348
0
{
349
0
  return opMOVx(code, address, MI, mode, 32, info, detail);
350
0
}
351
352
static bool opRRfn(uint16_t code, MCInst *MI, sh_insn insn, cs_mode mode,
353
       int size, int level, sh_info *info, cs_detail *detail)
354
0
{
355
0
  int m = (code >> 4) & 0x0f;
356
0
  int n = (code >> 8) & 0x0f;
357
0
  if (level > isalevel(mode))
358
0
    return MCDisassembler_Fail;
359
0
  MCInst_setOpcode(MI, insn);
360
0
  set_reg(info, SH_REG_R0 + m, read, detail);
361
0
  set_reg(info, SH_REG_R0 + n, write, detail);
362
0
  info->op.size = size;
363
0
  return MCDisassembler_Success;
364
0
}
365
366
#define opRR(level, __insn, __size) \
367
  static bool op##__insn(uint16_t code, uint64_t address, MCInst *MI, \
368
             cs_mode mode, sh_info *info, cs_detail *detail) \
369
0
  { \
370
0
    return opRRfn(code, MI, SH_INS_##__insn, mode, __size, level, \
371
0
            info, detail); \
372
0
  }
Unexecuted instantiation: SHDisassembler.c:opMUL_L
Unexecuted instantiation: SHDisassembler.c:opDIV0S
Unexecuted instantiation: SHDisassembler.c:opTST
Unexecuted instantiation: SHDisassembler.c:opAND
Unexecuted instantiation: SHDisassembler.c:opXOR
Unexecuted instantiation: SHDisassembler.c:opOR
Unexecuted instantiation: SHDisassembler.c:opCMP_STR
Unexecuted instantiation: SHDisassembler.c:opXTRCT
Unexecuted instantiation: SHDisassembler.c:opMULU_W
Unexecuted instantiation: SHDisassembler.c:opMULS_W
Unexecuted instantiation: SHDisassembler.c:opCMP_EQ
Unexecuted instantiation: SHDisassembler.c:opCMP_HS
Unexecuted instantiation: SHDisassembler.c:opCMP_GE
Unexecuted instantiation: SHDisassembler.c:opDIV1
Unexecuted instantiation: SHDisassembler.c:opDMULU_L
Unexecuted instantiation: SHDisassembler.c:opCMP_HI
Unexecuted instantiation: SHDisassembler.c:opCMP_GT
Unexecuted instantiation: SHDisassembler.c:opSUB
Unexecuted instantiation: SHDisassembler.c:opSUBC
Unexecuted instantiation: SHDisassembler.c:opSUBV
Unexecuted instantiation: SHDisassembler.c:opADD_r
Unexecuted instantiation: SHDisassembler.c:opDMULS_L
Unexecuted instantiation: SHDisassembler.c:opADDC
Unexecuted instantiation: SHDisassembler.c:opADDV
Unexecuted instantiation: SHDisassembler.c:opSHAD
Unexecuted instantiation: SHDisassembler.c:opSHLD
Unexecuted instantiation: SHDisassembler.c:opMOV
Unexecuted instantiation: SHDisassembler.c:opNOT
Unexecuted instantiation: SHDisassembler.c:opSWAP_B
Unexecuted instantiation: SHDisassembler.c:opSWAP_W
Unexecuted instantiation: SHDisassembler.c:opNEGC
Unexecuted instantiation: SHDisassembler.c:opNEG
Unexecuted instantiation: SHDisassembler.c:opEXTU_B
Unexecuted instantiation: SHDisassembler.c:opEXTU_W
Unexecuted instantiation: SHDisassembler.c:opEXTS_B
Unexecuted instantiation: SHDisassembler.c:opEXTS_W
373
374
/* mul.l - SH2 */
375
opRR(ISA_SH2, MUL_L, 0)
376
377
  static bool op0xx8(uint16_t code, uint64_t address, MCInst *MI,
378
         cs_mode mode, sh_info *info, cs_detail *detail)
379
0
{
380
0
  int insn_code = (code >> 4) & 0xf;
381
0
  static const struct ri_list list[] = {
382
0
    { 0, SH_INS_CLRT, ISA_ALL, none },
383
0
    { 1, SH_INS_SETT, ISA_ALL, none },
384
0
    { 2, SH_INS_CLRMAC, ISA_ALL, none },
385
0
    { 3, SH_INS_LDTLB, ISA_SH3, none },
386
0
    { 4, SH_INS_CLRS, ISA_SH3, none },
387
0
    { 5, SH_INS_SETS, ISA_SH3, none },
388
0
    { 6, SH_INS_NOTT, -(ISA_SH2A), none },
389
0
    { 8, SH_INS_CLRDMXY, ISA_SH4A, shdsp },
390
0
    { 9, SH_INS_SETDMX, ISA_SH4A, shdsp },
391
0
    { 12, SH_INS_SETDMY, ISA_SH4A, shdsp },
392
0
    { -1, SH_INS_INVALID, ISA_ALL, none },
393
0
  };
394
395
0
  sh_insn insn = lookup_insn(list, insn_code, mode);
396
0
  if (code & 0x0f00)
397
0
    return MCDisassembler_Fail;
398
399
0
  if (insn != SH_INS_INVALID) {
400
0
    MCInst_setOpcode(MI, insn);
401
0
    return MCDisassembler_Success;
402
0
  } else {
403
0
    return MCDisassembler_Fail;
404
0
  }
405
0
}
406
407
static bool op0xx9(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
408
       sh_info *info, cs_detail *detail)
409
0
{
410
0
  int insn_code = (code >> 4) & 0x0f;
411
0
  int r = (code >> 8) & 0x0f;
412
0
  static const struct ri_list list[] = {
413
0
    { 0, SH_INS_NOP, ISA_ALL, none },
414
0
    { 1, SH_INS_DIV0U, ISA_ALL, none },
415
0
    { 2, SH_INS_MOVT, ISA_ALL, none },
416
0
    { 3, SH_INS_MOVRT, -(ISA_SH2A), none },
417
0
    { -1, SH_INS_INVALID, ISA_ALL, none },
418
0
  };
419
0
  sh_insn insn = lookup_insn(list, insn_code, mode);
420
0
  if (insn != SH_INS_INVALID) {
421
0
    if (insn_code >= 2) {
422
      /// movt / movrt Rn
423
0
      set_reg(info, SH_REG_R0 + r, write, detail);
424
0
    } else if (r > 0) {
425
0
      insn = SH_INS_INVALID;
426
0
    }
427
0
  }
428
0
  if (insn != SH_INS_INVALID) {
429
0
    MCInst_setOpcode(MI, insn);
430
0
    return MCDisassembler_Success;
431
0
  } else {
432
0
    return MCDisassembler_Fail;
433
0
  }
434
0
}
435
436
static const struct ri_list sts_lds_regs[] = {
437
  { 0, SH_REG_MACH, ISA_ALL, none },
438
  { 1, SH_REG_MACL, ISA_ALL, none },
439
  { 2, SH_REG_PR, ISA_ALL, none },
440
  { 3, SH_REG_SGR, ISA_SH4, none },
441
  { 4, SH_REG_TBR, -(ISA_SH2A), none },
442
  { 5, SH_REG_FPUL, ISA_ALL, shfpu },
443
  { 6, SH_REG_FPSCR, ISA_ALL, shfpu },
444
  { 6, SH_REG_DSP_DSR, ISA_ALL, shdsp },
445
  { 7, SH_REG_DSP_A0, ISA_ALL, shdsp },
446
  { 8, SH_REG_DSP_X0, ISA_ALL, shdsp },
447
  { 9, SH_REG_DSP_X1, ISA_ALL, shdsp },
448
  { 10, SH_REG_DSP_Y0, ISA_ALL, shdsp },
449
  { 11, SH_REG_DSP_Y1, ISA_ALL, shdsp },
450
  { 15, SH_REG_DBR, ISA_SH4, none },
451
  { -1, SH_REG_INVALID, ISA_ALL, none },
452
};
453
454
static sh_reg opSTCSTS(uint16_t code, MCInst *MI, cs_mode mode, sh_info *info,
455
           cs_detail *detail)
456
0
{
457
0
  int s = (code >> 4) & 0x0f;
458
0
  int d = (code >> 8) & 0x0f;
459
0
  sh_reg reg;
460
0
  sh_insn insn;
461
462
0
  reg = lookup_regs(sts_lds_regs, s, mode);
463
0
  if (reg != SH_REG_INVALID) {
464
0
    if (s == 3 || s == 4 || s == 15) {
465
0
      insn = SH_INS_STC;
466
0
    } else {
467
0
      insn = SH_INS_STS;
468
0
    }
469
0
    MCInst_setOpcode(MI, insn);
470
0
    set_reg(info, reg, read, detail);
471
0
    return SH_REG_R0 + d;
472
0
  } else {
473
0
    return SH_REG_INVALID;
474
0
  }
475
0
}
476
477
static bool op0xxa(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
478
       sh_info *info, cs_detail *detail)
479
0
{
480
0
  sh_reg r = opSTCSTS(code, MI, mode, info, detail);
481
0
  if (r != SH_REG_INVALID) {
482
0
    set_reg(info, r, write, detail);
483
0
    return MCDisassembler_Success;
484
0
  } else
485
0
    return MCDisassembler_Fail;
486
0
}
487
488
static bool op0xxb(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
489
       sh_info *info, cs_detail *detail)
490
0
{
491
0
  int insn_code = (code >> 4) & 0x0f;
492
0
  int r = (code >> 8) & 0x0f;
493
0
  static const struct ri_list list[] = {
494
0
    { 0, SH_INS_RTS, ISA_ALL, none },
495
0
    { 1, SH_INS_SLEEP, ISA_ALL, none },
496
0
    { 2, SH_INS_RTE, ISA_ALL, none },
497
0
    { 5, SH_INS_RESBANK, -(ISA_SH2A), none },
498
0
    { 6, SH_INS_RTS_N, -(ISA_SH2A), none },
499
0
    { 7, SH_INS_RTV_N, -(ISA_SH2A), none },
500
0
    { 10, SH_INS_SYNCO, -(ISA_SH4A), none },
501
0
    { -1, SH_INS_INVALID, ISA_ALL, none },
502
0
  };
503
504
0
  sh_insn insn = lookup_insn(list, insn_code, mode);
505
0
  if (insn_code == 7) {
506
0
    set_reg(info, SH_REG_R0 + r, read, detail);
507
0
    regs_write(detail, SH_REG_R0);
508
0
  } else if (r > 0) {
509
0
    insn = SH_INS_INVALID;
510
0
  }
511
0
  if (insn != SH_INS_INVALID) {
512
0
    MCInst_setOpcode(MI, insn);
513
0
    return MCDisassembler_Success;
514
0
  } else {
515
0
    return MCDisassembler_Fail;
516
0
  }
517
0
}
518
519
static bool opMAC(uint16_t code, sh_insn op, MCInst *MI, sh_info *info,
520
      cs_detail *detail)
521
0
{
522
0
  nm(code, 0);
523
0
  MCInst_setOpcode(MI, op);
524
0
  set_mem(info, SH_OP_MEM_REG_POST, SH_REG_R0 + m, 0, 0, detail);
525
0
  set_mem(info, SH_OP_MEM_REG_POST, SH_REG_R0 + n, 0, 0, detail);
526
0
  return MCDisassembler_Success;
527
0
}
528
529
/// mac.l - sh2+
530
static bool opMAC_L(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
531
        sh_info *info, cs_detail *detail)
532
0
{
533
0
  if (isalevel(mode) < ISA_SH2)
534
0
    return MCDisassembler_Fail;
535
0
  return opMAC(code, SH_INS_MAC_L, MI, info, detail);
536
0
}
537
538
static bool opMAC_W(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
539
        sh_info *info, cs_detail *detail)
540
0
{
541
0
  return opMAC(code, SH_INS_MAC_W, MI, info, detail);
542
0
}
543
544
static bool opMOV_L_dsp(uint16_t code, uint64_t address, MCInst *MI,
545
      cs_mode mode, sh_info *info, cs_detail *detail)
546
0
{
547
0
  int dsp = (code & 0x0f) * 4;
548
0
  int rw = (code >> 14) & 1;
549
0
  nm(code, rw);
550
0
  MCInst_setOpcode(MI, SH_INS_MOV);
551
0
  set_mem_n(info, SH_OP_MEM_REG_DISP, SH_REG_R0 + n, dsp, 32, 1 - rw,
552
0
      detail);
553
0
  set_reg_n(info, SH_REG_R0 + m, rw, rw, detail);
554
0
  info->op.op_count = 2;
555
0
  return MCDisassembler_Success;
556
0
}
557
558
static bool opMOV_rind(uint16_t code, uint64_t address, MCInst *MI,
559
           cs_mode mode, sh_info *info, cs_detail *detail)
560
0
{
561
0
  int sz = (code & 0x03);
562
0
  int rw = (code >> 14) & 1;
563
0
  nm(code, rw);
564
0
  MCInst_setOpcode(MI, SH_INS_MOV);
565
0
  sz = 8 << sz;
566
0
  set_mem_n(info, SH_OP_MEM_REG_IND, SH_REG_R0 + n, 0, sz, 1 - rw,
567
0
      detail);
568
0
  set_reg_n(info, SH_REG_R0 + m, rw, rw, detail);
569
0
  info->op.op_count = 2;
570
0
  return MCDisassembler_Success;
571
0
}
572
573
static bool opMOV_rpd(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
574
          sh_info *info, cs_detail *detail)
575
0
{
576
0
  nm(code, 0);
577
0
  int sz = (code & 0x03);
578
0
  MCInst_setOpcode(MI, SH_INS_MOV);
579
0
  set_reg(info, SH_REG_R0 + m, read, detail);
580
0
  set_mem(info, SH_OP_MEM_REG_PRE, SH_REG_R0 + n, 0, 8 << sz, detail);
581
0
  return MCDisassembler_Success;
582
0
}
583
584
opRR(ISA_ALL, TST, 0) opRR(ISA_ALL, AND, 0) opRR(ISA_ALL, XOR, 0) opRR(
585
  ISA_ALL, OR, 0) opRR(ISA_ALL, CMP_STR, 0) opRR(ISA_ALL, XTRCT, 0)
586
  opRR(ISA_ALL, MULU_W, 16) opRR(ISA_ALL, MULS_W, 16) opRR(ISA_ALL,
587
                 CMP_EQ, 0)
588
    opRR(ISA_ALL, CMP_HI, 0) opRR(ISA_ALL, CMP_HS,
589
                0) opRR(ISA_ALL, CMP_GE, 0)
590
      opRR(ISA_ALL, CMP_GT, 0) opRR(ISA_ALL, SUB,
591
                  0) opRR(ISA_ALL, SUBC, 0)
592
        opRR(ISA_ALL, SUBV, 0) opRR(ISA_ALL, ADD_r, 0)
593
          opRR(ISA_ALL, ADDC, 0) opRR(ISA_ALL,
594
                    ADDV, 0)
595
            opRR(ISA_ALL, DIV0S, 0)
596
              opRR(ISA_ALL, DIV1, 0)
597
  /// DMULS / DMULU - SH2
598
  opRR(ISA_SH2, DMULS_L, 0) opRR(ISA_SH2, DMULU_L, 0)
599
600
    static bool op4xx0(uint16_t code, uint64_t address, MCInst *MI,
601
           cs_mode mode, sh_info *info,
602
           cs_detail *detail)
603
0
{
604
0
  int insn_code = (code >> 4) & 0x0f;
605
0
  int r = (code >> 8) & 0x0f;
606
0
  static const struct ri_list list[] = {
607
0
    { 0, SH_INS_SHLL, ISA_ALL, none },
608
0
    { 1, SH_INS_DT, ISA_SH2, none },
609
0
    { 2, SH_INS_SHAL, ISA_ALL, none },
610
0
    { 8, SH_INS_MULR, -(ISA_SH2A), none },
611
0
    { 15, SH_INS_MOVMU, -(ISA_SH2A), none },
612
0
    { -1, SH_INS_INVALID, ISA_ALL, none },
613
0
  };
614
0
  sh_insn insn = lookup_insn(list, insn_code, mode);
615
0
  if (insn != SH_INS_INVALID) {
616
0
    MCInst_setOpcode(MI, insn);
617
0
    if (insn_code < 8) {
618
0
      set_reg(info, SH_REG_R0 + r, write, detail);
619
0
    } else {
620
0
      switch (insn_code) {
621
0
      case 0x08:
622
0
        set_reg(info, SH_REG_R0, read, detail);
623
0
        set_reg(info, SH_REG_R0 + r, write, detail);
624
0
        break;
625
0
      case 0x0f:
626
0
        set_reg(info, SH_REG_R0 + r, read, detail);
627
0
        set_mem(info, SH_OP_MEM_REG_PRE, SH_REG_R15, 0,
628
0
          32, detail);
629
0
        break;
630
0
      }
631
0
    }
632
0
    return MCDisassembler_Success;
633
0
  } else {
634
0
    return MCDisassembler_Fail;
635
0
  }
636
0
}
637
638
static bool op4xx1(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
639
       sh_info *info, cs_detail *detail)
640
0
{
641
0
  int insn_code = (code >> 4) & 0x0f;
642
0
  int r = (code >> 8) & 0x0f;
643
0
  static const struct ri_list list[] = {
644
0
    { 0, SH_INS_SHLR, ISA_ALL, none },
645
0
    { 1, SH_INS_CMP_PZ, ISA_ALL, none },
646
0
    { 2, SH_INS_SHAR, ISA_ALL, none },
647
0
    { 8, SH_INS_CLIPU, -(ISA_SH2A), none },
648
0
    { 9, SH_INS_CLIPS, -(ISA_SH2A), none },
649
0
    { 14, SH_INS_STBANK, -(ISA_SH2A), none },
650
0
    { 15, SH_INS_MOVML, -(ISA_SH2A), none },
651
0
    { -1, SH_INS_INVALID, ISA_ALL, none },
652
0
  };
653
0
  sh_insn insn = lookup_insn(list, insn_code, mode);
654
0
  if (insn != SH_INS_INVALID) {
655
0
    MCInst_setOpcode(MI, insn);
656
0
    switch (insn_code) {
657
0
    case 14:
658
0
      set_reg(info, SH_REG_R0, read, detail);
659
0
      set_mem(info, SH_OP_MEM_REG_IND, SH_REG_R0 + r, 0, 0,
660
0
        detail);
661
0
      break;
662
0
    case 15:
663
0
      set_reg(info, SH_REG_R0 + r, read, detail);
664
0
      set_mem(info, SH_OP_MEM_REG_PRE, SH_REG_R15, 0, 32,
665
0
        detail);
666
0
      break;
667
0
    default:
668
0
      set_reg(info, SH_REG_R0 + r, write, detail);
669
0
      if (insn_code >= 8)
670
0
        info->op.size = 8;
671
0
      break;
672
0
    }
673
0
    return MCDisassembler_Success;
674
0
  } else {
675
0
    return MCDisassembler_Fail;
676
0
  }
677
0
}
678
679
static bool op4xx2(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
680
       sh_info *info, cs_detail *detail)
681
0
{
682
0
  sh_reg r = opSTCSTS(code, MI, mode, info, detail);
683
0
  if (r != SH_REG_INVALID) {
684
0
    set_mem(info, SH_OP_MEM_REG_PRE, r, 0, 32, detail);
685
0
    return MCDisassembler_Success;
686
0
  } else {
687
0
    return MCDisassembler_Fail;
688
0
  }
689
0
}
690
691
static bool opSTC_L(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
692
        sh_info *info, cs_detail *detail)
693
0
{
694
0
  sh_reg r = opSTCsrc(code, MI, mode, info, detail);
695
0
  if (r != SH_REG_INVALID) {
696
0
    set_mem(info, SH_OP_MEM_REG_PRE, r, 0, 32, detail);
697
0
    return MCDisassembler_Success;
698
0
  } else {
699
0
    return MCDisassembler_Fail;
700
0
  }
701
0
}
702
703
static bool op4xx4(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
704
       sh_info *info, cs_detail *detail)
705
0
{
706
0
  int r = (code >> 8) & 0x0f;
707
0
  int insn_code = (code >> 4) & 0x0f;
708
0
  static const struct ri_list list[] = {
709
0
    { 0, SH_INS_ROTL, ISA_ALL, none },
710
0
    { 1, SH_INS_SETRC, ISA_ALL, shdsp },
711
0
    { 2, SH_INS_ROTCL, ISA_ALL, none },
712
0
    { 3, SH_INS_LDRC, ISA_ALL, shdsp },
713
0
    { 8, SH_INS_DIVU, -(ISA_SH2A), none },
714
0
    { 9, SH_INS_DIVS, -(ISA_SH2A), none },
715
0
    { 15, SH_INS_MOVMU, -(ISA_SH2A), none },
716
0
    { -1, SH_INS_INVALID, ISA_ALL, none },
717
0
  };
718
0
  sh_insn insn = lookup_insn(list, insn_code, mode);
719
0
  if (insn != SH_INS_INVALID) {
720
0
    MCInst_setOpcode(MI, insn);
721
0
    switch (insn_code) {
722
0
    case 8:
723
0
    case 9:
724
0
      set_reg(info, SH_REG_R0, read, detail);
725
0
      break;
726
0
    case 15:
727
0
      set_mem(info, SH_OP_MEM_REG_POST, SH_REG_R15, 0, 32,
728
0
        detail);
729
0
      set_reg(info, SH_REG_R0 + r, read, detail);
730
0
      return MCDisassembler_Success;
731
0
    }
732
0
    set_reg(info, SH_REG_R0 + r, write, detail);
733
0
    return MCDisassembler_Success;
734
0
  } else {
735
0
    return MCDisassembler_Fail;
736
0
  }
737
0
}
738
739
static bool op4xx5(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
740
       sh_info *info, cs_detail *detail)
741
0
{
742
0
  int r = (code >> 8) & 0x0f;
743
0
  enum direction rw = read;
744
0
  static const struct ri_list list[] = {
745
0
    { 0, SH_INS_ROTR, ISA_ALL, none },
746
0
    { 1, SH_INS_CMP_PL, ISA_ALL, none },
747
0
    { 2, SH_INS_ROTCR, ISA_ALL, none },
748
0
    { 8, SH_INS_CLIPU, -(ISA_SH2A), none },
749
0
    { 9, SH_INS_CLIPS, -(ISA_SH2A), none },
750
0
    { 14, SH_INS_LDBANK, -(ISA_SH2A), none },
751
0
    { 15, SH_INS_MOVML, -(ISA_SH2A), none },
752
0
    { -1, SH_INS_INVALID, ISA_ALL, none },
753
0
  };
754
0
  int insn_code = (code >> 4) & 0x0f;
755
0
  sh_insn insn = lookup_insn(list, insn_code, mode);
756
0
  if (insn != SH_INS_INVALID) {
757
0
    MCInst_setOpcode(MI, insn);
758
0
    switch (insn_code) {
759
0
    case 0:
760
0
    case 2:
761
0
      rw = write;
762
0
      break;
763
0
    case 1:
764
0
      rw = read;
765
0
      break;
766
0
    case 8:
767
0
    case 9:
768
0
      info->op.size = 16;
769
0
      rw = write;
770
0
      break;
771
0
    case 0x0e:
772
0
      set_mem(info, SH_OP_MEM_REG_IND, SH_REG_R0 + r, 0, 0,
773
0
        detail);
774
0
      set_reg(info, SH_REG_R0, write, detail);
775
0
      return MCDisassembler_Success;
776
0
    case 0x0f:
777
0
      set_mem(info, SH_OP_MEM_REG_POST, SH_REG_R15, 0, 32,
778
0
        detail);
779
0
      set_reg(info, SH_REG_R0 + r, write, detail);
780
0
      return MCDisassembler_Success;
781
0
    }
782
0
    set_reg(info, SH_REG_R0 + r, rw, detail);
783
0
    return MCDisassembler_Success;
784
0
  } else {
785
0
    return MCDisassembler_Fail;
786
0
  }
787
0
}
788
789
static bool opLDCLDS(uint16_t code, MCInst *MI, cs_mode mode, sh_info *info,
790
         cs_detail *detail)
791
0
{
792
0
  int d = (code >> 4) & 0x0f;
793
0
  sh_reg reg = lookup_regs(sts_lds_regs, d, mode);
794
0
  sh_insn insn;
795
0
  if (reg != SH_REG_INVALID) {
796
0
    if (d == 3 || d == 4 || d == 15) {
797
0
      insn = SH_INS_LDC;
798
0
    } else {
799
0
      insn = SH_INS_LDS;
800
0
    }
801
0
    MCInst_setOpcode(MI, insn);
802
0
    set_reg(info, reg, write, detail);
803
0
    return MCDisassembler_Success;
804
0
  } else {
805
0
    return MCDisassembler_Fail;
806
0
  }
807
0
}
808
809
static bool op4xx6(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
810
       sh_info *info, cs_detail *detail)
811
0
{
812
0
  int r = (code >> 8) & 0x0f;
813
0
  set_mem(info, SH_OP_MEM_REG_POST, SH_REG_R0 + r, 0, 32, detail);
814
0
  return opLDCLDS(code, MI, mode, info, detail);
815
0
}
816
817
static bool opLDCdst(uint16_t code, MCInst *MI, cs_mode mode, sh_info *info,
818
         cs_detail *detail)
819
0
{
820
0
  int d = (code >> 4) & 0x0f;
821
0
  sh_reg dreg = lookup_regs(ldc_stc_regs, d, mode);
822
0
  if (dreg == SH_REG_INVALID)
823
0
    return MCDisassembler_Fail;
824
0
  MCInst_setOpcode(MI, SH_INS_LDC);
825
0
  set_reg(info, dreg, write, detail);
826
0
  return MCDisassembler_Success;
827
0
}
828
829
static bool opLDC_L(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
830
        sh_info *info, cs_detail *detail)
831
0
{
832
0
  int s = (code >> 8) & 0x0f;
833
0
  set_mem(info, SH_OP_MEM_REG_POST, SH_REG_R0 + s, 0, 32, detail);
834
0
  return opLDCdst(code, MI, mode, info, detail);
835
0
}
836
837
static bool op4xx8(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
838
       sh_info *info, cs_detail *detail)
839
0
{
840
0
  int r = (code >> 8) & 0x0f;
841
0
  sh_insn insn[] = { SH_INS_SHLL2, SH_INS_SHLL8, SH_INS_SHLL16 };
842
0
  int size = (code >> 4) & 0x0f;
843
0
  if (size >= ARR_SIZE(insn)) {
844
0
    return MCDisassembler_Fail;
845
0
  }
846
0
  MCInst_setOpcode(MI, insn[size]);
847
0
  set_reg(info, SH_REG_R0 + r, write, detail);
848
0
  return MCDisassembler_Success;
849
0
}
850
851
static bool op4xx9(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
852
       sh_info *info, cs_detail *detail)
853
0
{
854
0
  int r = (code >> 8) & 0x0f;
855
0
  static const struct ri_list list[] = {
856
0
    { 0, SH_INS_SHLR2, ISA_ALL, none },
857
0
    { 1, SH_INS_SHLR8, ISA_ALL, none },
858
0
    { 2, SH_INS_SHLR16, ISA_ALL, none },
859
0
    { 10, SH_INS_MOVUA, -(ISA_SH4A), none },
860
0
    { 14, SH_INS_MOVUA, -(ISA_SH4A), none },
861
0
    { -1, SH_INS_INVALID, ISA_ALL, none },
862
0
  };
863
0
  int op = (code >> 4) & 0x0f;
864
0
  sh_insn insn = lookup_insn(list, op, mode);
865
0
  sh_op_mem_type memop = SH_OP_MEM_INVALID;
866
0
  if (insn != SH_INS_INVALID) {
867
0
    MCInst_setOpcode(MI, insn);
868
0
    if (op < 8) {
869
0
      set_reg(info, SH_REG_R0 + r, write, detail);
870
0
    } else {
871
0
      memop = (op & 4) ? SH_OP_MEM_REG_POST :
872
0
             SH_OP_MEM_REG_IND;
873
0
      set_mem(info, memop, SH_REG_R0 + r, 0, 32, detail);
874
0
      set_reg(info, SH_REG_R0, write, detail);
875
0
    }
876
0
    return MCDisassembler_Success;
877
0
  } else {
878
0
    return MCDisassembler_Fail;
879
0
  }
880
0
}
881
882
static bool op4xxa(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
883
       sh_info *info, cs_detail *detail)
884
0
{
885
0
  int r = (code >> 8) & 0x0f;
886
0
  set_reg(info, SH_REG_R0 + r, read, detail);
887
0
  return opLDCLDS(code, MI, mode, info, detail);
888
0
}
889
890
static bool op4xxb(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
891
       sh_info *info, cs_detail *detail)
892
0
{
893
0
  int r = (code >> 8) & 0x0f;
894
0
  int insn_code = (code >> 4) & 0x0f;
895
0
  int sz = 0;
896
0
  int grp = SH_GRP_INVALID;
897
0
  sh_op_mem_type memop = SH_OP_MEM_INVALID;
898
0
  enum direction rw = read;
899
0
  static const struct ri_list list[] = {
900
0
    { 0, SH_INS_JSR, ISA_ALL, none },
901
0
    { 1, SH_INS_TAS, ISA_ALL, none },
902
0
    { 2, SH_INS_JMP, ISA_ALL, none },
903
0
    { 4, SH_INS_JSR_N, -(ISA_SH2A), none },
904
0
    { 8, SH_INS_MOV, -(ISA_SH2A), none },
905
0
    { 9, SH_INS_MOV, -(ISA_SH2A), none },
906
0
    { 10, SH_INS_MOV, -(ISA_SH2A), none },
907
0
    { 12, SH_INS_MOV, -(ISA_SH2A), none },
908
0
    { 13, SH_INS_MOV, -(ISA_SH2A), none },
909
0
    { 14, SH_INS_MOV, -(ISA_SH2A), none },
910
0
    { -1, SH_INS_INVALID, ISA_ALL, none },
911
0
  };
912
0
  sh_insn insn = lookup_insn(list, insn_code, mode);
913
0
  if (insn != SH_INS_INVALID) {
914
0
    MCInst_setOpcode(MI, insn);
915
0
    sz = 8 << ((code >> 4) & 3);
916
0
    switch (insn_code) {
917
0
    case 0:
918
0
    case 4:
919
0
      memop = SH_OP_MEM_REG_IND;
920
0
      grp = SH_GRP_CALL;
921
0
      break;
922
0
    case 1:
923
0
      memop = SH_OP_MEM_REG_IND;
924
0
      sz = 8;
925
0
      rw = write;
926
0
      break;
927
0
    case 2:
928
0
      MCInst_setOpcode(MI, SH_INS_JMP);
929
0
      grp = SH_GRP_JUMP;
930
0
      break;
931
0
    case 8:
932
0
    case 9:
933
0
    case 10:
934
0
      memop = SH_OP_MEM_REG_POST;
935
0
      rw = read;
936
0
      break;
937
0
    case 12:
938
0
    case 13:
939
0
    case 14:
940
0
      memop = SH_OP_MEM_REG_PRE;
941
0
      rw = write;
942
0
      break;
943
0
    }
944
0
    if (grp != SH_GRP_INVALID) {
945
0
      set_mem(info, SH_OP_MEM_REG_IND, SH_REG_R0 + r, 0, 0,
946
0
        detail);
947
0
      if (detail)
948
0
        set_groups(detail, 1, grp);
949
0
    } else {
950
0
      if (insn_code != 1) {
951
0
        set_reg_n(info, SH_REG_R0, rw, rw, detail);
952
0
        info->op.op_count++;
953
0
      }
954
0
      set_mem_n(info, memop, SH_REG_R0 + r, 0, sz, 1 - rw,
955
0
          detail);
956
0
      info->op.op_count++;
957
0
    }
958
0
    return MCDisassembler_Success;
959
0
  } else {
960
0
    return MCDisassembler_Fail;
961
0
  }
962
0
}
963
964
/* SHAD / SHLD - SH2A */
965
opRR(ISA_SH2A, SHAD, 0) opRR(ISA_SH2A, SHLD, 0)
966
967
  static bool opLDC(uint16_t code, uint64_t address, MCInst *MI,
968
        cs_mode mode, sh_info *info, cs_detail *detail)
969
0
{
970
0
  int s = (code >> 8) & 0x0f;
971
0
  set_reg(info, SH_REG_R0 + s, read, detail);
972
0
  return opLDCdst(code, MI, mode, info, detail);
973
0
}
974
975
opRR(ISA_ALL, MOV, 0)
976
977
  static bool opMOV_rpi(uint16_t code, uint64_t address, MCInst *MI,
978
            cs_mode mode, sh_info *info, cs_detail *detail)
979
0
{
980
0
  int sz = (code & 0x03);
981
0
  nm(code, 0);
982
0
  MCInst_setOpcode(MI, SH_INS_MOV);
983
0
  set_mem(info, SH_OP_MEM_REG_POST, SH_REG_R0 + m, 0, 8 << sz, detail);
984
0
  set_reg(info, SH_REG_R0 + n, write, detail);
985
0
  return MCDisassembler_Success;
986
0
}
987
988
opRR(ISA_ALL, NOT, 0) opRR(ISA_ALL, SWAP_B, 8) opRR(ISA_ALL, SWAP_W, 16)
989
  opRR(ISA_ALL, NEGC, 0) opRR(ISA_ALL, NEG, 0) opRR(ISA_ALL, EXTU_B, 8)
990
    opRR(ISA_ALL, EXTU_W, 16) opRR(ISA_ALL, EXTS_B,
991
                 8) opRR(ISA_ALL, EXTS_W, 16)
992
993
      static bool opADD_i(uint16_t code, uint64_t address,
994
              MCInst *MI, cs_mode mode,
995
              sh_info *info, cs_detail *detail)
996
0
{
997
0
  int r = (code >> 8) & 0x0f;
998
0
  MCInst_setOpcode(MI, SH_INS_ADD);
999
0
  set_imm(info, 1, code & 0xff);
1000
0
  set_reg(info, SH_REG_R0 + r, write, detail);
1001
0
  return MCDisassembler_Success;
1002
0
}
1003
1004
static bool opMOV_BW_dsp(uint16_t code, uint64_t address, MCInst *MI,
1005
       cs_mode mode, sh_info *info, cs_detail *detail)
1006
0
{
1007
0
  int dsp = (code & 0x0f);
1008
0
  int r = (code >> 4) & 0x0f;
1009
0
  int size = 1 + ((code >> 8) & 1);
1010
0
  int rw = (code >> 10) & 1;
1011
0
  MCInst_setOpcode(MI, SH_INS_MOV);
1012
0
  set_mem_n(info, SH_OP_MEM_REG_DISP, SH_REG_R0 + r, dsp * size, 8 * size,
1013
0
      1 - rw, detail);
1014
0
  set_reg_n(info, SH_REG_R0, rw, rw, detail);
1015
0
  info->op.op_count = 2;
1016
0
  return MCDisassembler_Success;
1017
0
}
1018
1019
static bool opSETRC(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
1020
        sh_info *info, cs_detail *detail)
1021
0
{
1022
0
  int imm = code & 0xff;
1023
0
  if (!(mode & CS_MODE_SHDSP))
1024
0
    return MCDisassembler_Fail;
1025
0
  MCInst_setOpcode(MI, SH_INS_SETRC);
1026
0
  set_imm(info, 0, imm);
1027
0
  return MCDisassembler_Success;
1028
0
}
1029
1030
static bool opJSR_N(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
1031
        sh_info *info, cs_detail *detail)
1032
0
{
1033
0
  int dsp = code & 0xff;
1034
0
  if (isalevel(mode) != ISA_SH2A)
1035
0
    return MCDisassembler_Fail;
1036
0
  MCInst_setOpcode(MI, SH_INS_JSR_N);
1037
0
  set_mem(info, SH_OP_MEM_TBR_DISP, SH_REG_INVALID, dsp * 4, 0, detail);
1038
0
  return MCDisassembler_Success;
1039
0
}
1040
1041
#define boperand(_code, _op, _imm, _reg) \
1042
0
  int _op = (code >> 3) & 1; \
1043
0
  int _imm = code & 7; \
1044
0
  int _reg = (code >> 4) & 0x0f
1045
1046
static bool op86xx(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
1047
       sh_info *info, cs_detail *detail)
1048
0
{
1049
0
  static const sh_insn bop[] = { SH_INS_BCLR, SH_INS_BSET };
1050
0
  boperand(code, op, imm, reg);
1051
0
  if (isalevel(mode) != ISA_SH2A)
1052
0
    return MCDisassembler_Fail;
1053
0
  MCInst_setOpcode(MI, bop[op]);
1054
0
  set_imm(info, 0, imm);
1055
0
  set_reg(info, SH_REG_R0 + reg, write, detail);
1056
0
  return MCDisassembler_Success;
1057
0
}
1058
1059
static bool op87xx(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
1060
       sh_info *info, cs_detail *detail)
1061
0
{
1062
0
  static const sh_insn bop[] = { SH_INS_BST, SH_INS_BLD };
1063
0
  boperand(code, op, imm, reg);
1064
0
  if (isalevel(mode) != ISA_SH2A)
1065
0
    return MCDisassembler_Fail;
1066
0
  MCInst_setOpcode(MI, bop[op]);
1067
0
  set_imm(info, 0, imm);
1068
0
  set_reg(info, SH_REG_R0 + reg, op ? read : write, detail);
1069
0
  return MCDisassembler_Success;
1070
0
}
1071
1072
static bool opCMP_EQi(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
1073
          sh_info *info, cs_detail *detail)
1074
0
{
1075
0
  MCInst_setOpcode(MI, SH_INS_CMP_EQ);
1076
0
  set_imm(info, 1, code & 0x00ff);
1077
0
  set_reg(info, SH_REG_R0, read, detail);
1078
0
  return MCDisassembler_Success;
1079
0
}
1080
1081
#define opBranch(level, insn) \
1082
  static bool op##insn(uint16_t code, uint64_t address, MCInst *MI, \
1083
           cs_mode mode, sh_info *info, cs_detail *detail) \
1084
0
  { \
1085
0
    int dsp = code & 0x00ff; \
1086
0
    if (level > isalevel(mode)) \
1087
0
      return MCDisassembler_Fail; \
1088
0
    if (dsp >= 0x80) \
1089
0
      dsp = -256 + dsp; \
1090
0
    MCInst_setOpcode(MI, SH_INS_##insn); \
1091
0
    set_mem(info, SH_OP_MEM_PCR, SH_REG_INVALID, \
1092
0
      address + 4 + dsp * 2, 0, detail); \
1093
0
    if (detail) \
1094
0
      set_groups(detail, 2, SH_GRP_JUMP, \
1095
0
           SH_GRP_BRANCH_RELATIVE); \
1096
0
    return MCDisassembler_Success; \
1097
0
  }
Unexecuted instantiation: SHDisassembler.c:opBT
Unexecuted instantiation: SHDisassembler.c:opBF
Unexecuted instantiation: SHDisassembler.c:opBT_S
Unexecuted instantiation: SHDisassembler.c:opBF_S
1098
1099
opBranch(ISA_ALL, BT) opBranch(ISA_ALL, BF)
1100
  /* bt/s / bf/s - SH2 */
1101
  opBranch(ISA_SH2, BT_S) opBranch(ISA_SH2, BF_S)
1102
1103
#define opLDRSE(insn) \
1104
  static bool op##insn(uint16_t code, uint64_t address, MCInst *MI, \
1105
           cs_mode mode, sh_info *info, cs_detail *detail) \
1106
0
  { \
1107
0
    int dsp = code & 0xff; \
1108
0
    if (!(mode & CS_MODE_SHDSP)) \
1109
0
      return MCDisassembler_Fail; \
1110
0
    MCInst_setOpcode(MI, SH_INS_##insn); \
1111
0
    set_mem(info, SH_OP_MEM_PCR, SH_REG_INVALID, \
1112
0
      address + 4 + dsp * 2, 0, detail); \
1113
0
    return MCDisassembler_Success; \
1114
0
  }
Unexecuted instantiation: SHDisassembler.c:opLDRS
Unexecuted instantiation: SHDisassembler.c:opLDRE
1115
1116
    static bool opLDRC(uint16_t code, uint64_t address, MCInst *MI,
1117
           cs_mode mode, sh_info *info,
1118
           cs_detail *detail)
1119
0
{
1120
0
  int imm = code & 0xff;
1121
0
  if (!(mode & CS_MODE_SHDSP) || isalevel(mode) != ISA_SH4A)
1122
0
    return MCDisassembler_Fail;
1123
0
  MCInst_setOpcode(MI, SH_INS_LDRC);
1124
0
  set_imm(info, 0, imm);
1125
0
  return MCDisassembler_Success;
1126
0
}
1127
1128
opLDRSE(LDRS) opLDRSE(LDRE)
1129
1130
#define opImmR0(insn) \
1131
  static bool op##insn##_i(uint16_t code, uint64_t address, MCInst *MI, \
1132
         cs_mode mode, sh_info *info, \
1133
         cs_detail *detail) \
1134
0
  { \
1135
0
    MCInst_setOpcode(MI, SH_INS_##insn); \
1136
0
    set_imm(info, 0, code & 0xff); \
1137
0
    set_reg(info, SH_REG_R0, write, detail); \
1138
0
    return MCDisassembler_Success; \
1139
0
  }
Unexecuted instantiation: SHDisassembler.c:opTST_i
Unexecuted instantiation: SHDisassembler.c:opAND_i
Unexecuted instantiation: SHDisassembler.c:opXOR_i
Unexecuted instantiation: SHDisassembler.c:opOR_i
1140
1141
  opImmR0(TST) opImmR0(AND) opImmR0(XOR) opImmR0(OR)
1142
1143
#define opImmMem(insn) \
1144
  static bool op##insn##_B(uint16_t code, uint64_t address, MCInst *MI, \
1145
         cs_mode mode, sh_info *info, \
1146
         cs_detail *detail) \
1147
0
  { \
1148
0
    MCInst_setOpcode(MI, SH_INS_##insn); \
1149
0
    set_imm(info, 0, code & 0xff); \
1150
0
    set_mem(info, SH_OP_MEM_GBR_R0, SH_REG_R0, 0, 8, detail); \
1151
0
    return MCDisassembler_Success; \
1152
0
  }
Unexecuted instantiation: SHDisassembler.c:opTST_B
Unexecuted instantiation: SHDisassembler.c:opAND_B
Unexecuted instantiation: SHDisassembler.c:opXOR_B
Unexecuted instantiation: SHDisassembler.c:opOR_B
1153
1154
    opImmMem(TST) opImmMem(AND) opImmMem(XOR) opImmMem(OR)
1155
1156
      static bool opMOV_pc(uint16_t code, uint64_t address,
1157
               MCInst *MI, cs_mode mode,
1158
               sh_info *info, cs_detail *detail)
1159
0
{
1160
0
  int sz = 16 << ((code >> 14) & 1);
1161
0
  int dsp = (code & 0x00ff) * (sz / 8);
1162
0
  int r = (code >> 8) & 0x0f;
1163
0
  MCInst_setOpcode(MI, SH_INS_MOV);
1164
0
  if (sz == 32)
1165
0
    address &= ~3;
1166
0
  set_mem(info, SH_OP_MEM_PCR, SH_REG_INVALID, address + 4 + dsp, sz,
1167
0
    detail);
1168
0
  set_reg(info, SH_REG_R0 + r, write, detail);
1169
0
  return MCDisassembler_Success;
1170
0
}
1171
1172
#define opBxx(insn, grp) \
1173
  static bool op##insn(uint16_t code, uint64_t address, MCInst *MI, \
1174
           cs_mode mode, sh_info *info, cs_detail *detail) \
1175
0
  { \
1176
0
    int dsp = (code & 0x0fff); \
1177
0
    if (dsp >= 0x800) \
1178
0
      dsp = -0x1000 + dsp; \
1179
0
    MCInst_setOpcode(MI, SH_INS_##insn); \
1180
0
    set_mem(info, SH_OP_MEM_PCR, SH_REG_INVALID, \
1181
0
      address + 4 + dsp * 2, 0, detail); \
1182
0
    if (detail) \
1183
0
      set_groups(detail, 2, grp, SH_GRP_BRANCH_RELATIVE); \
1184
0
    return MCDisassembler_Success; \
1185
0
  }
Unexecuted instantiation: SHDisassembler.c:opBRA
Unexecuted instantiation: SHDisassembler.c:opBSR
1186
1187
opBxx(BRA, SH_GRP_JUMP) opBxx(BSR, SH_GRP_CALL)
1188
1189
  static bool opMOV_gbr(uint16_t code, uint64_t address, MCInst *MI,
1190
            cs_mode mode, sh_info *info, cs_detail *detail)
1191
0
{
1192
0
  int sz = 8 << ((code >> 8) & 0x03);
1193
0
  int dsp = (code & 0x00ff) * (sz / 8);
1194
0
  int rw = (code >> 10) & 1;
1195
0
  MCInst_setOpcode(MI, SH_INS_MOV);
1196
0
  set_mem_n(info, SH_OP_MEM_GBR_DISP, SH_REG_GBR, dsp, sz, 1 - rw,
1197
0
      detail);
1198
0
  set_reg_n(info, SH_REG_R0, rw, rw, detail);
1199
0
  info->op.op_count = 2;
1200
0
  return MCDisassembler_Success;
1201
0
}
1202
1203
static bool opTRAPA(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
1204
        sh_info *info, cs_detail *detail)
1205
0
{
1206
0
  MCInst_setOpcode(MI, SH_INS_TRAPA);
1207
0
  set_imm(info, 0, code & 0xff);
1208
0
  if (detail)
1209
0
    set_groups(detail, 1, SH_GRP_INT);
1210
0
  return MCDisassembler_Success;
1211
0
}
1212
1213
static bool opMOVA(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
1214
       sh_info *info, cs_detail *detail)
1215
0
{
1216
0
  int dsp = (code & 0x00ff) * 4;
1217
0
  MCInst_setOpcode(MI, SH_INS_MOVA);
1218
0
  set_mem(info, SH_OP_MEM_PCR, SH_REG_INVALID, (address & ~3) + 4 + dsp,
1219
0
    0, detail);
1220
0
  set_reg(info, SH_REG_R0, write, detail);
1221
0
  return MCDisassembler_Success;
1222
0
}
1223
1224
static bool opMOV_i(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
1225
        sh_info *info, cs_detail *detail)
1226
0
{
1227
0
  int imm = (code & 0x00ff);
1228
0
  int r = (code >> 8) & 0x0f;
1229
0
  MCInst_setOpcode(MI, SH_INS_MOV);
1230
0
  set_imm(info, 1, imm);
1231
0
  set_reg(info, SH_REG_R0 + r, write, detail);
1232
0
  return MCDisassembler_Success;
1233
0
}
1234
1235
/* FPU instructions */
1236
#define opFRR(insn) \
1237
  static bool op##insn(uint16_t code, uint64_t address, MCInst *MI, \
1238
           cs_mode mode, sh_info *info, cs_detail *detail) \
1239
0
  { \
1240
0
    int m = (code >> 4) & 0x0f; \
1241
0
    int n = (code >> 8) & 0x0f; \
1242
0
    MCInst_setOpcode(MI, SH_INS_##insn); \
1243
0
    set_reg(info, SH_REG_FR0 + m, read, detail); \
1244
0
    set_reg(info, SH_REG_FR0 + n, write, detail); \
1245
0
    return MCDisassembler_Success; \
1246
0
  }
Unexecuted instantiation: SHDisassembler.c:opFADD
Unexecuted instantiation: SHDisassembler.c:opFSUB
Unexecuted instantiation: SHDisassembler.c:opFMUL
Unexecuted instantiation: SHDisassembler.c:opFDIV
1247
1248
#define opFRRcmp(insn) \
1249
  static bool op##insn(uint16_t code, uint64_t address, MCInst *MI, \
1250
           cs_mode mode, sh_info *info, cs_detail *detail) \
1251
0
  { \
1252
0
    int m = (code >> 4) & 0x0f; \
1253
0
    int n = (code >> 8) & 0x0f; \
1254
0
    MCInst_setOpcode(MI, SH_INS_##insn); \
1255
0
    set_reg(info, SH_REG_FR0 + m, read, detail); \
1256
0
    set_reg(info, SH_REG_FR0 + n, read, detail); \
1257
0
    return MCDisassembler_Success; \
1258
0
  }
Unexecuted instantiation: SHDisassembler.c:opFCMP_EQ
Unexecuted instantiation: SHDisassembler.c:opFCMP_GT
1259
1260
opFRR(FADD) opFRR(FSUB) opFRR(FMUL) opFRR(FDIV) opFRRcmp(FCMP_EQ)
1261
  opFRRcmp(FCMP_GT)
1262
1263
    static bool opFMOVm(MCInst *MI, enum direction rw,
1264
            uint16_t code, sh_op_mem_type address,
1265
            sh_info *info, cs_detail *detail)
1266
0
{
1267
0
  nm(code, (1 - rw));
1268
0
  MCInst_setOpcode(MI, SH_INS_FMOV);
1269
0
  set_mem_n(info, address, SH_REG_R0 + m, 0, 0, 1 - rw, detail);
1270
0
  set_reg_n(info, SH_REG_FR0 + n, rw, rw, detail);
1271
0
  info->op.op_count = 2;
1272
0
  return MCDisassembler_Success;
1273
0
}
1274
1275
static bool opfxx6(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
1276
       sh_info *info, cs_detail *detail)
1277
0
{
1278
0
  return opFMOVm(MI, write, code, SH_OP_MEM_REG_R0, info, detail);
1279
0
}
1280
1281
static bool opfxx7(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
1282
       sh_info *info, cs_detail *detail)
1283
0
{
1284
0
  return opFMOVm(MI, read, code, SH_OP_MEM_REG_R0, info, detail);
1285
0
}
1286
1287
static bool opfxx8(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
1288
       sh_info *info, cs_detail *detail)
1289
0
{
1290
0
  return opFMOVm(MI, write, code, SH_OP_MEM_REG_IND, info, detail);
1291
0
}
1292
1293
static bool opfxx9(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
1294
       sh_info *info, cs_detail *detail)
1295
0
{
1296
0
  return opFMOVm(MI, write, code, SH_OP_MEM_REG_POST, info, detail);
1297
0
}
1298
1299
static bool opfxxa(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
1300
       sh_info *info, cs_detail *detail)
1301
0
{
1302
0
  return opFMOVm(MI, read, code, SH_OP_MEM_REG_IND, info, detail);
1303
0
}
1304
1305
static bool opfxxb(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
1306
       sh_info *info, cs_detail *detail)
1307
0
{
1308
0
  return opFMOVm(MI, read, code, SH_OP_MEM_REG_PRE, info, detail);
1309
0
}
1310
1311
static bool opFMOV(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
1312
       sh_info *info, cs_detail *detail)
1313
0
{
1314
0
  nm(code, 0);
1315
0
  MCInst_setOpcode(MI, SH_INS_FMOV);
1316
0
  set_reg(info, SH_REG_FR0 + m, read, detail);
1317
0
  set_reg(info, SH_REG_FR0 + n, write, detail);
1318
0
  return MCDisassembler_Success;
1319
0
}
1320
1321
static bool opfxxd(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
1322
       sh_info *info, cs_detail *detail)
1323
0
{
1324
0
  int fr = (code >> 8) & 0x0f;
1325
0
  int dr = (code >> 9) & 0x07;
1326
0
  int fvn = (code >> 10) & 0x03;
1327
0
  int fvm = (code >> 8) & 0x03;
1328
0
  sh_insn insn = SH_INS_INVALID;
1329
0
  sh_reg s, d;
1330
0
  static const struct ri_list list[] = {
1331
0
    { 0, SH_INS_FSTS, ISA_ALL, shfpu },
1332
0
    { 1, SH_INS_FLDS, ISA_ALL, shfpu },
1333
0
    { 2, SH_INS_FLOAT, ISA_ALL, shfpu },
1334
0
    { 3, SH_INS_FTRC, ISA_ALL, shfpu },
1335
0
    { 4, SH_INS_FNEG, ISA_ALL, shfpu },
1336
0
    { 5, SH_INS_FABS, ISA_ALL, shfpu },
1337
0
    { 6, SH_INS_FSQRT, ISA_ALL, shfpu },
1338
0
    { 7, SH_INS_FSRRA, ISA_ALL, shfpu },
1339
0
    { 8, SH_INS_FLDI0, ISA_ALL, shfpu },
1340
0
    { 9, SH_INS_FLDI1, ISA_ALL, shfpu },
1341
0
    { 10, SH_INS_FCNVSD, ISA_SH4A, shfpu },
1342
0
    { 11, SH_INS_FCNVDS, ISA_SH4A, shfpu },
1343
0
    { 14, SH_INS_FIPR, ISA_SH4A, shfpu },
1344
0
    { -1, SH_INS_INVALID, ISA_ALL, none },
1345
0
  };
1346
0
  static const sh_insn chg[] = { SH_INS_FSCHG, SH_INS_FPCHG, SH_INS_FRCHG,
1347
0
               SH_INS_INVALID };
1348
0
  insn = lookup_insn(list, (code >> 4) & 0x0f, mode);
1349
0
  s = d = SH_REG_FPUL;
1350
0
  if (insn != SH_INS_INVALID) {
1351
0
    switch ((code >> 4) & 0x0f) {
1352
0
    case 0:
1353
0
    case 2:
1354
0
      d = SH_REG_FR0 + fr;
1355
0
      break;
1356
0
    case 1:
1357
0
    case 3:
1358
0
      s = SH_REG_FR0 + fr;
1359
0
      break;
1360
0
    case 10:
1361
0
      d = SH_REG_DR0 + dr;
1362
0
      break;
1363
0
    case 11:
1364
0
      s = SH_REG_DR0 + dr;
1365
0
      break;
1366
0
    case 14:
1367
0
      s = SH_REG_FV0 + fvm;
1368
0
      d = SH_REG_FV0 + fvn;
1369
0
      break;
1370
0
    default:
1371
0
      s = SH_REG_FR0 + fr;
1372
0
      d = SH_REG_INVALID;
1373
0
      break;
1374
0
    }
1375
0
  } else if ((code & 0x00f0) == 0x00f0) {
1376
0
    if ((code & 0x01ff) == 0x00fd) {
1377
0
      insn = SH_INS_FSCA;
1378
0
      d = SH_REG_DR0 + dr;
1379
0
    }
1380
0
    if ((code & 0x03ff) == 0x01fd) {
1381
0
      insn = SH_INS_FTRV;
1382
0
      s = SH_REG_XMATRX;
1383
0
      d = SH_REG_FV0 + fvn;
1384
0
    }
1385
0
    if ((code & 0x03ff) == 0x03fd) {
1386
0
      insn = chg[(code >> 10) & 3];
1387
0
      s = d = SH_REG_INVALID;
1388
0
    }
1389
0
  }
1390
0
  if (insn == SH_INS_INVALID) {
1391
0
    return MCDisassembler_Fail;
1392
0
  }
1393
0
  MCInst_setOpcode(MI, insn);
1394
0
  if (s != SH_REG_INVALID) {
1395
0
    set_reg(info, s, read, detail);
1396
0
  }
1397
0
  if (d != SH_REG_INVALID) {
1398
0
    set_reg(info, d, write, detail);
1399
0
  }
1400
0
  return MCDisassembler_Success;
1401
0
}
1402
1403
static bool opFMAC(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode,
1404
       sh_info *info, cs_detail *detail)
1405
0
{
1406
0
  int m = (code >> 4) & 0x0f;
1407
0
  int n = (code >> 8) & 0x0f;
1408
0
  MCInst_setOpcode(MI, SH_INS_FMAC);
1409
0
  set_reg(info, SH_REG_FR0, read, detail);
1410
0
  set_reg(info, SH_REG_FR0 + m, read, detail);
1411
0
  set_reg(info, SH_REG_FR0 + n, write, detail);
1412
0
  return MCDisassembler_Success;
1413
0
}
1414
1415
#include "SHInsnTable.inc"
1416
1417
static bool decode_long(uint32_t code, uint64_t address, MCInst *MI,
1418
      sh_info *info, cs_detail *detail)
1419
0
{
1420
0
  uint32_t imm;
1421
0
  sh_insn insn = SH_INS_INVALID;
1422
0
  int m, n;
1423
0
  int dsp;
1424
0
  int sz;
1425
0
  static const sh_insn bop[] = {
1426
0
    SH_INS_BCLR,  SH_INS_BSET,  SH_INS_BST, SH_INS_BLD,
1427
0
    SH_INS_BAND,  SH_INS_BOR, SH_INS_BXOR,  SH_INS_INVALID,
1428
0
    SH_INS_INVALID, SH_INS_INVALID, SH_INS_INVALID, SH_INS_BLDNOT,
1429
0
    SH_INS_BANDNOT, SH_INS_BORNOT,  SH_INS_INVALID, SH_INS_INVALID,
1430
0
  };
1431
0
  switch (code >> 28) {
1432
0
  case 0x0:
1433
0
    imm = ((code >> 4) & 0x000f0000) | (code & 0xffff);
1434
0
    n = (code >> 24) & 0x0f;
1435
0
    if (code & 0x00010000) {
1436
      // movi20s #imm,
1437
0
      imm <<= 8;
1438
0
      if (imm & (1 << (28 - 1)))
1439
0
        imm |= ~((1 << 28) - 1);
1440
0
      insn = SH_INS_MOVI20S;
1441
0
    } else {
1442
      // MOVI20
1443
0
      if (imm & (1 << (28 - 1)))
1444
0
        imm |= ~((1 << 20) - 1);
1445
0
      insn = SH_INS_MOVI20;
1446
0
    }
1447
0
    set_imm(info, 0, imm);
1448
0
    set_reg(info, SH_REG_R0 + n, write, detail);
1449
0
    break;
1450
0
  case 0x3:
1451
0
    n = (code >> 24) & 0x0f;
1452
0
    m = (code >> 20) & 0x0f;
1453
0
    sz = (code >> 12) & 0x03;
1454
0
    dsp = code & 0xfff;
1455
0
    if (!(code & 0x80000)) {
1456
0
      dsp <<= sz;
1457
0
      switch ((code >> 14) & 0x3) {
1458
0
      case 0: // mov.[bwl] Rm,@(disp,Rn)
1459
        // fmov.s DRm,@(disp,Rn)
1460
0
        if (sz < 3) {
1461
0
          insn = SH_INS_MOV;
1462
0
          set_reg(info, SH_REG_R0 + m, read,
1463
0
            detail);
1464
0
        } else {
1465
0
          insn = SH_INS_FMOV;
1466
0
          set_reg(info, SH_REG_DR0 + (m >> 1),
1467
0
            read, detail);
1468
0
        }
1469
0
        set_mem(info, SH_OP_MEM_REG_DISP, SH_REG_R0 + n,
1470
0
          dsp, 8 << sz, detail);
1471
0
        break;
1472
0
      case 1: // mov.[bwl] @(disp,Rm),Rn
1473
        // fmov.s @(disp,Rm),DRn
1474
0
        set_mem(info, SH_OP_MEM_REG_DISP, SH_REG_R0 + m,
1475
0
          dsp, 8 << sz, detail);
1476
0
        if (sz < 3) {
1477
0
          insn = SH_INS_MOV;
1478
0
          set_reg(info, SH_REG_R0 + n, write,
1479
0
            detail);
1480
0
        } else {
1481
0
          insn = SH_INS_FMOV;
1482
0
          set_reg(info, SH_REG_DR0 + (n >> 1),
1483
0
            write, detail);
1484
0
        }
1485
0
        break;
1486
0
      case 2: // movu.[bwl] @(disp,Rm),Rn
1487
0
        if (sz < 2) {
1488
0
          insn = SH_INS_MOVU;
1489
0
          set_mem(info, SH_OP_MEM_REG_DISP,
1490
0
            SH_REG_R0 + m, dsp, 8 << sz,
1491
0
            detail);
1492
0
          set_reg(info, SH_REG_R0 + n, write,
1493
0
            detail);
1494
0
        }
1495
0
        break;
1496
0
      }
1497
0
    } else {
1498
      // bitop #imm,@(disp,Rn)
1499
0
      insn = bop[(code >> 12) & 0x0f];
1500
0
      set_imm(info, 0, m & 7);
1501
0
      set_mem(info, SH_OP_MEM_REG_DISP, SH_REG_R0 + n, dsp, 8,
1502
0
        detail);
1503
0
    }
1504
0
  }
1505
0
  if (insn != SH_INS_INVALID) {
1506
0
    MCInst_setOpcode(MI, insn);
1507
0
    return MCDisassembler_Success;
1508
0
  } else {
1509
0
    return MCDisassembler_Fail;
1510
0
  }
1511
0
}
1512
1513
static const sh_reg dsp_areg[2][4] = {
1514
  { SH_REG_R4, SH_REG_R0, SH_REG_R5, SH_REG_R1 },
1515
  { SH_REG_R6, SH_REG_R7, SH_REG_R2, SH_REG_R3 },
1516
};
1517
1518
static bool decode_dsp_xy(sh_info *info, int xy, uint16_t code,
1519
        cs_detail *detail)
1520
0
{
1521
0
  int a = (code >> 8) & 3;
1522
0
  int d = (code >> 6) & 3;
1523
0
  int dir;
1524
0
  int sz;
1525
0
  int op;
1526
1527
0
  static const sh_reg dreg[4][4] = {
1528
0
    { SH_REG_DSP_A0, SH_REG_DSP_X0, SH_REG_DSP_A1, SH_REG_DSP_X1 },
1529
0
    { SH_REG_DSP_A0, SH_REG_DSP_A1, SH_REG_DSP_Y0, SH_REG_DSP_Y1 },
1530
0
    { SH_REG_DSP_X0, SH_REG_DSP_Y0, SH_REG_DSP_X1, SH_REG_DSP_Y1 },
1531
0
    { SH_REG_DSP_Y0, SH_REG_DSP_Y1, SH_REG_DSP_X0, SH_REG_DSP_X1 },
1532
0
  };
1533
1534
0
  if (xy) {
1535
0
    op = code & 3;
1536
0
    dir = 1 - ((code >> 4) & 1);
1537
0
    sz = (code >> 5) & 1;
1538
0
    if (code & 0x0c) {
1539
0
      info->op.operands[xy].dsp.insn = SH_INS_DSP_NOP;
1540
0
      return MCDisassembler_Success;
1541
0
    }
1542
0
  } else {
1543
0
    op = (code >> 2) & 3;
1544
0
    dir = 1 - ((code >> 5) & 1);
1545
0
    sz = (code >> 4) & 1;
1546
0
    if (code & 0x03) {
1547
0
      info->op.operands[xy].dsp.insn = SH_INS_DSP_NOP;
1548
0
      return MCDisassembler_Success;
1549
0
    }
1550
0
  }
1551
0
  info->op.operands[xy].dsp.size = 16 << sz;
1552
0
  info->op.operands[xy].dsp.insn = SH_INS_DSP_MOV;
1553
0
  info->op.operands[xy].dsp.operand[1 - dir] =
1554
0
    SH_OP_DSP_REG_IND + (op - 1);
1555
0
  info->op.operands[xy].dsp.operand[dir] = SH_OP_DSP_REG;
1556
0
  info->op.operands[xy].dsp.r[1 - dir] = dsp_areg[xy][a];
1557
0
  info->op.operands[xy].dsp.size = 16 << sz;
1558
0
  regs_rw(detail, dir,
1559
0
    info->op.operands[xy].dsp.r[dir] = dreg[xy * 2 + dir][d]);
1560
0
  switch (op) {
1561
0
  case 0x03:
1562
0
    regs_read(detail, SH_REG_R8 + xy);
1563
    // Fail through
1564
0
  case 0x02:
1565
0
    regs_write(detail, dsp_areg[xy][a]);
1566
0
    break;
1567
0
  case 0x01:
1568
0
    regs_read(detail, dsp_areg[xy][a]);
1569
0
    break;
1570
0
  default:
1571
0
    return MCDisassembler_Fail;
1572
0
  }
1573
0
  return MCDisassembler_Success;
1574
0
}
1575
1576
static bool set_dsp_move_d(sh_info *info, int xy, uint16_t code, cs_mode mode,
1577
         cs_detail *detail)
1578
0
{
1579
0
  int a;
1580
0
  int d;
1581
0
  int dir;
1582
0
  int op;
1583
0
  static const sh_reg base[] = { SH_REG_DSP_A0, SH_REG_DSP_X0 };
1584
0
  switch (xy) {
1585
0
  default:
1586
0
    printf("Invalid xy value %" PRId32 "\n", xy);
1587
0
    return MCDisassembler_Fail;
1588
0
  case 0:
1589
0
    op = (code >> 2) & 3;
1590
0
    dir = 1 - ((code >> 5) & 1);
1591
0
    d = (code >> 7) & 1;
1592
0
    a = (code >> 9) & 1;
1593
0
    break;
1594
0
  case 1:
1595
0
    op = (code >> 0) & 3;
1596
0
    dir = 1 - ((code >> 4) & 1);
1597
0
    d = (code >> 6) & 1;
1598
0
    a = (code >> 8) & 1;
1599
0
    break;
1600
0
  }
1601
0
  if (op == 0x00) {
1602
0
    if ((a || d || dir) && !(code & 0x0f))
1603
0
      return MCDisassembler_Fail;
1604
0
    info->op.operands[xy].dsp.insn = SH_INS_DSP_NOP;
1605
0
  } else {
1606
0
    info->op.operands[xy].dsp.insn = SH_INS_DSP_MOV;
1607
0
    info->op.operands[xy].dsp.operand[1 - dir] =
1608
0
      SH_OP_DSP_REG_IND + (op - 1);
1609
0
    info->op.operands[xy].dsp.operand[dir] = SH_OP_DSP_REG;
1610
0
    info->op.operands[xy].dsp.r[1 - dir] = SH_REG_R4 + xy * 2 + a;
1611
0
    info->op.operands[xy].dsp.size = 16;
1612
0
    regs_rw(detail, dir,
1613
0
      info->op.operands[xy].dsp.r[dir] =
1614
0
        base[dir] + d + dir ? (xy * 2) : 0);
1615
0
    switch (op) {
1616
0
    case 0x03:
1617
0
      regs_read(detail, SH_REG_R8 + a);
1618
      // Fail through
1619
0
    case 0x02:
1620
0
      regs_write(detail, SH_REG_R4 + xy * 2 + a);
1621
0
      break;
1622
0
    case 0x01:
1623
0
      regs_read(detail, SH_REG_R4 + xy * 2 + a);
1624
0
      break;
1625
0
    }
1626
0
  }
1627
0
  return MCDisassembler_Success;
1628
0
}
1629
1630
static bool decode_dsp_d(const uint16_t code, MCInst *MI, cs_mode mode,
1631
       sh_info *info, cs_detail *detail)
1632
0
{
1633
0
  bool ret, dsp_long;
1634
0
  MCInst_setOpcode(MI, SH_INS_DSP);
1635
0
  if ((code & 0x3ff) == 0) {
1636
0
    info->op.operands[0].dsp.insn = info->op.operands[1].dsp.insn =
1637
0
      SH_INS_DSP_NOP;
1638
0
    info->op.op_count = 2;
1639
0
    return MCDisassembler_Success;
1640
0
  }
1641
0
  dsp_long = false;
1642
0
  if (isalevel(mode) == ISA_SH4A) {
1643
0
    if (!(code & 0x03) && (code & 0x0f) >= 0x04) {
1644
0
      ret = decode_dsp_xy(info, 0, code, detail);
1645
0
      ret &= set_dsp_move_d(info, 1, code, mode, detail);
1646
0
      dsp_long |= true;
1647
0
    }
1648
0
    if ((code & 0x0f) <= 0x03 && (code & 0xff)) {
1649
0
      ret = decode_dsp_xy(info, 1, code, detail);
1650
0
      ret &= set_dsp_move_d(info, 0, code, mode, detail);
1651
0
      dsp_long |= true;
1652
0
    }
1653
0
  }
1654
0
  if (!dsp_long) {
1655
    /* X op */
1656
0
    ret = set_dsp_move_d(info, 0, code, mode, detail);
1657
    /* Y op */
1658
0
    ret &= set_dsp_move_d(info, 1, code, mode, detail);
1659
0
  }
1660
1661
0
  info->op.op_count = 2;
1662
0
  return ret;
1663
0
}
1664
1665
static bool decode_dsp_s(const uint16_t code, MCInst *MI, sh_info *info,
1666
       cs_detail *detail)
1667
0
{
1668
0
  int d = code & 1;
1669
0
  int s = (code >> 1) & 1;
1670
0
  int opr = (code >> 2) & 3;
1671
0
  int as = (code >> 8) & 3;
1672
0
  int ds = (code >> 4) & 0x0f;
1673
0
  static const sh_reg regs[] = {
1674
0
    SH_REG_DSP_RSV0, SH_REG_DSP_RSV1, SH_REG_DSP_RSV2,
1675
0
    SH_REG_DSP_RSV3, SH_REG_DSP_RSV4, SH_REG_DSP_A1,
1676
0
    SH_REG_DSP_RSV6, SH_REG_DSP_A0,   SH_REG_DSP_X0,
1677
0
    SH_REG_DSP_X1,   SH_REG_DSP_Y0,   SH_REG_DSP_Y1,
1678
0
    SH_REG_DSP_M0,   SH_REG_DSP_A1G,  SH_REG_DSP_M1,
1679
0
    SH_REG_DSP_A0G,
1680
0
  };
1681
1682
0
  if (regs[ds] == SH_REG_INVALID)
1683
0
    return MCDisassembler_Fail;
1684
1685
0
  MCInst_setOpcode(MI, SH_INS_DSP);
1686
0
  info->op.operands[0].dsp.insn = SH_INS_DSP_MOV;
1687
0
  info->op.operands[0].dsp.operand[1 - d] = SH_OP_DSP_REG;
1688
0
  info->op.operands[0].dsp.operand[d] = SH_OP_DSP_REG_PRE + opr;
1689
0
  info->op.operands[0].dsp.r[1 - d] = regs[ds];
1690
0
  info->op.operands[0].dsp.r[d] =
1691
0
    SH_REG_R2 + ((as < 2) ? (as + 2) : (as - 2));
1692
0
  switch (opr) {
1693
0
  case 3:
1694
0
    regs_read(detail, SH_REG_R8);
1695
    /* Fail through */
1696
0
  case 1:
1697
0
    regs_read(detail, info->op.operands[0].dsp.r[d]);
1698
0
    break;
1699
0
  case 0:
1700
0
  case 2:
1701
0
    regs_write(detail, info->op.operands[0].dsp.r[d]);
1702
0
  }
1703
0
  regs_rw(detail, d, regs[ds]);
1704
0
  info->op.operands[0].dsp.size = 16 << s;
1705
0
  info->op.op_count = 1;
1706
0
  return MCDisassembler_Success;
1707
0
}
1708
1709
static const sh_reg dsp_reg_sd[6][4] = {
1710
  { SH_REG_DSP_X0, SH_REG_DSP_X1, SH_REG_DSP_Y0, SH_REG_DSP_A1 },
1711
  { SH_REG_DSP_Y0, SH_REG_DSP_Y1, SH_REG_DSP_X0, SH_REG_DSP_A1 },
1712
  { SH_REG_DSP_X0, SH_REG_DSP_X1, SH_REG_DSP_A0, SH_REG_DSP_A1 },
1713
  { SH_REG_DSP_Y0, SH_REG_DSP_Y1, SH_REG_DSP_M0, SH_REG_DSP_M1 },
1714
  { SH_REG_DSP_M0, SH_REG_DSP_M1, SH_REG_DSP_A0, SH_REG_DSP_A1 },
1715
  { SH_REG_DSP_X0, SH_REG_DSP_Y0, SH_REG_DSP_A0, SH_REG_DSP_A1 },
1716
};
1717
typedef enum { f_se, f_sf, f_sx, f_sy, f_dg, f_du } dsp_reg_opr;
1718
static void set_reg_dsp_read(sh_info *info, int pos, dsp_reg_opr f, int r,
1719
           cs_detail *detail)
1720
0
{
1721
0
  info->op.operands[2].dsp.r[pos] = dsp_reg_sd[f][r];
1722
0
  regs_read(detail, dsp_reg_sd[f][r]);
1723
0
}
1724
1725
static void set_reg_dsp_write_gu(sh_info *info, int pos, dsp_reg_opr f, int r,
1726
         cs_detail *detail)
1727
0
{
1728
0
  info->op.operands[2].dsp.r[pos] = dsp_reg_sd[f][r];
1729
0
  regs_write(detail, dsp_reg_sd[f][r]);
1730
0
}
1731
1732
static const sh_reg regs_dz[] = {
1733
  SH_REG_DSP_RSV0, SH_REG_DSP_RSV1, SH_REG_DSP_RSV2, SH_REG_DSP_RSV3,
1734
  SH_REG_DSP_RSV4, SH_REG_DSP_A1,   SH_REG_DSP_RSV6, SH_REG_DSP_A0,
1735
  SH_REG_DSP_X0,   SH_REG_DSP_X1,   SH_REG_DSP_Y0,   SH_REG_DSP_Y1,
1736
  SH_REG_DSP_M0,   SH_REG_DSP_A1G,  SH_REG_DSP_M1,   SH_REG_DSP_A0G,
1737
};
1738
1739
static void set_reg_dsp_write_z(sh_info *info, int pos, int r,
1740
        cs_detail *detail)
1741
0
{
1742
0
  info->op.operands[2].dsp.r[pos] = regs_dz[r];
1743
0
  regs_write(detail, regs_dz[r]);
1744
0
}
1745
1746
static bool dsp_op_cc_3opr(uint32_t code, sh_info *info, sh_dsp_insn insn,
1747
         sh_dsp_insn insn2, cs_detail *detail)
1748
0
{
1749
0
  info->op.operands[2].dsp.cc = (code >> 8) & 3;
1750
0
  if (info->op.operands[2].dsp.cc > 0) {
1751
0
    info->op.operands[2].dsp.insn = insn;
1752
0
  } else {
1753
0
    if (insn2 != SH_INS_DSP_INVALID)
1754
0
      info->op.operands[2].dsp.insn = insn2;
1755
0
    else
1756
0
      return MCDisassembler_Fail;
1757
0
  }
1758
0
  if (info->op.operands[2].dsp.insn != SH_INS_DSP_PSUBr) {
1759
0
    set_reg_dsp_read(info, 0, f_sx, (code >> 6) & 3, detail);
1760
0
    set_reg_dsp_read(info, 1, f_sy, (code >> 4) & 3, detail);
1761
0
  } else {
1762
0
    set_reg_dsp_read(info, 1, f_sx, (code >> 6) & 3, detail);
1763
0
    set_reg_dsp_read(info, 0, f_sy, (code >> 4) & 3, detail);
1764
0
  }
1765
0
  set_reg_dsp_write_z(info, 2, code & 0x0f, detail);
1766
0
  info->op.op_count = 3;
1767
0
  return MCDisassembler_Success;
1768
0
}
1769
1770
static bool dsp_op_cc_2opr(uint32_t code, sh_info *info, sh_dsp_insn insn,
1771
         int xy, int b, cs_detail *detail)
1772
0
{
1773
0
  if (((code >> 8) & 3) == 0)
1774
0
    return MCDisassembler_Fail;
1775
0
  info->op.operands[2].dsp.insn = (sh_dsp_insn)insn;
1776
0
  set_reg_dsp_read(info, 0, xy, (code >> b) & 3, detail);
1777
0
  set_reg_dsp_write_z(info, 2, code & 0x0f, detail);
1778
0
  info->op.operands[2].dsp.cc = (code >> 8) & 3;
1779
0
  info->op.op_count = 3;
1780
0
  return MCDisassembler_Success;
1781
0
}
1782
1783
static bool dsp_op_cc0_2opr(uint32_t code, sh_info *info, sh_dsp_insn insn,
1784
          int xy, int b, cs_detail *detail)
1785
0
{
1786
0
  info->op.operands[2].dsp.insn = (sh_dsp_insn)insn;
1787
0
  set_reg_dsp_read(info, 0, xy, (code >> b) & 3, detail);
1788
0
  set_reg_dsp_write_z(info, 2, code & 0x0f, detail);
1789
0
  info->op.operands[2].dsp.cc = (code >> 8) & 3;
1790
0
  if (info->op.operands[2].dsp.cc == 1)
1791
0
    return MCDisassembler_Fail;
1792
0
  if (info->op.operands[2].dsp.cc == 0)
1793
0
    info->op.operands[2].dsp.cc = SH_DSP_CC_NONE;
1794
0
  info->op.op_count = 3;
1795
0
  return MCDisassembler_Success;
1796
0
}
1797
1798
static bool decode_dsp_3op(const uint32_t code, sh_info *info,
1799
         cs_detail *detail)
1800
0
{
1801
0
  int cc = (code >> 8) & 3;
1802
0
  int sx = (code >> 6) & 3;
1803
0
  int sy = (code >> 4) & 3;
1804
0
  int dz = (code >> 0) & 0x0f;
1805
1806
0
  if ((code & 0xef00) == 0x8000)
1807
0
    return MCDisassembler_Fail;
1808
0
  switch ((code >> 10) & 0x1f) {
1809
0
  case 0x00:
1810
0
    return dsp_op_cc_3opr(code, info, SH_INS_DSP_PSHL,
1811
0
              SH_INS_DSP_INVALID, detail);
1812
0
  case 0x01:
1813
0
    if (cc == 0) {
1814
0
      info->op.operands[2].dsp.insn = SH_INS_DSP_PCMP;
1815
0
      set_reg_dsp_read(info, 0, f_sx, sx, detail);
1816
0
      set_reg_dsp_read(info, 1, f_sy, sy, detail);
1817
0
      info->op.op_count = 3;
1818
0
      return MCDisassembler_Success;
1819
0
    } else {
1820
0
      return dsp_op_cc_3opr(code, info, SH_INS_DSP_PSUBr,
1821
0
                SH_INS_DSP_INVALID, detail);
1822
0
    }
1823
0
  case 0x02:
1824
0
    switch (sy) {
1825
0
    case 0:
1826
0
      if (cc == 0) {
1827
0
        info->op.operands[2].dsp.insn = SH_INS_DSP_PABS;
1828
0
        set_reg_dsp_read(info, 0, f_sx, sx, detail);
1829
0
        set_reg_dsp_write_z(info, 1, dz, detail);
1830
0
        info->op.op_count = 3;
1831
0
        return MCDisassembler_Success;
1832
0
      } else {
1833
0
        return dsp_op_cc_2opr(code, info,
1834
0
                  SH_INS_DSP_PDEC, f_sx, 6,
1835
0
                  detail);
1836
0
      }
1837
0
    case 1:
1838
0
      return dsp_op_cc0_2opr(code, info, SH_INS_DSP_PABS,
1839
0
                 f_sx, 6, detail);
1840
0
    default:
1841
0
      return MCDisassembler_Fail;
1842
0
    }
1843
0
  case 0x03:
1844
0
    if (cc != 0) {
1845
0
      info->op.operands[2].dsp.insn = SH_INS_DSP_PCLR;
1846
0
      info->op.operands[2].dsp.cc = cc;
1847
0
      set_reg_dsp_write_z(info, 0, dz, detail);
1848
0
      info->op.op_count = 3;
1849
0
      return MCDisassembler_Success;
1850
0
    } else
1851
0
      return MCDisassembler_Fail;
1852
0
  case 0x04:
1853
0
    return dsp_op_cc_3opr(code, info, SH_INS_DSP_PSHA,
1854
0
              SH_INS_DSP_INVALID, detail);
1855
0
  case 0x05:
1856
0
    return dsp_op_cc_3opr(code, info, SH_INS_DSP_PAND,
1857
0
              SH_INS_DSP_INVALID, detail);
1858
0
  case 0x06:
1859
0
    switch (sy) {
1860
0
    case 0:
1861
0
      if (cc == 0) {
1862
0
        info->op.operands[2].dsp.insn = SH_INS_DSP_PRND;
1863
0
        set_reg_dsp_read(info, 0, f_sx, sx, detail);
1864
0
        set_reg_dsp_write_z(info, 1, dz, detail);
1865
0
        info->op.op_count = 3;
1866
0
        return MCDisassembler_Success;
1867
0
      } else {
1868
0
        return dsp_op_cc_2opr(code, info,
1869
0
                  SH_INS_DSP_PINC, f_sx, 6,
1870
0
                  detail);
1871
0
      }
1872
0
    case 1:
1873
0
      return dsp_op_cc0_2opr(code, info, SH_INS_DSP_PRND,
1874
0
                 f_sx, 6, detail);
1875
0
    default:
1876
0
      return MCDisassembler_Fail;
1877
0
    }
1878
0
  case 0x07:
1879
0
    switch (sy) {
1880
0
    case 0:
1881
0
      return dsp_op_cc_2opr(code, info, SH_INS_DSP_PDMSB,
1882
0
                f_sx, 6, detail);
1883
0
    case 1:
1884
0
      return dsp_op_cc_2opr(code, info, SH_INS_DSP_PSWAP,
1885
0
                f_sx, 6, detail);
1886
0
    default:
1887
0
      return MCDisassembler_Fail;
1888
0
    }
1889
0
  case 0x08:
1890
0
    return dsp_op_cc_3opr(code, info, SH_INS_DSP_PSUB,
1891
0
              SH_INS_DSP_PSUBC, detail);
1892
0
  case 0x09:
1893
0
    return dsp_op_cc_3opr(code, info, SH_INS_DSP_PXOR,
1894
0
              SH_INS_DSP_PWSB, detail);
1895
0
  case 0x0a:
1896
0
    switch (sx) {
1897
0
    case 0:
1898
0
      if (cc == 0) {
1899
0
        info->op.operands[2].dsp.insn = SH_INS_DSP_PABS;
1900
0
        set_reg_dsp_read(info, 0, f_sy, sy, detail);
1901
0
        set_reg_dsp_write_z(info, 1, dz, detail);
1902
0
        info->op.op_count = 3;
1903
0
        return MCDisassembler_Success;
1904
0
      } else {
1905
0
        return dsp_op_cc_2opr(code, info,
1906
0
                  SH_INS_DSP_PDEC, f_sy, 4,
1907
0
                  detail);
1908
0
      }
1909
0
    case 1:
1910
0
      return dsp_op_cc_2opr(code, info, SH_INS_DSP_PABS, f_sy,
1911
0
                4, detail);
1912
0
    default:
1913
0
      return MCDisassembler_Fail;
1914
0
    }
1915
0
  case 0x0c:
1916
0
    if (cc == 0) {
1917
0
      info->op.operands[2].dsp.insn = SH_INS_DSP_PADDC;
1918
0
      set_reg_dsp_read(info, 0, f_sx, sx, detail);
1919
0
      set_reg_dsp_read(info, 1, f_sy, sy, detail);
1920
0
      set_reg_dsp_write_z(info, 2, dz, detail);
1921
0
      info->op.op_count = 3;
1922
0
      return MCDisassembler_Success;
1923
0
    } else {
1924
0
      return dsp_op_cc_3opr(code, info, SH_INS_DSP_PADD,
1925
0
                SH_INS_DSP_INVALID, detail);
1926
0
    }
1927
0
  case 0x0d:
1928
0
    return dsp_op_cc_3opr(code, info, SH_INS_DSP_POR,
1929
0
              SH_INS_DSP_PWAD, detail);
1930
0
  case 0x0e:
1931
0
    if (cc == 0) {
1932
0
      if (sx != 0)
1933
0
        return MCDisassembler_Fail;
1934
0
      info->op.operands[2].dsp.insn = SH_INS_DSP_PRND;
1935
0
      set_reg_dsp_read(info, 0, f_sy, sy, detail);
1936
0
      set_reg_dsp_write_z(info, 1, dz, detail);
1937
0
      info->op.op_count = 3;
1938
0
      return MCDisassembler_Success;
1939
0
    } else {
1940
0
      switch (sx) {
1941
0
      case 0:
1942
0
        return dsp_op_cc_2opr(code, info,
1943
0
                  SH_INS_DSP_PINC, f_sy, 4,
1944
0
                  detail);
1945
0
      case 1:
1946
0
        return dsp_op_cc_2opr(code, info,
1947
0
                  SH_INS_DSP_PRND, f_sy, 4,
1948
0
                  detail);
1949
0
      default:
1950
0
        return MCDisassembler_Fail;
1951
0
      }
1952
0
    }
1953
0
  case 0x0f:
1954
0
    switch (sx) {
1955
0
    case 0:
1956
0
      return dsp_op_cc_2opr(code, info, SH_INS_DSP_PDMSB,
1957
0
                f_sy, 4, detail);
1958
0
    case 1:
1959
0
      return dsp_op_cc_2opr(code, info, SH_INS_DSP_PSWAP,
1960
0
                f_sy, 4, detail);
1961
0
    default:
1962
0
      return MCDisassembler_Fail;
1963
0
    }
1964
0
  case 0x12:
1965
0
    return dsp_op_cc_2opr(code, info, SH_INS_DSP_PNEG, f_sx, 6,
1966
0
              detail);
1967
0
  case 0x13:
1968
0
  case 0x17:
1969
0
    if (cc > 0) {
1970
0
      info->op.operands[2].dsp.insn = SH_INS_DSP_PSTS;
1971
0
      info->op.operands[2].dsp.cc = cc;
1972
0
      regs_read(detail,
1973
0
          info->op.operands[2].dsp.r[0] =
1974
0
            SH_REG_MACH + ((code >> 12) & 1));
1975
0
      set_reg_dsp_write_z(info, 1, dz, detail);
1976
0
      info->op.op_count = 3;
1977
0
      return MCDisassembler_Success;
1978
0
    } else {
1979
0
      return MCDisassembler_Fail;
1980
0
    }
1981
0
  case 0x16:
1982
0
    return dsp_op_cc_2opr(code, info, SH_INS_DSP_PCOPY, f_sx, 6,
1983
0
              detail);
1984
0
  case 0x1a:
1985
0
    return dsp_op_cc_2opr(code, info, SH_INS_DSP_PNEG, f_sy, 4,
1986
0
              detail);
1987
0
  case 0x1b:
1988
0
  case 0x1f:
1989
0
    if (cc > 0) {
1990
0
      info->op.operands[2].dsp.insn = SH_INS_DSP_PLDS;
1991
0
      info->op.operands[2].dsp.cc = cc;
1992
0
      info->op.operands[2].dsp.r[0] = regs_dz[dz];
1993
0
      regs_read(detail, regs_dz[dz]);
1994
0
      regs_write(detail,
1995
0
           info->op.operands[2].dsp.r[1] =
1996
0
             SH_REG_MACH + ((code >> 12) & 1));
1997
0
      info->op.op_count = 3;
1998
0
      return MCDisassembler_Success;
1999
0
    } else {
2000
0
      return MCDisassembler_Fail;
2001
0
    }
2002
0
  case 0x1e:
2003
0
    return dsp_op_cc_2opr(code, info, SH_INS_DSP_PCOPY, f_sy, 4,
2004
0
              detail);
2005
0
  default:
2006
0
    return MCDisassembler_Fail;
2007
0
  }
2008
0
}
2009
2010
static bool decode_dsp_p(const uint32_t code, MCInst *MI, cs_mode mode,
2011
       sh_info *info, cs_detail *detail)
2012
0
{
2013
0
  int dz = code & 0x0f;
2014
0
  MCInst_setOpcode(MI, SH_INS_DSP);
2015
0
  if (!decode_dsp_d(code >> 16, MI, mode, info, detail))
2016
0
    return MCDisassembler_Fail;
2017
2018
0
  switch ((code >> 12) & 0x0f) {
2019
0
  case 0x00:
2020
0
  case 0x01:
2021
0
    if ((code >> 11) & 1)
2022
0
      return MCDisassembler_Fail;
2023
0
    info->op.operands[2].dsp.insn =
2024
0
      SH_INS_DSP_PSHL + ((code >> 12) & 1);
2025
0
    info->op.operands[2].dsp.imm = (code >> 4) & 0x7f;
2026
0
    set_reg_dsp_write_z(info, 1, dz, detail);
2027
0
    info->op.op_count = 3;
2028
0
    return MCDisassembler_Success;
2029
0
  case 0x04:
2030
0
    if ((((code >> 4) & 1) && isalevel(mode) != ISA_SH4A) ||
2031
0
        (!((code >> 4) & 1) && (code & 3)) ||
2032
0
        ((code >> 4) & 0x0f) >= 2)
2033
0
      return MCDisassembler_Fail;
2034
2035
0
    info->op.operands[2].dsp.insn =
2036
0
      SH_INS_DSP_PMULS + ((code >> 4) & 1);
2037
0
    set_reg_dsp_read(info, 0, f_se, (code >> 10) & 3, detail);
2038
0
    set_reg_dsp_read(info, 1, f_sf, (code >> 8) & 3, detail);
2039
0
    set_reg_dsp_write_gu(info, 2, f_dg, (code >> 2) & 3, detail);
2040
0
    if ((code >> 4) & 1)
2041
0
      set_reg_dsp_write_gu(info, 3, f_du, (code >> 0) & 3,
2042
0
               detail);
2043
0
    info->op.op_count = 3;
2044
0
    return MCDisassembler_Success;
2045
0
  case 0x06:
2046
0
  case 0x07:
2047
0
    info->op.operands[2].dsp.insn =
2048
0
      SH_INS_DSP_PSUB_PMULS + ((code >> 12) & 1);
2049
0
    set_reg_dsp_read(info, 0, f_sx, (code >> 6) & 3, detail);
2050
0
    set_reg_dsp_read(info, 1, f_sy, (code >> 4) & 3, detail);
2051
0
    set_reg_dsp_write_gu(info, 2, f_du, (code >> 0) & 3, detail);
2052
0
    set_reg_dsp_read(info, 3, f_se, (code >> 10) & 3, detail);
2053
0
    set_reg_dsp_read(info, 4, f_sf, (code >> 8) & 3, detail);
2054
0
    set_reg_dsp_write_gu(info, 5, f_dg, (code >> 2) & 3, detail);
2055
0
    info->op.op_count = 3;
2056
0
    return MCDisassembler_Success;
2057
0
  default:
2058
0
    if ((code >> 15) & 1)
2059
0
      return decode_dsp_3op(code, info, detail);
2060
0
  }
2061
0
  return MCDisassembler_Fail;
2062
0
}
2063
2064
static bool sh_disassemble(const uint8_t *code, MCInst *MI, uint64_t address,
2065
         cs_mode mode, uint16_t *size, int code_len,
2066
         sh_info *info, cs_detail *detail)
2067
0
{
2068
0
  int idx;
2069
0
  uint32_t insn;
2070
0
  bool dsp_result;
2071
0
  if (MODE_IS_BIG_ENDIAN(mode)) {
2072
0
    insn = code[0] << 8 | code[1];
2073
0
  } else {
2074
0
    insn = code[1] << 8 | code[0];
2075
0
  }
2076
0
  if (mode & CS_MODE_SH2A) {
2077
    /* SH2A 32bit instruction test */
2078
0
    if (((insn & 0xf007) == 0x3001 || (insn & 0xf00e) == 0x0000)) {
2079
0
      if (code_len < 4)
2080
0
        return MCDisassembler_Fail;
2081
0
      *size = 4;
2082
      // SH2A is only BIG ENDIAN.
2083
0
      insn <<= 16;
2084
0
      insn |= code[2] << 8 | code[3];
2085
0
      if (decode_long(insn, address, MI, info, detail))
2086
0
        return MCDisassembler_Success;
2087
0
    }
2088
0
  }
2089
  /* Co-processor instructions */
2090
0
  if ((insn & 0xf000) == 0xf000) {
2091
0
    if (mode & CS_MODE_SHDSP) {
2092
0
      dsp_result = MCDisassembler_Fail;
2093
0
      switch (insn >> 10 & 3) {
2094
0
      case 0:
2095
0
        *size = 2;
2096
0
        dsp_result = decode_dsp_d(insn, MI, mode, info,
2097
0
                detail);
2098
0
        break;
2099
0
      case 1:
2100
0
        *size = 2;
2101
0
        dsp_result =
2102
0
          decode_dsp_s(insn, MI, info, detail);
2103
0
        break;
2104
0
      case 2:
2105
0
        if (code_len < 4)
2106
0
          return MCDisassembler_Fail;
2107
0
        *size = 4;
2108
0
        if (MODE_IS_BIG_ENDIAN(mode)) {
2109
0
          insn <<= 16;
2110
0
          insn |= code[2] << 8 | code[3];
2111
0
        } else
2112
0
          insn |= (code[3] << 24) |
2113
0
            (code[2] << 16);
2114
0
        dsp_result = decode_dsp_p(insn, MI, mode, info,
2115
0
                detail);
2116
0
        break;
2117
0
      }
2118
0
      return dsp_result;
2119
0
    }
2120
0
    if ((mode & CS_MODE_SHFPU) == 0)
2121
0
      return MCDisassembler_Fail;
2122
0
  }
2123
2124
0
  *size = 2;
2125
0
  if ((insn & 0xf000) >= 0x8000 && (insn & 0xf000) < 0xf000) {
2126
0
    idx = insn >> 8;
2127
0
  } else {
2128
0
    idx = ((insn >> 8) & 0xf0) | (insn & 0x000f);
2129
0
  }
2130
2131
0
  if (idx < ARR_SIZE(decode) && decode[idx]) {
2132
0
    return decode[idx](insn, address, MI, mode, info, detail);
2133
0
  } else {
2134
0
    return MCDisassembler_Fail;
2135
0
  }
2136
0
}
2137
2138
bool SH_getInstruction(csh ud, const uint8_t *code, size_t code_len, MCInst *MI,
2139
           uint16_t *size, uint64_t address, void *inst_info)
2140
0
{
2141
0
  cs_struct *handle = (cs_struct *)ud;
2142
0
  sh_info *info = (sh_info *)handle->printer_info;
2143
0
  cs_detail *detail = MI->flat_insn->detail;
2144
2145
0
  if (code_len < 2) {
2146
0
    *size = 0;
2147
0
    return MCDisassembler_Fail;
2148
0
  }
2149
2150
0
  if (detail) {
2151
0
    memset(detail, 0, offsetof(cs_detail, sh) + sizeof(cs_sh));
2152
0
  }
2153
0
  memset(info, 0, sizeof(sh_info));
2154
0
  if (sh_disassemble(code, MI, address, handle->mode, size, code_len,
2155
0
         info, detail) == MCDisassembler_Fail) {
2156
0
    *size = 0;
2157
0
    return MCDisassembler_Fail;
2158
0
  } else {
2159
0
    if (detail)
2160
0
      detail->sh = info->op;
2161
0
    return MCDisassembler_Success;
2162
0
  }
2163
0
}
2164
2165
#ifndef CAPSTONE_DIET
2166
void SH_reg_access(const cs_insn *insn, cs_regs regs_read,
2167
       uint8_t *regs_read_count, cs_regs regs_write,
2168
       uint8_t *regs_write_count)
2169
0
{
2170
0
  if (insn->detail == NULL) {
2171
0
    *regs_read_count = 0;
2172
0
    *regs_write_count = 0;
2173
0
  } else {
2174
0
    *regs_read_count = insn->detail->regs_read_count;
2175
0
    *regs_write_count = insn->detail->regs_write_count;
2176
2177
0
    memcpy(regs_read, insn->detail->regs_read,
2178
0
           *regs_read_count * sizeof(insn->detail->regs_read[0]));
2179
0
    memcpy(regs_write, insn->detail->regs_write,
2180
0
           *regs_write_count * sizeof(insn->detail->regs_write[0]));
2181
0
  }
2182
0
}
2183
#endif