fsdev: improve error handling of backend init
[qemu/ar7.git] / target / hppa / translate.c
blob53aa1f88c40c6628ee493f15d48bd278ce52f76c
1 /*
2 * HPPA emulation cpu translation for qemu.
4 * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
21 #include "cpu.h"
22 #include "disas/disas.h"
23 #include "qemu/host-utils.h"
24 #include "exec/exec-all.h"
25 #include "tcg-op.h"
26 #include "exec/cpu_ldst.h"
27 #include "exec/helper-proto.h"
28 #include "exec/helper-gen.h"
29 #include "exec/translator.h"
30 #include "trace-tcg.h"
31 #include "exec/log.h"
33 typedef struct DisasCond {
34 TCGCond c;
35 TCGv a0, a1;
36 bool a0_is_n;
37 bool a1_is_0;
38 } DisasCond;
40 typedef struct DisasContext {
41 DisasContextBase base;
42 CPUState *cs;
44 target_ulong iaoq_f;
45 target_ulong iaoq_b;
46 target_ulong iaoq_n;
47 TCGv iaoq_n_var;
49 int ntemps;
50 TCGv temps[8];
52 DisasCond null_cond;
53 TCGLabel *null_lab;
55 bool psw_n_nonzero;
56 } DisasContext;
58 /* Target-specific return values from translate_one, indicating the
59 state of the TB. Note that DISAS_NEXT indicates that we are not
60 exiting the TB. */
62 /* We are not using a goto_tb (for whatever reason), but have updated
63 the iaq (for whatever reason), so don't do it again on exit. */
64 #define DISAS_IAQ_N_UPDATED DISAS_TARGET_0
66 /* We are exiting the TB, but have neither emitted a goto_tb, nor
67 updated the iaq for the next instruction to be executed. */
68 #define DISAS_IAQ_N_STALE DISAS_TARGET_1
70 typedef struct DisasInsn {
71 uint32_t insn, mask;
72 DisasJumpType (*trans)(DisasContext *ctx, uint32_t insn,
73 const struct DisasInsn *f);
74 union {
75 void (*ttt)(TCGv, TCGv, TCGv);
76 void (*weww)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32);
77 void (*dedd)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64);
78 void (*wew)(TCGv_i32, TCGv_env, TCGv_i32);
79 void (*ded)(TCGv_i64, TCGv_env, TCGv_i64);
80 void (*wed)(TCGv_i32, TCGv_env, TCGv_i64);
81 void (*dew)(TCGv_i64, TCGv_env, TCGv_i32);
82 } f;
83 } DisasInsn;
85 /* global register indexes */
86 static TCGv cpu_gr[32];
87 static TCGv cpu_iaoq_f;
88 static TCGv cpu_iaoq_b;
89 static TCGv cpu_sar;
90 static TCGv cpu_psw_n;
91 static TCGv cpu_psw_v;
92 static TCGv cpu_psw_cb;
93 static TCGv cpu_psw_cb_msb;
94 static TCGv cpu_cr26;
95 static TCGv cpu_cr27;
97 #include "exec/gen-icount.h"
99 void hppa_translate_init(void)
101 #define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
103 typedef struct { TCGv *var; const char *name; int ofs; } GlobalVar;
104 static const GlobalVar vars[] = {
105 DEF_VAR(sar),
106 DEF_VAR(cr26),
107 DEF_VAR(cr27),
108 DEF_VAR(psw_n),
109 DEF_VAR(psw_v),
110 DEF_VAR(psw_cb),
111 DEF_VAR(psw_cb_msb),
112 DEF_VAR(iaoq_f),
113 DEF_VAR(iaoq_b),
116 #undef DEF_VAR
118 /* Use the symbolic register names that match the disassembler. */
119 static const char gr_names[32][4] = {
120 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
121 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
122 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
123 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
126 int i;
128 TCGV_UNUSED(cpu_gr[0]);
129 for (i = 1; i < 32; i++) {
130 cpu_gr[i] = tcg_global_mem_new(cpu_env,
131 offsetof(CPUHPPAState, gr[i]),
132 gr_names[i]);
135 for (i = 0; i < ARRAY_SIZE(vars); ++i) {
136 const GlobalVar *v = &vars[i];
137 *v->var = tcg_global_mem_new(cpu_env, v->ofs, v->name);
141 static DisasCond cond_make_f(void)
143 DisasCond r = { .c = TCG_COND_NEVER };
144 TCGV_UNUSED(r.a0);
145 TCGV_UNUSED(r.a1);
146 return r;
149 static DisasCond cond_make_n(void)
151 DisasCond r = { .c = TCG_COND_NE, .a0_is_n = true, .a1_is_0 = true };
152 r.a0 = cpu_psw_n;
153 TCGV_UNUSED(r.a1);
154 return r;
157 static DisasCond cond_make_0(TCGCond c, TCGv a0)
159 DisasCond r = { .c = c, .a1_is_0 = true };
161 assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
162 r.a0 = tcg_temp_new();
163 tcg_gen_mov_tl(r.a0, a0);
164 TCGV_UNUSED(r.a1);
166 return r;
169 static DisasCond cond_make(TCGCond c, TCGv a0, TCGv a1)
171 DisasCond r = { .c = c };
173 assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
174 r.a0 = tcg_temp_new();
175 tcg_gen_mov_tl(r.a0, a0);
176 r.a1 = tcg_temp_new();
177 tcg_gen_mov_tl(r.a1, a1);
179 return r;
182 static void cond_prep(DisasCond *cond)
184 if (cond->a1_is_0) {
185 cond->a1_is_0 = false;
186 cond->a1 = tcg_const_tl(0);
190 static void cond_free(DisasCond *cond)
192 switch (cond->c) {
193 default:
194 if (!cond->a0_is_n) {
195 tcg_temp_free(cond->a0);
197 if (!cond->a1_is_0) {
198 tcg_temp_free(cond->a1);
200 cond->a0_is_n = false;
201 cond->a1_is_0 = false;
202 TCGV_UNUSED(cond->a0);
203 TCGV_UNUSED(cond->a1);
204 /* fallthru */
205 case TCG_COND_ALWAYS:
206 cond->c = TCG_COND_NEVER;
207 break;
208 case TCG_COND_NEVER:
209 break;
213 static TCGv get_temp(DisasContext *ctx)
215 unsigned i = ctx->ntemps++;
216 g_assert(i < ARRAY_SIZE(ctx->temps));
217 return ctx->temps[i] = tcg_temp_new();
220 static TCGv load_const(DisasContext *ctx, target_long v)
222 TCGv t = get_temp(ctx);
223 tcg_gen_movi_tl(t, v);
224 return t;
227 static TCGv load_gpr(DisasContext *ctx, unsigned reg)
229 if (reg == 0) {
230 TCGv t = get_temp(ctx);
231 tcg_gen_movi_tl(t, 0);
232 return t;
233 } else {
234 return cpu_gr[reg];
238 static TCGv dest_gpr(DisasContext *ctx, unsigned reg)
240 if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
241 return get_temp(ctx);
242 } else {
243 return cpu_gr[reg];
247 static void save_or_nullify(DisasContext *ctx, TCGv dest, TCGv t)
249 if (ctx->null_cond.c != TCG_COND_NEVER) {
250 cond_prep(&ctx->null_cond);
251 tcg_gen_movcond_tl(ctx->null_cond.c, dest, ctx->null_cond.a0,
252 ctx->null_cond.a1, dest, t);
253 } else {
254 tcg_gen_mov_tl(dest, t);
258 static void save_gpr(DisasContext *ctx, unsigned reg, TCGv t)
260 if (reg != 0) {
261 save_or_nullify(ctx, cpu_gr[reg], t);
265 #ifdef HOST_WORDS_BIGENDIAN
266 # define HI_OFS 0
267 # define LO_OFS 4
268 #else
269 # define HI_OFS 4
270 # define LO_OFS 0
271 #endif
273 static TCGv_i32 load_frw_i32(unsigned rt)
275 TCGv_i32 ret = tcg_temp_new_i32();
276 tcg_gen_ld_i32(ret, cpu_env,
277 offsetof(CPUHPPAState, fr[rt & 31])
278 + (rt & 32 ? LO_OFS : HI_OFS));
279 return ret;
282 static TCGv_i32 load_frw0_i32(unsigned rt)
284 if (rt == 0) {
285 return tcg_const_i32(0);
286 } else {
287 return load_frw_i32(rt);
291 static TCGv_i64 load_frw0_i64(unsigned rt)
293 if (rt == 0) {
294 return tcg_const_i64(0);
295 } else {
296 TCGv_i64 ret = tcg_temp_new_i64();
297 tcg_gen_ld32u_i64(ret, cpu_env,
298 offsetof(CPUHPPAState, fr[rt & 31])
299 + (rt & 32 ? LO_OFS : HI_OFS));
300 return ret;
304 static void save_frw_i32(unsigned rt, TCGv_i32 val)
306 tcg_gen_st_i32(val, cpu_env,
307 offsetof(CPUHPPAState, fr[rt & 31])
308 + (rt & 32 ? LO_OFS : HI_OFS));
311 #undef HI_OFS
312 #undef LO_OFS
314 static TCGv_i64 load_frd(unsigned rt)
316 TCGv_i64 ret = tcg_temp_new_i64();
317 tcg_gen_ld_i64(ret, cpu_env, offsetof(CPUHPPAState, fr[rt]));
318 return ret;
321 static TCGv_i64 load_frd0(unsigned rt)
323 if (rt == 0) {
324 return tcg_const_i64(0);
325 } else {
326 return load_frd(rt);
330 static void save_frd(unsigned rt, TCGv_i64 val)
332 tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt]));
335 /* Skip over the implementation of an insn that has been nullified.
336 Use this when the insn is too complex for a conditional move. */
337 static void nullify_over(DisasContext *ctx)
339 if (ctx->null_cond.c != TCG_COND_NEVER) {
340 /* The always condition should have been handled in the main loop. */
341 assert(ctx->null_cond.c != TCG_COND_ALWAYS);
343 ctx->null_lab = gen_new_label();
344 cond_prep(&ctx->null_cond);
346 /* If we're using PSW[N], copy it to a temp because... */
347 if (ctx->null_cond.a0_is_n) {
348 ctx->null_cond.a0_is_n = false;
349 ctx->null_cond.a0 = tcg_temp_new();
350 tcg_gen_mov_tl(ctx->null_cond.a0, cpu_psw_n);
352 /* ... we clear it before branching over the implementation,
353 so that (1) it's clear after nullifying this insn and
354 (2) if this insn nullifies the next, PSW[N] is valid. */
355 if (ctx->psw_n_nonzero) {
356 ctx->psw_n_nonzero = false;
357 tcg_gen_movi_tl(cpu_psw_n, 0);
360 tcg_gen_brcond_tl(ctx->null_cond.c, ctx->null_cond.a0,
361 ctx->null_cond.a1, ctx->null_lab);
362 cond_free(&ctx->null_cond);
366 /* Save the current nullification state to PSW[N]. */
367 static void nullify_save(DisasContext *ctx)
369 if (ctx->null_cond.c == TCG_COND_NEVER) {
370 if (ctx->psw_n_nonzero) {
371 tcg_gen_movi_tl(cpu_psw_n, 0);
373 return;
375 if (!ctx->null_cond.a0_is_n) {
376 cond_prep(&ctx->null_cond);
377 tcg_gen_setcond_tl(ctx->null_cond.c, cpu_psw_n,
378 ctx->null_cond.a0, ctx->null_cond.a1);
379 ctx->psw_n_nonzero = true;
381 cond_free(&ctx->null_cond);
384 /* Set a PSW[N] to X. The intention is that this is used immediately
385 before a goto_tb/exit_tb, so that there is no fallthru path to other
386 code within the TB. Therefore we do not update psw_n_nonzero. */
387 static void nullify_set(DisasContext *ctx, bool x)
389 if (ctx->psw_n_nonzero || x) {
390 tcg_gen_movi_tl(cpu_psw_n, x);
394 /* Mark the end of an instruction that may have been nullified.
395 This is the pair to nullify_over. */
396 static DisasJumpType nullify_end(DisasContext *ctx, DisasJumpType status)
398 TCGLabel *null_lab = ctx->null_lab;
400 if (likely(null_lab == NULL)) {
401 /* The current insn wasn't conditional or handled the condition
402 applied to it without a branch, so the (new) setting of
403 NULL_COND can be applied directly to the next insn. */
404 return status;
406 ctx->null_lab = NULL;
408 if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
409 /* The next instruction will be unconditional,
410 and NULL_COND already reflects that. */
411 gen_set_label(null_lab);
412 } else {
413 /* The insn that we just executed is itself nullifying the next
414 instruction. Store the condition in the PSW[N] global.
415 We asserted PSW[N] = 0 in nullify_over, so that after the
416 label we have the proper value in place. */
417 nullify_save(ctx);
418 gen_set_label(null_lab);
419 ctx->null_cond = cond_make_n();
422 assert(status != DISAS_NORETURN && status != DISAS_IAQ_N_UPDATED);
423 if (status == DISAS_NORETURN) {
424 status = DISAS_NEXT;
426 return status;
429 static void copy_iaoq_entry(TCGv dest, target_ulong ival, TCGv vval)
431 if (unlikely(ival == -1)) {
432 tcg_gen_mov_tl(dest, vval);
433 } else {
434 tcg_gen_movi_tl(dest, ival);
438 static inline target_ulong iaoq_dest(DisasContext *ctx, target_long disp)
440 return ctx->iaoq_f + disp + 8;
443 static void gen_excp_1(int exception)
445 TCGv_i32 t = tcg_const_i32(exception);
446 gen_helper_excp(cpu_env, t);
447 tcg_temp_free_i32(t);
450 static DisasJumpType gen_excp(DisasContext *ctx, int exception)
452 copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
453 copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
454 nullify_save(ctx);
455 gen_excp_1(exception);
456 return DISAS_NORETURN;
459 static DisasJumpType gen_illegal(DisasContext *ctx)
461 nullify_over(ctx);
462 return nullify_end(ctx, gen_excp(ctx, EXCP_SIGILL));
465 static bool use_goto_tb(DisasContext *ctx, target_ulong dest)
467 /* Suppress goto_tb in the case of single-steping and IO. */
468 if ((tb_cflags(ctx->base.tb) & CF_LAST_IO) || ctx->base.singlestep_enabled) {
469 return false;
471 return true;
474 /* If the next insn is to be nullified, and it's on the same page,
475 and we're not attempting to set a breakpoint on it, then we can
476 totally skip the nullified insn. This avoids creating and
477 executing a TB that merely branches to the next TB. */
478 static bool use_nullify_skip(DisasContext *ctx)
480 return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
481 && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
484 static void gen_goto_tb(DisasContext *ctx, int which,
485 target_ulong f, target_ulong b)
487 if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
488 tcg_gen_goto_tb(which);
489 tcg_gen_movi_tl(cpu_iaoq_f, f);
490 tcg_gen_movi_tl(cpu_iaoq_b, b);
491 tcg_gen_exit_tb((uintptr_t)ctx->base.tb + which);
492 } else {
493 copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b);
494 copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var);
495 if (ctx->base.singlestep_enabled) {
496 gen_excp_1(EXCP_DEBUG);
497 } else {
498 tcg_gen_lookup_and_goto_ptr();
503 /* PA has a habit of taking the LSB of a field and using that as the sign,
504 with the rest of the field becoming the least significant bits. */
505 static target_long low_sextract(uint32_t val, int pos, int len)
507 target_ulong x = -(target_ulong)extract32(val, pos, 1);
508 x = (x << (len - 1)) | extract32(val, pos + 1, len - 1);
509 return x;
512 static unsigned assemble_rt64(uint32_t insn)
514 unsigned r1 = extract32(insn, 6, 1);
515 unsigned r0 = extract32(insn, 0, 5);
516 return r1 * 32 + r0;
519 static unsigned assemble_ra64(uint32_t insn)
521 unsigned r1 = extract32(insn, 7, 1);
522 unsigned r0 = extract32(insn, 21, 5);
523 return r1 * 32 + r0;
526 static unsigned assemble_rb64(uint32_t insn)
528 unsigned r1 = extract32(insn, 12, 1);
529 unsigned r0 = extract32(insn, 16, 5);
530 return r1 * 32 + r0;
533 static unsigned assemble_rc64(uint32_t insn)
535 unsigned r2 = extract32(insn, 8, 1);
536 unsigned r1 = extract32(insn, 13, 3);
537 unsigned r0 = extract32(insn, 9, 2);
538 return r2 * 32 + r1 * 4 + r0;
541 static target_long assemble_12(uint32_t insn)
543 target_ulong x = -(target_ulong)(insn & 1);
544 x = (x << 1) | extract32(insn, 2, 1);
545 x = (x << 10) | extract32(insn, 3, 10);
546 return x;
549 static target_long assemble_16(uint32_t insn)
551 /* Take the name from PA2.0, which produces a 16-bit number
552 only with wide mode; otherwise a 14-bit number. Since we don't
553 implement wide mode, this is always the 14-bit number. */
554 return low_sextract(insn, 0, 14);
557 static target_long assemble_16a(uint32_t insn)
559 /* Take the name from PA2.0, which produces a 14-bit shifted number
560 only with wide mode; otherwise a 12-bit shifted number. Since we
561 don't implement wide mode, this is always the 12-bit number. */
562 target_ulong x = -(target_ulong)(insn & 1);
563 x = (x << 11) | extract32(insn, 2, 11);
564 return x << 2;
567 static target_long assemble_17(uint32_t insn)
569 target_ulong x = -(target_ulong)(insn & 1);
570 x = (x << 5) | extract32(insn, 16, 5);
571 x = (x << 1) | extract32(insn, 2, 1);
572 x = (x << 10) | extract32(insn, 3, 10);
573 return x << 2;
576 static target_long assemble_21(uint32_t insn)
578 target_ulong x = -(target_ulong)(insn & 1);
579 x = (x << 11) | extract32(insn, 1, 11);
580 x = (x << 2) | extract32(insn, 14, 2);
581 x = (x << 5) | extract32(insn, 16, 5);
582 x = (x << 2) | extract32(insn, 12, 2);
583 return x << 11;
586 static target_long assemble_22(uint32_t insn)
588 target_ulong x = -(target_ulong)(insn & 1);
589 x = (x << 10) | extract32(insn, 16, 10);
590 x = (x << 1) | extract32(insn, 2, 1);
591 x = (x << 10) | extract32(insn, 3, 10);
592 return x << 2;
595 /* The parisc documentation describes only the general interpretation of
596 the conditions, without describing their exact implementation. The
597 interpretations do not stand up well when considering ADD,C and SUB,B.
598 However, considering the Addition, Subtraction and Logical conditions
599 as a whole it would appear that these relations are similar to what
600 a traditional NZCV set of flags would produce. */
602 static DisasCond do_cond(unsigned cf, TCGv res, TCGv cb_msb, TCGv sv)
604 DisasCond cond;
605 TCGv tmp;
607 switch (cf >> 1) {
608 case 0: /* Never / TR */
609 cond = cond_make_f();
610 break;
611 case 1: /* = / <> (Z / !Z) */
612 cond = cond_make_0(TCG_COND_EQ, res);
613 break;
614 case 2: /* < / >= (N / !N) */
615 cond = cond_make_0(TCG_COND_LT, res);
616 break;
617 case 3: /* <= / > (N | Z / !N & !Z) */
618 cond = cond_make_0(TCG_COND_LE, res);
619 break;
620 case 4: /* NUV / UV (!C / C) */
621 cond = cond_make_0(TCG_COND_EQ, cb_msb);
622 break;
623 case 5: /* ZNV / VNZ (!C | Z / C & !Z) */
624 tmp = tcg_temp_new();
625 tcg_gen_neg_tl(tmp, cb_msb);
626 tcg_gen_and_tl(tmp, tmp, res);
627 cond = cond_make_0(TCG_COND_EQ, tmp);
628 tcg_temp_free(tmp);
629 break;
630 case 6: /* SV / NSV (V / !V) */
631 cond = cond_make_0(TCG_COND_LT, sv);
632 break;
633 case 7: /* OD / EV */
634 tmp = tcg_temp_new();
635 tcg_gen_andi_tl(tmp, res, 1);
636 cond = cond_make_0(TCG_COND_NE, tmp);
637 tcg_temp_free(tmp);
638 break;
639 default:
640 g_assert_not_reached();
642 if (cf & 1) {
643 cond.c = tcg_invert_cond(cond.c);
646 return cond;
649 /* Similar, but for the special case of subtraction without borrow, we
650 can use the inputs directly. This can allow other computation to be
651 deleted as unused. */
653 static DisasCond do_sub_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2, TCGv sv)
655 DisasCond cond;
657 switch (cf >> 1) {
658 case 1: /* = / <> */
659 cond = cond_make(TCG_COND_EQ, in1, in2);
660 break;
661 case 2: /* < / >= */
662 cond = cond_make(TCG_COND_LT, in1, in2);
663 break;
664 case 3: /* <= / > */
665 cond = cond_make(TCG_COND_LE, in1, in2);
666 break;
667 case 4: /* << / >>= */
668 cond = cond_make(TCG_COND_LTU, in1, in2);
669 break;
670 case 5: /* <<= / >> */
671 cond = cond_make(TCG_COND_LEU, in1, in2);
672 break;
673 default:
674 return do_cond(cf, res, sv, sv);
676 if (cf & 1) {
677 cond.c = tcg_invert_cond(cond.c);
680 return cond;
683 /* Similar, but for logicals, where the carry and overflow bits are not
684 computed, and use of them is undefined. */
686 static DisasCond do_log_cond(unsigned cf, TCGv res)
688 switch (cf >> 1) {
689 case 4: case 5: case 6:
690 cf &= 1;
691 break;
693 return do_cond(cf, res, res, res);
696 /* Similar, but for shift/extract/deposit conditions. */
698 static DisasCond do_sed_cond(unsigned orig, TCGv res)
700 unsigned c, f;
702 /* Convert the compressed condition codes to standard.
703 0-2 are the same as logicals (nv,<,<=), while 3 is OD.
704 4-7 are the reverse of 0-3. */
705 c = orig & 3;
706 if (c == 3) {
707 c = 7;
709 f = (orig & 4) / 4;
711 return do_log_cond(c * 2 + f, res);
714 /* Similar, but for unit conditions. */
716 static DisasCond do_unit_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2)
718 DisasCond cond;
719 TCGv tmp, cb;
721 TCGV_UNUSED(cb);
722 if (cf & 8) {
723 /* Since we want to test lots of carry-out bits all at once, do not
724 * do our normal thing and compute carry-in of bit B+1 since that
725 * leaves us with carry bits spread across two words.
727 cb = tcg_temp_new();
728 tmp = tcg_temp_new();
729 tcg_gen_or_tl(cb, in1, in2);
730 tcg_gen_and_tl(tmp, in1, in2);
731 tcg_gen_andc_tl(cb, cb, res);
732 tcg_gen_or_tl(cb, cb, tmp);
733 tcg_temp_free(tmp);
736 switch (cf >> 1) {
737 case 0: /* never / TR */
738 case 1: /* undefined */
739 case 5: /* undefined */
740 cond = cond_make_f();
741 break;
743 case 2: /* SBZ / NBZ */
744 /* See hasless(v,1) from
745 * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
747 tmp = tcg_temp_new();
748 tcg_gen_subi_tl(tmp, res, 0x01010101u);
749 tcg_gen_andc_tl(tmp, tmp, res);
750 tcg_gen_andi_tl(tmp, tmp, 0x80808080u);
751 cond = cond_make_0(TCG_COND_NE, tmp);
752 tcg_temp_free(tmp);
753 break;
755 case 3: /* SHZ / NHZ */
756 tmp = tcg_temp_new();
757 tcg_gen_subi_tl(tmp, res, 0x00010001u);
758 tcg_gen_andc_tl(tmp, tmp, res);
759 tcg_gen_andi_tl(tmp, tmp, 0x80008000u);
760 cond = cond_make_0(TCG_COND_NE, tmp);
761 tcg_temp_free(tmp);
762 break;
764 case 4: /* SDC / NDC */
765 tcg_gen_andi_tl(cb, cb, 0x88888888u);
766 cond = cond_make_0(TCG_COND_NE, cb);
767 break;
769 case 6: /* SBC / NBC */
770 tcg_gen_andi_tl(cb, cb, 0x80808080u);
771 cond = cond_make_0(TCG_COND_NE, cb);
772 break;
774 case 7: /* SHC / NHC */
775 tcg_gen_andi_tl(cb, cb, 0x80008000u);
776 cond = cond_make_0(TCG_COND_NE, cb);
777 break;
779 default:
780 g_assert_not_reached();
782 if (cf & 8) {
783 tcg_temp_free(cb);
785 if (cf & 1) {
786 cond.c = tcg_invert_cond(cond.c);
789 return cond;
792 /* Compute signed overflow for addition. */
793 static TCGv do_add_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
795 TCGv sv = get_temp(ctx);
796 TCGv tmp = tcg_temp_new();
798 tcg_gen_xor_tl(sv, res, in1);
799 tcg_gen_xor_tl(tmp, in1, in2);
800 tcg_gen_andc_tl(sv, sv, tmp);
801 tcg_temp_free(tmp);
803 return sv;
806 /* Compute signed overflow for subtraction. */
807 static TCGv do_sub_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
809 TCGv sv = get_temp(ctx);
810 TCGv tmp = tcg_temp_new();
812 tcg_gen_xor_tl(sv, res, in1);
813 tcg_gen_xor_tl(tmp, in1, in2);
814 tcg_gen_and_tl(sv, sv, tmp);
815 tcg_temp_free(tmp);
817 return sv;
820 static DisasJumpType do_add(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
821 unsigned shift, bool is_l, bool is_tsv, bool is_tc,
822 bool is_c, unsigned cf)
824 TCGv dest, cb, cb_msb, sv, tmp;
825 unsigned c = cf >> 1;
826 DisasCond cond;
828 dest = tcg_temp_new();
829 TCGV_UNUSED(cb);
830 TCGV_UNUSED(cb_msb);
832 if (shift) {
833 tmp = get_temp(ctx);
834 tcg_gen_shli_tl(tmp, in1, shift);
835 in1 = tmp;
838 if (!is_l || c == 4 || c == 5) {
839 TCGv zero = tcg_const_tl(0);
840 cb_msb = get_temp(ctx);
841 tcg_gen_add2_tl(dest, cb_msb, in1, zero, in2, zero);
842 if (is_c) {
843 tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero);
845 tcg_temp_free(zero);
846 if (!is_l) {
847 cb = get_temp(ctx);
848 tcg_gen_xor_tl(cb, in1, in2);
849 tcg_gen_xor_tl(cb, cb, dest);
851 } else {
852 tcg_gen_add_tl(dest, in1, in2);
853 if (is_c) {
854 tcg_gen_add_tl(dest, dest, cpu_psw_cb_msb);
858 /* Compute signed overflow if required. */
859 TCGV_UNUSED(sv);
860 if (is_tsv || c == 6) {
861 sv = do_add_sv(ctx, dest, in1, in2);
862 if (is_tsv) {
863 /* ??? Need to include overflow from shift. */
864 gen_helper_tsv(cpu_env, sv);
868 /* Emit any conditional trap before any writeback. */
869 cond = do_cond(cf, dest, cb_msb, sv);
870 if (is_tc) {
871 cond_prep(&cond);
872 tmp = tcg_temp_new();
873 tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
874 gen_helper_tcond(cpu_env, tmp);
875 tcg_temp_free(tmp);
878 /* Write back the result. */
879 if (!is_l) {
880 save_or_nullify(ctx, cpu_psw_cb, cb);
881 save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
883 save_gpr(ctx, rt, dest);
884 tcg_temp_free(dest);
886 /* Install the new nullification. */
887 cond_free(&ctx->null_cond);
888 ctx->null_cond = cond;
889 return DISAS_NEXT;
892 static DisasJumpType do_sub(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
893 bool is_tsv, bool is_b, bool is_tc, unsigned cf)
895 TCGv dest, sv, cb, cb_msb, zero, tmp;
896 unsigned c = cf >> 1;
897 DisasCond cond;
899 dest = tcg_temp_new();
900 cb = tcg_temp_new();
901 cb_msb = tcg_temp_new();
903 zero = tcg_const_tl(0);
904 if (is_b) {
905 /* DEST,C = IN1 + ~IN2 + C. */
906 tcg_gen_not_tl(cb, in2);
907 tcg_gen_add2_tl(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero);
908 tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cb, zero);
909 tcg_gen_xor_tl(cb, cb, in1);
910 tcg_gen_xor_tl(cb, cb, dest);
911 } else {
912 /* DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer
913 operations by seeding the high word with 1 and subtracting. */
914 tcg_gen_movi_tl(cb_msb, 1);
915 tcg_gen_sub2_tl(dest, cb_msb, in1, cb_msb, in2, zero);
916 tcg_gen_eqv_tl(cb, in1, in2);
917 tcg_gen_xor_tl(cb, cb, dest);
919 tcg_temp_free(zero);
921 /* Compute signed overflow if required. */
922 TCGV_UNUSED(sv);
923 if (is_tsv || c == 6) {
924 sv = do_sub_sv(ctx, dest, in1, in2);
925 if (is_tsv) {
926 gen_helper_tsv(cpu_env, sv);
930 /* Compute the condition. We cannot use the special case for borrow. */
931 if (!is_b) {
932 cond = do_sub_cond(cf, dest, in1, in2, sv);
933 } else {
934 cond = do_cond(cf, dest, cb_msb, sv);
937 /* Emit any conditional trap before any writeback. */
938 if (is_tc) {
939 cond_prep(&cond);
940 tmp = tcg_temp_new();
941 tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
942 gen_helper_tcond(cpu_env, tmp);
943 tcg_temp_free(tmp);
946 /* Write back the result. */
947 save_or_nullify(ctx, cpu_psw_cb, cb);
948 save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
949 save_gpr(ctx, rt, dest);
950 tcg_temp_free(dest);
952 /* Install the new nullification. */
953 cond_free(&ctx->null_cond);
954 ctx->null_cond = cond;
955 return DISAS_NEXT;
958 static DisasJumpType do_cmpclr(DisasContext *ctx, unsigned rt, TCGv in1,
959 TCGv in2, unsigned cf)
961 TCGv dest, sv;
962 DisasCond cond;
964 dest = tcg_temp_new();
965 tcg_gen_sub_tl(dest, in1, in2);
967 /* Compute signed overflow if required. */
968 TCGV_UNUSED(sv);
969 if ((cf >> 1) == 6) {
970 sv = do_sub_sv(ctx, dest, in1, in2);
973 /* Form the condition for the compare. */
974 cond = do_sub_cond(cf, dest, in1, in2, sv);
976 /* Clear. */
977 tcg_gen_movi_tl(dest, 0);
978 save_gpr(ctx, rt, dest);
979 tcg_temp_free(dest);
981 /* Install the new nullification. */
982 cond_free(&ctx->null_cond);
983 ctx->null_cond = cond;
984 return DISAS_NEXT;
987 static DisasJumpType do_log(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
988 unsigned cf, void (*fn)(TCGv, TCGv, TCGv))
990 TCGv dest = dest_gpr(ctx, rt);
992 /* Perform the operation, and writeback. */
993 fn(dest, in1, in2);
994 save_gpr(ctx, rt, dest);
996 /* Install the new nullification. */
997 cond_free(&ctx->null_cond);
998 if (cf) {
999 ctx->null_cond = do_log_cond(cf, dest);
1001 return DISAS_NEXT;
1004 static DisasJumpType do_unit(DisasContext *ctx, unsigned rt, TCGv in1,
1005 TCGv in2, unsigned cf, bool is_tc,
1006 void (*fn)(TCGv, TCGv, TCGv))
1008 TCGv dest;
1009 DisasCond cond;
1011 if (cf == 0) {
1012 dest = dest_gpr(ctx, rt);
1013 fn(dest, in1, in2);
1014 save_gpr(ctx, rt, dest);
1015 cond_free(&ctx->null_cond);
1016 } else {
1017 dest = tcg_temp_new();
1018 fn(dest, in1, in2);
1020 cond = do_unit_cond(cf, dest, in1, in2);
1022 if (is_tc) {
1023 TCGv tmp = tcg_temp_new();
1024 cond_prep(&cond);
1025 tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
1026 gen_helper_tcond(cpu_env, tmp);
1027 tcg_temp_free(tmp);
1029 save_gpr(ctx, rt, dest);
1031 cond_free(&ctx->null_cond);
1032 ctx->null_cond = cond;
1034 return DISAS_NEXT;
1037 /* Emit a memory load. The modify parameter should be
1038 * < 0 for pre-modify,
1039 * > 0 for post-modify,
1040 * = 0 for no base register update.
1042 static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1043 unsigned rx, int scale, target_long disp,
1044 int modify, TCGMemOp mop)
1046 TCGv addr, base;
1048 /* Caller uses nullify_over/nullify_end. */
1049 assert(ctx->null_cond.c == TCG_COND_NEVER);
1051 addr = tcg_temp_new();
1052 base = load_gpr(ctx, rb);
1054 /* Note that RX is mutually exclusive with DISP. */
1055 if (rx) {
1056 tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
1057 tcg_gen_add_tl(addr, addr, base);
1058 } else {
1059 tcg_gen_addi_tl(addr, base, disp);
1062 if (modify == 0) {
1063 tcg_gen_qemu_ld_i32(dest, addr, MMU_USER_IDX, mop);
1064 } else {
1065 tcg_gen_qemu_ld_i32(dest, (modify < 0 ? addr : base),
1066 MMU_USER_IDX, mop);
1067 save_gpr(ctx, rb, addr);
1069 tcg_temp_free(addr);
1072 static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1073 unsigned rx, int scale, target_long disp,
1074 int modify, TCGMemOp mop)
1076 TCGv addr, base;
1078 /* Caller uses nullify_over/nullify_end. */
1079 assert(ctx->null_cond.c == TCG_COND_NEVER);
1081 addr = tcg_temp_new();
1082 base = load_gpr(ctx, rb);
1084 /* Note that RX is mutually exclusive with DISP. */
1085 if (rx) {
1086 tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
1087 tcg_gen_add_tl(addr, addr, base);
1088 } else {
1089 tcg_gen_addi_tl(addr, base, disp);
1092 if (modify == 0) {
1093 tcg_gen_qemu_ld_i64(dest, addr, MMU_USER_IDX, mop);
1094 } else {
1095 tcg_gen_qemu_ld_i64(dest, (modify < 0 ? addr : base),
1096 MMU_USER_IDX, mop);
1097 save_gpr(ctx, rb, addr);
1099 tcg_temp_free(addr);
1102 static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1103 unsigned rx, int scale, target_long disp,
1104 int modify, TCGMemOp mop)
1106 TCGv addr, base;
1108 /* Caller uses nullify_over/nullify_end. */
1109 assert(ctx->null_cond.c == TCG_COND_NEVER);
1111 addr = tcg_temp_new();
1112 base = load_gpr(ctx, rb);
1114 /* Note that RX is mutually exclusive with DISP. */
1115 if (rx) {
1116 tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
1117 tcg_gen_add_tl(addr, addr, base);
1118 } else {
1119 tcg_gen_addi_tl(addr, base, disp);
1122 tcg_gen_qemu_st_i32(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
1124 if (modify != 0) {
1125 save_gpr(ctx, rb, addr);
1127 tcg_temp_free(addr);
1130 static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1131 unsigned rx, int scale, target_long disp,
1132 int modify, TCGMemOp mop)
1134 TCGv addr, base;
1136 /* Caller uses nullify_over/nullify_end. */
1137 assert(ctx->null_cond.c == TCG_COND_NEVER);
1139 addr = tcg_temp_new();
1140 base = load_gpr(ctx, rb);
1142 /* Note that RX is mutually exclusive with DISP. */
1143 if (rx) {
1144 tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
1145 tcg_gen_add_tl(addr, addr, base);
1146 } else {
1147 tcg_gen_addi_tl(addr, base, disp);
1150 tcg_gen_qemu_st_i64(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
1152 if (modify != 0) {
1153 save_gpr(ctx, rb, addr);
1155 tcg_temp_free(addr);
1158 #if TARGET_LONG_BITS == 64
1159 #define do_load_tl do_load_64
1160 #define do_store_tl do_store_64
1161 #else
1162 #define do_load_tl do_load_32
1163 #define do_store_tl do_store_32
1164 #endif
1166 static DisasJumpType do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1167 unsigned rx, int scale, target_long disp,
1168 int modify, TCGMemOp mop)
1170 TCGv dest;
1172 nullify_over(ctx);
1174 if (modify == 0) {
1175 /* No base register update. */
1176 dest = dest_gpr(ctx, rt);
1177 } else {
1178 /* Make sure if RT == RB, we see the result of the load. */
1179 dest = get_temp(ctx);
1181 do_load_tl(ctx, dest, rb, rx, scale, disp, modify, mop);
1182 save_gpr(ctx, rt, dest);
1184 return nullify_end(ctx, DISAS_NEXT);
1187 static DisasJumpType do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
1188 unsigned rx, int scale, target_long disp,
1189 int modify)
1191 TCGv_i32 tmp;
1193 nullify_over(ctx);
1195 tmp = tcg_temp_new_i32();
1196 do_load_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
1197 save_frw_i32(rt, tmp);
1198 tcg_temp_free_i32(tmp);
1200 if (rt == 0) {
1201 gen_helper_loaded_fr0(cpu_env);
1204 return nullify_end(ctx, DISAS_NEXT);
1207 static DisasJumpType do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1208 unsigned rx, int scale, target_long disp,
1209 int modify)
1211 TCGv_i64 tmp;
1213 nullify_over(ctx);
1215 tmp = tcg_temp_new_i64();
1216 do_load_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
1217 save_frd(rt, tmp);
1218 tcg_temp_free_i64(tmp);
1220 if (rt == 0) {
1221 gen_helper_loaded_fr0(cpu_env);
1224 return nullify_end(ctx, DISAS_NEXT);
1227 static DisasJumpType do_store(DisasContext *ctx, unsigned rt, unsigned rb,
1228 target_long disp, int modify, TCGMemOp mop)
1230 nullify_over(ctx);
1231 do_store_tl(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, modify, mop);
1232 return nullify_end(ctx, DISAS_NEXT);
1235 static DisasJumpType do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1236 unsigned rx, int scale, target_long disp,
1237 int modify)
1239 TCGv_i32 tmp;
1241 nullify_over(ctx);
1243 tmp = load_frw_i32(rt);
1244 do_store_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
1245 tcg_temp_free_i32(tmp);
1247 return nullify_end(ctx, DISAS_NEXT);
1250 static DisasJumpType do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1251 unsigned rx, int scale, target_long disp,
1252 int modify)
1254 TCGv_i64 tmp;
1256 nullify_over(ctx);
1258 tmp = load_frd(rt);
1259 do_store_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
1260 tcg_temp_free_i64(tmp);
1262 return nullify_end(ctx, DISAS_NEXT);
1265 static DisasJumpType do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1266 void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1268 TCGv_i32 tmp;
1270 nullify_over(ctx);
1271 tmp = load_frw0_i32(ra);
1273 func(tmp, cpu_env, tmp);
1275 save_frw_i32(rt, tmp);
1276 tcg_temp_free_i32(tmp);
1277 return nullify_end(ctx, DISAS_NEXT);
1280 static DisasJumpType do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1281 void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1283 TCGv_i32 dst;
1284 TCGv_i64 src;
1286 nullify_over(ctx);
1287 src = load_frd(ra);
1288 dst = tcg_temp_new_i32();
1290 func(dst, cpu_env, src);
1292 tcg_temp_free_i64(src);
1293 save_frw_i32(rt, dst);
1294 tcg_temp_free_i32(dst);
1295 return nullify_end(ctx, DISAS_NEXT);
1298 static DisasJumpType do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1299 void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1301 TCGv_i64 tmp;
1303 nullify_over(ctx);
1304 tmp = load_frd0(ra);
1306 func(tmp, cpu_env, tmp);
1308 save_frd(rt, tmp);
1309 tcg_temp_free_i64(tmp);
1310 return nullify_end(ctx, DISAS_NEXT);
1313 static DisasJumpType do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1314 void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1316 TCGv_i32 src;
1317 TCGv_i64 dst;
1319 nullify_over(ctx);
1320 src = load_frw0_i32(ra);
1321 dst = tcg_temp_new_i64();
1323 func(dst, cpu_env, src);
1325 tcg_temp_free_i32(src);
1326 save_frd(rt, dst);
1327 tcg_temp_free_i64(dst);
1328 return nullify_end(ctx, DISAS_NEXT);
1331 static DisasJumpType do_fop_weww(DisasContext *ctx, unsigned rt,
1332 unsigned ra, unsigned rb,
1333 void (*func)(TCGv_i32, TCGv_env,
1334 TCGv_i32, TCGv_i32))
1336 TCGv_i32 a, b;
1338 nullify_over(ctx);
1339 a = load_frw0_i32(ra);
1340 b = load_frw0_i32(rb);
1342 func(a, cpu_env, a, b);
1344 tcg_temp_free_i32(b);
1345 save_frw_i32(rt, a);
1346 tcg_temp_free_i32(a);
1347 return nullify_end(ctx, DISAS_NEXT);
1350 static DisasJumpType do_fop_dedd(DisasContext *ctx, unsigned rt,
1351 unsigned ra, unsigned rb,
1352 void (*func)(TCGv_i64, TCGv_env,
1353 TCGv_i64, TCGv_i64))
1355 TCGv_i64 a, b;
1357 nullify_over(ctx);
1358 a = load_frd0(ra);
1359 b = load_frd0(rb);
1361 func(a, cpu_env, a, b);
1363 tcg_temp_free_i64(b);
1364 save_frd(rt, a);
1365 tcg_temp_free_i64(a);
1366 return nullify_end(ctx, DISAS_NEXT);
1369 /* Emit an unconditional branch to a direct target, which may or may not
1370 have already had nullification handled. */
1371 static DisasJumpType do_dbranch(DisasContext *ctx, target_ulong dest,
1372 unsigned link, bool is_n)
1374 if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
1375 if (link != 0) {
1376 copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
1378 ctx->iaoq_n = dest;
1379 if (is_n) {
1380 ctx->null_cond.c = TCG_COND_ALWAYS;
1382 return DISAS_NEXT;
1383 } else {
1384 nullify_over(ctx);
1386 if (link != 0) {
1387 copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
1390 if (is_n && use_nullify_skip(ctx)) {
1391 nullify_set(ctx, 0);
1392 gen_goto_tb(ctx, 0, dest, dest + 4);
1393 } else {
1394 nullify_set(ctx, is_n);
1395 gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
1398 nullify_end(ctx, DISAS_NEXT);
1400 nullify_set(ctx, 0);
1401 gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
1402 return DISAS_NORETURN;
1406 /* Emit a conditional branch to a direct target. If the branch itself
1407 is nullified, we should have already used nullify_over. */
1408 static DisasJumpType do_cbranch(DisasContext *ctx, target_long disp, bool is_n,
1409 DisasCond *cond)
1411 target_ulong dest = iaoq_dest(ctx, disp);
1412 TCGLabel *taken = NULL;
1413 TCGCond c = cond->c;
1414 bool n;
1416 assert(ctx->null_cond.c == TCG_COND_NEVER);
1418 /* Handle TRUE and NEVER as direct branches. */
1419 if (c == TCG_COND_ALWAYS) {
1420 return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
1422 if (c == TCG_COND_NEVER) {
1423 return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
1426 taken = gen_new_label();
1427 cond_prep(cond);
1428 tcg_gen_brcond_tl(c, cond->a0, cond->a1, taken);
1429 cond_free(cond);
1431 /* Not taken: Condition not satisfied; nullify on backward branches. */
1432 n = is_n && disp < 0;
1433 if (n && use_nullify_skip(ctx)) {
1434 nullify_set(ctx, 0);
1435 gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
1436 } else {
1437 if (!n && ctx->null_lab) {
1438 gen_set_label(ctx->null_lab);
1439 ctx->null_lab = NULL;
1441 nullify_set(ctx, n);
1442 gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
1445 gen_set_label(taken);
1447 /* Taken: Condition satisfied; nullify on forward branches. */
1448 n = is_n && disp >= 0;
1449 if (n && use_nullify_skip(ctx)) {
1450 nullify_set(ctx, 0);
1451 gen_goto_tb(ctx, 1, dest, dest + 4);
1452 } else {
1453 nullify_set(ctx, n);
1454 gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
1457 /* Not taken: the branch itself was nullified. */
1458 if (ctx->null_lab) {
1459 gen_set_label(ctx->null_lab);
1460 ctx->null_lab = NULL;
1461 return DISAS_IAQ_N_STALE;
1462 } else {
1463 return DISAS_NORETURN;
1467 /* Emit an unconditional branch to an indirect target. This handles
1468 nullification of the branch itself. */
1469 static DisasJumpType do_ibranch(DisasContext *ctx, TCGv dest,
1470 unsigned link, bool is_n)
1472 TCGv a0, a1, next, tmp;
1473 TCGCond c;
1475 assert(ctx->null_lab == NULL);
1477 if (ctx->null_cond.c == TCG_COND_NEVER) {
1478 if (link != 0) {
1479 copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
1481 next = get_temp(ctx);
1482 tcg_gen_mov_tl(next, dest);
1483 ctx->iaoq_n = -1;
1484 ctx->iaoq_n_var = next;
1485 if (is_n) {
1486 ctx->null_cond.c = TCG_COND_ALWAYS;
1488 } else if (is_n && use_nullify_skip(ctx)) {
1489 /* The (conditional) branch, B, nullifies the next insn, N,
1490 and we're allowed to skip execution N (no single-step or
1491 tracepoint in effect). Since the goto_ptr that we must use
1492 for the indirect branch consumes no special resources, we
1493 can (conditionally) skip B and continue execution. */
1494 /* The use_nullify_skip test implies we have a known control path. */
1495 tcg_debug_assert(ctx->iaoq_b != -1);
1496 tcg_debug_assert(ctx->iaoq_n != -1);
1498 /* We do have to handle the non-local temporary, DEST, before
1499 branching. Since IOAQ_F is not really live at this point, we
1500 can simply store DEST optimistically. Similarly with IAOQ_B. */
1501 tcg_gen_mov_tl(cpu_iaoq_f, dest);
1502 tcg_gen_addi_tl(cpu_iaoq_b, dest, 4);
1504 nullify_over(ctx);
1505 if (link != 0) {
1506 tcg_gen_movi_tl(cpu_gr[link], ctx->iaoq_n);
1508 tcg_gen_lookup_and_goto_ptr();
1509 return nullify_end(ctx, DISAS_NEXT);
1510 } else {
1511 cond_prep(&ctx->null_cond);
1512 c = ctx->null_cond.c;
1513 a0 = ctx->null_cond.a0;
1514 a1 = ctx->null_cond.a1;
1516 tmp = tcg_temp_new();
1517 next = get_temp(ctx);
1519 copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var);
1520 tcg_gen_movcond_tl(c, next, a0, a1, tmp, dest);
1521 ctx->iaoq_n = -1;
1522 ctx->iaoq_n_var = next;
1524 if (link != 0) {
1525 tcg_gen_movcond_tl(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
1528 if (is_n) {
1529 /* The branch nullifies the next insn, which means the state of N
1530 after the branch is the inverse of the state of N that applied
1531 to the branch. */
1532 tcg_gen_setcond_tl(tcg_invert_cond(c), cpu_psw_n, a0, a1);
1533 cond_free(&ctx->null_cond);
1534 ctx->null_cond = cond_make_n();
1535 ctx->psw_n_nonzero = true;
1536 } else {
1537 cond_free(&ctx->null_cond);
1541 return DISAS_NEXT;
1544 /* On Linux, page zero is normally marked execute only + gateway.
1545 Therefore normal read or write is supposed to fail, but specific
1546 offsets have kernel code mapped to raise permissions to implement
1547 system calls. Handling this via an explicit check here, rather
1548 in than the "be disp(sr2,r0)" instruction that probably sent us
1549 here, is the easiest way to handle the branch delay slot on the
1550 aforementioned BE. */
1551 static DisasJumpType do_page_zero(DisasContext *ctx)
1553 /* If by some means we get here with PSW[N]=1, that implies that
1554 the B,GATE instruction would be skipped, and we'd fault on the
1555 next insn within the privilaged page. */
1556 switch (ctx->null_cond.c) {
1557 case TCG_COND_NEVER:
1558 break;
1559 case TCG_COND_ALWAYS:
1560 tcg_gen_movi_tl(cpu_psw_n, 0);
1561 goto do_sigill;
1562 default:
1563 /* Since this is always the first (and only) insn within the
1564 TB, we should know the state of PSW[N] from TB->FLAGS. */
1565 g_assert_not_reached();
1568 /* Check that we didn't arrive here via some means that allowed
1569 non-sequential instruction execution. Normally the PSW[B] bit
1570 detects this by disallowing the B,GATE instruction to execute
1571 under such conditions. */
1572 if (ctx->iaoq_b != ctx->iaoq_f + 4) {
1573 goto do_sigill;
1576 switch (ctx->iaoq_f) {
1577 case 0x00: /* Null pointer call */
1578 gen_excp_1(EXCP_SIGSEGV);
1579 return DISAS_NORETURN;
1581 case 0xb0: /* LWS */
1582 gen_excp_1(EXCP_SYSCALL_LWS);
1583 return DISAS_NORETURN;
1585 case 0xe0: /* SET_THREAD_POINTER */
1586 tcg_gen_mov_tl(cpu_cr27, cpu_gr[26]);
1587 tcg_gen_mov_tl(cpu_iaoq_f, cpu_gr[31]);
1588 tcg_gen_addi_tl(cpu_iaoq_b, cpu_iaoq_f, 4);
1589 return DISAS_IAQ_N_UPDATED;
1591 case 0x100: /* SYSCALL */
1592 gen_excp_1(EXCP_SYSCALL);
1593 return DISAS_NORETURN;
1595 default:
1596 do_sigill:
1597 gen_excp_1(EXCP_SIGILL);
1598 return DISAS_NORETURN;
1602 static DisasJumpType trans_nop(DisasContext *ctx, uint32_t insn,
1603 const DisasInsn *di)
1605 cond_free(&ctx->null_cond);
1606 return DISAS_NEXT;
1609 static DisasJumpType trans_break(DisasContext *ctx, uint32_t insn,
1610 const DisasInsn *di)
1612 nullify_over(ctx);
1613 return nullify_end(ctx, gen_excp(ctx, EXCP_DEBUG));
1616 static DisasJumpType trans_sync(DisasContext *ctx, uint32_t insn,
1617 const DisasInsn *di)
1619 /* No point in nullifying the memory barrier. */
1620 tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1622 cond_free(&ctx->null_cond);
1623 return DISAS_NEXT;
1626 static DisasJumpType trans_mfia(DisasContext *ctx, uint32_t insn,
1627 const DisasInsn *di)
1629 unsigned rt = extract32(insn, 0, 5);
1630 TCGv tmp = dest_gpr(ctx, rt);
1631 tcg_gen_movi_tl(tmp, ctx->iaoq_f);
1632 save_gpr(ctx, rt, tmp);
1634 cond_free(&ctx->null_cond);
1635 return DISAS_NEXT;
1638 static DisasJumpType trans_mfsp(DisasContext *ctx, uint32_t insn,
1639 const DisasInsn *di)
1641 unsigned rt = extract32(insn, 0, 5);
1642 TCGv tmp = dest_gpr(ctx, rt);
1644 /* ??? We don't implement space registers. */
1645 tcg_gen_movi_tl(tmp, 0);
1646 save_gpr(ctx, rt, tmp);
1648 cond_free(&ctx->null_cond);
1649 return DISAS_NEXT;
1652 static DisasJumpType trans_mfctl(DisasContext *ctx, uint32_t insn,
1653 const DisasInsn *di)
1655 unsigned rt = extract32(insn, 0, 5);
1656 unsigned ctl = extract32(insn, 21, 5);
1657 TCGv tmp;
1659 switch (ctl) {
1660 case 11: /* SAR */
1661 #ifdef TARGET_HPPA64
1662 if (extract32(insn, 14, 1) == 0) {
1663 /* MFSAR without ,W masks low 5 bits. */
1664 tmp = dest_gpr(ctx, rt);
1665 tcg_gen_andi_tl(tmp, cpu_sar, 31);
1666 save_gpr(ctx, rt, tmp);
1667 break;
1669 #endif
1670 save_gpr(ctx, rt, cpu_sar);
1671 break;
1672 case 16: /* Interval Timer */
1673 tmp = dest_gpr(ctx, rt);
1674 tcg_gen_movi_tl(tmp, 0); /* FIXME */
1675 save_gpr(ctx, rt, tmp);
1676 break;
1677 case 26:
1678 save_gpr(ctx, rt, cpu_cr26);
1679 break;
1680 case 27:
1681 save_gpr(ctx, rt, cpu_cr27);
1682 break;
1683 default:
1684 /* All other control registers are privileged. */
1685 return gen_illegal(ctx);
1688 cond_free(&ctx->null_cond);
1689 return DISAS_NEXT;
1692 static DisasJumpType trans_mtctl(DisasContext *ctx, uint32_t insn,
1693 const DisasInsn *di)
1695 unsigned rin = extract32(insn, 16, 5);
1696 unsigned ctl = extract32(insn, 21, 5);
1697 TCGv tmp;
1699 if (ctl == 11) { /* SAR */
1700 tmp = tcg_temp_new();
1701 tcg_gen_andi_tl(tmp, load_gpr(ctx, rin), TARGET_LONG_BITS - 1);
1702 save_or_nullify(ctx, cpu_sar, tmp);
1703 tcg_temp_free(tmp);
1704 } else {
1705 /* All other control registers are privileged or read-only. */
1706 return gen_illegal(ctx);
1709 cond_free(&ctx->null_cond);
1710 return DISAS_NEXT;
1713 static DisasJumpType trans_mtsarcm(DisasContext *ctx, uint32_t insn,
1714 const DisasInsn *di)
1716 unsigned rin = extract32(insn, 16, 5);
1717 TCGv tmp = tcg_temp_new();
1719 tcg_gen_not_tl(tmp, load_gpr(ctx, rin));
1720 tcg_gen_andi_tl(tmp, tmp, TARGET_LONG_BITS - 1);
1721 save_or_nullify(ctx, cpu_sar, tmp);
1722 tcg_temp_free(tmp);
1724 cond_free(&ctx->null_cond);
1725 return DISAS_NEXT;
1728 static DisasJumpType trans_ldsid(DisasContext *ctx, uint32_t insn,
1729 const DisasInsn *di)
1731 unsigned rt = extract32(insn, 0, 5);
1732 TCGv dest = dest_gpr(ctx, rt);
1734 /* Since we don't implement space registers, this returns zero. */
1735 tcg_gen_movi_tl(dest, 0);
1736 save_gpr(ctx, rt, dest);
1738 cond_free(&ctx->null_cond);
1739 return DISAS_NEXT;
1742 static const DisasInsn table_system[] = {
1743 { 0x00000000u, 0xfc001fe0u, trans_break },
1744 /* We don't implement space register, so MTSP is a nop. */
1745 { 0x00001820u, 0xffe01fffu, trans_nop },
1746 { 0x00001840u, 0xfc00ffffu, trans_mtctl },
1747 { 0x016018c0u, 0xffe0ffffu, trans_mtsarcm },
1748 { 0x000014a0u, 0xffffffe0u, trans_mfia },
1749 { 0x000004a0u, 0xffff1fe0u, trans_mfsp },
1750 { 0x000008a0u, 0xfc1fffe0u, trans_mfctl },
1751 { 0x00000400u, 0xffffffffu, trans_sync },
1752 { 0x000010a0u, 0xfc1f3fe0u, trans_ldsid },
1755 static DisasJumpType trans_base_idx_mod(DisasContext *ctx, uint32_t insn,
1756 const DisasInsn *di)
1758 unsigned rb = extract32(insn, 21, 5);
1759 unsigned rx = extract32(insn, 16, 5);
1760 TCGv dest = dest_gpr(ctx, rb);
1761 TCGv src1 = load_gpr(ctx, rb);
1762 TCGv src2 = load_gpr(ctx, rx);
1764 /* The only thing we need to do is the base register modification. */
1765 tcg_gen_add_tl(dest, src1, src2);
1766 save_gpr(ctx, rb, dest);
1768 cond_free(&ctx->null_cond);
1769 return DISAS_NEXT;
1772 static DisasJumpType trans_probe(DisasContext *ctx, uint32_t insn,
1773 const DisasInsn *di)
1775 unsigned rt = extract32(insn, 0, 5);
1776 unsigned rb = extract32(insn, 21, 5);
1777 unsigned is_write = extract32(insn, 6, 1);
1778 TCGv dest;
1780 nullify_over(ctx);
1782 /* ??? Do something with priv level operand. */
1783 dest = dest_gpr(ctx, rt);
1784 if (is_write) {
1785 gen_helper_probe_w(dest, load_gpr(ctx, rb));
1786 } else {
1787 gen_helper_probe_r(dest, load_gpr(ctx, rb));
1789 save_gpr(ctx, rt, dest);
1790 return nullify_end(ctx, DISAS_NEXT);
1793 static const DisasInsn table_mem_mgmt[] = {
1794 { 0x04003280u, 0xfc003fffu, trans_nop }, /* fdc, disp */
1795 { 0x04001280u, 0xfc003fffu, trans_nop }, /* fdc, index */
1796 { 0x040012a0u, 0xfc003fffu, trans_base_idx_mod }, /* fdc, index, base mod */
1797 { 0x040012c0u, 0xfc003fffu, trans_nop }, /* fdce */
1798 { 0x040012e0u, 0xfc003fffu, trans_base_idx_mod }, /* fdce, base mod */
1799 { 0x04000280u, 0xfc001fffu, trans_nop }, /* fic 0a */
1800 { 0x040002a0u, 0xfc001fffu, trans_base_idx_mod }, /* fic 0a, base mod */
1801 { 0x040013c0u, 0xfc003fffu, trans_nop }, /* fic 4f */
1802 { 0x040013e0u, 0xfc003fffu, trans_base_idx_mod }, /* fic 4f, base mod */
1803 { 0x040002c0u, 0xfc001fffu, trans_nop }, /* fice */
1804 { 0x040002e0u, 0xfc001fffu, trans_base_idx_mod }, /* fice, base mod */
1805 { 0x04002700u, 0xfc003fffu, trans_nop }, /* pdc */
1806 { 0x04002720u, 0xfc003fffu, trans_base_idx_mod }, /* pdc, base mod */
1807 { 0x04001180u, 0xfc003fa0u, trans_probe }, /* probe */
1808 { 0x04003180u, 0xfc003fa0u, trans_probe }, /* probei */
1811 static DisasJumpType trans_add(DisasContext *ctx, uint32_t insn,
1812 const DisasInsn *di)
1814 unsigned r2 = extract32(insn, 21, 5);
1815 unsigned r1 = extract32(insn, 16, 5);
1816 unsigned cf = extract32(insn, 12, 4);
1817 unsigned ext = extract32(insn, 8, 4);
1818 unsigned shift = extract32(insn, 6, 2);
1819 unsigned rt = extract32(insn, 0, 5);
1820 TCGv tcg_r1, tcg_r2;
1821 bool is_c = false;
1822 bool is_l = false;
1823 bool is_tc = false;
1824 bool is_tsv = false;
1825 DisasJumpType ret;
1827 switch (ext) {
1828 case 0x6: /* ADD, SHLADD */
1829 break;
1830 case 0xa: /* ADD,L, SHLADD,L */
1831 is_l = true;
1832 break;
1833 case 0xe: /* ADD,TSV, SHLADD,TSV (1) */
1834 is_tsv = true;
1835 break;
1836 case 0x7: /* ADD,C */
1837 is_c = true;
1838 break;
1839 case 0xf: /* ADD,C,TSV */
1840 is_c = is_tsv = true;
1841 break;
1842 default:
1843 return gen_illegal(ctx);
1846 if (cf) {
1847 nullify_over(ctx);
1849 tcg_r1 = load_gpr(ctx, r1);
1850 tcg_r2 = load_gpr(ctx, r2);
1851 ret = do_add(ctx, rt, tcg_r1, tcg_r2, shift, is_l, is_tsv, is_tc, is_c, cf);
1852 return nullify_end(ctx, ret);
1855 static DisasJumpType trans_sub(DisasContext *ctx, uint32_t insn,
1856 const DisasInsn *di)
1858 unsigned r2 = extract32(insn, 21, 5);
1859 unsigned r1 = extract32(insn, 16, 5);
1860 unsigned cf = extract32(insn, 12, 4);
1861 unsigned ext = extract32(insn, 6, 6);
1862 unsigned rt = extract32(insn, 0, 5);
1863 TCGv tcg_r1, tcg_r2;
1864 bool is_b = false;
1865 bool is_tc = false;
1866 bool is_tsv = false;
1867 DisasJumpType ret;
1869 switch (ext) {
1870 case 0x10: /* SUB */
1871 break;
1872 case 0x30: /* SUB,TSV */
1873 is_tsv = true;
1874 break;
1875 case 0x14: /* SUB,B */
1876 is_b = true;
1877 break;
1878 case 0x34: /* SUB,B,TSV */
1879 is_b = is_tsv = true;
1880 break;
1881 case 0x13: /* SUB,TC */
1882 is_tc = true;
1883 break;
1884 case 0x33: /* SUB,TSV,TC */
1885 is_tc = is_tsv = true;
1886 break;
1887 default:
1888 return gen_illegal(ctx);
1891 if (cf) {
1892 nullify_over(ctx);
1894 tcg_r1 = load_gpr(ctx, r1);
1895 tcg_r2 = load_gpr(ctx, r2);
1896 ret = do_sub(ctx, rt, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, cf);
1897 return nullify_end(ctx, ret);
1900 static DisasJumpType trans_log(DisasContext *ctx, uint32_t insn,
1901 const DisasInsn *di)
1903 unsigned r2 = extract32(insn, 21, 5);
1904 unsigned r1 = extract32(insn, 16, 5);
1905 unsigned cf = extract32(insn, 12, 4);
1906 unsigned rt = extract32(insn, 0, 5);
1907 TCGv tcg_r1, tcg_r2;
1908 DisasJumpType ret;
1910 if (cf) {
1911 nullify_over(ctx);
1913 tcg_r1 = load_gpr(ctx, r1);
1914 tcg_r2 = load_gpr(ctx, r2);
1915 ret = do_log(ctx, rt, tcg_r1, tcg_r2, cf, di->f.ttt);
1916 return nullify_end(ctx, ret);
1919 /* OR r,0,t -> COPY (according to gas) */
1920 static DisasJumpType trans_copy(DisasContext *ctx, uint32_t insn,
1921 const DisasInsn *di)
1923 unsigned r1 = extract32(insn, 16, 5);
1924 unsigned rt = extract32(insn, 0, 5);
1926 if (r1 == 0) {
1927 TCGv dest = dest_gpr(ctx, rt);
1928 tcg_gen_movi_tl(dest, 0);
1929 save_gpr(ctx, rt, dest);
1930 } else {
1931 save_gpr(ctx, rt, cpu_gr[r1]);
1933 cond_free(&ctx->null_cond);
1934 return DISAS_NEXT;
1937 static DisasJumpType trans_cmpclr(DisasContext *ctx, uint32_t insn,
1938 const DisasInsn *di)
1940 unsigned r2 = extract32(insn, 21, 5);
1941 unsigned r1 = extract32(insn, 16, 5);
1942 unsigned cf = extract32(insn, 12, 4);
1943 unsigned rt = extract32(insn, 0, 5);
1944 TCGv tcg_r1, tcg_r2;
1945 DisasJumpType ret;
1947 if (cf) {
1948 nullify_over(ctx);
1950 tcg_r1 = load_gpr(ctx, r1);
1951 tcg_r2 = load_gpr(ctx, r2);
1952 ret = do_cmpclr(ctx, rt, tcg_r1, tcg_r2, cf);
1953 return nullify_end(ctx, ret);
1956 static DisasJumpType trans_uxor(DisasContext *ctx, uint32_t insn,
1957 const DisasInsn *di)
1959 unsigned r2 = extract32(insn, 21, 5);
1960 unsigned r1 = extract32(insn, 16, 5);
1961 unsigned cf = extract32(insn, 12, 4);
1962 unsigned rt = extract32(insn, 0, 5);
1963 TCGv tcg_r1, tcg_r2;
1964 DisasJumpType ret;
1966 if (cf) {
1967 nullify_over(ctx);
1969 tcg_r1 = load_gpr(ctx, r1);
1970 tcg_r2 = load_gpr(ctx, r2);
1971 ret = do_unit(ctx, rt, tcg_r1, tcg_r2, cf, false, tcg_gen_xor_tl);
1972 return nullify_end(ctx, ret);
1975 static DisasJumpType trans_uaddcm(DisasContext *ctx, uint32_t insn,
1976 const DisasInsn *di)
1978 unsigned r2 = extract32(insn, 21, 5);
1979 unsigned r1 = extract32(insn, 16, 5);
1980 unsigned cf = extract32(insn, 12, 4);
1981 unsigned is_tc = extract32(insn, 6, 1);
1982 unsigned rt = extract32(insn, 0, 5);
1983 TCGv tcg_r1, tcg_r2, tmp;
1984 DisasJumpType ret;
1986 if (cf) {
1987 nullify_over(ctx);
1989 tcg_r1 = load_gpr(ctx, r1);
1990 tcg_r2 = load_gpr(ctx, r2);
1991 tmp = get_temp(ctx);
1992 tcg_gen_not_tl(tmp, tcg_r2);
1993 ret = do_unit(ctx, rt, tcg_r1, tmp, cf, is_tc, tcg_gen_add_tl);
1994 return nullify_end(ctx, ret);
1997 static DisasJumpType trans_dcor(DisasContext *ctx, uint32_t insn,
1998 const DisasInsn *di)
2000 unsigned r2 = extract32(insn, 21, 5);
2001 unsigned cf = extract32(insn, 12, 4);
2002 unsigned is_i = extract32(insn, 6, 1);
2003 unsigned rt = extract32(insn, 0, 5);
2004 TCGv tmp;
2005 DisasJumpType ret;
2007 nullify_over(ctx);
2009 tmp = get_temp(ctx);
2010 tcg_gen_shri_tl(tmp, cpu_psw_cb, 3);
2011 if (!is_i) {
2012 tcg_gen_not_tl(tmp, tmp);
2014 tcg_gen_andi_tl(tmp, tmp, 0x11111111);
2015 tcg_gen_muli_tl(tmp, tmp, 6);
2016 ret = do_unit(ctx, rt, tmp, load_gpr(ctx, r2), cf, false,
2017 is_i ? tcg_gen_add_tl : tcg_gen_sub_tl);
2019 return nullify_end(ctx, ret);
2022 static DisasJumpType trans_ds(DisasContext *ctx, uint32_t insn,
2023 const DisasInsn *di)
2025 unsigned r2 = extract32(insn, 21, 5);
2026 unsigned r1 = extract32(insn, 16, 5);
2027 unsigned cf = extract32(insn, 12, 4);
2028 unsigned rt = extract32(insn, 0, 5);
2029 TCGv dest, add1, add2, addc, zero, in1, in2;
2031 nullify_over(ctx);
2033 in1 = load_gpr(ctx, r1);
2034 in2 = load_gpr(ctx, r2);
2036 add1 = tcg_temp_new();
2037 add2 = tcg_temp_new();
2038 addc = tcg_temp_new();
2039 dest = tcg_temp_new();
2040 zero = tcg_const_tl(0);
2042 /* Form R1 << 1 | PSW[CB]{8}. */
2043 tcg_gen_add_tl(add1, in1, in1);
2044 tcg_gen_add_tl(add1, add1, cpu_psw_cb_msb);
2046 /* Add or subtract R2, depending on PSW[V]. Proper computation of
2047 carry{8} requires that we subtract via + ~R2 + 1, as described in
2048 the manual. By extracting and masking V, we can produce the
2049 proper inputs to the addition without movcond. */
2050 tcg_gen_sari_tl(addc, cpu_psw_v, TARGET_LONG_BITS - 1);
2051 tcg_gen_xor_tl(add2, in2, addc);
2052 tcg_gen_andi_tl(addc, addc, 1);
2053 /* ??? This is only correct for 32-bit. */
2054 tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
2055 tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
2057 tcg_temp_free(addc);
2058 tcg_temp_free(zero);
2060 /* Write back the result register. */
2061 save_gpr(ctx, rt, dest);
2063 /* Write back PSW[CB]. */
2064 tcg_gen_xor_tl(cpu_psw_cb, add1, add2);
2065 tcg_gen_xor_tl(cpu_psw_cb, cpu_psw_cb, dest);
2067 /* Write back PSW[V] for the division step. */
2068 tcg_gen_neg_tl(cpu_psw_v, cpu_psw_cb_msb);
2069 tcg_gen_xor_tl(cpu_psw_v, cpu_psw_v, in2);
2071 /* Install the new nullification. */
2072 if (cf) {
2073 TCGv sv;
2074 TCGV_UNUSED(sv);
2075 if (cf >> 1 == 6) {
2076 /* ??? The lshift is supposed to contribute to overflow. */
2077 sv = do_add_sv(ctx, dest, add1, add2);
2079 ctx->null_cond = do_cond(cf, dest, cpu_psw_cb_msb, sv);
2082 tcg_temp_free(add1);
2083 tcg_temp_free(add2);
2084 tcg_temp_free(dest);
2086 return nullify_end(ctx, DISAS_NEXT);
2089 static const DisasInsn table_arith_log[] = {
2090 { 0x08000240u, 0xfc00ffffu, trans_nop }, /* or x,y,0 */
2091 { 0x08000240u, 0xffe0ffe0u, trans_copy }, /* or x,0,t */
2092 { 0x08000000u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_andc_tl },
2093 { 0x08000200u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_and_tl },
2094 { 0x08000240u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_or_tl },
2095 { 0x08000280u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_xor_tl },
2096 { 0x08000880u, 0xfc000fe0u, trans_cmpclr },
2097 { 0x08000380u, 0xfc000fe0u, trans_uxor },
2098 { 0x08000980u, 0xfc000fa0u, trans_uaddcm },
2099 { 0x08000b80u, 0xfc1f0fa0u, trans_dcor },
2100 { 0x08000440u, 0xfc000fe0u, trans_ds },
2101 { 0x08000700u, 0xfc0007e0u, trans_add }, /* add */
2102 { 0x08000400u, 0xfc0006e0u, trans_sub }, /* sub; sub,b; sub,tsv */
2103 { 0x080004c0u, 0xfc0007e0u, trans_sub }, /* sub,tc; sub,tsv,tc */
2104 { 0x08000200u, 0xfc000320u, trans_add }, /* shladd */
2107 static DisasJumpType trans_addi(DisasContext *ctx, uint32_t insn)
2109 target_long im = low_sextract(insn, 0, 11);
2110 unsigned e1 = extract32(insn, 11, 1);
2111 unsigned cf = extract32(insn, 12, 4);
2112 unsigned rt = extract32(insn, 16, 5);
2113 unsigned r2 = extract32(insn, 21, 5);
2114 unsigned o1 = extract32(insn, 26, 1);
2115 TCGv tcg_im, tcg_r2;
2116 DisasJumpType ret;
2118 if (cf) {
2119 nullify_over(ctx);
2122 tcg_im = load_const(ctx, im);
2123 tcg_r2 = load_gpr(ctx, r2);
2124 ret = do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf);
2126 return nullify_end(ctx, ret);
2129 static DisasJumpType trans_subi(DisasContext *ctx, uint32_t insn)
2131 target_long im = low_sextract(insn, 0, 11);
2132 unsigned e1 = extract32(insn, 11, 1);
2133 unsigned cf = extract32(insn, 12, 4);
2134 unsigned rt = extract32(insn, 16, 5);
2135 unsigned r2 = extract32(insn, 21, 5);
2136 TCGv tcg_im, tcg_r2;
2137 DisasJumpType ret;
2139 if (cf) {
2140 nullify_over(ctx);
2143 tcg_im = load_const(ctx, im);
2144 tcg_r2 = load_gpr(ctx, r2);
2145 ret = do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf);
2147 return nullify_end(ctx, ret);
2150 static DisasJumpType trans_cmpiclr(DisasContext *ctx, uint32_t insn)
2152 target_long im = low_sextract(insn, 0, 11);
2153 unsigned cf = extract32(insn, 12, 4);
2154 unsigned rt = extract32(insn, 16, 5);
2155 unsigned r2 = extract32(insn, 21, 5);
2156 TCGv tcg_im, tcg_r2;
2157 DisasJumpType ret;
2159 if (cf) {
2160 nullify_over(ctx);
2163 tcg_im = load_const(ctx, im);
2164 tcg_r2 = load_gpr(ctx, r2);
2165 ret = do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf);
2167 return nullify_end(ctx, ret);
2170 static DisasJumpType trans_ld_idx_i(DisasContext *ctx, uint32_t insn,
2171 const DisasInsn *di)
2173 unsigned rt = extract32(insn, 0, 5);
2174 unsigned m = extract32(insn, 5, 1);
2175 unsigned sz = extract32(insn, 6, 2);
2176 unsigned a = extract32(insn, 13, 1);
2177 int disp = low_sextract(insn, 16, 5);
2178 unsigned rb = extract32(insn, 21, 5);
2179 int modify = (m ? (a ? -1 : 1) : 0);
2180 TCGMemOp mop = MO_TE | sz;
2182 return do_load(ctx, rt, rb, 0, 0, disp, modify, mop);
2185 static DisasJumpType trans_ld_idx_x(DisasContext *ctx, uint32_t insn,
2186 const DisasInsn *di)
2188 unsigned rt = extract32(insn, 0, 5);
2189 unsigned m = extract32(insn, 5, 1);
2190 unsigned sz = extract32(insn, 6, 2);
2191 unsigned u = extract32(insn, 13, 1);
2192 unsigned rx = extract32(insn, 16, 5);
2193 unsigned rb = extract32(insn, 21, 5);
2194 TCGMemOp mop = MO_TE | sz;
2196 return do_load(ctx, rt, rb, rx, u ? sz : 0, 0, m, mop);
2199 static DisasJumpType trans_st_idx_i(DisasContext *ctx, uint32_t insn,
2200 const DisasInsn *di)
2202 int disp = low_sextract(insn, 0, 5);
2203 unsigned m = extract32(insn, 5, 1);
2204 unsigned sz = extract32(insn, 6, 2);
2205 unsigned a = extract32(insn, 13, 1);
2206 unsigned rr = extract32(insn, 16, 5);
2207 unsigned rb = extract32(insn, 21, 5);
2208 int modify = (m ? (a ? -1 : 1) : 0);
2209 TCGMemOp mop = MO_TE | sz;
2211 return do_store(ctx, rr, rb, disp, modify, mop);
2214 static DisasJumpType trans_ldcw(DisasContext *ctx, uint32_t insn,
2215 const DisasInsn *di)
2217 unsigned rt = extract32(insn, 0, 5);
2218 unsigned m = extract32(insn, 5, 1);
2219 unsigned i = extract32(insn, 12, 1);
2220 unsigned au = extract32(insn, 13, 1);
2221 unsigned rx = extract32(insn, 16, 5);
2222 unsigned rb = extract32(insn, 21, 5);
2223 TCGMemOp mop = MO_TEUL | MO_ALIGN_16;
2224 TCGv zero, addr, base, dest;
2225 int modify, disp = 0, scale = 0;
2227 nullify_over(ctx);
2229 /* ??? Share more code with do_load and do_load_{32,64}. */
2231 if (i) {
2232 modify = (m ? (au ? -1 : 1) : 0);
2233 disp = low_sextract(rx, 0, 5);
2234 rx = 0;
2235 } else {
2236 modify = m;
2237 if (au) {
2238 scale = mop & MO_SIZE;
2241 if (modify) {
2242 /* Base register modification. Make sure if RT == RB, we see
2243 the result of the load. */
2244 dest = get_temp(ctx);
2245 } else {
2246 dest = dest_gpr(ctx, rt);
2249 addr = tcg_temp_new();
2250 base = load_gpr(ctx, rb);
2251 if (rx) {
2252 tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
2253 tcg_gen_add_tl(addr, addr, base);
2254 } else {
2255 tcg_gen_addi_tl(addr, base, disp);
2258 zero = tcg_const_tl(0);
2259 tcg_gen_atomic_xchg_tl(dest, (modify <= 0 ? addr : base),
2260 zero, MMU_USER_IDX, mop);
2261 if (modify) {
2262 save_gpr(ctx, rb, addr);
2264 save_gpr(ctx, rt, dest);
2266 return nullify_end(ctx, DISAS_NEXT);
2269 static DisasJumpType trans_stby(DisasContext *ctx, uint32_t insn,
2270 const DisasInsn *di)
2272 target_long disp = low_sextract(insn, 0, 5);
2273 unsigned m = extract32(insn, 5, 1);
2274 unsigned a = extract32(insn, 13, 1);
2275 unsigned rt = extract32(insn, 16, 5);
2276 unsigned rb = extract32(insn, 21, 5);
2277 TCGv addr, val;
2279 nullify_over(ctx);
2281 addr = tcg_temp_new();
2282 if (m || disp == 0) {
2283 tcg_gen_mov_tl(addr, load_gpr(ctx, rb));
2284 } else {
2285 tcg_gen_addi_tl(addr, load_gpr(ctx, rb), disp);
2287 val = load_gpr(ctx, rt);
2289 if (a) {
2290 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
2291 gen_helper_stby_e_parallel(cpu_env, addr, val);
2292 } else {
2293 gen_helper_stby_e(cpu_env, addr, val);
2295 } else {
2296 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
2297 gen_helper_stby_b_parallel(cpu_env, addr, val);
2298 } else {
2299 gen_helper_stby_b(cpu_env, addr, val);
2303 if (m) {
2304 tcg_gen_addi_tl(addr, addr, disp);
2305 tcg_gen_andi_tl(addr, addr, ~3);
2306 save_gpr(ctx, rb, addr);
2308 tcg_temp_free(addr);
2310 return nullify_end(ctx, DISAS_NEXT);
2313 static const DisasInsn table_index_mem[] = {
2314 { 0x0c001000u, 0xfc001300, trans_ld_idx_i }, /* LD[BHWD], im */
2315 { 0x0c000000u, 0xfc001300, trans_ld_idx_x }, /* LD[BHWD], rx */
2316 { 0x0c001200u, 0xfc001300, trans_st_idx_i }, /* ST[BHWD] */
2317 { 0x0c0001c0u, 0xfc0003c0, trans_ldcw },
2318 { 0x0c001300u, 0xfc0013c0, trans_stby },
2321 static DisasJumpType trans_ldil(DisasContext *ctx, uint32_t insn)
2323 unsigned rt = extract32(insn, 21, 5);
2324 target_long i = assemble_21(insn);
2325 TCGv tcg_rt = dest_gpr(ctx, rt);
2327 tcg_gen_movi_tl(tcg_rt, i);
2328 save_gpr(ctx, rt, tcg_rt);
2329 cond_free(&ctx->null_cond);
2331 return DISAS_NEXT;
2334 static DisasJumpType trans_addil(DisasContext *ctx, uint32_t insn)
2336 unsigned rt = extract32(insn, 21, 5);
2337 target_long i = assemble_21(insn);
2338 TCGv tcg_rt = load_gpr(ctx, rt);
2339 TCGv tcg_r1 = dest_gpr(ctx, 1);
2341 tcg_gen_addi_tl(tcg_r1, tcg_rt, i);
2342 save_gpr(ctx, 1, tcg_r1);
2343 cond_free(&ctx->null_cond);
2345 return DISAS_NEXT;
2348 static DisasJumpType trans_ldo(DisasContext *ctx, uint32_t insn)
2350 unsigned rb = extract32(insn, 21, 5);
2351 unsigned rt = extract32(insn, 16, 5);
2352 target_long i = assemble_16(insn);
2353 TCGv tcg_rt = dest_gpr(ctx, rt);
2355 /* Special case rb == 0, for the LDI pseudo-op.
2356 The COPY pseudo-op is handled for free within tcg_gen_addi_tl. */
2357 if (rb == 0) {
2358 tcg_gen_movi_tl(tcg_rt, i);
2359 } else {
2360 tcg_gen_addi_tl(tcg_rt, cpu_gr[rb], i);
2362 save_gpr(ctx, rt, tcg_rt);
2363 cond_free(&ctx->null_cond);
2365 return DISAS_NEXT;
2368 static DisasJumpType trans_load(DisasContext *ctx, uint32_t insn,
2369 bool is_mod, TCGMemOp mop)
2371 unsigned rb = extract32(insn, 21, 5);
2372 unsigned rt = extract32(insn, 16, 5);
2373 target_long i = assemble_16(insn);
2375 return do_load(ctx, rt, rb, 0, 0, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
2378 static DisasJumpType trans_load_w(DisasContext *ctx, uint32_t insn)
2380 unsigned rb = extract32(insn, 21, 5);
2381 unsigned rt = extract32(insn, 16, 5);
2382 target_long i = assemble_16a(insn);
2383 unsigned ext2 = extract32(insn, 1, 2);
2385 switch (ext2) {
2386 case 0:
2387 case 1:
2388 /* FLDW without modification. */
2389 return do_floadw(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
2390 case 2:
2391 /* LDW with modification. Note that the sign of I selects
2392 post-dec vs pre-inc. */
2393 return do_load(ctx, rt, rb, 0, 0, i, (i < 0 ? 1 : -1), MO_TEUL);
2394 default:
2395 return gen_illegal(ctx);
2399 static DisasJumpType trans_fload_mod(DisasContext *ctx, uint32_t insn)
2401 target_long i = assemble_16a(insn);
2402 unsigned t1 = extract32(insn, 1, 1);
2403 unsigned a = extract32(insn, 2, 1);
2404 unsigned t0 = extract32(insn, 16, 5);
2405 unsigned rb = extract32(insn, 21, 5);
2407 /* FLDW with modification. */
2408 return do_floadw(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
2411 static DisasJumpType trans_store(DisasContext *ctx, uint32_t insn,
2412 bool is_mod, TCGMemOp mop)
2414 unsigned rb = extract32(insn, 21, 5);
2415 unsigned rt = extract32(insn, 16, 5);
2416 target_long i = assemble_16(insn);
2418 return do_store(ctx, rt, rb, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
2421 static DisasJumpType trans_store_w(DisasContext *ctx, uint32_t insn)
2423 unsigned rb = extract32(insn, 21, 5);
2424 unsigned rt = extract32(insn, 16, 5);
2425 target_long i = assemble_16a(insn);
2426 unsigned ext2 = extract32(insn, 1, 2);
2428 switch (ext2) {
2429 case 0:
2430 case 1:
2431 /* FSTW without modification. */
2432 return do_fstorew(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
2433 case 2:
2434 /* LDW with modification. */
2435 return do_store(ctx, rt, rb, i, (i < 0 ? 1 : -1), MO_TEUL);
2436 default:
2437 return gen_illegal(ctx);
2441 static DisasJumpType trans_fstore_mod(DisasContext *ctx, uint32_t insn)
2443 target_long i = assemble_16a(insn);
2444 unsigned t1 = extract32(insn, 1, 1);
2445 unsigned a = extract32(insn, 2, 1);
2446 unsigned t0 = extract32(insn, 16, 5);
2447 unsigned rb = extract32(insn, 21, 5);
2449 /* FSTW with modification. */
2450 return do_fstorew(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
2453 static DisasJumpType trans_copr_w(DisasContext *ctx, uint32_t insn)
2455 unsigned t0 = extract32(insn, 0, 5);
2456 unsigned m = extract32(insn, 5, 1);
2457 unsigned t1 = extract32(insn, 6, 1);
2458 unsigned ext3 = extract32(insn, 7, 3);
2459 /* unsigned cc = extract32(insn, 10, 2); */
2460 unsigned i = extract32(insn, 12, 1);
2461 unsigned ua = extract32(insn, 13, 1);
2462 unsigned rx = extract32(insn, 16, 5);
2463 unsigned rb = extract32(insn, 21, 5);
2464 unsigned rt = t1 * 32 + t0;
2465 int modify = (m ? (ua ? -1 : 1) : 0);
2466 int disp, scale;
2468 if (i == 0) {
2469 scale = (ua ? 2 : 0);
2470 disp = 0;
2471 modify = m;
2472 } else {
2473 disp = low_sextract(rx, 0, 5);
2474 scale = 0;
2475 rx = 0;
2476 modify = (m ? (ua ? -1 : 1) : 0);
2479 switch (ext3) {
2480 case 0: /* FLDW */
2481 return do_floadw(ctx, rt, rb, rx, scale, disp, modify);
2482 case 4: /* FSTW */
2483 return do_fstorew(ctx, rt, rb, rx, scale, disp, modify);
2485 return gen_illegal(ctx);
2488 static DisasJumpType trans_copr_dw(DisasContext *ctx, uint32_t insn)
2490 unsigned rt = extract32(insn, 0, 5);
2491 unsigned m = extract32(insn, 5, 1);
2492 unsigned ext4 = extract32(insn, 6, 4);
2493 /* unsigned cc = extract32(insn, 10, 2); */
2494 unsigned i = extract32(insn, 12, 1);
2495 unsigned ua = extract32(insn, 13, 1);
2496 unsigned rx = extract32(insn, 16, 5);
2497 unsigned rb = extract32(insn, 21, 5);
2498 int modify = (m ? (ua ? -1 : 1) : 0);
2499 int disp, scale;
2501 if (i == 0) {
2502 scale = (ua ? 3 : 0);
2503 disp = 0;
2504 modify = m;
2505 } else {
2506 disp = low_sextract(rx, 0, 5);
2507 scale = 0;
2508 rx = 0;
2509 modify = (m ? (ua ? -1 : 1) : 0);
2512 switch (ext4) {
2513 case 0: /* FLDD */
2514 return do_floadd(ctx, rt, rb, rx, scale, disp, modify);
2515 case 8: /* FSTD */
2516 return do_fstored(ctx, rt, rb, rx, scale, disp, modify);
2517 default:
2518 return gen_illegal(ctx);
2522 static DisasJumpType trans_cmpb(DisasContext *ctx, uint32_t insn,
2523 bool is_true, bool is_imm, bool is_dw)
2525 target_long disp = assemble_12(insn) * 4;
2526 unsigned n = extract32(insn, 1, 1);
2527 unsigned c = extract32(insn, 13, 3);
2528 unsigned r = extract32(insn, 21, 5);
2529 unsigned cf = c * 2 + !is_true;
2530 TCGv dest, in1, in2, sv;
2531 DisasCond cond;
2533 nullify_over(ctx);
2535 if (is_imm) {
2536 in1 = load_const(ctx, low_sextract(insn, 16, 5));
2537 } else {
2538 in1 = load_gpr(ctx, extract32(insn, 16, 5));
2540 in2 = load_gpr(ctx, r);
2541 dest = get_temp(ctx);
2543 tcg_gen_sub_tl(dest, in1, in2);
2545 TCGV_UNUSED(sv);
2546 if (c == 6) {
2547 sv = do_sub_sv(ctx, dest, in1, in2);
2550 cond = do_sub_cond(cf, dest, in1, in2, sv);
2551 return do_cbranch(ctx, disp, n, &cond);
2554 static DisasJumpType trans_addb(DisasContext *ctx, uint32_t insn,
2555 bool is_true, bool is_imm)
2557 target_long disp = assemble_12(insn) * 4;
2558 unsigned n = extract32(insn, 1, 1);
2559 unsigned c = extract32(insn, 13, 3);
2560 unsigned r = extract32(insn, 21, 5);
2561 unsigned cf = c * 2 + !is_true;
2562 TCGv dest, in1, in2, sv, cb_msb;
2563 DisasCond cond;
2565 nullify_over(ctx);
2567 if (is_imm) {
2568 in1 = load_const(ctx, low_sextract(insn, 16, 5));
2569 } else {
2570 in1 = load_gpr(ctx, extract32(insn, 16, 5));
2572 in2 = load_gpr(ctx, r);
2573 dest = dest_gpr(ctx, r);
2574 TCGV_UNUSED(sv);
2575 TCGV_UNUSED(cb_msb);
2577 switch (c) {
2578 default:
2579 tcg_gen_add_tl(dest, in1, in2);
2580 break;
2581 case 4: case 5:
2582 cb_msb = get_temp(ctx);
2583 tcg_gen_movi_tl(cb_msb, 0);
2584 tcg_gen_add2_tl(dest, cb_msb, in1, cb_msb, in2, cb_msb);
2585 break;
2586 case 6:
2587 tcg_gen_add_tl(dest, in1, in2);
2588 sv = do_add_sv(ctx, dest, in1, in2);
2589 break;
2592 cond = do_cond(cf, dest, cb_msb, sv);
2593 return do_cbranch(ctx, disp, n, &cond);
2596 static DisasJumpType trans_bb(DisasContext *ctx, uint32_t insn)
2598 target_long disp = assemble_12(insn) * 4;
2599 unsigned n = extract32(insn, 1, 1);
2600 unsigned c = extract32(insn, 15, 1);
2601 unsigned r = extract32(insn, 16, 5);
2602 unsigned p = extract32(insn, 21, 5);
2603 unsigned i = extract32(insn, 26, 1);
2604 TCGv tmp, tcg_r;
2605 DisasCond cond;
2607 nullify_over(ctx);
2609 tmp = tcg_temp_new();
2610 tcg_r = load_gpr(ctx, r);
2611 if (i) {
2612 tcg_gen_shli_tl(tmp, tcg_r, p);
2613 } else {
2614 tcg_gen_shl_tl(tmp, tcg_r, cpu_sar);
2617 cond = cond_make_0(c ? TCG_COND_GE : TCG_COND_LT, tmp);
2618 tcg_temp_free(tmp);
2619 return do_cbranch(ctx, disp, n, &cond);
2622 static DisasJumpType trans_movb(DisasContext *ctx, uint32_t insn, bool is_imm)
2624 target_long disp = assemble_12(insn) * 4;
2625 unsigned n = extract32(insn, 1, 1);
2626 unsigned c = extract32(insn, 13, 3);
2627 unsigned t = extract32(insn, 16, 5);
2628 unsigned r = extract32(insn, 21, 5);
2629 TCGv dest;
2630 DisasCond cond;
2632 nullify_over(ctx);
2634 dest = dest_gpr(ctx, r);
2635 if (is_imm) {
2636 tcg_gen_movi_tl(dest, low_sextract(t, 0, 5));
2637 } else if (t == 0) {
2638 tcg_gen_movi_tl(dest, 0);
2639 } else {
2640 tcg_gen_mov_tl(dest, cpu_gr[t]);
2643 cond = do_sed_cond(c, dest);
2644 return do_cbranch(ctx, disp, n, &cond);
2647 static DisasJumpType trans_shrpw_sar(DisasContext *ctx, uint32_t insn,
2648 const DisasInsn *di)
2650 unsigned rt = extract32(insn, 0, 5);
2651 unsigned c = extract32(insn, 13, 3);
2652 unsigned r1 = extract32(insn, 16, 5);
2653 unsigned r2 = extract32(insn, 21, 5);
2654 TCGv dest;
2656 if (c) {
2657 nullify_over(ctx);
2660 dest = dest_gpr(ctx, rt);
2661 if (r1 == 0) {
2662 tcg_gen_ext32u_tl(dest, load_gpr(ctx, r2));
2663 tcg_gen_shr_tl(dest, dest, cpu_sar);
2664 } else if (r1 == r2) {
2665 TCGv_i32 t32 = tcg_temp_new_i32();
2666 tcg_gen_trunc_tl_i32(t32, load_gpr(ctx, r2));
2667 tcg_gen_rotr_i32(t32, t32, cpu_sar);
2668 tcg_gen_extu_i32_tl(dest, t32);
2669 tcg_temp_free_i32(t32);
2670 } else {
2671 TCGv_i64 t = tcg_temp_new_i64();
2672 TCGv_i64 s = tcg_temp_new_i64();
2674 tcg_gen_concat_tl_i64(t, load_gpr(ctx, r2), load_gpr(ctx, r1));
2675 tcg_gen_extu_tl_i64(s, cpu_sar);
2676 tcg_gen_shr_i64(t, t, s);
2677 tcg_gen_trunc_i64_tl(dest, t);
2679 tcg_temp_free_i64(t);
2680 tcg_temp_free_i64(s);
2682 save_gpr(ctx, rt, dest);
2684 /* Install the new nullification. */
2685 cond_free(&ctx->null_cond);
2686 if (c) {
2687 ctx->null_cond = do_sed_cond(c, dest);
2689 return nullify_end(ctx, DISAS_NEXT);
2692 static DisasJumpType trans_shrpw_imm(DisasContext *ctx, uint32_t insn,
2693 const DisasInsn *di)
2695 unsigned rt = extract32(insn, 0, 5);
2696 unsigned cpos = extract32(insn, 5, 5);
2697 unsigned c = extract32(insn, 13, 3);
2698 unsigned r1 = extract32(insn, 16, 5);
2699 unsigned r2 = extract32(insn, 21, 5);
2700 unsigned sa = 31 - cpos;
2701 TCGv dest, t2;
2703 if (c) {
2704 nullify_over(ctx);
2707 dest = dest_gpr(ctx, rt);
2708 t2 = load_gpr(ctx, r2);
2709 if (r1 == r2) {
2710 TCGv_i32 t32 = tcg_temp_new_i32();
2711 tcg_gen_trunc_tl_i32(t32, t2);
2712 tcg_gen_rotri_i32(t32, t32, sa);
2713 tcg_gen_extu_i32_tl(dest, t32);
2714 tcg_temp_free_i32(t32);
2715 } else if (r1 == 0) {
2716 tcg_gen_extract_tl(dest, t2, sa, 32 - sa);
2717 } else {
2718 TCGv t0 = tcg_temp_new();
2719 tcg_gen_extract_tl(t0, t2, sa, 32 - sa);
2720 tcg_gen_deposit_tl(dest, t0, cpu_gr[r1], 32 - sa, sa);
2721 tcg_temp_free(t0);
2723 save_gpr(ctx, rt, dest);
2725 /* Install the new nullification. */
2726 cond_free(&ctx->null_cond);
2727 if (c) {
2728 ctx->null_cond = do_sed_cond(c, dest);
2730 return nullify_end(ctx, DISAS_NEXT);
2733 static DisasJumpType trans_extrw_sar(DisasContext *ctx, uint32_t insn,
2734 const DisasInsn *di)
2736 unsigned clen = extract32(insn, 0, 5);
2737 unsigned is_se = extract32(insn, 10, 1);
2738 unsigned c = extract32(insn, 13, 3);
2739 unsigned rt = extract32(insn, 16, 5);
2740 unsigned rr = extract32(insn, 21, 5);
2741 unsigned len = 32 - clen;
2742 TCGv dest, src, tmp;
2744 if (c) {
2745 nullify_over(ctx);
2748 dest = dest_gpr(ctx, rt);
2749 src = load_gpr(ctx, rr);
2750 tmp = tcg_temp_new();
2752 /* Recall that SAR is using big-endian bit numbering. */
2753 tcg_gen_xori_tl(tmp, cpu_sar, TARGET_LONG_BITS - 1);
2754 if (is_se) {
2755 tcg_gen_sar_tl(dest, src, tmp);
2756 tcg_gen_sextract_tl(dest, dest, 0, len);
2757 } else {
2758 tcg_gen_shr_tl(dest, src, tmp);
2759 tcg_gen_extract_tl(dest, dest, 0, len);
2761 tcg_temp_free(tmp);
2762 save_gpr(ctx, rt, dest);
2764 /* Install the new nullification. */
2765 cond_free(&ctx->null_cond);
2766 if (c) {
2767 ctx->null_cond = do_sed_cond(c, dest);
2769 return nullify_end(ctx, DISAS_NEXT);
2772 static DisasJumpType trans_extrw_imm(DisasContext *ctx, uint32_t insn,
2773 const DisasInsn *di)
2775 unsigned clen = extract32(insn, 0, 5);
2776 unsigned pos = extract32(insn, 5, 5);
2777 unsigned is_se = extract32(insn, 10, 1);
2778 unsigned c = extract32(insn, 13, 3);
2779 unsigned rt = extract32(insn, 16, 5);
2780 unsigned rr = extract32(insn, 21, 5);
2781 unsigned len = 32 - clen;
2782 unsigned cpos = 31 - pos;
2783 TCGv dest, src;
2785 if (c) {
2786 nullify_over(ctx);
2789 dest = dest_gpr(ctx, rt);
2790 src = load_gpr(ctx, rr);
2791 if (is_se) {
2792 tcg_gen_sextract_tl(dest, src, cpos, len);
2793 } else {
2794 tcg_gen_extract_tl(dest, src, cpos, len);
2796 save_gpr(ctx, rt, dest);
2798 /* Install the new nullification. */
2799 cond_free(&ctx->null_cond);
2800 if (c) {
2801 ctx->null_cond = do_sed_cond(c, dest);
2803 return nullify_end(ctx, DISAS_NEXT);
2806 static const DisasInsn table_sh_ex[] = {
2807 { 0xd0000000u, 0xfc001fe0u, trans_shrpw_sar },
2808 { 0xd0000800u, 0xfc001c00u, trans_shrpw_imm },
2809 { 0xd0001000u, 0xfc001be0u, trans_extrw_sar },
2810 { 0xd0001800u, 0xfc001800u, trans_extrw_imm },
2813 static DisasJumpType trans_depw_imm_c(DisasContext *ctx, uint32_t insn,
2814 const DisasInsn *di)
2816 unsigned clen = extract32(insn, 0, 5);
2817 unsigned cpos = extract32(insn, 5, 5);
2818 unsigned nz = extract32(insn, 10, 1);
2819 unsigned c = extract32(insn, 13, 3);
2820 target_long val = low_sextract(insn, 16, 5);
2821 unsigned rt = extract32(insn, 21, 5);
2822 unsigned len = 32 - clen;
2823 target_long mask0, mask1;
2824 TCGv dest;
2826 if (c) {
2827 nullify_over(ctx);
2829 if (cpos + len > 32) {
2830 len = 32 - cpos;
2833 dest = dest_gpr(ctx, rt);
2834 mask0 = deposit64(0, cpos, len, val);
2835 mask1 = deposit64(-1, cpos, len, val);
2837 if (nz) {
2838 TCGv src = load_gpr(ctx, rt);
2839 if (mask1 != -1) {
2840 tcg_gen_andi_tl(dest, src, mask1);
2841 src = dest;
2843 tcg_gen_ori_tl(dest, src, mask0);
2844 } else {
2845 tcg_gen_movi_tl(dest, mask0);
2847 save_gpr(ctx, rt, dest);
2849 /* Install the new nullification. */
2850 cond_free(&ctx->null_cond);
2851 if (c) {
2852 ctx->null_cond = do_sed_cond(c, dest);
2854 return nullify_end(ctx, DISAS_NEXT);
2857 static DisasJumpType trans_depw_imm(DisasContext *ctx, uint32_t insn,
2858 const DisasInsn *di)
2860 unsigned clen = extract32(insn, 0, 5);
2861 unsigned cpos = extract32(insn, 5, 5);
2862 unsigned nz = extract32(insn, 10, 1);
2863 unsigned c = extract32(insn, 13, 3);
2864 unsigned rr = extract32(insn, 16, 5);
2865 unsigned rt = extract32(insn, 21, 5);
2866 unsigned rs = nz ? rt : 0;
2867 unsigned len = 32 - clen;
2868 TCGv dest, val;
2870 if (c) {
2871 nullify_over(ctx);
2873 if (cpos + len > 32) {
2874 len = 32 - cpos;
2877 dest = dest_gpr(ctx, rt);
2878 val = load_gpr(ctx, rr);
2879 if (rs == 0) {
2880 tcg_gen_deposit_z_tl(dest, val, cpos, len);
2881 } else {
2882 tcg_gen_deposit_tl(dest, cpu_gr[rs], val, cpos, len);
2884 save_gpr(ctx, rt, dest);
2886 /* Install the new nullification. */
2887 cond_free(&ctx->null_cond);
2888 if (c) {
2889 ctx->null_cond = do_sed_cond(c, dest);
2891 return nullify_end(ctx, DISAS_NEXT);
2894 static DisasJumpType trans_depw_sar(DisasContext *ctx, uint32_t insn,
2895 const DisasInsn *di)
2897 unsigned clen = extract32(insn, 0, 5);
2898 unsigned nz = extract32(insn, 10, 1);
2899 unsigned i = extract32(insn, 12, 1);
2900 unsigned c = extract32(insn, 13, 3);
2901 unsigned rt = extract32(insn, 21, 5);
2902 unsigned rs = nz ? rt : 0;
2903 unsigned len = 32 - clen;
2904 TCGv val, mask, tmp, shift, dest;
2905 unsigned msb = 1U << (len - 1);
2907 if (c) {
2908 nullify_over(ctx);
2911 if (i) {
2912 val = load_const(ctx, low_sextract(insn, 16, 5));
2913 } else {
2914 val = load_gpr(ctx, extract32(insn, 16, 5));
2916 dest = dest_gpr(ctx, rt);
2917 shift = tcg_temp_new();
2918 tmp = tcg_temp_new();
2920 /* Convert big-endian bit numbering in SAR to left-shift. */
2921 tcg_gen_xori_tl(shift, cpu_sar, TARGET_LONG_BITS - 1);
2923 mask = tcg_const_tl(msb + (msb - 1));
2924 tcg_gen_and_tl(tmp, val, mask);
2925 if (rs) {
2926 tcg_gen_shl_tl(mask, mask, shift);
2927 tcg_gen_shl_tl(tmp, tmp, shift);
2928 tcg_gen_andc_tl(dest, cpu_gr[rs], mask);
2929 tcg_gen_or_tl(dest, dest, tmp);
2930 } else {
2931 tcg_gen_shl_tl(dest, tmp, shift);
2933 tcg_temp_free(shift);
2934 tcg_temp_free(mask);
2935 tcg_temp_free(tmp);
2936 save_gpr(ctx, rt, dest);
2938 /* Install the new nullification. */
2939 cond_free(&ctx->null_cond);
2940 if (c) {
2941 ctx->null_cond = do_sed_cond(c, dest);
2943 return nullify_end(ctx, DISAS_NEXT);
2946 static const DisasInsn table_depw[] = {
2947 { 0xd4000000u, 0xfc000be0u, trans_depw_sar },
2948 { 0xd4000800u, 0xfc001800u, trans_depw_imm },
2949 { 0xd4001800u, 0xfc001800u, trans_depw_imm_c },
2952 static DisasJumpType trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
2954 unsigned n = extract32(insn, 1, 1);
2955 unsigned b = extract32(insn, 21, 5);
2956 target_long disp = assemble_17(insn);
2958 /* unsigned s = low_uextract(insn, 13, 3); */
2959 /* ??? It seems like there should be a good way of using
2960 "be disp(sr2, r0)", the canonical gateway entry mechanism
2961 to our advantage. But that appears to be inconvenient to
2962 manage along side branch delay slots. Therefore we handle
2963 entry into the gateway page via absolute address. */
2965 /* Since we don't implement spaces, just branch. Do notice the special
2966 case of "be disp(*,r0)" using a direct branch to disp, so that we can
2967 goto_tb to the TB containing the syscall. */
2968 if (b == 0) {
2969 return do_dbranch(ctx, disp, is_l ? 31 : 0, n);
2970 } else {
2971 TCGv tmp = get_temp(ctx);
2972 tcg_gen_addi_tl(tmp, load_gpr(ctx, b), disp);
2973 return do_ibranch(ctx, tmp, is_l ? 31 : 0, n);
2977 static DisasJumpType trans_bl(DisasContext *ctx, uint32_t insn,
2978 const DisasInsn *di)
2980 unsigned n = extract32(insn, 1, 1);
2981 unsigned link = extract32(insn, 21, 5);
2982 target_long disp = assemble_17(insn);
2984 return do_dbranch(ctx, iaoq_dest(ctx, disp), link, n);
2987 static DisasJumpType trans_bl_long(DisasContext *ctx, uint32_t insn,
2988 const DisasInsn *di)
2990 unsigned n = extract32(insn, 1, 1);
2991 target_long disp = assemble_22(insn);
2993 return do_dbranch(ctx, iaoq_dest(ctx, disp), 2, n);
2996 static DisasJumpType trans_blr(DisasContext *ctx, uint32_t insn,
2997 const DisasInsn *di)
2999 unsigned n = extract32(insn, 1, 1);
3000 unsigned rx = extract32(insn, 16, 5);
3001 unsigned link = extract32(insn, 21, 5);
3002 TCGv tmp = get_temp(ctx);
3004 tcg_gen_shli_tl(tmp, load_gpr(ctx, rx), 3);
3005 tcg_gen_addi_tl(tmp, tmp, ctx->iaoq_f + 8);
3006 return do_ibranch(ctx, tmp, link, n);
3009 static DisasJumpType trans_bv(DisasContext *ctx, uint32_t insn,
3010 const DisasInsn *di)
3012 unsigned n = extract32(insn, 1, 1);
3013 unsigned rx = extract32(insn, 16, 5);
3014 unsigned rb = extract32(insn, 21, 5);
3015 TCGv dest;
3017 if (rx == 0) {
3018 dest = load_gpr(ctx, rb);
3019 } else {
3020 dest = get_temp(ctx);
3021 tcg_gen_shli_tl(dest, load_gpr(ctx, rx), 3);
3022 tcg_gen_add_tl(dest, dest, load_gpr(ctx, rb));
3024 return do_ibranch(ctx, dest, 0, n);
3027 static DisasJumpType trans_bve(DisasContext *ctx, uint32_t insn,
3028 const DisasInsn *di)
3030 unsigned n = extract32(insn, 1, 1);
3031 unsigned rb = extract32(insn, 21, 5);
3032 unsigned link = extract32(insn, 13, 1) ? 2 : 0;
3034 return do_ibranch(ctx, load_gpr(ctx, rb), link, n);
3037 static const DisasInsn table_branch[] = {
3038 { 0xe8000000u, 0xfc006000u, trans_bl }, /* B,L and B,L,PUSH */
3039 { 0xe800a000u, 0xfc00e000u, trans_bl_long },
3040 { 0xe8004000u, 0xfc00fffdu, trans_blr },
3041 { 0xe800c000u, 0xfc00fffdu, trans_bv },
3042 { 0xe800d000u, 0xfc00dffcu, trans_bve },
3045 static DisasJumpType trans_fop_wew_0c(DisasContext *ctx, uint32_t insn,
3046 const DisasInsn *di)
3048 unsigned rt = extract32(insn, 0, 5);
3049 unsigned ra = extract32(insn, 21, 5);
3050 return do_fop_wew(ctx, rt, ra, di->f.wew);
3053 static DisasJumpType trans_fop_wew_0e(DisasContext *ctx, uint32_t insn,
3054 const DisasInsn *di)
3056 unsigned rt = assemble_rt64(insn);
3057 unsigned ra = assemble_ra64(insn);
3058 return do_fop_wew(ctx, rt, ra, di->f.wew);
3061 static DisasJumpType trans_fop_ded(DisasContext *ctx, uint32_t insn,
3062 const DisasInsn *di)
3064 unsigned rt = extract32(insn, 0, 5);
3065 unsigned ra = extract32(insn, 21, 5);
3066 return do_fop_ded(ctx, rt, ra, di->f.ded);
3069 static DisasJumpType trans_fop_wed_0c(DisasContext *ctx, uint32_t insn,
3070 const DisasInsn *di)
3072 unsigned rt = extract32(insn, 0, 5);
3073 unsigned ra = extract32(insn, 21, 5);
3074 return do_fop_wed(ctx, rt, ra, di->f.wed);
3077 static DisasJumpType trans_fop_wed_0e(DisasContext *ctx, uint32_t insn,
3078 const DisasInsn *di)
3080 unsigned rt = assemble_rt64(insn);
3081 unsigned ra = extract32(insn, 21, 5);
3082 return do_fop_wed(ctx, rt, ra, di->f.wed);
3085 static DisasJumpType trans_fop_dew_0c(DisasContext *ctx, uint32_t insn,
3086 const DisasInsn *di)
3088 unsigned rt = extract32(insn, 0, 5);
3089 unsigned ra = extract32(insn, 21, 5);
3090 return do_fop_dew(ctx, rt, ra, di->f.dew);
3093 static DisasJumpType trans_fop_dew_0e(DisasContext *ctx, uint32_t insn,
3094 const DisasInsn *di)
3096 unsigned rt = extract32(insn, 0, 5);
3097 unsigned ra = assemble_ra64(insn);
3098 return do_fop_dew(ctx, rt, ra, di->f.dew);
3101 static DisasJumpType trans_fop_weww_0c(DisasContext *ctx, uint32_t insn,
3102 const DisasInsn *di)
3104 unsigned rt = extract32(insn, 0, 5);
3105 unsigned rb = extract32(insn, 16, 5);
3106 unsigned ra = extract32(insn, 21, 5);
3107 return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
3110 static DisasJumpType trans_fop_weww_0e(DisasContext *ctx, uint32_t insn,
3111 const DisasInsn *di)
3113 unsigned rt = assemble_rt64(insn);
3114 unsigned rb = assemble_rb64(insn);
3115 unsigned ra = assemble_ra64(insn);
3116 return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
3119 static DisasJumpType trans_fop_dedd(DisasContext *ctx, uint32_t insn,
3120 const DisasInsn *di)
3122 unsigned rt = extract32(insn, 0, 5);
3123 unsigned rb = extract32(insn, 16, 5);
3124 unsigned ra = extract32(insn, 21, 5);
3125 return do_fop_dedd(ctx, rt, ra, rb, di->f.dedd);
3128 static void gen_fcpy_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3130 tcg_gen_mov_i32(dst, src);
3133 static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3135 tcg_gen_mov_i64(dst, src);
3138 static void gen_fabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3140 tcg_gen_andi_i32(dst, src, INT32_MAX);
3143 static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3145 tcg_gen_andi_i64(dst, src, INT64_MAX);
3148 static void gen_fneg_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3150 tcg_gen_xori_i32(dst, src, INT32_MIN);
3153 static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3155 tcg_gen_xori_i64(dst, src, INT64_MIN);
3158 static void gen_fnegabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3160 tcg_gen_ori_i32(dst, src, INT32_MIN);
3163 static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3165 tcg_gen_ori_i64(dst, src, INT64_MIN);
3168 static DisasJumpType do_fcmp_s(DisasContext *ctx, unsigned ra, unsigned rb,
3169 unsigned y, unsigned c)
3171 TCGv_i32 ta, tb, tc, ty;
3173 nullify_over(ctx);
3175 ta = load_frw0_i32(ra);
3176 tb = load_frw0_i32(rb);
3177 ty = tcg_const_i32(y);
3178 tc = tcg_const_i32(c);
3180 gen_helper_fcmp_s(cpu_env, ta, tb, ty, tc);
3182 tcg_temp_free_i32(ta);
3183 tcg_temp_free_i32(tb);
3184 tcg_temp_free_i32(ty);
3185 tcg_temp_free_i32(tc);
3187 return nullify_end(ctx, DISAS_NEXT);
3190 static DisasJumpType trans_fcmp_s_0c(DisasContext *ctx, uint32_t insn,
3191 const DisasInsn *di)
3193 unsigned c = extract32(insn, 0, 5);
3194 unsigned y = extract32(insn, 13, 3);
3195 unsigned rb = extract32(insn, 16, 5);
3196 unsigned ra = extract32(insn, 21, 5);
3197 return do_fcmp_s(ctx, ra, rb, y, c);
3200 static DisasJumpType trans_fcmp_s_0e(DisasContext *ctx, uint32_t insn,
3201 const DisasInsn *di)
3203 unsigned c = extract32(insn, 0, 5);
3204 unsigned y = extract32(insn, 13, 3);
3205 unsigned rb = assemble_rb64(insn);
3206 unsigned ra = assemble_ra64(insn);
3207 return do_fcmp_s(ctx, ra, rb, y, c);
3210 static DisasJumpType trans_fcmp_d(DisasContext *ctx, uint32_t insn,
3211 const DisasInsn *di)
3213 unsigned c = extract32(insn, 0, 5);
3214 unsigned y = extract32(insn, 13, 3);
3215 unsigned rb = extract32(insn, 16, 5);
3216 unsigned ra = extract32(insn, 21, 5);
3217 TCGv_i64 ta, tb;
3218 TCGv_i32 tc, ty;
3220 nullify_over(ctx);
3222 ta = load_frd0(ra);
3223 tb = load_frd0(rb);
3224 ty = tcg_const_i32(y);
3225 tc = tcg_const_i32(c);
3227 gen_helper_fcmp_d(cpu_env, ta, tb, ty, tc);
3229 tcg_temp_free_i64(ta);
3230 tcg_temp_free_i64(tb);
3231 tcg_temp_free_i32(ty);
3232 tcg_temp_free_i32(tc);
3234 return nullify_end(ctx, DISAS_NEXT);
3237 static DisasJumpType trans_ftest_t(DisasContext *ctx, uint32_t insn,
3238 const DisasInsn *di)
3240 unsigned y = extract32(insn, 13, 3);
3241 unsigned cbit = (y ^ 1) - 1;
3242 TCGv t;
3244 nullify_over(ctx);
3246 t = tcg_temp_new();
3247 tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
3248 tcg_gen_extract_tl(t, t, 21 - cbit, 1);
3249 ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3250 tcg_temp_free(t);
3252 return nullify_end(ctx, DISAS_NEXT);
3255 static DisasJumpType trans_ftest_q(DisasContext *ctx, uint32_t insn,
3256 const DisasInsn *di)
3258 unsigned c = extract32(insn, 0, 5);
3259 int mask;
3260 bool inv = false;
3261 TCGv t;
3263 nullify_over(ctx);
3265 t = tcg_temp_new();
3266 tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
3268 switch (c) {
3269 case 0: /* simple */
3270 tcg_gen_andi_tl(t, t, 0x4000000);
3271 ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3272 goto done;
3273 case 2: /* rej */
3274 inv = true;
3275 /* fallthru */
3276 case 1: /* acc */
3277 mask = 0x43ff800;
3278 break;
3279 case 6: /* rej8 */
3280 inv = true;
3281 /* fallthru */
3282 case 5: /* acc8 */
3283 mask = 0x43f8000;
3284 break;
3285 case 9: /* acc6 */
3286 mask = 0x43e0000;
3287 break;
3288 case 13: /* acc4 */
3289 mask = 0x4380000;
3290 break;
3291 case 17: /* acc2 */
3292 mask = 0x4200000;
3293 break;
3294 default:
3295 return gen_illegal(ctx);
3297 if (inv) {
3298 TCGv c = load_const(ctx, mask);
3299 tcg_gen_or_tl(t, t, c);
3300 ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
3301 } else {
3302 tcg_gen_andi_tl(t, t, mask);
3303 ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
3305 done:
3306 return nullify_end(ctx, DISAS_NEXT);
3309 static DisasJumpType trans_xmpyu(DisasContext *ctx, uint32_t insn,
3310 const DisasInsn *di)
3312 unsigned rt = extract32(insn, 0, 5);
3313 unsigned rb = assemble_rb64(insn);
3314 unsigned ra = assemble_ra64(insn);
3315 TCGv_i64 a, b;
3317 nullify_over(ctx);
3319 a = load_frw0_i64(ra);
3320 b = load_frw0_i64(rb);
3321 tcg_gen_mul_i64(a, a, b);
3322 save_frd(rt, a);
3323 tcg_temp_free_i64(a);
3324 tcg_temp_free_i64(b);
3326 return nullify_end(ctx, DISAS_NEXT);
3329 #define FOP_DED trans_fop_ded, .f.ded
3330 #define FOP_DEDD trans_fop_dedd, .f.dedd
3332 #define FOP_WEW trans_fop_wew_0c, .f.wew
3333 #define FOP_DEW trans_fop_dew_0c, .f.dew
3334 #define FOP_WED trans_fop_wed_0c, .f.wed
3335 #define FOP_WEWW trans_fop_weww_0c, .f.weww
3337 static const DisasInsn table_float_0c[] = {
3338 /* floating point class zero */
3339 { 0x30004000, 0xfc1fffe0, FOP_WEW = gen_fcpy_s },
3340 { 0x30006000, 0xfc1fffe0, FOP_WEW = gen_fabs_s },
3341 { 0x30008000, 0xfc1fffe0, FOP_WEW = gen_helper_fsqrt_s },
3342 { 0x3000a000, 0xfc1fffe0, FOP_WEW = gen_helper_frnd_s },
3343 { 0x3000c000, 0xfc1fffe0, FOP_WEW = gen_fneg_s },
3344 { 0x3000e000, 0xfc1fffe0, FOP_WEW = gen_fnegabs_s },
3346 { 0x30004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
3347 { 0x30006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
3348 { 0x30008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
3349 { 0x3000a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
3350 { 0x3000c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
3351 { 0x3000e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
3353 /* floating point class three */
3354 { 0x30000600, 0xfc00ffe0, FOP_WEWW = gen_helper_fadd_s },
3355 { 0x30002600, 0xfc00ffe0, FOP_WEWW = gen_helper_fsub_s },
3356 { 0x30004600, 0xfc00ffe0, FOP_WEWW = gen_helper_fmpy_s },
3357 { 0x30006600, 0xfc00ffe0, FOP_WEWW = gen_helper_fdiv_s },
3359 { 0x30000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
3360 { 0x30002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
3361 { 0x30004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
3362 { 0x30006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
3364 /* floating point class one */
3365 /* float/float */
3366 { 0x30000a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_s },
3367 { 0x30002200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_d },
3368 /* int/float */
3369 { 0x30008200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_w_s },
3370 { 0x30008a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_dw_s },
3371 { 0x3000a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_w_d },
3372 { 0x3000aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
3373 /* float/int */
3374 { 0x30010200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_w },
3375 { 0x30010a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_w },
3376 { 0x30012200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_dw },
3377 { 0x30012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
3378 /* float/int truncate */
3379 { 0x30018200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_w },
3380 { 0x30018a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_w },
3381 { 0x3001a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_dw },
3382 { 0x3001aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
3383 /* uint/float */
3384 { 0x30028200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_uw_s },
3385 { 0x30028a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_udw_s },
3386 { 0x3002a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_uw_d },
3387 { 0x3002aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
3388 /* float/uint */
3389 { 0x30030200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_uw },
3390 { 0x30030a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_uw },
3391 { 0x30032200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_udw },
3392 { 0x30032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
3393 /* float/uint truncate */
3394 { 0x30038200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_uw },
3395 { 0x30038a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_uw },
3396 { 0x3003a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_udw },
3397 { 0x3003aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
3399 /* floating point class two */
3400 { 0x30000400, 0xfc001fe0, trans_fcmp_s_0c },
3401 { 0x30000c00, 0xfc001fe0, trans_fcmp_d },
3402 { 0x30002420, 0xffffffe0, trans_ftest_q },
3403 { 0x30000420, 0xffff1fff, trans_ftest_t },
3405 /* FID. Note that ra == rt == 0, which via fcpy puts 0 into fr0.
3406 This is machine/revision == 0, which is reserved for simulator. */
3407 { 0x30000000, 0xffffffff, FOP_WEW = gen_fcpy_s },
3410 #undef FOP_WEW
3411 #undef FOP_DEW
3412 #undef FOP_WED
3413 #undef FOP_WEWW
3414 #define FOP_WEW trans_fop_wew_0e, .f.wew
3415 #define FOP_DEW trans_fop_dew_0e, .f.dew
3416 #define FOP_WED trans_fop_wed_0e, .f.wed
3417 #define FOP_WEWW trans_fop_weww_0e, .f.weww
3419 static const DisasInsn table_float_0e[] = {
3420 /* floating point class zero */
3421 { 0x38004000, 0xfc1fff20, FOP_WEW = gen_fcpy_s },
3422 { 0x38006000, 0xfc1fff20, FOP_WEW = gen_fabs_s },
3423 { 0x38008000, 0xfc1fff20, FOP_WEW = gen_helper_fsqrt_s },
3424 { 0x3800a000, 0xfc1fff20, FOP_WEW = gen_helper_frnd_s },
3425 { 0x3800c000, 0xfc1fff20, FOP_WEW = gen_fneg_s },
3426 { 0x3800e000, 0xfc1fff20, FOP_WEW = gen_fnegabs_s },
3428 { 0x38004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
3429 { 0x38006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
3430 { 0x38008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
3431 { 0x3800a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
3432 { 0x3800c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
3433 { 0x3800e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
3435 /* floating point class three */
3436 { 0x38000600, 0xfc00ef20, FOP_WEWW = gen_helper_fadd_s },
3437 { 0x38002600, 0xfc00ef20, FOP_WEWW = gen_helper_fsub_s },
3438 { 0x38004600, 0xfc00ef20, FOP_WEWW = gen_helper_fmpy_s },
3439 { 0x38006600, 0xfc00ef20, FOP_WEWW = gen_helper_fdiv_s },
3441 { 0x38000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
3442 { 0x38002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
3443 { 0x38004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
3444 { 0x38006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
3446 { 0x38004700, 0xfc00ef60, trans_xmpyu },
3448 /* floating point class one */
3449 /* float/float */
3450 { 0x38000a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_s },
3451 { 0x38002200, 0xfc1fffc0, FOP_DEW = gen_helper_fcnv_s_d },
3452 /* int/float */
3453 { 0x38008200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_w_s },
3454 { 0x38008a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_dw_s },
3455 { 0x3800a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_w_d },
3456 { 0x3800aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
3457 /* float/int */
3458 { 0x38010200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_w },
3459 { 0x38010a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_w },
3460 { 0x38012200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_dw },
3461 { 0x38012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
3462 /* float/int truncate */
3463 { 0x38018200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_w },
3464 { 0x38018a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_w },
3465 { 0x3801a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_dw },
3466 { 0x3801aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
3467 /* uint/float */
3468 { 0x38028200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_uw_s },
3469 { 0x38028a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_udw_s },
3470 { 0x3802a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_uw_d },
3471 { 0x3802aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
3472 /* float/uint */
3473 { 0x38030200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_uw },
3474 { 0x38030a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_uw },
3475 { 0x38032200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_udw },
3476 { 0x38032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
3477 /* float/uint truncate */
3478 { 0x38038200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_uw },
3479 { 0x38038a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_uw },
3480 { 0x3803a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_udw },
3481 { 0x3803aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
3483 /* floating point class two */
3484 { 0x38000400, 0xfc000f60, trans_fcmp_s_0e },
3485 { 0x38000c00, 0xfc001fe0, trans_fcmp_d },
3488 #undef FOP_WEW
3489 #undef FOP_DEW
3490 #undef FOP_WED
3491 #undef FOP_WEWW
3492 #undef FOP_DED
3493 #undef FOP_DEDD
3495 /* Convert the fmpyadd single-precision register encodings to standard. */
3496 static inline int fmpyadd_s_reg(unsigned r)
3498 return (r & 16) * 2 + 16 + (r & 15);
3501 static DisasJumpType trans_fmpyadd(DisasContext *ctx,
3502 uint32_t insn, bool is_sub)
3504 unsigned tm = extract32(insn, 0, 5);
3505 unsigned f = extract32(insn, 5, 1);
3506 unsigned ra = extract32(insn, 6, 5);
3507 unsigned ta = extract32(insn, 11, 5);
3508 unsigned rm2 = extract32(insn, 16, 5);
3509 unsigned rm1 = extract32(insn, 21, 5);
3511 nullify_over(ctx);
3513 /* Independent multiply & add/sub, with undefined behaviour
3514 if outputs overlap inputs. */
3515 if (f == 0) {
3516 tm = fmpyadd_s_reg(tm);
3517 ra = fmpyadd_s_reg(ra);
3518 ta = fmpyadd_s_reg(ta);
3519 rm2 = fmpyadd_s_reg(rm2);
3520 rm1 = fmpyadd_s_reg(rm1);
3521 do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
3522 do_fop_weww(ctx, ta, ta, ra,
3523 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
3524 } else {
3525 do_fop_dedd(ctx, tm, rm1, rm2, gen_helper_fmpy_d);
3526 do_fop_dedd(ctx, ta, ta, ra,
3527 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
3530 return nullify_end(ctx, DISAS_NEXT);
3533 static DisasJumpType trans_fmpyfadd_s(DisasContext *ctx, uint32_t insn,
3534 const DisasInsn *di)
3536 unsigned rt = assemble_rt64(insn);
3537 unsigned neg = extract32(insn, 5, 1);
3538 unsigned rm1 = assemble_ra64(insn);
3539 unsigned rm2 = assemble_rb64(insn);
3540 unsigned ra3 = assemble_rc64(insn);
3541 TCGv_i32 a, b, c;
3543 nullify_over(ctx);
3544 a = load_frw0_i32(rm1);
3545 b = load_frw0_i32(rm2);
3546 c = load_frw0_i32(ra3);
3548 if (neg) {
3549 gen_helper_fmpynfadd_s(a, cpu_env, a, b, c);
3550 } else {
3551 gen_helper_fmpyfadd_s(a, cpu_env, a, b, c);
3554 tcg_temp_free_i32(b);
3555 tcg_temp_free_i32(c);
3556 save_frw_i32(rt, a);
3557 tcg_temp_free_i32(a);
3558 return nullify_end(ctx, DISAS_NEXT);
3561 static DisasJumpType trans_fmpyfadd_d(DisasContext *ctx, uint32_t insn,
3562 const DisasInsn *di)
3564 unsigned rt = extract32(insn, 0, 5);
3565 unsigned neg = extract32(insn, 5, 1);
3566 unsigned rm1 = extract32(insn, 21, 5);
3567 unsigned rm2 = extract32(insn, 16, 5);
3568 unsigned ra3 = assemble_rc64(insn);
3569 TCGv_i64 a, b, c;
3571 nullify_over(ctx);
3572 a = load_frd0(rm1);
3573 b = load_frd0(rm2);
3574 c = load_frd0(ra3);
3576 if (neg) {
3577 gen_helper_fmpynfadd_d(a, cpu_env, a, b, c);
3578 } else {
3579 gen_helper_fmpyfadd_d(a, cpu_env, a, b, c);
3582 tcg_temp_free_i64(b);
3583 tcg_temp_free_i64(c);
3584 save_frd(rt, a);
3585 tcg_temp_free_i64(a);
3586 return nullify_end(ctx, DISAS_NEXT);
3589 static const DisasInsn table_fp_fused[] = {
3590 { 0xb8000000u, 0xfc000800u, trans_fmpyfadd_s },
3591 { 0xb8000800u, 0xfc0019c0u, trans_fmpyfadd_d }
3594 static DisasJumpType translate_table_int(DisasContext *ctx, uint32_t insn,
3595 const DisasInsn table[], size_t n)
3597 size_t i;
3598 for (i = 0; i < n; ++i) {
3599 if ((insn & table[i].mask) == table[i].insn) {
3600 return table[i].trans(ctx, insn, &table[i]);
3603 return gen_illegal(ctx);
3606 #define translate_table(ctx, insn, table) \
3607 translate_table_int(ctx, insn, table, ARRAY_SIZE(table))
3609 static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
3611 uint32_t opc = extract32(insn, 26, 6);
3613 switch (opc) {
3614 case 0x00: /* system op */
3615 return translate_table(ctx, insn, table_system);
3616 case 0x01:
3617 return translate_table(ctx, insn, table_mem_mgmt);
3618 case 0x02:
3619 return translate_table(ctx, insn, table_arith_log);
3620 case 0x03:
3621 return translate_table(ctx, insn, table_index_mem);
3622 case 0x06:
3623 return trans_fmpyadd(ctx, insn, false);
3624 case 0x08:
3625 return trans_ldil(ctx, insn);
3626 case 0x09:
3627 return trans_copr_w(ctx, insn);
3628 case 0x0A:
3629 return trans_addil(ctx, insn);
3630 case 0x0B:
3631 return trans_copr_dw(ctx, insn);
3632 case 0x0C:
3633 return translate_table(ctx, insn, table_float_0c);
3634 case 0x0D:
3635 return trans_ldo(ctx, insn);
3636 case 0x0E:
3637 return translate_table(ctx, insn, table_float_0e);
3639 case 0x10:
3640 return trans_load(ctx, insn, false, MO_UB);
3641 case 0x11:
3642 return trans_load(ctx, insn, false, MO_TEUW);
3643 case 0x12:
3644 return trans_load(ctx, insn, false, MO_TEUL);
3645 case 0x13:
3646 return trans_load(ctx, insn, true, MO_TEUL);
3647 case 0x16:
3648 return trans_fload_mod(ctx, insn);
3649 case 0x17:
3650 return trans_load_w(ctx, insn);
3651 case 0x18:
3652 return trans_store(ctx, insn, false, MO_UB);
3653 case 0x19:
3654 return trans_store(ctx, insn, false, MO_TEUW);
3655 case 0x1A:
3656 return trans_store(ctx, insn, false, MO_TEUL);
3657 case 0x1B:
3658 return trans_store(ctx, insn, true, MO_TEUL);
3659 case 0x1E:
3660 return trans_fstore_mod(ctx, insn);
3661 case 0x1F:
3662 return trans_store_w(ctx, insn);
3664 case 0x20:
3665 return trans_cmpb(ctx, insn, true, false, false);
3666 case 0x21:
3667 return trans_cmpb(ctx, insn, true, true, false);
3668 case 0x22:
3669 return trans_cmpb(ctx, insn, false, false, false);
3670 case 0x23:
3671 return trans_cmpb(ctx, insn, false, true, false);
3672 case 0x24:
3673 return trans_cmpiclr(ctx, insn);
3674 case 0x25:
3675 return trans_subi(ctx, insn);
3676 case 0x26:
3677 return trans_fmpyadd(ctx, insn, true);
3678 case 0x27:
3679 return trans_cmpb(ctx, insn, true, false, true);
3680 case 0x28:
3681 return trans_addb(ctx, insn, true, false);
3682 case 0x29:
3683 return trans_addb(ctx, insn, true, true);
3684 case 0x2A:
3685 return trans_addb(ctx, insn, false, false);
3686 case 0x2B:
3687 return trans_addb(ctx, insn, false, true);
3688 case 0x2C:
3689 case 0x2D:
3690 return trans_addi(ctx, insn);
3691 case 0x2E:
3692 return translate_table(ctx, insn, table_fp_fused);
3693 case 0x2F:
3694 return trans_cmpb(ctx, insn, false, false, true);
3696 case 0x30:
3697 case 0x31:
3698 return trans_bb(ctx, insn);
3699 case 0x32:
3700 return trans_movb(ctx, insn, false);
3701 case 0x33:
3702 return trans_movb(ctx, insn, true);
3703 case 0x34:
3704 return translate_table(ctx, insn, table_sh_ex);
3705 case 0x35:
3706 return translate_table(ctx, insn, table_depw);
3707 case 0x38:
3708 return trans_be(ctx, insn, false);
3709 case 0x39:
3710 return trans_be(ctx, insn, true);
3711 case 0x3A:
3712 return translate_table(ctx, insn, table_branch);
3714 case 0x04: /* spopn */
3715 case 0x05: /* diag */
3716 case 0x0F: /* product specific */
3717 break;
3719 case 0x07: /* unassigned */
3720 case 0x15: /* unassigned */
3721 case 0x1D: /* unassigned */
3722 case 0x37: /* unassigned */
3723 case 0x3F: /* unassigned */
3724 default:
3725 break;
3727 return gen_illegal(ctx);
3730 static int hppa_tr_init_disas_context(DisasContextBase *dcbase,
3731 CPUState *cs, int max_insns)
3733 DisasContext *ctx = container_of(dcbase, DisasContext, base);
3734 TranslationBlock *tb = ctx->base.tb;
3735 int i, bound;
3737 ctx->cs = cs;
3738 ctx->iaoq_f = tb->pc;
3739 ctx->iaoq_b = tb->cs_base;
3740 ctx->iaoq_n = -1;
3741 TCGV_UNUSED(ctx->iaoq_n_var);
3743 ctx->ntemps = 0;
3744 for (i = 0; i < ARRAY_SIZE(ctx->temps); ++i) {
3745 TCGV_UNUSED(ctx->temps[i]);
3748 bound = -(tb->pc | TARGET_PAGE_MASK) / 4;
3749 return MIN(max_insns, bound);
3752 static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
3754 DisasContext *ctx = container_of(dcbase, DisasContext, base);
3756 /* Seed the nullification status from PSW[N], as shown in TB->FLAGS. */
3757 ctx->null_cond = cond_make_f();
3758 ctx->psw_n_nonzero = false;
3759 if (ctx->base.tb->flags & 1) {
3760 ctx->null_cond.c = TCG_COND_ALWAYS;
3761 ctx->psw_n_nonzero = true;
3763 ctx->null_lab = NULL;
3766 static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
3768 DisasContext *ctx = container_of(dcbase, DisasContext, base);
3770 tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b);
3773 static bool hppa_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
3774 const CPUBreakpoint *bp)
3776 DisasContext *ctx = container_of(dcbase, DisasContext, base);
3778 ctx->base.is_jmp = gen_excp(ctx, EXCP_DEBUG);
3779 ctx->base.pc_next = ctx->iaoq_f + 4;
3780 return true;
3783 static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
3785 DisasContext *ctx = container_of(dcbase, DisasContext, base);
3786 CPUHPPAState *env = cs->env_ptr;
3787 DisasJumpType ret;
3788 int i, n;
3790 /* Execute one insn. */
3791 if (ctx->iaoq_f < TARGET_PAGE_SIZE) {
3792 ret = do_page_zero(ctx);
3793 assert(ret != DISAS_NEXT);
3794 } else {
3795 /* Always fetch the insn, even if nullified, so that we check
3796 the page permissions for execute. */
3797 uint32_t insn = cpu_ldl_code(env, ctx->iaoq_f);
3799 /* Set up the IA queue for the next insn.
3800 This will be overwritten by a branch. */
3801 if (ctx->iaoq_b == -1) {
3802 ctx->iaoq_n = -1;
3803 ctx->iaoq_n_var = get_temp(ctx);
3804 tcg_gen_addi_tl(ctx->iaoq_n_var, cpu_iaoq_b, 4);
3805 } else {
3806 ctx->iaoq_n = ctx->iaoq_b + 4;
3807 TCGV_UNUSED(ctx->iaoq_n_var);
3810 if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
3811 ctx->null_cond.c = TCG_COND_NEVER;
3812 ret = DISAS_NEXT;
3813 } else {
3814 ret = translate_one(ctx, insn);
3815 assert(ctx->null_lab == NULL);
3819 /* Free any temporaries allocated. */
3820 for (i = 0, n = ctx->ntemps; i < n; ++i) {
3821 tcg_temp_free(ctx->temps[i]);
3822 TCGV_UNUSED(ctx->temps[i]);
3824 ctx->ntemps = 0;
3826 /* Advance the insn queue. */
3827 /* ??? The non-linear instruction restriction is purely due to
3828 the debugging dump. Otherwise we *could* follow unconditional
3829 branches within the same page. */
3830 if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
3831 if (ctx->null_cond.c == TCG_COND_NEVER
3832 || ctx->null_cond.c == TCG_COND_ALWAYS) {
3833 nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
3834 gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
3835 ret = DISAS_NORETURN;
3836 } else {
3837 ret = DISAS_IAQ_N_STALE;
3840 ctx->iaoq_f = ctx->iaoq_b;
3841 ctx->iaoq_b = ctx->iaoq_n;
3842 ctx->base.is_jmp = ret;
3844 if (ret == DISAS_NORETURN || ret == DISAS_IAQ_N_UPDATED) {
3845 return;
3847 if (ctx->iaoq_f == -1) {
3848 tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b);
3849 copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
3850 nullify_save(ctx);
3851 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
3852 } else if (ctx->iaoq_b == -1) {
3853 tcg_gen_mov_tl(cpu_iaoq_b, ctx->iaoq_n_var);
3857 static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
3859 DisasContext *ctx = container_of(dcbase, DisasContext, base);
3861 switch (ctx->base.is_jmp) {
3862 case DISAS_NORETURN:
3863 break;
3864 case DISAS_TOO_MANY:
3865 case DISAS_IAQ_N_STALE:
3866 copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
3867 copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
3868 nullify_save(ctx);
3869 /* FALLTHRU */
3870 case DISAS_IAQ_N_UPDATED:
3871 if (ctx->base.singlestep_enabled) {
3872 gen_excp_1(EXCP_DEBUG);
3873 } else {
3874 tcg_gen_lookup_and_goto_ptr();
3876 break;
3877 default:
3878 g_assert_not_reached();
3881 /* We don't actually use this during normal translation,
3882 but we should interact with the generic main loop. */
3883 ctx->base.pc_next = ctx->base.tb->pc + 4 * ctx->base.num_insns;
3886 static void hppa_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs)
3888 TranslationBlock *tb = dcbase->tb;
3890 switch (tb->pc) {
3891 case 0x00:
3892 qemu_log("IN:\n0x00000000: (null)\n");
3893 break;
3894 case 0xb0:
3895 qemu_log("IN:\n0x000000b0: light-weight-syscall\n");
3896 break;
3897 case 0xe0:
3898 qemu_log("IN:\n0x000000e0: set-thread-pointer-syscall\n");
3899 break;
3900 case 0x100:
3901 qemu_log("IN:\n0x00000100: syscall\n");
3902 break;
3903 default:
3904 qemu_log("IN: %s\n", lookup_symbol(tb->pc));
3905 log_target_disas(cs, tb->pc, tb->size);
3906 break;
3910 static const TranslatorOps hppa_tr_ops = {
3911 .init_disas_context = hppa_tr_init_disas_context,
3912 .tb_start = hppa_tr_tb_start,
3913 .insn_start = hppa_tr_insn_start,
3914 .breakpoint_check = hppa_tr_breakpoint_check,
3915 .translate_insn = hppa_tr_translate_insn,
3916 .tb_stop = hppa_tr_tb_stop,
3917 .disas_log = hppa_tr_disas_log,
3920 void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
3923 DisasContext ctx;
3924 translator_loop(&hppa_tr_ops, &ctx.base, cs, tb);
3927 void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb,
3928 target_ulong *data)
3930 env->iaoq_f = data[0];
3931 if (data[1] != -1) {
3932 env->iaoq_b = data[1];
3934 /* Since we were executing the instruction at IAOQ_F, and took some
3935 sort of action that provoked the cpu_restore_state, we can infer
3936 that the instruction was not nullified. */
3937 env->psw_n = 0;