Coverage Report

Created: 2026-07-16 06:55

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