Coverage Report

Created: 2026-08-14 06:51

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