master
c 2,312 lines 61.4 KB
Raw
1 /*
2 * RX translation
3 *
4 * Copyright (c) 2019 Yoshinori Sato
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2 or later, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "qemu/osdep.h"
20 #include "qemu/bswap.h"
21 #include "qemu/qemu-print.h"
22 #include "cpu.h"
23 #include "tcg/tcg-op.h"
24 #include "exec/helper-proto.h"
25 #include "exec/helper-gen.h"
26 #include "exec/translator.h"
27 #include "exec/translation-block.h"
28 #include "exec/log.h"
29
30 #define HELPER_H "helper.h"
31 #include "exec/helper-info.c.inc"
32 #undef HELPER_H
33
34
35 typedef struct DisasContext {
36 DisasContextBase base;
37 CPURXState *env;
38 uint32_t pc;
39 uint32_t tb_flags;
40 } DisasContext;
41
42 typedef struct DisasCompare {
43 TCGv_i32 value;
44 TCGv_i32 temp;
45 TCGCond cond;
46 } DisasCompare;
47
48 const char *rx_crname(uint8_t cr)
49 {
50 static const char *cr_names[] = {
51 "psw", "pc", "usp", "fpsw", "", "", "", "",
52 "bpsw", "bpc", "isp", "fintv", "intb", "", "", ""
53 };
54 if (cr >= ARRAY_SIZE(cr_names)) {
55 return "illegal";
56 }
57 return cr_names[cr];
58 }
59
60 /* Target-specific values for dc->base.is_jmp. */
61 #define DISAS_JUMP DISAS_TARGET_0
62 #define DISAS_UPDATE DISAS_TARGET_1
63 #define DISAS_EXIT DISAS_TARGET_2
64
65 /* global register indexes */
66 static TCGv_i32 cpu_regs[16];
67 static TCGv_i32 cpu_psw_o, cpu_psw_s, cpu_psw_z, cpu_psw_c;
68 static TCGv_i32 cpu_psw_i, cpu_psw_pm, cpu_psw_u, cpu_psw_ipl;
69 static TCGv_i32 cpu_usp, cpu_fpsw, cpu_bpsw, cpu_bpc, cpu_isp;
70 static TCGv_i32 cpu_fintv, cpu_intb, cpu_pc;
71 static TCGv_i64 cpu_acc;
72
73 #define cpu_sp cpu_regs[0]
74
75 static inline MemOp mo_endian(DisasContext *dc)
76 {
77 return MO_LE;
78 }
79
80 /* decoder helper */
81 static uint32_t decode_load_bytes(DisasContext *ctx, uint32_t insn,
82 int i, int n)
83 {
84 while (++i <= n) {
85 uint8_t b = translator_ldub(ctx->env, &ctx->base, ctx->base.pc_next++);
86 insn |= b << (32 - i * 8);
87 }
88 return insn;
89 }
90
91 static uint32_t li(DisasContext *ctx, int sz)
92 {
93 vaddr addr;
94 uint32_t tmp;
95 MemOp endian = mo_endian(ctx);
96 CPURXState *env = ctx->env;
97 addr = ctx->base.pc_next;
98
99 switch (sz) {
100 case 1:
101 ctx->base.pc_next += 1;
102 return (int8_t)translator_ldub(env, &ctx->base, addr);
103 case 2:
104 ctx->base.pc_next += 2;
105 return (int16_t) translator_lduw_end(env, &ctx->base, addr, endian);
106 case 3:
107 ctx->base.pc_next += 3;
108 tmp = (int8_t)translator_ldub(env, &ctx->base, addr + 2);
109 tmp <<= 16;
110 tmp |= translator_lduw_end(env, &ctx->base, addr, endian);
111 return tmp;
112 case 0:
113 ctx->base.pc_next += 4;
114 return translator_ldl_end(env, &ctx->base, addr, endian);
115 default:
116 g_assert_not_reached();
117 }
118 return 0;
119 }
120
121 static int bdsp_s(DisasContext *ctx, int d)
122 {
123 /*
124 * 0 -> 8
125 * 1 -> 9
126 * 2 -> 10
127 * 3 -> 3
128 * :
129 * 7 -> 7
130 */
131 if (d < 3) {
132 d += 8;
133 }
134 return d;
135 }
136
137 /* Include the auto-generated decoder. */
138 #include "decode-insns.c.inc"
139
140 void rx_cpu_dump_state(CPUState *cs, FILE *f, int flags)
141 {
142 CPURXState *env = cpu_env(cs);
143 int i;
144 uint32_t psw;
145
146 psw = rx_cpu_pack_psw(env);
147 qemu_fprintf(f, "pc=0x%08x psw=0x%08x\n",
148 env->pc, psw);
149 for (i = 0; i < 16; i += 4) {
150 qemu_fprintf(f, "r%d=0x%08x r%d=0x%08x r%d=0x%08x r%d=0x%08x\n",
151 i, env->regs[i], i + 1, env->regs[i + 1],
152 i + 2, env->regs[i + 2], i + 3, env->regs[i + 3]);
153 }
154 }
155
156 static void gen_goto_tb(DisasContext *dc, unsigned tb_slot_idx, vaddr dest)
157 {
158 if (translator_use_goto_tb(&dc->base, dest)) {
159 tcg_gen_goto_tb(tb_slot_idx);
160 tcg_gen_movi_i32(cpu_pc, dest);
161 tcg_gen_exit_tb(dc->base.tb, tb_slot_idx);
162 } else {
163 tcg_gen_movi_i32(cpu_pc, dest);
164 tcg_gen_lookup_and_goto_ptr();
165 }
166 dc->base.is_jmp = DISAS_NORETURN;
167 }
168
169 /* generic load wrapper */
170 static void rx_gen_ld(DisasContext *ctx, MemOp size, TCGv_i32 reg, TCGv_i32 mem)
171 {
172 tcg_gen_qemu_ld_i32(reg, mem, 0, size | MO_SIGN | mo_endian(ctx));
173 }
174
175 /* unsigned load wrapper */
176 static void rx_gen_ldu(DisasContext *ctx, MemOp size, TCGv_i32 reg, TCGv_i32 mem)
177 {
178 tcg_gen_qemu_ld_i32(reg, mem, 0, size | mo_endian(ctx));
179 }
180
181 /* generic store wrapper */
182 static void rx_gen_st(DisasContext *ctx, MemOp size, TCGv_i32 reg, TCGv_i32 mem)
183 {
184 tcg_gen_qemu_st_i32(reg, mem, 0, size | mo_endian(ctx));
185 }
186
187 /* [ri, rb] */
188 static void rx_gen_regindex(DisasContext *ctx, TCGv_i32 mem,
189 int size, int ri, int rb)
190 {
191 tcg_gen_shli_i32(mem, cpu_regs[ri], size);
192 tcg_gen_add_i32(mem, mem, cpu_regs[rb]);
193 }
194
195 /* dsp[reg] */
196 static TCGv_i32 rx_index_addr(DisasContext *ctx, TCGv_i32 mem,
197 int ld, int size, int reg)
198 {
199 uint32_t dsp;
200
201 switch (ld) {
202 case 0:
203 return cpu_regs[reg];
204 case 1:
205 dsp = translator_ldub(ctx->env, &ctx->base, ctx->base.pc_next) << size;
206 tcg_gen_addi_i32(mem, cpu_regs[reg], dsp);
207 ctx->base.pc_next += 1;
208 return mem;
209 case 2:
210 dsp = translator_lduw_end(ctx->env, &ctx->base, ctx->base.pc_next,
211 mo_endian(ctx)) << size;
212 tcg_gen_addi_i32(mem, cpu_regs[reg], dsp);
213 ctx->base.pc_next += 2;
214 return mem;
215 default:
216 g_assert_not_reached();
217 }
218 }
219
220 static inline MemOp mi_to_mop(unsigned mi)
221 {
222 static const MemOp mop[5] = { MO_SB, MO_SW, MO_UL, MO_UW, MO_UB };
223 tcg_debug_assert(mi < 5);
224 return mop[mi];
225 }
226
227 /* load source operand */
228 static TCGv_i32 rx_load_source(DisasContext *ctx, TCGv_i32 mem,
229 int ld, int mi, int rs)
230 {
231 TCGv_i32 addr;
232 MemOp mop;
233 if (ld < 3) {
234 mop = mi_to_mop(mi);
235 addr = rx_index_addr(ctx, mem, ld, mop & MO_SIZE, rs);
236 tcg_gen_qemu_ld_i32(mem, addr, 0, mop | mo_endian(ctx));
237 return mem;
238 } else {
239 return cpu_regs[rs];
240 }
241 }
242
243 /* Processor mode check */
244 static int is_privileged(DisasContext *ctx, int is_exception)
245 {
246 if (FIELD_EX32(ctx->tb_flags, PSW, PM)) {
247 if (is_exception) {
248 gen_helper_raise_privilege_violation(tcg_env);
249 }
250 return 0;
251 } else {
252 return 1;
253 }
254 }
255
256 /* generate QEMU condition */
257 static void psw_cond(DisasCompare *dc, uint32_t cond)
258 {
259 tcg_debug_assert(cond < 16);
260 switch (cond) {
261 case 0: /* z */
262 dc->cond = TCG_COND_EQ;
263 dc->value = cpu_psw_z;
264 break;
265 case 1: /* nz */
266 dc->cond = TCG_COND_NE;
267 dc->value = cpu_psw_z;
268 break;
269 case 2: /* c */
270 dc->cond = TCG_COND_NE;
271 dc->value = cpu_psw_c;
272 break;
273 case 3: /* nc */
274 dc->cond = TCG_COND_EQ;
275 dc->value = cpu_psw_c;
276 break;
277 case 4: /* gtu (C& ~Z) == 1 */
278 case 5: /* leu (C& ~Z) == 0 */
279 tcg_gen_setcondi_i32(TCG_COND_NE, dc->temp, cpu_psw_z, 0);
280 tcg_gen_and_i32(dc->temp, dc->temp, cpu_psw_c);
281 dc->cond = (cond == 4) ? TCG_COND_NE : TCG_COND_EQ;
282 dc->value = dc->temp;
283 break;
284 case 6: /* pz (S == 0) */
285 dc->cond = TCG_COND_GE;
286 dc->value = cpu_psw_s;
287 break;
288 case 7: /* n (S == 1) */
289 dc->cond = TCG_COND_LT;
290 dc->value = cpu_psw_s;
291 break;
292 case 8: /* ge (S^O)==0 */
293 case 9: /* lt (S^O)==1 */
294 tcg_gen_xor_i32(dc->temp, cpu_psw_o, cpu_psw_s);
295 dc->cond = (cond == 8) ? TCG_COND_GE : TCG_COND_LT;
296 dc->value = dc->temp;
297 break;
298 case 10: /* gt ((S^O)|Z)==0 */
299 case 11: /* le ((S^O)|Z)==1 */
300 tcg_gen_xor_i32(dc->temp, cpu_psw_o, cpu_psw_s);
301 tcg_gen_sari_i32(dc->temp, dc->temp, 31);
302 tcg_gen_andc_i32(dc->temp, cpu_psw_z, dc->temp);
303 dc->cond = (cond == 10) ? TCG_COND_NE : TCG_COND_EQ;
304 dc->value = dc->temp;
305 break;
306 case 12: /* o */
307 dc->cond = TCG_COND_LT;
308 dc->value = cpu_psw_o;
309 break;
310 case 13: /* no */
311 dc->cond = TCG_COND_GE;
312 dc->value = cpu_psw_o;
313 break;
314 case 14: /* always true */
315 dc->cond = TCG_COND_ALWAYS;
316 dc->value = dc->temp;
317 break;
318 case 15: /* always false */
319 dc->cond = TCG_COND_NEVER;
320 dc->value = dc->temp;
321 break;
322 }
323 }
324
325 static void move_from_cr(DisasContext *ctx, TCGv_i32 ret, int cr, uint32_t pc)
326 {
327 switch (cr) {
328 case 0: /* PSW */
329 gen_helper_pack_psw(ret, tcg_env);
330 break;
331 case 1: /* PC */
332 tcg_gen_movi_i32(ret, pc);
333 break;
334 case 2: /* USP */
335 if (FIELD_EX32(ctx->tb_flags, PSW, U)) {
336 tcg_gen_mov_i32(ret, cpu_sp);
337 } else {
338 tcg_gen_mov_i32(ret, cpu_usp);
339 }
340 break;
341 case 3: /* FPSW */
342 tcg_gen_mov_i32(ret, cpu_fpsw);
343 break;
344 case 8: /* BPSW */
345 tcg_gen_mov_i32(ret, cpu_bpsw);
346 break;
347 case 9: /* BPC */
348 tcg_gen_mov_i32(ret, cpu_bpc);
349 break;
350 case 10: /* ISP */
351 if (FIELD_EX32(ctx->tb_flags, PSW, U)) {
352 tcg_gen_mov_i32(ret, cpu_isp);
353 } else {
354 tcg_gen_mov_i32(ret, cpu_sp);
355 }
356 break;
357 case 11: /* FINTV */
358 tcg_gen_mov_i32(ret, cpu_fintv);
359 break;
360 case 12: /* INTB */
361 tcg_gen_mov_i32(ret, cpu_intb);
362 break;
363 default:
364 qemu_log_mask(LOG_GUEST_ERROR, "Unimplement control register %d", cr);
365 /* Unimplement registers return 0 */
366 tcg_gen_movi_i32(ret, 0);
367 break;
368 }
369 }
370
371 static void move_to_cr(DisasContext *ctx, TCGv_i32 val, int cr)
372 {
373 if (cr >= 8 && !is_privileged(ctx, 0)) {
374 /* Some control registers can only be written in privileged mode. */
375 qemu_log_mask(LOG_GUEST_ERROR,
376 "disallow control register write %s", rx_crname(cr));
377 return;
378 }
379 switch (cr) {
380 case 0: /* PSW */
381 gen_helper_set_psw(tcg_env, val);
382 if (is_privileged(ctx, 0)) {
383 /* PSW.{I,U} may be updated here. exit TB. */
384 ctx->base.is_jmp = DISAS_UPDATE;
385 }
386 break;
387 /* case 1: to PC not supported */
388 case 2: /* USP */
389 if (FIELD_EX32(ctx->tb_flags, PSW, U)) {
390 tcg_gen_mov_i32(cpu_sp, val);
391 } else {
392 tcg_gen_mov_i32(cpu_usp, val);
393 }
394 break;
395 case 3: /* FPSW */
396 gen_helper_set_fpsw(tcg_env, val);
397 break;
398 case 8: /* BPSW */
399 tcg_gen_mov_i32(cpu_bpsw, val);
400 break;
401 case 9: /* BPC */
402 tcg_gen_mov_i32(cpu_bpc, val);
403 break;
404 case 10: /* ISP */
405 if (FIELD_EX32(ctx->tb_flags, PSW, U)) {
406 tcg_gen_mov_i32(cpu_isp, val);
407 } else {
408 tcg_gen_mov_i32(cpu_sp, val);
409 }
410 break;
411 case 11: /* FINTV */
412 tcg_gen_mov_i32(cpu_fintv, val);
413 break;
414 case 12: /* INTB */
415 tcg_gen_mov_i32(cpu_intb, val);
416 break;
417 default:
418 qemu_log_mask(LOG_GUEST_ERROR,
419 "Unimplement control register %d", cr);
420 break;
421 }
422 }
423
424 static void push(DisasContext *ctx, TCGv_i32 val)
425 {
426 tcg_gen_subi_i32(cpu_sp, cpu_sp, 4);
427 rx_gen_st(ctx, MO_32, val, cpu_sp);
428 }
429
430 static void pop(DisasContext *ctx, TCGv_i32 ret)
431 {
432 rx_gen_ld(ctx, MO_32, ret, cpu_sp);
433 tcg_gen_addi_i32(cpu_sp, cpu_sp, 4);
434 }
435
436 /* mov.<bwl> rs,dsp5[rd] */
437 static bool trans_MOV_rm(DisasContext *ctx, arg_MOV_rm *a)
438 {
439 TCGv_i32 mem;
440 mem = tcg_temp_new_i32();
441 tcg_gen_addi_i32(mem, cpu_regs[a->rd], a->dsp << a->sz);
442 rx_gen_st(ctx, a->sz, cpu_regs[a->rs], mem);
443 return true;
444 }
445
446 /* mov.<bwl> dsp5[rs],rd */
447 static bool trans_MOV_mr(DisasContext *ctx, arg_MOV_mr *a)
448 {
449 TCGv_i32 mem;
450 mem = tcg_temp_new_i32();
451 tcg_gen_addi_i32(mem, cpu_regs[a->rs], a->dsp << a->sz);
452 rx_gen_ld(ctx, a->sz, cpu_regs[a->rd], mem);
453 return true;
454 }
455
456 /* mov.l #uimm4,rd */
457 /* mov.l #uimm8,rd */
458 /* mov.l #imm,rd */
459 static bool trans_MOV_ir(DisasContext *ctx, arg_MOV_ir *a)
460 {
461 tcg_gen_movi_i32(cpu_regs[a->rd], a->imm);
462 return true;
463 }
464
465 /* mov.<bwl> #uimm8,dsp[rd] */
466 /* mov.<bwl> #imm, dsp[rd] */
467 static bool trans_MOV_im(DisasContext *ctx, arg_MOV_im *a)
468 {
469 TCGv_i32 imm, mem;
470 imm = tcg_constant_i32(a->imm);
471 mem = tcg_temp_new_i32();
472 tcg_gen_addi_i32(mem, cpu_regs[a->rd], a->dsp << a->sz);
473 rx_gen_st(ctx, a->sz, imm, mem);
474 return true;
475 }
476
477 /* mov.<bwl> [ri,rb],rd */
478 static bool trans_MOV_ar(DisasContext *ctx, arg_MOV_ar *a)
479 {
480 TCGv_i32 mem;
481 mem = tcg_temp_new_i32();
482 rx_gen_regindex(ctx, mem, a->sz, a->ri, a->rb);
483 rx_gen_ld(ctx, a->sz, cpu_regs[a->rd], mem);
484 return true;
485 }
486
487 /* mov.<bwl> rd,[ri,rb] */
488 static bool trans_MOV_ra(DisasContext *ctx, arg_MOV_ra *a)
489 {
490 TCGv_i32 mem;
491 mem = tcg_temp_new_i32();
492 rx_gen_regindex(ctx, mem, a->sz, a->ri, a->rb);
493 rx_gen_st(ctx, a->sz, cpu_regs[a->rs], mem);
494 return true;
495 }
496
497 /* mov.<bwl> dsp[rs],dsp[rd] */
498 /* mov.<bwl> rs,dsp[rd] */
499 /* mov.<bwl> dsp[rs],rd */
500 /* mov.<bwl> rs,rd */
501 static bool trans_MOV_mm(DisasContext *ctx, arg_MOV_mm *a)
502 {
503 TCGv_i32 tmp, mem, addr;
504
505 if (a->lds == 3 && a->ldd == 3) {
506 /* mov.<bwl> rs,rd */
507 tcg_gen_ext_i32(cpu_regs[a->rd], cpu_regs[a->rs], a->sz | MO_SIGN);
508 return true;
509 }
510
511 mem = tcg_temp_new_i32();
512 if (a->lds == 3) {
513 /* mov.<bwl> rs,dsp[rd] */
514 addr = rx_index_addr(ctx, mem, a->ldd, a->sz, a->rs);
515 rx_gen_st(ctx, a->sz, cpu_regs[a->rd], addr);
516 } else if (a->ldd == 3) {
517 /* mov.<bwl> dsp[rs],rd */
518 addr = rx_index_addr(ctx, mem, a->lds, a->sz, a->rs);
519 rx_gen_ld(ctx, a->sz, cpu_regs[a->rd], addr);
520 } else {
521 /* mov.<bwl> dsp[rs],dsp[rd] */
522 tmp = tcg_temp_new_i32();
523 addr = rx_index_addr(ctx, mem, a->lds, a->sz, a->rs);
524 rx_gen_ld(ctx, a->sz, tmp, addr);
525 addr = rx_index_addr(ctx, mem, a->ldd, a->sz, a->rd);
526 rx_gen_st(ctx, a->sz, tmp, addr);
527 }
528 return true;
529 }
530
531 /* mov.<bwl> rs,[rd+] */
532 /* mov.<bwl> rs,[-rd] */
533 static bool trans_MOV_rp(DisasContext *ctx, arg_MOV_rp *a)
534 {
535 TCGv_i32 val;
536 val = tcg_temp_new_i32();
537 tcg_gen_mov_i32(val, cpu_regs[a->rs]);
538 if (a->ad == 1) {
539 tcg_gen_subi_i32(cpu_regs[a->rd], cpu_regs[a->rd], 1 << a->sz);
540 }
541 rx_gen_st(ctx, a->sz, val, cpu_regs[a->rd]);
542 if (a->ad == 0) {
543 tcg_gen_addi_i32(cpu_regs[a->rd], cpu_regs[a->rd], 1 << a->sz);
544 }
545 return true;
546 }
547
548 /* mov.<bwl> [rd+],rs */
549 /* mov.<bwl> [-rd],rs */
550 static bool trans_MOV_pr(DisasContext *ctx, arg_MOV_pr *a)
551 {
552 TCGv_i32 val;
553 val = tcg_temp_new_i32();
554 if (a->ad == 1) {
555 tcg_gen_subi_i32(cpu_regs[a->rd], cpu_regs[a->rd], 1 << a->sz);
556 }
557 rx_gen_ld(ctx, a->sz, val, cpu_regs[a->rd]);
558 if (a->ad == 0) {
559 tcg_gen_addi_i32(cpu_regs[a->rd], cpu_regs[a->rd], 1 << a->sz);
560 }
561 tcg_gen_mov_i32(cpu_regs[a->rs], val);
562 return true;
563 }
564
565 /* movu.<bw> dsp5[rs],rd */
566 /* movu.<bw> dsp[rs],rd */
567 static bool trans_MOVU_mr(DisasContext *ctx, arg_MOVU_mr *a)
568 {
569 TCGv_i32 mem;
570 mem = tcg_temp_new_i32();
571 tcg_gen_addi_i32(mem, cpu_regs[a->rs], a->dsp << a->sz);
572 rx_gen_ldu(ctx, a->sz, cpu_regs[a->rd], mem);
573 return true;
574 }
575
576 /* movu.<bw> rs,rd */
577 static bool trans_MOVU_rr(DisasContext *ctx, arg_MOVU_rr *a)
578 {
579 tcg_gen_ext_i32(cpu_regs[a->rd], cpu_regs[a->rs], a->sz);
580 return true;
581 }
582
583 /* movu.<bw> [ri,rb],rd */
584 static bool trans_MOVU_ar(DisasContext *ctx, arg_MOVU_ar *a)
585 {
586 TCGv_i32 mem;
587 mem = tcg_temp_new_i32();
588 rx_gen_regindex(ctx, mem, a->sz, a->ri, a->rb);
589 rx_gen_ldu(ctx, a->sz, cpu_regs[a->rd], mem);
590 return true;
591 }
592
593 /* movu.<bw> [rd+],rs */
594 /* mov.<bw> [-rd],rs */
595 static bool trans_MOVU_pr(DisasContext *ctx, arg_MOVU_pr *a)
596 {
597 TCGv_i32 val;
598 val = tcg_temp_new_i32();
599 if (a->ad == 1) {
600 tcg_gen_subi_i32(cpu_regs[a->rd], cpu_regs[a->rd], 1 << a->sz);
601 }
602 rx_gen_ldu(ctx, a->sz, val, cpu_regs[a->rd]);
603 if (a->ad == 0) {
604 tcg_gen_addi_i32(cpu_regs[a->rd], cpu_regs[a->rd], 1 << a->sz);
605 }
606 tcg_gen_mov_i32(cpu_regs[a->rs], val);
607 return true;
608 }
609
610
611 /* pop rd */
612 static bool trans_POP(DisasContext *ctx, arg_POP *a)
613 {
614 /* mov.l [r0+], rd */
615 arg_MOV_rp mov_a;
616 mov_a.rd = 0;
617 mov_a.rs = a->rd;
618 mov_a.ad = 0;
619 mov_a.sz = MO_32;
620 trans_MOV_pr(ctx, &mov_a);
621 return true;
622 }
623
624 /* popc cr */
625 static bool trans_POPC(DisasContext *ctx, arg_POPC *a)
626 {
627 TCGv_i32 val;
628 val = tcg_temp_new_i32();
629 pop(ctx, val);
630 move_to_cr(ctx, val, a->cr);
631 return true;
632 }
633
634 /* popm rd-rd2 */
635 static bool trans_POPM(DisasContext *ctx, arg_POPM *a)
636 {
637 int r;
638 if (a->rd == 0 || a->rd >= a->rd2) {
639 qemu_log_mask(LOG_GUEST_ERROR,
640 "Invalid register ranges r%d-r%d", a->rd, a->rd2);
641 }
642 r = a->rd;
643 while (r <= a->rd2 && r < 16) {
644 pop(ctx, cpu_regs[r++]);
645 }
646 return true;
647 }
648
649
650 /* push.<bwl> rs */
651 static bool trans_PUSH_r(DisasContext *ctx, arg_PUSH_r *a)
652 {
653 TCGv_i32 val;
654 val = tcg_temp_new_i32();
655 tcg_gen_mov_i32(val, cpu_regs[a->rs]);
656 tcg_gen_subi_i32(cpu_sp, cpu_sp, 4);
657 rx_gen_st(ctx, a->sz, val, cpu_sp);
658 return true;
659 }
660
661 /* push.<bwl> dsp[rs] */
662 static bool trans_PUSH_m(DisasContext *ctx, arg_PUSH_m *a)
663 {
664 TCGv_i32 mem, val, addr;
665 mem = tcg_temp_new_i32();
666 val = tcg_temp_new_i32();
667 addr = rx_index_addr(ctx, mem, a->ld, a->sz, a->rs);
668 rx_gen_ld(ctx, a->sz, val, addr);
669 tcg_gen_subi_i32(cpu_sp, cpu_sp, 4);
670 rx_gen_st(ctx, a->sz, val, cpu_sp);
671 return true;
672 }
673
674 /* pushc rx */
675 static bool trans_PUSHC(DisasContext *ctx, arg_PUSHC *a)
676 {
677 TCGv_i32 val;
678 val = tcg_temp_new_i32();
679 move_from_cr(ctx, val, a->cr, ctx->pc);
680 push(ctx, val);
681 return true;
682 }
683
684 /* pushm rs-rs2 */
685 static bool trans_PUSHM(DisasContext *ctx, arg_PUSHM *a)
686 {
687 int r;
688
689 if (a->rs == 0 || a->rs >= a->rs2) {
690 qemu_log_mask(LOG_GUEST_ERROR,
691 "Invalid register ranges r%d-r%d", a->rs, a->rs2);
692 }
693 r = a->rs2;
694 while (r >= a->rs && r >= 0) {
695 push(ctx, cpu_regs[r--]);
696 }
697 return true;
698 }
699
700 /* xchg rs,rd */
701 static bool trans_XCHG_rr(DisasContext *ctx, arg_XCHG_rr *a)
702 {
703 TCGv_i32 tmp;
704 tmp = tcg_temp_new_i32();
705 tcg_gen_mov_i32(tmp, cpu_regs[a->rs]);
706 tcg_gen_mov_i32(cpu_regs[a->rs], cpu_regs[a->rd]);
707 tcg_gen_mov_i32(cpu_regs[a->rd], tmp);
708 return true;
709 }
710
711 /* xchg dsp[rs].<mi>,rd */
712 static bool trans_XCHG_mr(DisasContext *ctx, arg_XCHG_mr *a)
713 {
714 TCGv_i32 mem, addr;
715 mem = tcg_temp_new_i32();
716 switch (a->mi) {
717 case 0: /* dsp[rs].b */
718 case 1: /* dsp[rs].w */
719 case 2: /* dsp[rs].l */
720 addr = rx_index_addr(ctx, mem, a->ld, a->mi, a->rs);
721 break;
722 case 3: /* dsp[rs].uw */
723 case 4: /* dsp[rs].ub */
724 addr = rx_index_addr(ctx, mem, a->ld, 4 - a->mi, a->rs);
725 break;
726 default:
727 g_assert_not_reached();
728 }
729 tcg_gen_atomic_xchg_i32(cpu_regs[a->rd], addr, cpu_regs[a->rd],
730 0, mi_to_mop(a->mi));
731 return true;
732 }
733
734 static void stcond(TCGCond cond, int rd, int imm)
735 {
736 TCGv_i32 z;
737 TCGv_i32 _imm;
738 z = tcg_constant_i32(0);
739 _imm = tcg_constant_i32(imm);
740 tcg_gen_movcond_i32(cond, cpu_regs[rd], cpu_psw_z, z,
741 _imm, cpu_regs[rd]);
742 }
743
744 /* stz #imm,rd */
745 static bool trans_STZ(DisasContext *ctx, arg_STZ *a)
746 {
747 stcond(TCG_COND_EQ, a->rd, a->imm);
748 return true;
749 }
750
751 /* stnz #imm,rd */
752 static bool trans_STNZ(DisasContext *ctx, arg_STNZ *a)
753 {
754 stcond(TCG_COND_NE, a->rd, a->imm);
755 return true;
756 }
757
758 /* sccnd.<bwl> rd */
759 /* sccnd.<bwl> dsp:[rd] */
760 static bool trans_SCCnd(DisasContext *ctx, arg_SCCnd *a)
761 {
762 DisasCompare dc;
763 TCGv_i32 val, mem, addr;
764 dc.temp = tcg_temp_new_i32();
765 psw_cond(&dc, a->cd);
766 if (a->ld < 3) {
767 val = tcg_temp_new_i32();
768 mem = tcg_temp_new_i32();
769 tcg_gen_setcondi_i32(dc.cond, val, dc.value, 0);
770 addr = rx_index_addr(ctx, mem, a->sz, a->ld, a->rd);
771 rx_gen_st(ctx, a->sz, val, addr);
772 } else {
773 tcg_gen_setcondi_i32(dc.cond, cpu_regs[a->rd], dc.value, 0);
774 }
775 return true;
776 }
777
778 /* rtsd #imm */
779 static bool trans_RTSD_i(DisasContext *ctx, arg_RTSD_i *a)
780 {
781 tcg_gen_addi_i32(cpu_sp, cpu_sp, a->imm << 2);
782 pop(ctx, cpu_pc);
783 ctx->base.is_jmp = DISAS_JUMP;
784 return true;
785 }
786
787 /* rtsd #imm, rd-rd2 */
788 static bool trans_RTSD_irr(DisasContext *ctx, arg_RTSD_irr *a)
789 {
790 int dst;
791 int adj;
792
793 if (a->rd2 >= a->rd) {
794 adj = a->imm - (a->rd2 - a->rd + 1);
795 } else {
796 adj = a->imm - (15 - a->rd + 1);
797 }
798
799 tcg_gen_addi_i32(cpu_sp, cpu_sp, adj << 2);
800 dst = a->rd;
801 while (dst <= a->rd2 && dst < 16) {
802 pop(ctx, cpu_regs[dst++]);
803 }
804 pop(ctx, cpu_pc);
805 ctx->base.is_jmp = DISAS_JUMP;
806 return true;
807 }
808
809 typedef void (*op2fn)(TCGv_i32 ret, TCGv_i32 arg1);
810 typedef void (*op3fn)(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2);
811
812 static void rx_gen_op_rr(op2fn opr, int dst, int src)
813 {
814 opr(cpu_regs[dst], cpu_regs[src]);
815 }
816
817 static void rx_gen_op_rrr(op3fn opr, int dst, int src, int src2)
818 {
819 opr(cpu_regs[dst], cpu_regs[src], cpu_regs[src2]);
820 }
821
822 static void rx_gen_op_irr(op3fn opr, int dst, int src, uint32_t src2)
823 {
824 TCGv_i32 imm = tcg_constant_i32(src2);
825 opr(cpu_regs[dst], cpu_regs[src], imm);
826 }
827
828 static void rx_gen_op_mr(op3fn opr, DisasContext *ctx,
829 int dst, int src, int ld, int mi)
830 {
831 TCGv_i32 val, mem;
832 mem = tcg_temp_new_i32();
833 val = rx_load_source(ctx, mem, ld, mi, src);
834 opr(cpu_regs[dst], cpu_regs[dst], val);
835 }
836
837 static void rx_and(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
838 {
839 tcg_gen_and_i32(cpu_psw_s, arg1, arg2);
840 tcg_gen_mov_i32(cpu_psw_z, cpu_psw_s);
841 tcg_gen_mov_i32(ret, cpu_psw_s);
842 }
843
844 /* and #uimm:4, rd */
845 /* and #imm, rd */
846 static bool trans_AND_ir(DisasContext *ctx, arg_AND_ir *a)
847 {
848 rx_gen_op_irr(rx_and, a->rd, a->rd, a->imm);
849 return true;
850 }
851
852 /* and dsp[rs], rd */
853 /* and rs,rd */
854 static bool trans_AND_mr(DisasContext *ctx, arg_AND_mr *a)
855 {
856 rx_gen_op_mr(rx_and, ctx, a->rd, a->rs, a->ld, a->mi);
857 return true;
858 }
859
860 /* and rs,rs2,rd */
861 static bool trans_AND_rrr(DisasContext *ctx, arg_AND_rrr *a)
862 {
863 rx_gen_op_rrr(rx_and, a->rd, a->rs, a->rs2);
864 return true;
865 }
866
867 static void rx_or(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
868 {
869 tcg_gen_or_i32(cpu_psw_s, arg1, arg2);
870 tcg_gen_mov_i32(cpu_psw_z, cpu_psw_s);
871 tcg_gen_mov_i32(ret, cpu_psw_s);
872 }
873
874 /* or #uimm:4, rd */
875 /* or #imm, rd */
876 static bool trans_OR_ir(DisasContext *ctx, arg_OR_ir *a)
877 {
878 rx_gen_op_irr(rx_or, a->rd, a->rd, a->imm);
879 return true;
880 }
881
882 /* or dsp[rs], rd */
883 /* or rs,rd */
884 static bool trans_OR_mr(DisasContext *ctx, arg_OR_mr *a)
885 {
886 rx_gen_op_mr(rx_or, ctx, a->rd, a->rs, a->ld, a->mi);
887 return true;
888 }
889
890 /* or rs,rs2,rd */
891 static bool trans_OR_rrr(DisasContext *ctx, arg_OR_rrr *a)
892 {
893 rx_gen_op_rrr(rx_or, a->rd, a->rs, a->rs2);
894 return true;
895 }
896
897 static void rx_xor(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
898 {
899 tcg_gen_xor_i32(cpu_psw_s, arg1, arg2);
900 tcg_gen_mov_i32(cpu_psw_z, cpu_psw_s);
901 tcg_gen_mov_i32(ret, cpu_psw_s);
902 }
903
904 /* xor #imm, rd */
905 static bool trans_XOR_ir(DisasContext *ctx, arg_XOR_ir *a)
906 {
907 rx_gen_op_irr(rx_xor, a->rd, a->rd, a->imm);
908 return true;
909 }
910
911 /* xor dsp[rs], rd */
912 /* xor rs,rd */
913 static bool trans_XOR_mr(DisasContext *ctx, arg_XOR_mr *a)
914 {
915 rx_gen_op_mr(rx_xor, ctx, a->rd, a->rs, a->ld, a->mi);
916 return true;
917 }
918
919 static void rx_tst(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
920 {
921 tcg_gen_and_i32(cpu_psw_s, arg1, arg2);
922 tcg_gen_mov_i32(cpu_psw_z, cpu_psw_s);
923 }
924
925 /* tst #imm, rd */
926 static bool trans_TST_ir(DisasContext *ctx, arg_TST_ir *a)
927 {
928 rx_gen_op_irr(rx_tst, a->rd, a->rd, a->imm);
929 return true;
930 }
931
932 /* tst dsp[rs], rd */
933 /* tst rs, rd */
934 static bool trans_TST_mr(DisasContext *ctx, arg_TST_mr *a)
935 {
936 rx_gen_op_mr(rx_tst, ctx, a->rd, a->rs, a->ld, a->mi);
937 return true;
938 }
939
940 static void rx_not(TCGv_i32 ret, TCGv_i32 arg1)
941 {
942 tcg_gen_not_i32(ret, arg1);
943 tcg_gen_mov_i32(cpu_psw_z, ret);
944 tcg_gen_mov_i32(cpu_psw_s, ret);
945 }
946
947 /* not rd */
948 /* not rs, rd */
949 static bool trans_NOT_rr(DisasContext *ctx, arg_NOT_rr *a)
950 {
951 rx_gen_op_rr(rx_not, a->rd, a->rs);
952 return true;
953 }
954
955 static void rx_neg(TCGv_i32 ret, TCGv_i32 arg1)
956 {
957 tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_psw_o, arg1, 0x80000000);
958 tcg_gen_neg_i32(ret, arg1);
959 tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_psw_c, ret, 0);
960 tcg_gen_mov_i32(cpu_psw_z, ret);
961 tcg_gen_mov_i32(cpu_psw_s, ret);
962 }
963
964
965 /* neg rd */
966 /* neg rs, rd */
967 static bool trans_NEG_rr(DisasContext *ctx, arg_NEG_rr *a)
968 {
969 rx_gen_op_rr(rx_neg, a->rd, a->rs);
970 return true;
971 }
972
973 /* ret = arg1 + arg2 + psw_c */
974 static void rx_adc(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
975 {
976 TCGv_i32 z = tcg_constant_i32(0);
977 tcg_gen_add2_i32(cpu_psw_s, cpu_psw_c, arg1, z, cpu_psw_c, z);
978 tcg_gen_add2_i32(cpu_psw_s, cpu_psw_c, cpu_psw_s, cpu_psw_c, arg2, z);
979 tcg_gen_xor_i32(cpu_psw_o, cpu_psw_s, arg1);
980 tcg_gen_xor_i32(cpu_psw_z, arg1, arg2);
981 tcg_gen_andc_i32(cpu_psw_o, cpu_psw_o, cpu_psw_z);
982 tcg_gen_mov_i32(cpu_psw_z, cpu_psw_s);
983 tcg_gen_mov_i32(ret, cpu_psw_s);
984 }
985
986 /* adc #imm, rd */
987 static bool trans_ADC_ir(DisasContext *ctx, arg_ADC_ir *a)
988 {
989 rx_gen_op_irr(rx_adc, a->rd, a->rd, a->imm);
990 return true;
991 }
992
993 /* adc rs, rd */
994 static bool trans_ADC_rr(DisasContext *ctx, arg_ADC_rr *a)
995 {
996 rx_gen_op_rrr(rx_adc, a->rd, a->rd, a->rs);
997 return true;
998 }
999
1000 /* adc dsp[rs], rd */
1001 static bool trans_ADC_mr(DisasContext *ctx, arg_ADC_mr *a)
1002 {
1003 /* mi only 2 */
1004 if (a->mi != 2) {
1005 return false;
1006 }
1007 rx_gen_op_mr(rx_adc, ctx, a->rd, a->rs, a->ld, a->mi);
1008 return true;
1009 }
1010
1011 /* ret = arg1 + arg2 */
1012 static void rx_add(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
1013 {
1014 TCGv_i32 z = tcg_constant_i32(0);
1015 tcg_gen_add2_i32(cpu_psw_s, cpu_psw_c, arg1, z, arg2, z);
1016 tcg_gen_xor_i32(cpu_psw_o, cpu_psw_s, arg1);
1017 tcg_gen_xor_i32(cpu_psw_z, arg1, arg2);
1018 tcg_gen_andc_i32(cpu_psw_o, cpu_psw_o, cpu_psw_z);
1019 tcg_gen_mov_i32(cpu_psw_z, cpu_psw_s);
1020 tcg_gen_mov_i32(ret, cpu_psw_s);
1021 }
1022
1023 /* add #uimm4, rd */
1024 /* add #imm, rs, rd */
1025 static bool trans_ADD_irr(DisasContext *ctx, arg_ADD_irr *a)
1026 {
1027 rx_gen_op_irr(rx_add, a->rd, a->rs2, a->imm);
1028 return true;
1029 }
1030
1031 /* add rs, rd */
1032 /* add dsp[rs], rd */
1033 static bool trans_ADD_mr(DisasContext *ctx, arg_ADD_mr *a)
1034 {
1035 rx_gen_op_mr(rx_add, ctx, a->rd, a->rs, a->ld, a->mi);
1036 return true;
1037 }
1038
1039 /* add rs, rs2, rd */
1040 static bool trans_ADD_rrr(DisasContext *ctx, arg_ADD_rrr *a)
1041 {
1042 rx_gen_op_rrr(rx_add, a->rd, a->rs, a->rs2);
1043 return true;
1044 }
1045
1046 /* ret = arg1 - arg2 */
1047 static void rx_sub(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
1048 {
1049 tcg_gen_sub_i32(cpu_psw_s, arg1, arg2);
1050 tcg_gen_setcond_i32(TCG_COND_GEU, cpu_psw_c, arg1, arg2);
1051 tcg_gen_xor_i32(cpu_psw_o, cpu_psw_s, arg1);
1052 tcg_gen_xor_i32(cpu_psw_z, arg1, arg2);
1053 tcg_gen_and_i32(cpu_psw_o, cpu_psw_o, cpu_psw_z);
1054 tcg_gen_mov_i32(cpu_psw_z, cpu_psw_s);
1055 /* CMP not required return */
1056 if (ret) {
1057 tcg_gen_mov_i32(ret, cpu_psw_s);
1058 }
1059 }
1060
1061 static void rx_cmp(TCGv_i32 dummy, TCGv_i32 arg1, TCGv_i32 arg2)
1062 {
1063 rx_sub(NULL, arg1, arg2);
1064 }
1065
1066 /* ret = arg1 - arg2 - !psw_c */
1067 /* -> ret = arg1 + ~arg2 + psw_c */
1068 static void rx_sbb(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
1069 {
1070 TCGv_i32 temp;
1071 temp = tcg_temp_new_i32();
1072 tcg_gen_not_i32(temp, arg2);
1073 rx_adc(ret, arg1, temp);
1074 }
1075
1076 /* cmp #imm4, rs2 */
1077 /* cmp #imm8, rs2 */
1078 /* cmp #imm, rs2 */
1079 static bool trans_CMP_ir(DisasContext *ctx, arg_CMP_ir *a)
1080 {
1081 rx_gen_op_irr(rx_cmp, 0, a->rs2, a->imm);
1082 return true;
1083 }
1084
1085 /* cmp rs, rs2 */
1086 /* cmp dsp[rs], rs2 */
1087 static bool trans_CMP_mr(DisasContext *ctx, arg_CMP_mr *a)
1088 {
1089 rx_gen_op_mr(rx_cmp, ctx, a->rd, a->rs, a->ld, a->mi);
1090 return true;
1091 }
1092
1093 /* sub #imm4, rd */
1094 static bool trans_SUB_ir(DisasContext *ctx, arg_SUB_ir *a)
1095 {
1096 rx_gen_op_irr(rx_sub, a->rd, a->rd, a->imm);
1097 return true;
1098 }
1099
1100 /* sub rs, rd */
1101 /* sub dsp[rs], rd */
1102 static bool trans_SUB_mr(DisasContext *ctx, arg_SUB_mr *a)
1103 {
1104 rx_gen_op_mr(rx_sub, ctx, a->rd, a->rs, a->ld, a->mi);
1105 return true;
1106 }
1107
1108 /* sub rs2, rs, rd */
1109 static bool trans_SUB_rrr(DisasContext *ctx, arg_SUB_rrr *a)
1110 {
1111 rx_gen_op_rrr(rx_sub, a->rd, a->rs2, a->rs);
1112 return true;
1113 }
1114
1115 /* sbb rs, rd */
1116 static bool trans_SBB_rr(DisasContext *ctx, arg_SBB_rr *a)
1117 {
1118 rx_gen_op_rrr(rx_sbb, a->rd, a->rd, a->rs);
1119 return true;
1120 }
1121
1122 /* sbb dsp[rs], rd */
1123 static bool trans_SBB_mr(DisasContext *ctx, arg_SBB_mr *a)
1124 {
1125 /* mi only 2 */
1126 if (a->mi != 2) {
1127 return false;
1128 }
1129 rx_gen_op_mr(rx_sbb, ctx, a->rd, a->rs, a->ld, a->mi);
1130 return true;
1131 }
1132
1133 /* abs rd */
1134 /* abs rs, rd */
1135 static bool trans_ABS_rr(DisasContext *ctx, arg_ABS_rr *a)
1136 {
1137 rx_gen_op_rr(tcg_gen_abs_i32, a->rd, a->rs);
1138 return true;
1139 }
1140
1141 /* max #imm, rd */
1142 static bool trans_MAX_ir(DisasContext *ctx, arg_MAX_ir *a)
1143 {
1144 rx_gen_op_irr(tcg_gen_smax_i32, a->rd, a->rd, a->imm);
1145 return true;
1146 }
1147
1148 /* max rs, rd */
1149 /* max dsp[rs], rd */
1150 static bool trans_MAX_mr(DisasContext *ctx, arg_MAX_mr *a)
1151 {
1152 rx_gen_op_mr(tcg_gen_smax_i32, ctx, a->rd, a->rs, a->ld, a->mi);
1153 return true;
1154 }
1155
1156 /* min #imm, rd */
1157 static bool trans_MIN_ir(DisasContext *ctx, arg_MIN_ir *a)
1158 {
1159 rx_gen_op_irr(tcg_gen_smin_i32, a->rd, a->rd, a->imm);
1160 return true;
1161 }
1162
1163 /* min rs, rd */
1164 /* min dsp[rs], rd */
1165 static bool trans_MIN_mr(DisasContext *ctx, arg_MIN_mr *a)
1166 {
1167 rx_gen_op_mr(tcg_gen_smin_i32, ctx, a->rd, a->rs, a->ld, a->mi);
1168 return true;
1169 }
1170
1171 /* mul #uimm4, rd */
1172 /* mul #imm, rd */
1173 static bool trans_MUL_ir(DisasContext *ctx, arg_MUL_ir *a)
1174 {
1175 rx_gen_op_irr(tcg_gen_mul_i32, a->rd, a->rd, a->imm);
1176 return true;
1177 }
1178
1179 /* mul rs, rd */
1180 /* mul dsp[rs], rd */
1181 static bool trans_MUL_mr(DisasContext *ctx, arg_MUL_mr *a)
1182 {
1183 rx_gen_op_mr(tcg_gen_mul_i32, ctx, a->rd, a->rs, a->ld, a->mi);
1184 return true;
1185 }
1186
1187 /* mul rs, rs2, rd */
1188 static bool trans_MUL_rrr(DisasContext *ctx, arg_MUL_rrr *a)
1189 {
1190 rx_gen_op_rrr(tcg_gen_mul_i32, a->rd, a->rs, a->rs2);
1191 return true;
1192 }
1193
1194 /* emul #imm, rd */
1195 static bool trans_EMUL_ir(DisasContext *ctx, arg_EMUL_ir *a)
1196 {
1197 TCGv_i32 imm = tcg_constant_i32(a->imm);
1198 if (a->rd > 14) {
1199 qemu_log_mask(LOG_GUEST_ERROR, "rd too large %d", a->rd);
1200 }
1201 tcg_gen_muls2_i32(cpu_regs[a->rd], cpu_regs[(a->rd + 1) & 15],
1202 cpu_regs[a->rd], imm);
1203 return true;
1204 }
1205
1206 /* emul rs, rd */
1207 /* emul dsp[rs], rd */
1208 static bool trans_EMUL_mr(DisasContext *ctx, arg_EMUL_mr *a)
1209 {
1210 TCGv_i32 val, mem;
1211 if (a->rd > 14) {
1212 qemu_log_mask(LOG_GUEST_ERROR, "rd too large %d", a->rd);
1213 }
1214 mem = tcg_temp_new_i32();
1215 val = rx_load_source(ctx, mem, a->ld, a->mi, a->rs);
1216 tcg_gen_muls2_i32(cpu_regs[a->rd], cpu_regs[(a->rd + 1) & 15],
1217 cpu_regs[a->rd], val);
1218 return true;
1219 }
1220
1221 /* emulu #imm, rd */
1222 static bool trans_EMULU_ir(DisasContext *ctx, arg_EMULU_ir *a)
1223 {
1224 TCGv_i32 imm = tcg_constant_i32(a->imm);
1225 if (a->rd > 14) {
1226 qemu_log_mask(LOG_GUEST_ERROR, "rd too large %d", a->rd);
1227 }
1228 tcg_gen_mulu2_i32(cpu_regs[a->rd], cpu_regs[(a->rd + 1) & 15],
1229 cpu_regs[a->rd], imm);
1230 return true;
1231 }
1232
1233 /* emulu rs, rd */
1234 /* emulu dsp[rs], rd */
1235 static bool trans_EMULU_mr(DisasContext *ctx, arg_EMULU_mr *a)
1236 {
1237 TCGv_i32 val, mem;
1238 if (a->rd > 14) {
1239 qemu_log_mask(LOG_GUEST_ERROR, "rd too large %d", a->rd);
1240 }
1241 mem = tcg_temp_new_i32();
1242 val = rx_load_source(ctx, mem, a->ld, a->mi, a->rs);
1243 tcg_gen_mulu2_i32(cpu_regs[a->rd], cpu_regs[(a->rd + 1) & 15],
1244 cpu_regs[a->rd], val);
1245 return true;
1246 }
1247
1248 static void rx_div(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
1249 {
1250 gen_helper_div(ret, tcg_env, arg1, arg2);
1251 }
1252
1253 static void rx_divu(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
1254 {
1255 gen_helper_divu(ret, tcg_env, arg1, arg2);
1256 }
1257
1258 /* div #imm, rd */
1259 static bool trans_DIV_ir(DisasContext *ctx, arg_DIV_ir *a)
1260 {
1261 rx_gen_op_irr(rx_div, a->rd, a->rd, a->imm);
1262 return true;
1263 }
1264
1265 /* div rs, rd */
1266 /* div dsp[rs], rd */
1267 static bool trans_DIV_mr(DisasContext *ctx, arg_DIV_mr *a)
1268 {
1269 rx_gen_op_mr(rx_div, ctx, a->rd, a->rs, a->ld, a->mi);
1270 return true;
1271 }
1272
1273 /* divu #imm, rd */
1274 static bool trans_DIVU_ir(DisasContext *ctx, arg_DIVU_ir *a)
1275 {
1276 rx_gen_op_irr(rx_divu, a->rd, a->rd, a->imm);
1277 return true;
1278 }
1279
1280 /* divu rs, rd */
1281 /* divu dsp[rs], rd */
1282 static bool trans_DIVU_mr(DisasContext *ctx, arg_DIVU_mr *a)
1283 {
1284 rx_gen_op_mr(rx_divu, ctx, a->rd, a->rs, a->ld, a->mi);
1285 return true;
1286 }
1287
1288
1289 /* shll #imm:5, rd */
1290 /* shll #imm:5, rs2, rd */
1291 static bool trans_SHLL_irr(DisasContext *ctx, arg_SHLL_irr *a)
1292 {
1293 TCGv_i32 tmp;
1294 tmp = tcg_temp_new_i32();
1295 if (a->imm) {
1296 tcg_gen_sari_i32(cpu_psw_c, cpu_regs[a->rs2], 32 - a->imm);
1297 tcg_gen_shli_i32(cpu_regs[a->rd], cpu_regs[a->rs2], a->imm);
1298 tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_psw_o, cpu_psw_c, 0);
1299 tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, cpu_psw_c, 0xffffffff);
1300 tcg_gen_or_i32(cpu_psw_o, cpu_psw_o, tmp);
1301 tcg_gen_setcondi_i32(TCG_COND_NE, cpu_psw_c, cpu_psw_c, 0);
1302 } else {
1303 tcg_gen_mov_i32(cpu_regs[a->rd], cpu_regs[a->rs2]);
1304 tcg_gen_movi_i32(cpu_psw_c, 0);
1305 tcg_gen_movi_i32(cpu_psw_o, 0);
1306 }
1307 tcg_gen_mov_i32(cpu_psw_z, cpu_regs[a->rd]);
1308 tcg_gen_mov_i32(cpu_psw_s, cpu_regs[a->rd]);
1309 return true;
1310 }
1311
1312 /* shll rs, rd */
1313 static bool trans_SHLL_rr(DisasContext *ctx, arg_SHLL_rr *a)
1314 {
1315 TCGLabel *noshift, *done;
1316 TCGv_i32 count, tmp;
1317
1318 noshift = gen_new_label();
1319 done = gen_new_label();
1320 /* if (cpu_regs[a->rs]) { */
1321 tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_regs[a->rs], 0, noshift);
1322 count = tcg_temp_new_i32();
1323 tmp = tcg_temp_new_i32();
1324 tcg_gen_andi_i32(tmp, cpu_regs[a->rs], 31);
1325 tcg_gen_sub_i32(count, tcg_constant_i32(32), tmp);
1326 tcg_gen_sar_i32(cpu_psw_c, cpu_regs[a->rd], count);
1327 tcg_gen_shl_i32(cpu_regs[a->rd], cpu_regs[a->rd], tmp);
1328 tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_psw_o, cpu_psw_c, 0);
1329 tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, cpu_psw_c, 0xffffffff);
1330 tcg_gen_or_i32(cpu_psw_o, cpu_psw_o, tmp);
1331 tcg_gen_setcondi_i32(TCG_COND_NE, cpu_psw_c, cpu_psw_c, 0);
1332 tcg_gen_br(done);
1333 /* } else { */
1334 gen_set_label(noshift);
1335 tcg_gen_movi_i32(cpu_psw_c, 0);
1336 tcg_gen_movi_i32(cpu_psw_o, 0);
1337 /* } */
1338 gen_set_label(done);
1339 tcg_gen_mov_i32(cpu_psw_z, cpu_regs[a->rd]);
1340 tcg_gen_mov_i32(cpu_psw_s, cpu_regs[a->rd]);
1341 return true;
1342 }
1343
1344 static void shiftr_imm(uint32_t rd, uint32_t rs, uint32_t imm,
1345 unsigned int alith)
1346 {
1347 static void (* const gen_sXri[])(TCGv_i32 ret, TCGv_i32 arg1, int arg2) = {
1348 tcg_gen_shri_i32, tcg_gen_sari_i32,
1349 };
1350 tcg_debug_assert(alith < 2);
1351 if (imm) {
1352 gen_sXri[alith](cpu_regs[rd], cpu_regs[rs], imm - 1);
1353 tcg_gen_andi_i32(cpu_psw_c, cpu_regs[rd], 0x00000001);
1354 gen_sXri[alith](cpu_regs[rd], cpu_regs[rd], 1);
1355 } else {
1356 tcg_gen_mov_i32(cpu_regs[rd], cpu_regs[rs]);
1357 tcg_gen_movi_i32(cpu_psw_c, 0);
1358 }
1359 tcg_gen_movi_i32(cpu_psw_o, 0);
1360 tcg_gen_mov_i32(cpu_psw_z, cpu_regs[rd]);
1361 tcg_gen_mov_i32(cpu_psw_s, cpu_regs[rd]);
1362 }
1363
1364 static void shiftr_reg(uint32_t rd, uint32_t rs, unsigned int alith)
1365 {
1366 TCGLabel *noshift, *done;
1367 TCGv_i32 count;
1368 static void (* const gen_sXri[])(TCGv_i32 ret, TCGv_i32 arg1, int arg2) = {
1369 tcg_gen_shri_i32, tcg_gen_sari_i32,
1370 };
1371 static void (* const gen_sXr[])(TCGv_i32 ret,
1372 TCGv_i32 arg1, TCGv_i32 arg2) = {
1373 tcg_gen_shr_i32, tcg_gen_sar_i32,
1374 };
1375 tcg_debug_assert(alith < 2);
1376 noshift = gen_new_label();
1377 done = gen_new_label();
1378 count = tcg_temp_new_i32();
1379 /* if (cpu_regs[rs]) { */
1380 tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_regs[rs], 0, noshift);
1381 tcg_gen_andi_i32(count, cpu_regs[rs], 31);
1382 tcg_gen_subi_i32(count, count, 1);
1383 gen_sXr[alith](cpu_regs[rd], cpu_regs[rd], count);
1384 tcg_gen_andi_i32(cpu_psw_c, cpu_regs[rd], 0x00000001);
1385 gen_sXri[alith](cpu_regs[rd], cpu_regs[rd], 1);
1386 tcg_gen_br(done);
1387 /* } else { */
1388 gen_set_label(noshift);
1389 tcg_gen_movi_i32(cpu_psw_c, 0);
1390 /* } */
1391 gen_set_label(done);
1392 tcg_gen_movi_i32(cpu_psw_o, 0);
1393 tcg_gen_mov_i32(cpu_psw_z, cpu_regs[rd]);
1394 tcg_gen_mov_i32(cpu_psw_s, cpu_regs[rd]);
1395 }
1396
1397 /* shar #imm:5, rd */
1398 /* shar #imm:5, rs2, rd */
1399 static bool trans_SHAR_irr(DisasContext *ctx, arg_SHAR_irr *a)
1400 {
1401 shiftr_imm(a->rd, a->rs2, a->imm, 1);
1402 return true;
1403 }
1404
1405 /* shar rs, rd */
1406 static bool trans_SHAR_rr(DisasContext *ctx, arg_SHAR_rr *a)
1407 {
1408 shiftr_reg(a->rd, a->rs, 1);
1409 return true;
1410 }
1411
1412 /* shlr #imm:5, rd */
1413 /* shlr #imm:5, rs2, rd */
1414 static bool trans_SHLR_irr(DisasContext *ctx, arg_SHLR_irr *a)
1415 {
1416 shiftr_imm(a->rd, a->rs2, a->imm, 0);
1417 return true;
1418 }
1419
1420 /* shlr rs, rd */
1421 static bool trans_SHLR_rr(DisasContext *ctx, arg_SHLR_rr *a)
1422 {
1423 shiftr_reg(a->rd, a->rs, 0);
1424 return true;
1425 }
1426
1427 /* rolc rd */
1428 static bool trans_ROLC(DisasContext *ctx, arg_ROLC *a)
1429 {
1430 TCGv_i32 tmp;
1431 tmp = tcg_temp_new_i32();
1432 tcg_gen_shri_i32(tmp, cpu_regs[a->rd], 31);
1433 tcg_gen_shli_i32(cpu_regs[a->rd], cpu_regs[a->rd], 1);
1434 tcg_gen_or_i32(cpu_regs[a->rd], cpu_regs[a->rd], cpu_psw_c);
1435 tcg_gen_mov_i32(cpu_psw_c, tmp);
1436 tcg_gen_mov_i32(cpu_psw_z, cpu_regs[a->rd]);
1437 tcg_gen_mov_i32(cpu_psw_s, cpu_regs[a->rd]);
1438 return true;
1439 }
1440
1441 /* rorc rd */
1442 static bool trans_RORC(DisasContext *ctx, arg_RORC *a)
1443 {
1444 TCGv_i32 tmp;
1445 tmp = tcg_temp_new_i32();
1446 tcg_gen_andi_i32(tmp, cpu_regs[a->rd], 0x00000001);
1447 tcg_gen_shri_i32(cpu_regs[a->rd], cpu_regs[a->rd], 1);
1448 tcg_gen_shli_i32(cpu_psw_c, cpu_psw_c, 31);
1449 tcg_gen_or_i32(cpu_regs[a->rd], cpu_regs[a->rd], cpu_psw_c);
1450 tcg_gen_mov_i32(cpu_psw_c, tmp);
1451 tcg_gen_mov_i32(cpu_psw_z, cpu_regs[a->rd]);
1452 tcg_gen_mov_i32(cpu_psw_s, cpu_regs[a->rd]);
1453 return true;
1454 }
1455
1456 enum {ROTR = 0, ROTL = 1};
1457 enum {ROT_IMM = 0, ROT_REG = 1};
1458 static void rx_rot(int ir, int dir, int rd, int src)
1459 {
1460 switch (dir) {
1461 case ROTL:
1462 if (ir == ROT_IMM) {
1463 tcg_gen_rotli_i32(cpu_regs[rd], cpu_regs[rd], src);
1464 } else {
1465 tcg_gen_rotl_i32(cpu_regs[rd], cpu_regs[rd], cpu_regs[src]);
1466 }
1467 tcg_gen_andi_i32(cpu_psw_c, cpu_regs[rd], 0x00000001);
1468 break;
1469 case ROTR:
1470 if (ir == ROT_IMM) {
1471 tcg_gen_rotri_i32(cpu_regs[rd], cpu_regs[rd], src);
1472 } else {
1473 tcg_gen_rotr_i32(cpu_regs[rd], cpu_regs[rd], cpu_regs[src]);
1474 }
1475 tcg_gen_shri_i32(cpu_psw_c, cpu_regs[rd], 31);
1476 break;
1477 }
1478 tcg_gen_mov_i32(cpu_psw_z, cpu_regs[rd]);
1479 tcg_gen_mov_i32(cpu_psw_s, cpu_regs[rd]);
1480 }
1481
1482 /* rotl #imm, rd */
1483 static bool trans_ROTL_ir(DisasContext *ctx, arg_ROTL_ir *a)
1484 {
1485 rx_rot(ROT_IMM, ROTL, a->rd, a->imm);
1486 return true;
1487 }
1488
1489 /* rotl rs, rd */
1490 static bool trans_ROTL_rr(DisasContext *ctx, arg_ROTL_rr *a)
1491 {
1492 rx_rot(ROT_REG, ROTL, a->rd, a->rs);
1493 return true;
1494 }
1495
1496 /* rotr #imm, rd */
1497 static bool trans_ROTR_ir(DisasContext *ctx, arg_ROTR_ir *a)
1498 {
1499 rx_rot(ROT_IMM, ROTR, a->rd, a->imm);
1500 return true;
1501 }
1502
1503 /* rotr rs, rd */
1504 static bool trans_ROTR_rr(DisasContext *ctx, arg_ROTR_rr *a)
1505 {
1506 rx_rot(ROT_REG, ROTR, a->rd, a->rs);
1507 return true;
1508 }
1509
1510 /* revl rs, rd */
1511 static bool trans_REVL(DisasContext *ctx, arg_REVL *a)
1512 {
1513 tcg_gen_bswap32_i32(cpu_regs[a->rd], cpu_regs[a->rs]);
1514 return true;
1515 }
1516
1517 /* revw rs, rd */
1518 static bool trans_REVW(DisasContext *ctx, arg_REVW *a)
1519 {
1520 TCGv_i32 tmp;
1521 tmp = tcg_temp_new_i32();
1522 tcg_gen_andi_i32(tmp, cpu_regs[a->rs], 0x00ff00ff);
1523 tcg_gen_shli_i32(tmp, tmp, 8);
1524 tcg_gen_shri_i32(cpu_regs[a->rd], cpu_regs[a->rs], 8);
1525 tcg_gen_andi_i32(cpu_regs[a->rd], cpu_regs[a->rd], 0x00ff00ff);
1526 tcg_gen_or_i32(cpu_regs[a->rd], cpu_regs[a->rd], tmp);
1527 return true;
1528 }
1529
1530 /* conditional branch helper */
1531 static void rx_bcnd_main(DisasContext *ctx, int cd, int dst)
1532 {
1533 DisasCompare dc;
1534 TCGLabel *t, *done;
1535
1536 switch (cd) {
1537 case 0 ... 13:
1538 dc.temp = tcg_temp_new_i32();
1539 psw_cond(&dc, cd);
1540 t = gen_new_label();
1541 done = gen_new_label();
1542 tcg_gen_brcondi_i32(dc.cond, dc.value, 0, t);
1543 gen_goto_tb(ctx, 0, ctx->base.pc_next);
1544 tcg_gen_br(done);
1545 gen_set_label(t);
1546 gen_goto_tb(ctx, 1, ctx->pc + dst);
1547 gen_set_label(done);
1548 break;
1549 case 14:
1550 /* always true case */
1551 gen_goto_tb(ctx, 0, ctx->pc + dst);
1552 break;
1553 case 15:
1554 /* always false case */
1555 /* Nothing do */
1556 break;
1557 }
1558 }
1559
1560 /* beq dsp:3 / bne dsp:3 */
1561 /* beq dsp:8 / bne dsp:8 */
1562 /* bc dsp:8 / bnc dsp:8 */
1563 /* bgtu dsp:8 / bleu dsp:8 */
1564 /* bpz dsp:8 / bn dsp:8 */
1565 /* bge dsp:8 / blt dsp:8 */
1566 /* bgt dsp:8 / ble dsp:8 */
1567 /* bo dsp:8 / bno dsp:8 */
1568 /* beq dsp:16 / bne dsp:16 */
1569 static bool trans_BCnd(DisasContext *ctx, arg_BCnd *a)
1570 {
1571 rx_bcnd_main(ctx, a->cd, a->dsp);
1572 return true;
1573 }
1574
1575 /* bra dsp:3 */
1576 /* bra dsp:8 */
1577 /* bra dsp:16 */
1578 /* bra dsp:24 */
1579 static bool trans_BRA(DisasContext *ctx, arg_BRA *a)
1580 {
1581 rx_bcnd_main(ctx, 14, a->dsp);
1582 return true;
1583 }
1584
1585 /* bra rs */
1586 static bool trans_BRA_l(DisasContext *ctx, arg_BRA_l *a)
1587 {
1588 tcg_gen_addi_i32(cpu_pc, cpu_regs[a->rd], ctx->pc);
1589 ctx->base.is_jmp = DISAS_JUMP;
1590 return true;
1591 }
1592
1593 static void rx_save_pc(DisasContext *ctx)
1594 {
1595 TCGv_i32 pc = tcg_constant_i32(ctx->base.pc_next);
1596 push(ctx, pc);
1597 }
1598
1599 /* jmp rs */
1600 static bool trans_JMP(DisasContext *ctx, arg_JMP *a)
1601 {
1602 tcg_gen_mov_i32(cpu_pc, cpu_regs[a->rs]);
1603 ctx->base.is_jmp = DISAS_JUMP;
1604 return true;
1605 }
1606
1607 /* jsr rs */
1608 static bool trans_JSR(DisasContext *ctx, arg_JSR *a)
1609 {
1610 rx_save_pc(ctx);
1611 tcg_gen_mov_i32(cpu_pc, cpu_regs[a->rs]);
1612 ctx->base.is_jmp = DISAS_JUMP;
1613 return true;
1614 }
1615
1616 /* bsr dsp:16 */
1617 /* bsr dsp:24 */
1618 static bool trans_BSR(DisasContext *ctx, arg_BSR *a)
1619 {
1620 rx_save_pc(ctx);
1621 rx_bcnd_main(ctx, 14, a->dsp);
1622 return true;
1623 }
1624
1625 /* bsr rs */
1626 static bool trans_BSR_l(DisasContext *ctx, arg_BSR_l *a)
1627 {
1628 rx_save_pc(ctx);
1629 tcg_gen_addi_i32(cpu_pc, cpu_regs[a->rd], ctx->pc);
1630 ctx->base.is_jmp = DISAS_JUMP;
1631 return true;
1632 }
1633
1634 /* rts */
1635 static bool trans_RTS(DisasContext *ctx, arg_RTS *a)
1636 {
1637 pop(ctx, cpu_pc);
1638 ctx->base.is_jmp = DISAS_JUMP;
1639 return true;
1640 }
1641
1642 /* nop */
1643 static bool trans_NOP(DisasContext *ctx, arg_NOP *a)
1644 {
1645 return true;
1646 }
1647
1648 /* scmpu */
1649 static bool trans_SCMPU(DisasContext *ctx, arg_SCMPU *a)
1650 {
1651 gen_helper_scmpu(tcg_env);
1652 return true;
1653 }
1654
1655 /* smovu */
1656 static bool trans_SMOVU(DisasContext *ctx, arg_SMOVU *a)
1657 {
1658 gen_helper_smovu(tcg_env);
1659 return true;
1660 }
1661
1662 /* smovf */
1663 static bool trans_SMOVF(DisasContext *ctx, arg_SMOVF *a)
1664 {
1665 gen_helper_smovf(tcg_env);
1666 return true;
1667 }
1668
1669 /* smovb */
1670 static bool trans_SMOVB(DisasContext *ctx, arg_SMOVB *a)
1671 {
1672 gen_helper_smovb(tcg_env);
1673 return true;
1674 }
1675
1676 #define STRING(op) \
1677 do { \
1678 TCGv_i32 size = tcg_constant_i32(a->sz); \
1679 gen_helper_##op(tcg_env, size); \
1680 } while (0)
1681
1682 /* suntile.<bwl> */
1683 static bool trans_SUNTIL(DisasContext *ctx, arg_SUNTIL *a)
1684 {
1685 STRING(suntil);
1686 return true;
1687 }
1688
1689 /* swhile.<bwl> */
1690 static bool trans_SWHILE(DisasContext *ctx, arg_SWHILE *a)
1691 {
1692 STRING(swhile);
1693 return true;
1694 }
1695 /* sstr.<bwl> */
1696 static bool trans_SSTR(DisasContext *ctx, arg_SSTR *a)
1697 {
1698 STRING(sstr);
1699 return true;
1700 }
1701
1702 /* rmpa.<bwl> */
1703 static bool trans_RMPA(DisasContext *ctx, arg_RMPA *a)
1704 {
1705 STRING(rmpa);
1706 return true;
1707 }
1708
1709 static void rx_mul64hi(TCGv_i64 ret, int rs, int rs2)
1710 {
1711 TCGv_i64 tmp0, tmp1;
1712 tmp0 = tcg_temp_new_i64();
1713 tmp1 = tcg_temp_new_i64();
1714 tcg_gen_ext_i32_i64(tmp0, cpu_regs[rs]);
1715 tcg_gen_sari_i64(tmp0, tmp0, 16);
1716 tcg_gen_ext_i32_i64(tmp1, cpu_regs[rs2]);
1717 tcg_gen_sari_i64(tmp1, tmp1, 16);
1718 tcg_gen_mul_i64(ret, tmp0, tmp1);
1719 tcg_gen_shli_i64(ret, ret, 16);
1720 }
1721
1722 static void rx_mul64lo(TCGv_i64 ret, int rs, int rs2)
1723 {
1724 TCGv_i64 tmp0, tmp1;
1725 tmp0 = tcg_temp_new_i64();
1726 tmp1 = tcg_temp_new_i64();
1727 tcg_gen_ext_i32_i64(tmp0, cpu_regs[rs]);
1728 tcg_gen_ext16s_i64(tmp0, tmp0);
1729 tcg_gen_ext_i32_i64(tmp1, cpu_regs[rs2]);
1730 tcg_gen_ext16s_i64(tmp1, tmp1);
1731 tcg_gen_mul_i64(ret, tmp0, tmp1);
1732 tcg_gen_shli_i64(ret, ret, 16);
1733 }
1734
1735 /* mulhi rs,rs2 */
1736 static bool trans_MULHI(DisasContext *ctx, arg_MULHI *a)
1737 {
1738 rx_mul64hi(cpu_acc, a->rs, a->rs2);
1739 return true;
1740 }
1741
1742 /* mullo rs,rs2 */
1743 static bool trans_MULLO(DisasContext *ctx, arg_MULLO *a)
1744 {
1745 rx_mul64lo(cpu_acc, a->rs, a->rs2);
1746 return true;
1747 }
1748
1749 /* machi rs,rs2 */
1750 static bool trans_MACHI(DisasContext *ctx, arg_MACHI *a)
1751 {
1752 TCGv_i64 tmp;
1753 tmp = tcg_temp_new_i64();
1754 rx_mul64hi(tmp, a->rs, a->rs2);
1755 tcg_gen_add_i64(cpu_acc, cpu_acc, tmp);
1756 return true;
1757 }
1758
1759 /* maclo rs,rs2 */
1760 static bool trans_MACLO(DisasContext *ctx, arg_MACLO *a)
1761 {
1762 TCGv_i64 tmp;
1763 tmp = tcg_temp_new_i64();
1764 rx_mul64lo(tmp, a->rs, a->rs2);
1765 tcg_gen_add_i64(cpu_acc, cpu_acc, tmp);
1766 return true;
1767 }
1768
1769 /* mvfachi rd */
1770 static bool trans_MVFACHI(DisasContext *ctx, arg_MVFACHI *a)
1771 {
1772 tcg_gen_extrh_i64_i32(cpu_regs[a->rd], cpu_acc);
1773 return true;
1774 }
1775
1776 /* mvfacmi rd */
1777 static bool trans_MVFACMI(DisasContext *ctx, arg_MVFACMI *a)
1778 {
1779 TCGv_i64 rd64;
1780 rd64 = tcg_temp_new_i64();
1781 tcg_gen_extract_i64(rd64, cpu_acc, 16, 32);
1782 tcg_gen_extrl_i64_i32(cpu_regs[a->rd], rd64);
1783 return true;
1784 }
1785
1786 /* mvtachi rs */
1787 static bool trans_MVTACHI(DisasContext *ctx, arg_MVTACHI *a)
1788 {
1789 TCGv_i64 rs64;
1790 rs64 = tcg_temp_new_i64();
1791 tcg_gen_extu_i32_i64(rs64, cpu_regs[a->rs]);
1792 tcg_gen_deposit_i64(cpu_acc, cpu_acc, rs64, 32, 32);
1793 return true;
1794 }
1795
1796 /* mvtaclo rs */
1797 static bool trans_MVTACLO(DisasContext *ctx, arg_MVTACLO *a)
1798 {
1799 TCGv_i64 rs64;
1800 rs64 = tcg_temp_new_i64();
1801 tcg_gen_extu_i32_i64(rs64, cpu_regs[a->rs]);
1802 tcg_gen_deposit_i64(cpu_acc, cpu_acc, rs64, 0, 32);
1803 return true;
1804 }
1805
1806 /* racw #imm */
1807 static bool trans_RACW(DisasContext *ctx, arg_RACW *a)
1808 {
1809 TCGv_i32 imm = tcg_constant_i32(a->imm + 1);
1810 gen_helper_racw(tcg_env, imm);
1811 return true;
1812 }
1813
1814 /* sat rd */
1815 static bool trans_SAT(DisasContext *ctx, arg_SAT *a)
1816 {
1817 TCGv_i32 tmp, z;
1818 tmp = tcg_temp_new_i32();
1819 z = tcg_constant_i32(0);
1820 /* S == 1 -> 0xffffffff / S == 0 -> 0x00000000 */
1821 tcg_gen_sari_i32(tmp, cpu_psw_s, 31);
1822 /* S == 1 -> 0x7fffffff / S == 0 -> 0x80000000 */
1823 tcg_gen_xori_i32(tmp, tmp, 0x80000000);
1824 tcg_gen_movcond_i32(TCG_COND_LT, cpu_regs[a->rd],
1825 cpu_psw_o, z, tmp, cpu_regs[a->rd]);
1826 return true;
1827 }
1828
1829 /* satr */
1830 static bool trans_SATR(DisasContext *ctx, arg_SATR *a)
1831 {
1832 gen_helper_satr(tcg_env);
1833 return true;
1834 }
1835
1836 #define cat3(a, b, c) a##b##c
1837 #define FOP(name, op) \
1838 static bool cat3(trans_, name, _ir)(DisasContext *ctx, \
1839 cat3(arg_, name, _ir) * a) \
1840 { \
1841 TCGv_i32 imm = tcg_constant_i32(li(ctx, 0)); \
1842 gen_helper_##op(cpu_regs[a->rd], tcg_env, \
1843 cpu_regs[a->rd], imm); \
1844 return true; \
1845 } \
1846 static bool cat3(trans_, name, _mr)(DisasContext *ctx, \
1847 cat3(arg_, name, _mr) * a) \
1848 { \
1849 TCGv_i32 val, mem; \
1850 mem = tcg_temp_new_i32(); \
1851 val = rx_load_source(ctx, mem, a->ld, MO_32, a->rs); \
1852 gen_helper_##op(cpu_regs[a->rd], tcg_env, \
1853 cpu_regs[a->rd], val); \
1854 return true; \
1855 }
1856
1857 #define FCONVOP(name, op) \
1858 static bool trans_##name(DisasContext *ctx, arg_##name * a) \
1859 { \
1860 TCGv_i32 val, mem; \
1861 mem = tcg_temp_new_i32(); \
1862 val = rx_load_source(ctx, mem, a->ld, MO_32, a->rs); \
1863 gen_helper_##op(cpu_regs[a->rd], tcg_env, val); \
1864 return true; \
1865 }
1866
1867 FOP(FADD, fadd)
1868 FOP(FSUB, fsub)
1869 FOP(FMUL, fmul)
1870 FOP(FDIV, fdiv)
1871
1872 /* fcmp #imm, rd */
1873 static bool trans_FCMP_ir(DisasContext *ctx, arg_FCMP_ir * a)
1874 {
1875 TCGv_i32 imm = tcg_constant_i32(li(ctx, 0));
1876 gen_helper_fcmp(tcg_env, cpu_regs[a->rd], imm);
1877 return true;
1878 }
1879
1880 /* fcmp dsp[rs], rd */
1881 /* fcmp rs, rd */
1882 static bool trans_FCMP_mr(DisasContext *ctx, arg_FCMP_mr *a)
1883 {
1884 TCGv_i32 val, mem;
1885 mem = tcg_temp_new_i32();
1886 val = rx_load_source(ctx, mem, a->ld, MO_32, a->rs);
1887 gen_helper_fcmp(tcg_env, cpu_regs[a->rd], val);
1888 return true;
1889 }
1890
1891 FCONVOP(FTOI, ftoi)
1892 FCONVOP(ROUND, round)
1893
1894 /* itof rs, rd */
1895 /* itof dsp[rs], rd */
1896 static bool trans_ITOF(DisasContext *ctx, arg_ITOF * a)
1897 {
1898 TCGv_i32 val, mem;
1899 mem = tcg_temp_new_i32();
1900 val = rx_load_source(ctx, mem, a->ld, a->mi, a->rs);
1901 gen_helper_itof(cpu_regs[a->rd], tcg_env, val);
1902 return true;
1903 }
1904
1905 static void rx_bsetm(DisasContext *ctx, TCGv_i32 mem, TCGv_i32 mask)
1906 {
1907 TCGv_i32 val;
1908 val = tcg_temp_new_i32();
1909 rx_gen_ld(ctx, MO_8, val, mem);
1910 tcg_gen_or_i32(val, val, mask);
1911 rx_gen_st(ctx, MO_8, val, mem);
1912 }
1913
1914 static void rx_bclrm(DisasContext *ctx, TCGv_i32 mem, TCGv_i32 mask)
1915 {
1916 TCGv_i32 val;
1917 val = tcg_temp_new_i32();
1918 rx_gen_ld(ctx, MO_8, val, mem);
1919 tcg_gen_andc_i32(val, val, mask);
1920 rx_gen_st(ctx, MO_8, val, mem);
1921 }
1922
1923 static void rx_btstm(DisasContext *ctx, TCGv_i32 mem, TCGv_i32 mask)
1924 {
1925 TCGv_i32 val;
1926 val = tcg_temp_new_i32();
1927 rx_gen_ld(ctx, MO_8, val, mem);
1928 tcg_gen_and_i32(val, val, mask);
1929 tcg_gen_setcondi_i32(TCG_COND_NE, cpu_psw_c, val, 0);
1930 tcg_gen_mov_i32(cpu_psw_z, cpu_psw_c);
1931 }
1932
1933 static void rx_bnotm(DisasContext *ctx, TCGv_i32 mem, TCGv_i32 mask)
1934 {
1935 TCGv_i32 val;
1936 val = tcg_temp_new_i32();
1937 rx_gen_ld(ctx, MO_8, val, mem);
1938 tcg_gen_xor_i32(val, val, mask);
1939 rx_gen_st(ctx, MO_8, val, mem);
1940 }
1941
1942 static void rx_bsetr(DisasContext *ctx, TCGv_i32 reg, TCGv_i32 mask)
1943 {
1944 tcg_gen_or_i32(reg, reg, mask);
1945 }
1946
1947 static void rx_bclrr(DisasContext *ctx, TCGv_i32 reg, TCGv_i32 mask)
1948 {
1949 tcg_gen_andc_i32(reg, reg, mask);
1950 }
1951
1952 static void rx_btstr(DisasContext *ctx, TCGv_i32 reg, TCGv_i32 mask)
1953 {
1954 TCGv_i32 t0;
1955 t0 = tcg_temp_new_i32();
1956 tcg_gen_and_i32(t0, reg, mask);
1957 tcg_gen_setcondi_i32(TCG_COND_NE, cpu_psw_c, t0, 0);
1958 tcg_gen_mov_i32(cpu_psw_z, cpu_psw_c);
1959 }
1960
1961 static void rx_bnotr(DisasContext *ctx, TCGv_i32 reg, TCGv_i32 mask)
1962 {
1963 tcg_gen_xor_i32(reg, reg, mask);
1964 }
1965
1966 #define BITOP(name, op) \
1967 static bool cat3(trans_, name, _im)(DisasContext *ctx, \
1968 cat3(arg_, name, _im) * a) \
1969 { \
1970 TCGv_i32 mask, mem, addr; \
1971 mem = tcg_temp_new_i32(); \
1972 mask = tcg_constant_i32(1 << a->imm); \
1973 addr = rx_index_addr(ctx, mem, a->ld, MO_8, a->rs); \
1974 cat3(rx_, op, m)(ctx, addr, mask); \
1975 return true; \
1976 } \
1977 static bool cat3(trans_, name, _ir)(DisasContext *ctx, \
1978 cat3(arg_, name, _ir) * a) \
1979 { \
1980 TCGv_i32 mask; \
1981 mask = tcg_constant_i32(1 << a->imm); \
1982 cat3(rx_, op, r)(ctx, cpu_regs[a->rd], mask); \
1983 return true; \
1984 } \
1985 static bool cat3(trans_, name, _rr)(DisasContext *ctx, \
1986 cat3(arg_, name, _rr) * a) \
1987 { \
1988 TCGv_i32 mask, b; \
1989 mask = tcg_temp_new_i32(); \
1990 b = tcg_temp_new_i32(); \
1991 tcg_gen_andi_i32(b, cpu_regs[a->rs], 31); \
1992 tcg_gen_shl_i32(mask, tcg_constant_i32(1), b); \
1993 cat3(rx_, op, r)(ctx, cpu_regs[a->rd], mask); \
1994 return true; \
1995 } \
1996 static bool cat3(trans_, name, _rm)(DisasContext *ctx, \
1997 cat3(arg_, name, _rm) * a) \
1998 { \
1999 TCGv_i32 mask, mem, addr, b; \
2000 mask = tcg_temp_new_i32(); \
2001 b = tcg_temp_new_i32(); \
2002 tcg_gen_andi_i32(b, cpu_regs[a->rd], 7); \
2003 tcg_gen_shl_i32(mask, tcg_constant_i32(1), b); \
2004 mem = tcg_temp_new_i32(); \
2005 addr = rx_index_addr(ctx, mem, a->ld, MO_8, a->rs); \
2006 cat3(rx_, op, m)(ctx, addr, mask); \
2007 return true; \
2008 }
2009
2010 BITOP(BSET, bset)
2011 BITOP(BCLR, bclr)
2012 BITOP(BTST, btst)
2013 BITOP(BNOT, bnot)
2014
2015 static void bmcnd_op(TCGv_i32 val, TCGCond cond, int pos)
2016 {
2017 TCGv_i32 bit;
2018 DisasCompare dc;
2019 dc.temp = tcg_temp_new_i32();
2020 bit = tcg_temp_new_i32();
2021 psw_cond(&dc, cond);
2022 tcg_gen_andi_i32(val, val, ~(1 << pos));
2023 tcg_gen_setcondi_i32(dc.cond, bit, dc.value, 0);
2024 tcg_gen_deposit_i32(val, val, bit, pos, 1);
2025 }
2026
2027 /* bmcnd #imm, dsp[rd] */
2028 static bool trans_BMCnd_im(DisasContext *ctx, arg_BMCnd_im *a)
2029 {
2030 TCGv_i32 val, mem, addr;
2031 val = tcg_temp_new_i32();
2032 mem = tcg_temp_new_i32();
2033 addr = rx_index_addr(ctx, mem, a->ld, MO_8, a->rd);
2034 rx_gen_ld(ctx, MO_8, val, addr);
2035 bmcnd_op(val, a->cd, a->imm);
2036 rx_gen_st(ctx, MO_8, val, addr);
2037 return true;
2038 }
2039
2040 /* bmcond #imm, rd */
2041 static bool trans_BMCnd_ir(DisasContext *ctx, arg_BMCnd_ir *a)
2042 {
2043 bmcnd_op(cpu_regs[a->rd], a->cd, a->imm);
2044 return true;
2045 }
2046
2047 enum {
2048 PSW_C = 0,
2049 PSW_Z = 1,
2050 PSW_S = 2,
2051 PSW_O = 3,
2052 PSW_I = 8,
2053 PSW_U = 9,
2054 };
2055
2056 static void clrsetpsw(DisasContext *ctx, int cb, int val)
2057 {
2058 if (cb < 8) {
2059 switch (cb) {
2060 case PSW_C:
2061 tcg_gen_movi_i32(cpu_psw_c, val);
2062 break;
2063 case PSW_Z:
2064 tcg_gen_movi_i32(cpu_psw_z, val == 0);
2065 break;
2066 case PSW_S:
2067 tcg_gen_movi_i32(cpu_psw_s, val ? -1 : 0);
2068 break;
2069 case PSW_O:
2070 tcg_gen_movi_i32(cpu_psw_o, val << 31);
2071 break;
2072 default:
2073 qemu_log_mask(LOG_GUEST_ERROR, "Invalid destination %d", cb);
2074 break;
2075 }
2076 } else if (is_privileged(ctx, 0)) {
2077 switch (cb) {
2078 case PSW_I:
2079 tcg_gen_movi_i32(cpu_psw_i, val);
2080 ctx->base.is_jmp = DISAS_UPDATE;
2081 break;
2082 case PSW_U:
2083 if (FIELD_EX32(ctx->tb_flags, PSW, U) != val) {
2084 ctx->tb_flags = FIELD_DP32(ctx->tb_flags, PSW, U, val);
2085 tcg_gen_movi_i32(cpu_psw_u, val);
2086 tcg_gen_mov_i32(val ? cpu_isp : cpu_usp, cpu_sp);
2087 tcg_gen_mov_i32(cpu_sp, val ? cpu_usp : cpu_isp);
2088 }
2089 break;
2090 default:
2091 qemu_log_mask(LOG_GUEST_ERROR, "Invalid destination %d", cb);
2092 break;
2093 }
2094 }
2095 }
2096
2097 /* clrpsw psw */
2098 static bool trans_CLRPSW(DisasContext *ctx, arg_CLRPSW *a)
2099 {
2100 clrsetpsw(ctx, a->cb, 0);
2101 return true;
2102 }
2103
2104 /* setpsw psw */
2105 static bool trans_SETPSW(DisasContext *ctx, arg_SETPSW *a)
2106 {
2107 clrsetpsw(ctx, a->cb, 1);
2108 return true;
2109 }
2110
2111 /* mvtipl #imm */
2112 static bool trans_MVTIPL(DisasContext *ctx, arg_MVTIPL *a)
2113 {
2114 if (is_privileged(ctx, 1)) {
2115 tcg_gen_movi_i32(cpu_psw_ipl, a->imm);
2116 ctx->base.is_jmp = DISAS_UPDATE;
2117 }
2118 return true;
2119 }
2120
2121 /* mvtc #imm, rd */
2122 static bool trans_MVTC_i(DisasContext *ctx, arg_MVTC_i *a)
2123 {
2124 TCGv_i32 imm;
2125
2126 imm = tcg_constant_i32(a->imm);
2127 move_to_cr(ctx, imm, a->cr);
2128 return true;
2129 }
2130
2131 /* mvtc rs, rd */
2132 static bool trans_MVTC_r(DisasContext *ctx, arg_MVTC_r *a)
2133 {
2134 move_to_cr(ctx, cpu_regs[a->rs], a->cr);
2135 return true;
2136 }
2137
2138 /* mvfc rs, rd */
2139 static bool trans_MVFC(DisasContext *ctx, arg_MVFC *a)
2140 {
2141 move_from_cr(ctx, cpu_regs[a->rd], a->cr, ctx->pc);
2142 return true;
2143 }
2144
2145 /* rtfi */
2146 static bool trans_RTFI(DisasContext *ctx, arg_RTFI *a)
2147 {
2148 TCGv_i32 psw;
2149 if (is_privileged(ctx, 1)) {
2150 psw = tcg_temp_new_i32();
2151 tcg_gen_mov_i32(cpu_pc, cpu_bpc);
2152 tcg_gen_mov_i32(psw, cpu_bpsw);
2153 gen_helper_set_psw_rte(tcg_env, psw);
2154 ctx->base.is_jmp = DISAS_EXIT;
2155 }
2156 return true;
2157 }
2158
2159 /* rte */
2160 static bool trans_RTE(DisasContext *ctx, arg_RTE *a)
2161 {
2162 TCGv_i32 psw;
2163 if (is_privileged(ctx, 1)) {
2164 psw = tcg_temp_new_i32();
2165 pop(ctx, cpu_pc);
2166 pop(ctx, psw);
2167 gen_helper_set_psw_rte(tcg_env, psw);
2168 ctx->base.is_jmp = DISAS_EXIT;
2169 }
2170 return true;
2171 }
2172
2173 /* brk */
2174 static bool trans_BRK(DisasContext *ctx, arg_BRK *a)
2175 {
2176 tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next);
2177 gen_helper_rxbrk(tcg_env);
2178 ctx->base.is_jmp = DISAS_NORETURN;
2179 return true;
2180 }
2181
2182 /* int #imm */
2183 static bool trans_INT(DisasContext *ctx, arg_INT *a)
2184 {
2185 TCGv_i32 vec;
2186
2187 tcg_debug_assert(a->imm < 0x100);
2188 vec = tcg_constant_i32(a->imm);
2189 tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next);
2190 gen_helper_rxint(tcg_env, vec);
2191 ctx->base.is_jmp = DISAS_NORETURN;
2192 return true;
2193 }
2194
2195 /* wait */
2196 static bool trans_WAIT(DisasContext *ctx, arg_WAIT *a)
2197 {
2198 if (is_privileged(ctx, 1)) {
2199 tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next);
2200 gen_helper_wait(tcg_env);
2201 }
2202 return true;
2203 }
2204
2205 static void rx_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
2206 {
2207 DisasContext *ctx = container_of(dcbase, DisasContext, base);
2208 ctx->env = cpu_env(cs);
2209 ctx->tb_flags = ctx->base.tb->flags;
2210 }
2211
2212 static void rx_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
2213 {
2214 }
2215
2216 static void rx_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
2217 {
2218 DisasContext *ctx = container_of(dcbase, DisasContext, base);
2219
2220 tcg_gen_insn_start(ctx->base.pc_next, 0, 0);
2221 }
2222
2223 static void rx_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
2224 {
2225 DisasContext *ctx = container_of(dcbase, DisasContext, base);
2226 uint32_t insn;
2227
2228 ctx->pc = ctx->base.pc_next;
2229 insn = decode_load(ctx);
2230 if (!decode(ctx, insn)) {
2231 gen_helper_raise_illegal_instruction(tcg_env);
2232 }
2233 }
2234
2235 static void rx_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
2236 {
2237 DisasContext *ctx = container_of(dcbase, DisasContext, base);
2238
2239 switch (ctx->base.is_jmp) {
2240 case DISAS_NEXT:
2241 case DISAS_TOO_MANY:
2242 gen_goto_tb(ctx, 0, dcbase->pc_next);
2243 break;
2244 case DISAS_JUMP:
2245 tcg_gen_lookup_and_goto_ptr();
2246 break;
2247 case DISAS_UPDATE:
2248 tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next);
2249 /* fall through */
2250 case DISAS_EXIT:
2251 tcg_gen_exit_tb(NULL, 0);
2252 break;
2253 case DISAS_NORETURN:
2254 break;
2255 default:
2256 g_assert_not_reached();
2257 }
2258 }
2259
2260 static const TranslatorOps rx_tr_ops = {
2261 .init_disas_context = rx_tr_init_disas_context,
2262 .tb_start = rx_tr_tb_start,
2263 .insn_start = rx_tr_insn_start,
2264 .translate_insn = rx_tr_translate_insn,
2265 .tb_stop = rx_tr_tb_stop,
2266 };
2267
2268 void rx_translate_code(CPUState *cs, TranslationBlock *tb,
2269 int *max_insns, vaddr pc, void *host_pc)
2270 {
2271 DisasContext dc;
2272
2273 translator_loop(cs, tb, max_insns, pc, host_pc, &rx_tr_ops, &dc.base,
2274 TCG_TYPE_VA);
2275 }
2276
2277 #define ALLOC_REGISTER(sym, name) \
2278 cpu_##sym = tcg_global_mem_new_i32(tcg_env, \
2279 offsetof(CPURXState, sym), name)
2280
2281 void rx_translate_init(void)
2282 {
2283 static const char * const regnames[NUM_REGS] = {
2284 "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
2285 "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"
2286 };
2287 int i;
2288
2289 for (i = 0; i < NUM_REGS; i++) {
2290 cpu_regs[i] = tcg_global_mem_new_i32(tcg_env,
2291 offsetof(CPURXState, regs[i]),
2292 regnames[i]);
2293 }
2294 ALLOC_REGISTER(pc, "PC");
2295 ALLOC_REGISTER(psw_o, "PSW(O)");
2296 ALLOC_REGISTER(psw_s, "PSW(S)");
2297 ALLOC_REGISTER(psw_z, "PSW(Z)");
2298 ALLOC_REGISTER(psw_c, "PSW(C)");
2299 ALLOC_REGISTER(psw_u, "PSW(U)");
2300 ALLOC_REGISTER(psw_i, "PSW(I)");
2301 ALLOC_REGISTER(psw_pm, "PSW(PM)");
2302 ALLOC_REGISTER(psw_ipl, "PSW(IPL)");
2303 ALLOC_REGISTER(usp, "USP");
2304 ALLOC_REGISTER(fpsw, "FPSW");
2305 ALLOC_REGISTER(bpsw, "BPSW");
2306 ALLOC_REGISTER(bpc, "BPC");
2307 ALLOC_REGISTER(isp, "ISP");
2308 ALLOC_REGISTER(fintv, "FINTV");
2309 ALLOC_REGISTER(intb, "INTB");
2310 cpu_acc = tcg_global_mem_new_i64(tcg_env,
2311 offsetof(CPURXState, acc), "ACC");
2312 }