scsi-disk: support reporting of rotation rate
[qemu/ar7.git] / target / hppa / translate.c
blob26242f4b3cd49b070c86938373ab5090acb7cb6e
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_env cpu_env;
87 static TCGv cpu_gr[32];
88 static TCGv cpu_iaoq_f;
89 static TCGv cpu_iaoq_b;
90 static TCGv cpu_sar;
91 static TCGv cpu_psw_n;
92 static TCGv cpu_psw_v;
93 static TCGv cpu_psw_cb;
94 static TCGv cpu_psw_cb_msb;
95 static TCGv cpu_cr26;
96 static TCGv cpu_cr27;
98 #include "exec/gen-icount.h"
100 void hppa_translate_init(void)
102 #define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
104 typedef struct { TCGv *var; const char *name; int ofs; } GlobalVar;
105 static const GlobalVar vars[] = {
106 DEF_VAR(sar),
107 DEF_VAR(cr26),
108 DEF_VAR(cr27),
109 DEF_VAR(psw_n),
110 DEF_VAR(psw_v),
111 DEF_VAR(psw_cb),
112 DEF_VAR(psw_cb_msb),
113 DEF_VAR(iaoq_f),
114 DEF_VAR(iaoq_b),
117 #undef DEF_VAR
119 /* Use the symbolic register names that match the disassembler. */
120 static const char gr_names[32][4] = {
121 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
122 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
123 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
124 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
127 static bool done_init = 0;
128 int i;
130 if (done_init) {
131 return;
133 done_init = 1;
135 cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
136 tcg_ctx.tcg_env = cpu_env;
138 TCGV_UNUSED(cpu_gr[0]);
139 for (i = 1; i < 32; i++) {
140 cpu_gr[i] = tcg_global_mem_new(cpu_env,
141 offsetof(CPUHPPAState, gr[i]),
142 gr_names[i]);
145 for (i = 0; i < ARRAY_SIZE(vars); ++i) {
146 const GlobalVar *v = &vars[i];
147 *v->var = tcg_global_mem_new(cpu_env, v->ofs, v->name);
151 static DisasCond cond_make_f(void)
153 DisasCond r = { .c = TCG_COND_NEVER };
154 TCGV_UNUSED(r.a0);
155 TCGV_UNUSED(r.a1);
156 return r;
159 static DisasCond cond_make_n(void)
161 DisasCond r = { .c = TCG_COND_NE, .a0_is_n = true, .a1_is_0 = true };
162 r.a0 = cpu_psw_n;
163 TCGV_UNUSED(r.a1);
164 return r;
167 static DisasCond cond_make_0(TCGCond c, TCGv a0)
169 DisasCond r = { .c = c, .a1_is_0 = true };
171 assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
172 r.a0 = tcg_temp_new();
173 tcg_gen_mov_tl(r.a0, a0);
174 TCGV_UNUSED(r.a1);
176 return r;
179 static DisasCond cond_make(TCGCond c, TCGv a0, TCGv a1)
181 DisasCond r = { .c = c };
183 assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
184 r.a0 = tcg_temp_new();
185 tcg_gen_mov_tl(r.a0, a0);
186 r.a1 = tcg_temp_new();
187 tcg_gen_mov_tl(r.a1, a1);
189 return r;
192 static void cond_prep(DisasCond *cond)
194 if (cond->a1_is_0) {
195 cond->a1_is_0 = false;
196 cond->a1 = tcg_const_tl(0);
200 static void cond_free(DisasCond *cond)
202 switch (cond->c) {
203 default:
204 if (!cond->a0_is_n) {
205 tcg_temp_free(cond->a0);
207 if (!cond->a1_is_0) {
208 tcg_temp_free(cond->a1);
210 cond->a0_is_n = false;
211 cond->a1_is_0 = false;
212 TCGV_UNUSED(cond->a0);
213 TCGV_UNUSED(cond->a1);
214 /* fallthru */
215 case TCG_COND_ALWAYS:
216 cond->c = TCG_COND_NEVER;
217 break;
218 case TCG_COND_NEVER:
219 break;
223 static TCGv get_temp(DisasContext *ctx)
225 unsigned i = ctx->ntemps++;
226 g_assert(i < ARRAY_SIZE(ctx->temps));
227 return ctx->temps[i] = tcg_temp_new();
230 static TCGv load_const(DisasContext *ctx, target_long v)
232 TCGv t = get_temp(ctx);
233 tcg_gen_movi_tl(t, v);
234 return t;
237 static TCGv load_gpr(DisasContext *ctx, unsigned reg)
239 if (reg == 0) {
240 TCGv t = get_temp(ctx);
241 tcg_gen_movi_tl(t, 0);
242 return t;
243 } else {
244 return cpu_gr[reg];
248 static TCGv dest_gpr(DisasContext *ctx, unsigned reg)
250 if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
251 return get_temp(ctx);
252 } else {
253 return cpu_gr[reg];
257 static void save_or_nullify(DisasContext *ctx, TCGv dest, TCGv t)
259 if (ctx->null_cond.c != TCG_COND_NEVER) {
260 cond_prep(&ctx->null_cond);
261 tcg_gen_movcond_tl(ctx->null_cond.c, dest, ctx->null_cond.a0,
262 ctx->null_cond.a1, dest, t);
263 } else {
264 tcg_gen_mov_tl(dest, t);
268 static void save_gpr(DisasContext *ctx, unsigned reg, TCGv t)
270 if (reg != 0) {
271 save_or_nullify(ctx, cpu_gr[reg], t);
275 #ifdef HOST_WORDS_BIGENDIAN
276 # define HI_OFS 0
277 # define LO_OFS 4
278 #else
279 # define HI_OFS 4
280 # define LO_OFS 0
281 #endif
283 static TCGv_i32 load_frw_i32(unsigned rt)
285 TCGv_i32 ret = tcg_temp_new_i32();
286 tcg_gen_ld_i32(ret, cpu_env,
287 offsetof(CPUHPPAState, fr[rt & 31])
288 + (rt & 32 ? LO_OFS : HI_OFS));
289 return ret;
292 static TCGv_i32 load_frw0_i32(unsigned rt)
294 if (rt == 0) {
295 return tcg_const_i32(0);
296 } else {
297 return load_frw_i32(rt);
301 static TCGv_i64 load_frw0_i64(unsigned rt)
303 if (rt == 0) {
304 return tcg_const_i64(0);
305 } else {
306 TCGv_i64 ret = tcg_temp_new_i64();
307 tcg_gen_ld32u_i64(ret, cpu_env,
308 offsetof(CPUHPPAState, fr[rt & 31])
309 + (rt & 32 ? LO_OFS : HI_OFS));
310 return ret;
314 static void save_frw_i32(unsigned rt, TCGv_i32 val)
316 tcg_gen_st_i32(val, cpu_env,
317 offsetof(CPUHPPAState, fr[rt & 31])
318 + (rt & 32 ? LO_OFS : HI_OFS));
321 #undef HI_OFS
322 #undef LO_OFS
324 static TCGv_i64 load_frd(unsigned rt)
326 TCGv_i64 ret = tcg_temp_new_i64();
327 tcg_gen_ld_i64(ret, cpu_env, offsetof(CPUHPPAState, fr[rt]));
328 return ret;
331 static TCGv_i64 load_frd0(unsigned rt)
333 if (rt == 0) {
334 return tcg_const_i64(0);
335 } else {
336 return load_frd(rt);
340 static void save_frd(unsigned rt, TCGv_i64 val)
342 tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt]));
345 /* Skip over the implementation of an insn that has been nullified.
346 Use this when the insn is too complex for a conditional move. */
347 static void nullify_over(DisasContext *ctx)
349 if (ctx->null_cond.c != TCG_COND_NEVER) {
350 /* The always condition should have been handled in the main loop. */
351 assert(ctx->null_cond.c != TCG_COND_ALWAYS);
353 ctx->null_lab = gen_new_label();
354 cond_prep(&ctx->null_cond);
356 /* If we're using PSW[N], copy it to a temp because... */
357 if (ctx->null_cond.a0_is_n) {
358 ctx->null_cond.a0_is_n = false;
359 ctx->null_cond.a0 = tcg_temp_new();
360 tcg_gen_mov_tl(ctx->null_cond.a0, cpu_psw_n);
362 /* ... we clear it before branching over the implementation,
363 so that (1) it's clear after nullifying this insn and
364 (2) if this insn nullifies the next, PSW[N] is valid. */
365 if (ctx->psw_n_nonzero) {
366 ctx->psw_n_nonzero = false;
367 tcg_gen_movi_tl(cpu_psw_n, 0);
370 tcg_gen_brcond_tl(ctx->null_cond.c, ctx->null_cond.a0,
371 ctx->null_cond.a1, ctx->null_lab);
372 cond_free(&ctx->null_cond);
376 /* Save the current nullification state to PSW[N]. */
377 static void nullify_save(DisasContext *ctx)
379 if (ctx->null_cond.c == TCG_COND_NEVER) {
380 if (ctx->psw_n_nonzero) {
381 tcg_gen_movi_tl(cpu_psw_n, 0);
383 return;
385 if (!ctx->null_cond.a0_is_n) {
386 cond_prep(&ctx->null_cond);
387 tcg_gen_setcond_tl(ctx->null_cond.c, cpu_psw_n,
388 ctx->null_cond.a0, ctx->null_cond.a1);
389 ctx->psw_n_nonzero = true;
391 cond_free(&ctx->null_cond);
394 /* Set a PSW[N] to X. The intention is that this is used immediately
395 before a goto_tb/exit_tb, so that there is no fallthru path to other
396 code within the TB. Therefore we do not update psw_n_nonzero. */
397 static void nullify_set(DisasContext *ctx, bool x)
399 if (ctx->psw_n_nonzero || x) {
400 tcg_gen_movi_tl(cpu_psw_n, x);
404 /* Mark the end of an instruction that may have been nullified.
405 This is the pair to nullify_over. */
406 static DisasJumpType nullify_end(DisasContext *ctx, DisasJumpType status)
408 TCGLabel *null_lab = ctx->null_lab;
410 if (likely(null_lab == NULL)) {
411 /* The current insn wasn't conditional or handled the condition
412 applied to it without a branch, so the (new) setting of
413 NULL_COND can be applied directly to the next insn. */
414 return status;
416 ctx->null_lab = NULL;
418 if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
419 /* The next instruction will be unconditional,
420 and NULL_COND already reflects that. */
421 gen_set_label(null_lab);
422 } else {
423 /* The insn that we just executed is itself nullifying the next
424 instruction. Store the condition in the PSW[N] global.
425 We asserted PSW[N] = 0 in nullify_over, so that after the
426 label we have the proper value in place. */
427 nullify_save(ctx);
428 gen_set_label(null_lab);
429 ctx->null_cond = cond_make_n();
432 assert(status != DISAS_NORETURN && status != DISAS_IAQ_N_UPDATED);
433 if (status == DISAS_NORETURN) {
434 status = DISAS_NEXT;
436 return status;
439 static void copy_iaoq_entry(TCGv dest, target_ulong ival, TCGv vval)
441 if (unlikely(ival == -1)) {
442 tcg_gen_mov_tl(dest, vval);
443 } else {
444 tcg_gen_movi_tl(dest, ival);
448 static inline target_ulong iaoq_dest(DisasContext *ctx, target_long disp)
450 return ctx->iaoq_f + disp + 8;
453 static void gen_excp_1(int exception)
455 TCGv_i32 t = tcg_const_i32(exception);
456 gen_helper_excp(cpu_env, t);
457 tcg_temp_free_i32(t);
460 static DisasJumpType gen_excp(DisasContext *ctx, int exception)
462 copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
463 copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
464 nullify_save(ctx);
465 gen_excp_1(exception);
466 return DISAS_NORETURN;
469 static DisasJumpType gen_illegal(DisasContext *ctx)
471 nullify_over(ctx);
472 return nullify_end(ctx, gen_excp(ctx, EXCP_SIGILL));
475 static bool use_goto_tb(DisasContext *ctx, target_ulong dest)
477 /* Suppress goto_tb in the case of single-steping and IO. */
478 if ((ctx->base.tb->cflags & CF_LAST_IO) || ctx->base.singlestep_enabled) {
479 return false;
481 return true;
484 /* If the next insn is to be nullified, and it's on the same page,
485 and we're not attempting to set a breakpoint on it, then we can
486 totally skip the nullified insn. This avoids creating and
487 executing a TB that merely branches to the next TB. */
488 static bool use_nullify_skip(DisasContext *ctx)
490 return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
491 && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
494 static void gen_goto_tb(DisasContext *ctx, int which,
495 target_ulong f, target_ulong b)
497 if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
498 tcg_gen_goto_tb(which);
499 tcg_gen_movi_tl(cpu_iaoq_f, f);
500 tcg_gen_movi_tl(cpu_iaoq_b, b);
501 tcg_gen_exit_tb((uintptr_t)ctx->base.tb + which);
502 } else {
503 copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b);
504 copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var);
505 if (ctx->base.singlestep_enabled) {
506 gen_excp_1(EXCP_DEBUG);
507 } else {
508 tcg_gen_lookup_and_goto_ptr();
513 /* PA has a habit of taking the LSB of a field and using that as the sign,
514 with the rest of the field becoming the least significant bits. */
515 static target_long low_sextract(uint32_t val, int pos, int len)
517 target_ulong x = -(target_ulong)extract32(val, pos, 1);
518 x = (x << (len - 1)) | extract32(val, pos + 1, len - 1);
519 return x;
522 static unsigned assemble_rt64(uint32_t insn)
524 unsigned r1 = extract32(insn, 6, 1);
525 unsigned r0 = extract32(insn, 0, 5);
526 return r1 * 32 + r0;
529 static unsigned assemble_ra64(uint32_t insn)
531 unsigned r1 = extract32(insn, 7, 1);
532 unsigned r0 = extract32(insn, 21, 5);
533 return r1 * 32 + r0;
536 static unsigned assemble_rb64(uint32_t insn)
538 unsigned r1 = extract32(insn, 12, 1);
539 unsigned r0 = extract32(insn, 16, 5);
540 return r1 * 32 + r0;
543 static unsigned assemble_rc64(uint32_t insn)
545 unsigned r2 = extract32(insn, 8, 1);
546 unsigned r1 = extract32(insn, 13, 3);
547 unsigned r0 = extract32(insn, 9, 2);
548 return r2 * 32 + r1 * 4 + r0;
551 static target_long assemble_12(uint32_t insn)
553 target_ulong x = -(target_ulong)(insn & 1);
554 x = (x << 1) | extract32(insn, 2, 1);
555 x = (x << 10) | extract32(insn, 3, 10);
556 return x;
559 static target_long assemble_16(uint32_t insn)
561 /* Take the name from PA2.0, which produces a 16-bit number
562 only with wide mode; otherwise a 14-bit number. Since we don't
563 implement wide mode, this is always the 14-bit number. */
564 return low_sextract(insn, 0, 14);
567 static target_long assemble_16a(uint32_t insn)
569 /* Take the name from PA2.0, which produces a 14-bit shifted number
570 only with wide mode; otherwise a 12-bit shifted number. Since we
571 don't implement wide mode, this is always the 12-bit number. */
572 target_ulong x = -(target_ulong)(insn & 1);
573 x = (x << 11) | extract32(insn, 2, 11);
574 return x << 2;
577 static target_long assemble_17(uint32_t insn)
579 target_ulong x = -(target_ulong)(insn & 1);
580 x = (x << 5) | extract32(insn, 16, 5);
581 x = (x << 1) | extract32(insn, 2, 1);
582 x = (x << 10) | extract32(insn, 3, 10);
583 return x << 2;
586 static target_long assemble_21(uint32_t insn)
588 target_ulong x = -(target_ulong)(insn & 1);
589 x = (x << 11) | extract32(insn, 1, 11);
590 x = (x << 2) | extract32(insn, 14, 2);
591 x = (x << 5) | extract32(insn, 16, 5);
592 x = (x << 2) | extract32(insn, 12, 2);
593 return x << 11;
596 static target_long assemble_22(uint32_t insn)
598 target_ulong x = -(target_ulong)(insn & 1);
599 x = (x << 10) | extract32(insn, 16, 10);
600 x = (x << 1) | extract32(insn, 2, 1);
601 x = (x << 10) | extract32(insn, 3, 10);
602 return x << 2;
605 /* The parisc documentation describes only the general interpretation of
606 the conditions, without describing their exact implementation. The
607 interpretations do not stand up well when considering ADD,C and SUB,B.
608 However, considering the Addition, Subtraction and Logical conditions
609 as a whole it would appear that these relations are similar to what
610 a traditional NZCV set of flags would produce. */
612 static DisasCond do_cond(unsigned cf, TCGv res, TCGv cb_msb, TCGv sv)
614 DisasCond cond;
615 TCGv tmp;
617 switch (cf >> 1) {
618 case 0: /* Never / TR */
619 cond = cond_make_f();
620 break;
621 case 1: /* = / <> (Z / !Z) */
622 cond = cond_make_0(TCG_COND_EQ, res);
623 break;
624 case 2: /* < / >= (N / !N) */
625 cond = cond_make_0(TCG_COND_LT, res);
626 break;
627 case 3: /* <= / > (N | Z / !N & !Z) */
628 cond = cond_make_0(TCG_COND_LE, res);
629 break;
630 case 4: /* NUV / UV (!C / C) */
631 cond = cond_make_0(TCG_COND_EQ, cb_msb);
632 break;
633 case 5: /* ZNV / VNZ (!C | Z / C & !Z) */
634 tmp = tcg_temp_new();
635 tcg_gen_neg_tl(tmp, cb_msb);
636 tcg_gen_and_tl(tmp, tmp, res);
637 cond = cond_make_0(TCG_COND_EQ, tmp);
638 tcg_temp_free(tmp);
639 break;
640 case 6: /* SV / NSV (V / !V) */
641 cond = cond_make_0(TCG_COND_LT, sv);
642 break;
643 case 7: /* OD / EV */
644 tmp = tcg_temp_new();
645 tcg_gen_andi_tl(tmp, res, 1);
646 cond = cond_make_0(TCG_COND_NE, tmp);
647 tcg_temp_free(tmp);
648 break;
649 default:
650 g_assert_not_reached();
652 if (cf & 1) {
653 cond.c = tcg_invert_cond(cond.c);
656 return cond;
659 /* Similar, but for the special case of subtraction without borrow, we
660 can use the inputs directly. This can allow other computation to be
661 deleted as unused. */
663 static DisasCond do_sub_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2, TCGv sv)
665 DisasCond cond;
667 switch (cf >> 1) {
668 case 1: /* = / <> */
669 cond = cond_make(TCG_COND_EQ, in1, in2);
670 break;
671 case 2: /* < / >= */
672 cond = cond_make(TCG_COND_LT, in1, in2);
673 break;
674 case 3: /* <= / > */
675 cond = cond_make(TCG_COND_LE, in1, in2);
676 break;
677 case 4: /* << / >>= */
678 cond = cond_make(TCG_COND_LTU, in1, in2);
679 break;
680 case 5: /* <<= / >> */
681 cond = cond_make(TCG_COND_LEU, in1, in2);
682 break;
683 default:
684 return do_cond(cf, res, sv, sv);
686 if (cf & 1) {
687 cond.c = tcg_invert_cond(cond.c);
690 return cond;
693 /* Similar, but for logicals, where the carry and overflow bits are not
694 computed, and use of them is undefined. */
696 static DisasCond do_log_cond(unsigned cf, TCGv res)
698 switch (cf >> 1) {
699 case 4: case 5: case 6:
700 cf &= 1;
701 break;
703 return do_cond(cf, res, res, res);
706 /* Similar, but for shift/extract/deposit conditions. */
708 static DisasCond do_sed_cond(unsigned orig, TCGv res)
710 unsigned c, f;
712 /* Convert the compressed condition codes to standard.
713 0-2 are the same as logicals (nv,<,<=), while 3 is OD.
714 4-7 are the reverse of 0-3. */
715 c = orig & 3;
716 if (c == 3) {
717 c = 7;
719 f = (orig & 4) / 4;
721 return do_log_cond(c * 2 + f, res);
724 /* Similar, but for unit conditions. */
726 static DisasCond do_unit_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2)
728 DisasCond cond;
729 TCGv tmp, cb;
731 TCGV_UNUSED(cb);
732 if (cf & 8) {
733 /* Since we want to test lots of carry-out bits all at once, do not
734 * do our normal thing and compute carry-in of bit B+1 since that
735 * leaves us with carry bits spread across two words.
737 cb = tcg_temp_new();
738 tmp = tcg_temp_new();
739 tcg_gen_or_tl(cb, in1, in2);
740 tcg_gen_and_tl(tmp, in1, in2);
741 tcg_gen_andc_tl(cb, cb, res);
742 tcg_gen_or_tl(cb, cb, tmp);
743 tcg_temp_free(tmp);
746 switch (cf >> 1) {
747 case 0: /* never / TR */
748 case 1: /* undefined */
749 case 5: /* undefined */
750 cond = cond_make_f();
751 break;
753 case 2: /* SBZ / NBZ */
754 /* See hasless(v,1) from
755 * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
757 tmp = tcg_temp_new();
758 tcg_gen_subi_tl(tmp, res, 0x01010101u);
759 tcg_gen_andc_tl(tmp, tmp, res);
760 tcg_gen_andi_tl(tmp, tmp, 0x80808080u);
761 cond = cond_make_0(TCG_COND_NE, tmp);
762 tcg_temp_free(tmp);
763 break;
765 case 3: /* SHZ / NHZ */
766 tmp = tcg_temp_new();
767 tcg_gen_subi_tl(tmp, res, 0x00010001u);
768 tcg_gen_andc_tl(tmp, tmp, res);
769 tcg_gen_andi_tl(tmp, tmp, 0x80008000u);
770 cond = cond_make_0(TCG_COND_NE, tmp);
771 tcg_temp_free(tmp);
772 break;
774 case 4: /* SDC / NDC */
775 tcg_gen_andi_tl(cb, cb, 0x88888888u);
776 cond = cond_make_0(TCG_COND_NE, cb);
777 break;
779 case 6: /* SBC / NBC */
780 tcg_gen_andi_tl(cb, cb, 0x80808080u);
781 cond = cond_make_0(TCG_COND_NE, cb);
782 break;
784 case 7: /* SHC / NHC */
785 tcg_gen_andi_tl(cb, cb, 0x80008000u);
786 cond = cond_make_0(TCG_COND_NE, cb);
787 break;
789 default:
790 g_assert_not_reached();
792 if (cf & 8) {
793 tcg_temp_free(cb);
795 if (cf & 1) {
796 cond.c = tcg_invert_cond(cond.c);
799 return cond;
802 /* Compute signed overflow for addition. */
803 static TCGv do_add_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
805 TCGv sv = get_temp(ctx);
806 TCGv tmp = tcg_temp_new();
808 tcg_gen_xor_tl(sv, res, in1);
809 tcg_gen_xor_tl(tmp, in1, in2);
810 tcg_gen_andc_tl(sv, sv, tmp);
811 tcg_temp_free(tmp);
813 return sv;
816 /* Compute signed overflow for subtraction. */
817 static TCGv do_sub_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
819 TCGv sv = get_temp(ctx);
820 TCGv tmp = tcg_temp_new();
822 tcg_gen_xor_tl(sv, res, in1);
823 tcg_gen_xor_tl(tmp, in1, in2);
824 tcg_gen_and_tl(sv, sv, tmp);
825 tcg_temp_free(tmp);
827 return sv;
830 static DisasJumpType do_add(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
831 unsigned shift, bool is_l, bool is_tsv, bool is_tc,
832 bool is_c, unsigned cf)
834 TCGv dest, cb, cb_msb, sv, tmp;
835 unsigned c = cf >> 1;
836 DisasCond cond;
838 dest = tcg_temp_new();
839 TCGV_UNUSED(cb);
840 TCGV_UNUSED(cb_msb);
842 if (shift) {
843 tmp = get_temp(ctx);
844 tcg_gen_shli_tl(tmp, in1, shift);
845 in1 = tmp;
848 if (!is_l || c == 4 || c == 5) {
849 TCGv zero = tcg_const_tl(0);
850 cb_msb = get_temp(ctx);
851 tcg_gen_add2_tl(dest, cb_msb, in1, zero, in2, zero);
852 if (is_c) {
853 tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero);
855 tcg_temp_free(zero);
856 if (!is_l) {
857 cb = get_temp(ctx);
858 tcg_gen_xor_tl(cb, in1, in2);
859 tcg_gen_xor_tl(cb, cb, dest);
861 } else {
862 tcg_gen_add_tl(dest, in1, in2);
863 if (is_c) {
864 tcg_gen_add_tl(dest, dest, cpu_psw_cb_msb);
868 /* Compute signed overflow if required. */
869 TCGV_UNUSED(sv);
870 if (is_tsv || c == 6) {
871 sv = do_add_sv(ctx, dest, in1, in2);
872 if (is_tsv) {
873 /* ??? Need to include overflow from shift. */
874 gen_helper_tsv(cpu_env, sv);
878 /* Emit any conditional trap before any writeback. */
879 cond = do_cond(cf, dest, cb_msb, sv);
880 if (is_tc) {
881 cond_prep(&cond);
882 tmp = tcg_temp_new();
883 tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
884 gen_helper_tcond(cpu_env, tmp);
885 tcg_temp_free(tmp);
888 /* Write back the result. */
889 if (!is_l) {
890 save_or_nullify(ctx, cpu_psw_cb, cb);
891 save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
893 save_gpr(ctx, rt, dest);
894 tcg_temp_free(dest);
896 /* Install the new nullification. */
897 cond_free(&ctx->null_cond);
898 ctx->null_cond = cond;
899 return DISAS_NEXT;
902 static DisasJumpType do_sub(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
903 bool is_tsv, bool is_b, bool is_tc, unsigned cf)
905 TCGv dest, sv, cb, cb_msb, zero, tmp;
906 unsigned c = cf >> 1;
907 DisasCond cond;
909 dest = tcg_temp_new();
910 cb = tcg_temp_new();
911 cb_msb = tcg_temp_new();
913 zero = tcg_const_tl(0);
914 if (is_b) {
915 /* DEST,C = IN1 + ~IN2 + C. */
916 tcg_gen_not_tl(cb, in2);
917 tcg_gen_add2_tl(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero);
918 tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cb, zero);
919 tcg_gen_xor_tl(cb, cb, in1);
920 tcg_gen_xor_tl(cb, cb, dest);
921 } else {
922 /* DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer
923 operations by seeding the high word with 1 and subtracting. */
924 tcg_gen_movi_tl(cb_msb, 1);
925 tcg_gen_sub2_tl(dest, cb_msb, in1, cb_msb, in2, zero);
926 tcg_gen_eqv_tl(cb, in1, in2);
927 tcg_gen_xor_tl(cb, cb, dest);
929 tcg_temp_free(zero);
931 /* Compute signed overflow if required. */
932 TCGV_UNUSED(sv);
933 if (is_tsv || c == 6) {
934 sv = do_sub_sv(ctx, dest, in1, in2);
935 if (is_tsv) {
936 gen_helper_tsv(cpu_env, sv);
940 /* Compute the condition. We cannot use the special case for borrow. */
941 if (!is_b) {
942 cond = do_sub_cond(cf, dest, in1, in2, sv);
943 } else {
944 cond = do_cond(cf, dest, cb_msb, sv);
947 /* Emit any conditional trap before any writeback. */
948 if (is_tc) {
949 cond_prep(&cond);
950 tmp = tcg_temp_new();
951 tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
952 gen_helper_tcond(cpu_env, tmp);
953 tcg_temp_free(tmp);
956 /* Write back the result. */
957 save_or_nullify(ctx, cpu_psw_cb, cb);
958 save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
959 save_gpr(ctx, rt, dest);
960 tcg_temp_free(dest);
962 /* Install the new nullification. */
963 cond_free(&ctx->null_cond);
964 ctx->null_cond = cond;
965 return DISAS_NEXT;
968 static DisasJumpType do_cmpclr(DisasContext *ctx, unsigned rt, TCGv in1,
969 TCGv in2, unsigned cf)
971 TCGv dest, sv;
972 DisasCond cond;
974 dest = tcg_temp_new();
975 tcg_gen_sub_tl(dest, in1, in2);
977 /* Compute signed overflow if required. */
978 TCGV_UNUSED(sv);
979 if ((cf >> 1) == 6) {
980 sv = do_sub_sv(ctx, dest, in1, in2);
983 /* Form the condition for the compare. */
984 cond = do_sub_cond(cf, dest, in1, in2, sv);
986 /* Clear. */
987 tcg_gen_movi_tl(dest, 0);
988 save_gpr(ctx, rt, dest);
989 tcg_temp_free(dest);
991 /* Install the new nullification. */
992 cond_free(&ctx->null_cond);
993 ctx->null_cond = cond;
994 return DISAS_NEXT;
997 static DisasJumpType do_log(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
998 unsigned cf, void (*fn)(TCGv, TCGv, TCGv))
1000 TCGv dest = dest_gpr(ctx, rt);
1002 /* Perform the operation, and writeback. */
1003 fn(dest, in1, in2);
1004 save_gpr(ctx, rt, dest);
1006 /* Install the new nullification. */
1007 cond_free(&ctx->null_cond);
1008 if (cf) {
1009 ctx->null_cond = do_log_cond(cf, dest);
1011 return DISAS_NEXT;
1014 static DisasJumpType do_unit(DisasContext *ctx, unsigned rt, TCGv in1,
1015 TCGv in2, unsigned cf, bool is_tc,
1016 void (*fn)(TCGv, TCGv, TCGv))
1018 TCGv dest;
1019 DisasCond cond;
1021 if (cf == 0) {
1022 dest = dest_gpr(ctx, rt);
1023 fn(dest, in1, in2);
1024 save_gpr(ctx, rt, dest);
1025 cond_free(&ctx->null_cond);
1026 } else {
1027 dest = tcg_temp_new();
1028 fn(dest, in1, in2);
1030 cond = do_unit_cond(cf, dest, in1, in2);
1032 if (is_tc) {
1033 TCGv tmp = tcg_temp_new();
1034 cond_prep(&cond);
1035 tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
1036 gen_helper_tcond(cpu_env, tmp);
1037 tcg_temp_free(tmp);
1039 save_gpr(ctx, rt, dest);
1041 cond_free(&ctx->null_cond);
1042 ctx->null_cond = cond;
1044 return DISAS_NEXT;
1047 /* Emit a memory load. The modify parameter should be
1048 * < 0 for pre-modify,
1049 * > 0 for post-modify,
1050 * = 0 for no base register update.
1052 static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1053 unsigned rx, int scale, target_long disp,
1054 int modify, TCGMemOp mop)
1056 TCGv addr, base;
1058 /* Caller uses nullify_over/nullify_end. */
1059 assert(ctx->null_cond.c == TCG_COND_NEVER);
1061 addr = tcg_temp_new();
1062 base = load_gpr(ctx, rb);
1064 /* Note that RX is mutually exclusive with DISP. */
1065 if (rx) {
1066 tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
1067 tcg_gen_add_tl(addr, addr, base);
1068 } else {
1069 tcg_gen_addi_tl(addr, base, disp);
1072 if (modify == 0) {
1073 tcg_gen_qemu_ld_i32(dest, addr, MMU_USER_IDX, mop);
1074 } else {
1075 tcg_gen_qemu_ld_i32(dest, (modify < 0 ? addr : base),
1076 MMU_USER_IDX, mop);
1077 save_gpr(ctx, rb, addr);
1079 tcg_temp_free(addr);
1082 static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1083 unsigned rx, int scale, target_long disp,
1084 int modify, TCGMemOp mop)
1086 TCGv addr, base;
1088 /* Caller uses nullify_over/nullify_end. */
1089 assert(ctx->null_cond.c == TCG_COND_NEVER);
1091 addr = tcg_temp_new();
1092 base = load_gpr(ctx, rb);
1094 /* Note that RX is mutually exclusive with DISP. */
1095 if (rx) {
1096 tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
1097 tcg_gen_add_tl(addr, addr, base);
1098 } else {
1099 tcg_gen_addi_tl(addr, base, disp);
1102 if (modify == 0) {
1103 tcg_gen_qemu_ld_i64(dest, addr, MMU_USER_IDX, mop);
1104 } else {
1105 tcg_gen_qemu_ld_i64(dest, (modify < 0 ? addr : base),
1106 MMU_USER_IDX, mop);
1107 save_gpr(ctx, rb, addr);
1109 tcg_temp_free(addr);
1112 static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1113 unsigned rx, int scale, target_long disp,
1114 int modify, TCGMemOp mop)
1116 TCGv addr, base;
1118 /* Caller uses nullify_over/nullify_end. */
1119 assert(ctx->null_cond.c == TCG_COND_NEVER);
1121 addr = tcg_temp_new();
1122 base = load_gpr(ctx, rb);
1124 /* Note that RX is mutually exclusive with DISP. */
1125 if (rx) {
1126 tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
1127 tcg_gen_add_tl(addr, addr, base);
1128 } else {
1129 tcg_gen_addi_tl(addr, base, disp);
1132 tcg_gen_qemu_st_i32(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
1134 if (modify != 0) {
1135 save_gpr(ctx, rb, addr);
1137 tcg_temp_free(addr);
1140 static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1141 unsigned rx, int scale, target_long disp,
1142 int modify, TCGMemOp mop)
1144 TCGv addr, base;
1146 /* Caller uses nullify_over/nullify_end. */
1147 assert(ctx->null_cond.c == TCG_COND_NEVER);
1149 addr = tcg_temp_new();
1150 base = load_gpr(ctx, rb);
1152 /* Note that RX is mutually exclusive with DISP. */
1153 if (rx) {
1154 tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
1155 tcg_gen_add_tl(addr, addr, base);
1156 } else {
1157 tcg_gen_addi_tl(addr, base, disp);
1160 tcg_gen_qemu_st_i64(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
1162 if (modify != 0) {
1163 save_gpr(ctx, rb, addr);
1165 tcg_temp_free(addr);
1168 #if TARGET_LONG_BITS == 64
1169 #define do_load_tl do_load_64
1170 #define do_store_tl do_store_64
1171 #else
1172 #define do_load_tl do_load_32
1173 #define do_store_tl do_store_32
1174 #endif
1176 static DisasJumpType do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1177 unsigned rx, int scale, target_long disp,
1178 int modify, TCGMemOp mop)
1180 TCGv dest;
1182 nullify_over(ctx);
1184 if (modify == 0) {
1185 /* No base register update. */
1186 dest = dest_gpr(ctx, rt);
1187 } else {
1188 /* Make sure if RT == RB, we see the result of the load. */
1189 dest = get_temp(ctx);
1191 do_load_tl(ctx, dest, rb, rx, scale, disp, modify, mop);
1192 save_gpr(ctx, rt, dest);
1194 return nullify_end(ctx, DISAS_NEXT);
1197 static DisasJumpType do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
1198 unsigned rx, int scale, target_long disp,
1199 int modify)
1201 TCGv_i32 tmp;
1203 nullify_over(ctx);
1205 tmp = tcg_temp_new_i32();
1206 do_load_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
1207 save_frw_i32(rt, tmp);
1208 tcg_temp_free_i32(tmp);
1210 if (rt == 0) {
1211 gen_helper_loaded_fr0(cpu_env);
1214 return nullify_end(ctx, DISAS_NEXT);
1217 static DisasJumpType do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1218 unsigned rx, int scale, target_long disp,
1219 int modify)
1221 TCGv_i64 tmp;
1223 nullify_over(ctx);
1225 tmp = tcg_temp_new_i64();
1226 do_load_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
1227 save_frd(rt, tmp);
1228 tcg_temp_free_i64(tmp);
1230 if (rt == 0) {
1231 gen_helper_loaded_fr0(cpu_env);
1234 return nullify_end(ctx, DISAS_NEXT);
1237 static DisasJumpType do_store(DisasContext *ctx, unsigned rt, unsigned rb,
1238 target_long disp, int modify, TCGMemOp mop)
1240 nullify_over(ctx);
1241 do_store_tl(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, modify, mop);
1242 return nullify_end(ctx, DISAS_NEXT);
1245 static DisasJumpType do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1246 unsigned rx, int scale, target_long disp,
1247 int modify)
1249 TCGv_i32 tmp;
1251 nullify_over(ctx);
1253 tmp = load_frw_i32(rt);
1254 do_store_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
1255 tcg_temp_free_i32(tmp);
1257 return nullify_end(ctx, DISAS_NEXT);
1260 static DisasJumpType do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1261 unsigned rx, int scale, target_long disp,
1262 int modify)
1264 TCGv_i64 tmp;
1266 nullify_over(ctx);
1268 tmp = load_frd(rt);
1269 do_store_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
1270 tcg_temp_free_i64(tmp);
1272 return nullify_end(ctx, DISAS_NEXT);
1275 static DisasJumpType do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1276 void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1278 TCGv_i32 tmp;
1280 nullify_over(ctx);
1281 tmp = load_frw0_i32(ra);
1283 func(tmp, cpu_env, tmp);
1285 save_frw_i32(rt, tmp);
1286 tcg_temp_free_i32(tmp);
1287 return nullify_end(ctx, DISAS_NEXT);
1290 static DisasJumpType do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1291 void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1293 TCGv_i32 dst;
1294 TCGv_i64 src;
1296 nullify_over(ctx);
1297 src = load_frd(ra);
1298 dst = tcg_temp_new_i32();
1300 func(dst, cpu_env, src);
1302 tcg_temp_free_i64(src);
1303 save_frw_i32(rt, dst);
1304 tcg_temp_free_i32(dst);
1305 return nullify_end(ctx, DISAS_NEXT);
1308 static DisasJumpType do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1309 void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1311 TCGv_i64 tmp;
1313 nullify_over(ctx);
1314 tmp = load_frd0(ra);
1316 func(tmp, cpu_env, tmp);
1318 save_frd(rt, tmp);
1319 tcg_temp_free_i64(tmp);
1320 return nullify_end(ctx, DISAS_NEXT);
1323 static DisasJumpType do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1324 void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1326 TCGv_i32 src;
1327 TCGv_i64 dst;
1329 nullify_over(ctx);
1330 src = load_frw0_i32(ra);
1331 dst = tcg_temp_new_i64();
1333 func(dst, cpu_env, src);
1335 tcg_temp_free_i32(src);
1336 save_frd(rt, dst);
1337 tcg_temp_free_i64(dst);
1338 return nullify_end(ctx, DISAS_NEXT);
1341 static DisasJumpType do_fop_weww(DisasContext *ctx, unsigned rt,
1342 unsigned ra, unsigned rb,
1343 void (*func)(TCGv_i32, TCGv_env,
1344 TCGv_i32, TCGv_i32))
1346 TCGv_i32 a, b;
1348 nullify_over(ctx);
1349 a = load_frw0_i32(ra);
1350 b = load_frw0_i32(rb);
1352 func(a, cpu_env, a, b);
1354 tcg_temp_free_i32(b);
1355 save_frw_i32(rt, a);
1356 tcg_temp_free_i32(a);
1357 return nullify_end(ctx, DISAS_NEXT);
1360 static DisasJumpType do_fop_dedd(DisasContext *ctx, unsigned rt,
1361 unsigned ra, unsigned rb,
1362 void (*func)(TCGv_i64, TCGv_env,
1363 TCGv_i64, TCGv_i64))
1365 TCGv_i64 a, b;
1367 nullify_over(ctx);
1368 a = load_frd0(ra);
1369 b = load_frd0(rb);
1371 func(a, cpu_env, a, b);
1373 tcg_temp_free_i64(b);
1374 save_frd(rt, a);
1375 tcg_temp_free_i64(a);
1376 return nullify_end(ctx, DISAS_NEXT);
1379 /* Emit an unconditional branch to a direct target, which may or may not
1380 have already had nullification handled. */
1381 static DisasJumpType do_dbranch(DisasContext *ctx, target_ulong dest,
1382 unsigned link, bool is_n)
1384 if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
1385 if (link != 0) {
1386 copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
1388 ctx->iaoq_n = dest;
1389 if (is_n) {
1390 ctx->null_cond.c = TCG_COND_ALWAYS;
1392 return DISAS_NEXT;
1393 } else {
1394 nullify_over(ctx);
1396 if (link != 0) {
1397 copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
1400 if (is_n && use_nullify_skip(ctx)) {
1401 nullify_set(ctx, 0);
1402 gen_goto_tb(ctx, 0, dest, dest + 4);
1403 } else {
1404 nullify_set(ctx, is_n);
1405 gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
1408 nullify_end(ctx, DISAS_NEXT);
1410 nullify_set(ctx, 0);
1411 gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
1412 return DISAS_NORETURN;
1416 /* Emit a conditional branch to a direct target. If the branch itself
1417 is nullified, we should have already used nullify_over. */
1418 static DisasJumpType do_cbranch(DisasContext *ctx, target_long disp, bool is_n,
1419 DisasCond *cond)
1421 target_ulong dest = iaoq_dest(ctx, disp);
1422 TCGLabel *taken = NULL;
1423 TCGCond c = cond->c;
1424 bool n;
1426 assert(ctx->null_cond.c == TCG_COND_NEVER);
1428 /* Handle TRUE and NEVER as direct branches. */
1429 if (c == TCG_COND_ALWAYS) {
1430 return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
1432 if (c == TCG_COND_NEVER) {
1433 return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
1436 taken = gen_new_label();
1437 cond_prep(cond);
1438 tcg_gen_brcond_tl(c, cond->a0, cond->a1, taken);
1439 cond_free(cond);
1441 /* Not taken: Condition not satisfied; nullify on backward branches. */
1442 n = is_n && disp < 0;
1443 if (n && use_nullify_skip(ctx)) {
1444 nullify_set(ctx, 0);
1445 gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
1446 } else {
1447 if (!n && ctx->null_lab) {
1448 gen_set_label(ctx->null_lab);
1449 ctx->null_lab = NULL;
1451 nullify_set(ctx, n);
1452 gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
1455 gen_set_label(taken);
1457 /* Taken: Condition satisfied; nullify on forward branches. */
1458 n = is_n && disp >= 0;
1459 if (n && use_nullify_skip(ctx)) {
1460 nullify_set(ctx, 0);
1461 gen_goto_tb(ctx, 1, dest, dest + 4);
1462 } else {
1463 nullify_set(ctx, n);
1464 gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
1467 /* Not taken: the branch itself was nullified. */
1468 if (ctx->null_lab) {
1469 gen_set_label(ctx->null_lab);
1470 ctx->null_lab = NULL;
1471 return DISAS_IAQ_N_STALE;
1472 } else {
1473 return DISAS_NORETURN;
1477 /* Emit an unconditional branch to an indirect target. This handles
1478 nullification of the branch itself. */
1479 static DisasJumpType do_ibranch(DisasContext *ctx, TCGv dest,
1480 unsigned link, bool is_n)
1482 TCGv a0, a1, next, tmp;
1483 TCGCond c;
1485 assert(ctx->null_lab == NULL);
1487 if (ctx->null_cond.c == TCG_COND_NEVER) {
1488 if (link != 0) {
1489 copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
1491 next = get_temp(ctx);
1492 tcg_gen_mov_tl(next, dest);
1493 ctx->iaoq_n = -1;
1494 ctx->iaoq_n_var = next;
1495 if (is_n) {
1496 ctx->null_cond.c = TCG_COND_ALWAYS;
1498 } else if (is_n && use_nullify_skip(ctx)) {
1499 /* The (conditional) branch, B, nullifies the next insn, N,
1500 and we're allowed to skip execution N (no single-step or
1501 tracepoint in effect). Since the goto_ptr that we must use
1502 for the indirect branch consumes no special resources, we
1503 can (conditionally) skip B and continue execution. */
1504 /* The use_nullify_skip test implies we have a known control path. */
1505 tcg_debug_assert(ctx->iaoq_b != -1);
1506 tcg_debug_assert(ctx->iaoq_n != -1);
1508 /* We do have to handle the non-local temporary, DEST, before
1509 branching. Since IOAQ_F is not really live at this point, we
1510 can simply store DEST optimistically. Similarly with IAOQ_B. */
1511 tcg_gen_mov_tl(cpu_iaoq_f, dest);
1512 tcg_gen_addi_tl(cpu_iaoq_b, dest, 4);
1514 nullify_over(ctx);
1515 if (link != 0) {
1516 tcg_gen_movi_tl(cpu_gr[link], ctx->iaoq_n);
1518 tcg_gen_lookup_and_goto_ptr();
1519 return nullify_end(ctx, DISAS_NEXT);
1520 } else {
1521 cond_prep(&ctx->null_cond);
1522 c = ctx->null_cond.c;
1523 a0 = ctx->null_cond.a0;
1524 a1 = ctx->null_cond.a1;
1526 tmp = tcg_temp_new();
1527 next = get_temp(ctx);
1529 copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var);
1530 tcg_gen_movcond_tl(c, next, a0, a1, tmp, dest);
1531 ctx->iaoq_n = -1;
1532 ctx->iaoq_n_var = next;
1534 if (link != 0) {
1535 tcg_gen_movcond_tl(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
1538 if (is_n) {
1539 /* The branch nullifies the next insn, which means the state of N
1540 after the branch is the inverse of the state of N that applied
1541 to the branch. */
1542 tcg_gen_setcond_tl(tcg_invert_cond(c), cpu_psw_n, a0, a1);
1543 cond_free(&ctx->null_cond);
1544 ctx->null_cond = cond_make_n();
1545 ctx->psw_n_nonzero = true;
1546 } else {
1547 cond_free(&ctx->null_cond);
1551 return DISAS_NEXT;
1554 /* On Linux, page zero is normally marked execute only + gateway.
1555 Therefore normal read or write is supposed to fail, but specific
1556 offsets have kernel code mapped to raise permissions to implement
1557 system calls. Handling this via an explicit check here, rather
1558 in than the "be disp(sr2,r0)" instruction that probably sent us
1559 here, is the easiest way to handle the branch delay slot on the
1560 aforementioned BE. */
1561 static DisasJumpType do_page_zero(DisasContext *ctx)
1563 /* If by some means we get here with PSW[N]=1, that implies that
1564 the B,GATE instruction would be skipped, and we'd fault on the
1565 next insn within the privilaged page. */
1566 switch (ctx->null_cond.c) {
1567 case TCG_COND_NEVER:
1568 break;
1569 case TCG_COND_ALWAYS:
1570 tcg_gen_movi_tl(cpu_psw_n, 0);
1571 goto do_sigill;
1572 default:
1573 /* Since this is always the first (and only) insn within the
1574 TB, we should know the state of PSW[N] from TB->FLAGS. */
1575 g_assert_not_reached();
1578 /* Check that we didn't arrive here via some means that allowed
1579 non-sequential instruction execution. Normally the PSW[B] bit
1580 detects this by disallowing the B,GATE instruction to execute
1581 under such conditions. */
1582 if (ctx->iaoq_b != ctx->iaoq_f + 4) {
1583 goto do_sigill;
1586 switch (ctx->iaoq_f) {
1587 case 0x00: /* Null pointer call */
1588 gen_excp_1(EXCP_SIGSEGV);
1589 return DISAS_NORETURN;
1591 case 0xb0: /* LWS */
1592 gen_excp_1(EXCP_SYSCALL_LWS);
1593 return DISAS_NORETURN;
1595 case 0xe0: /* SET_THREAD_POINTER */
1596 tcg_gen_mov_tl(cpu_cr27, cpu_gr[26]);
1597 tcg_gen_mov_tl(cpu_iaoq_f, cpu_gr[31]);
1598 tcg_gen_addi_tl(cpu_iaoq_b, cpu_iaoq_f, 4);
1599 return DISAS_IAQ_N_UPDATED;
1601 case 0x100: /* SYSCALL */
1602 gen_excp_1(EXCP_SYSCALL);
1603 return DISAS_NORETURN;
1605 default:
1606 do_sigill:
1607 gen_excp_1(EXCP_SIGILL);
1608 return DISAS_NORETURN;
1612 static DisasJumpType trans_nop(DisasContext *ctx, uint32_t insn,
1613 const DisasInsn *di)
1615 cond_free(&ctx->null_cond);
1616 return DISAS_NEXT;
1619 static DisasJumpType trans_break(DisasContext *ctx, uint32_t insn,
1620 const DisasInsn *di)
1622 nullify_over(ctx);
1623 return nullify_end(ctx, gen_excp(ctx, EXCP_DEBUG));
1626 static DisasJumpType trans_sync(DisasContext *ctx, uint32_t insn,
1627 const DisasInsn *di)
1629 /* No point in nullifying the memory barrier. */
1630 tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1632 cond_free(&ctx->null_cond);
1633 return DISAS_NEXT;
1636 static DisasJumpType trans_mfia(DisasContext *ctx, uint32_t insn,
1637 const DisasInsn *di)
1639 unsigned rt = extract32(insn, 0, 5);
1640 TCGv tmp = dest_gpr(ctx, rt);
1641 tcg_gen_movi_tl(tmp, ctx->iaoq_f);
1642 save_gpr(ctx, rt, tmp);
1644 cond_free(&ctx->null_cond);
1645 return DISAS_NEXT;
1648 static DisasJumpType trans_mfsp(DisasContext *ctx, uint32_t insn,
1649 const DisasInsn *di)
1651 unsigned rt = extract32(insn, 0, 5);
1652 TCGv tmp = dest_gpr(ctx, rt);
1654 /* ??? We don't implement space registers. */
1655 tcg_gen_movi_tl(tmp, 0);
1656 save_gpr(ctx, rt, tmp);
1658 cond_free(&ctx->null_cond);
1659 return DISAS_NEXT;
1662 static DisasJumpType trans_mfctl(DisasContext *ctx, uint32_t insn,
1663 const DisasInsn *di)
1665 unsigned rt = extract32(insn, 0, 5);
1666 unsigned ctl = extract32(insn, 21, 5);
1667 TCGv tmp;
1669 switch (ctl) {
1670 case 11: /* SAR */
1671 #ifdef TARGET_HPPA64
1672 if (extract32(insn, 14, 1) == 0) {
1673 /* MFSAR without ,W masks low 5 bits. */
1674 tmp = dest_gpr(ctx, rt);
1675 tcg_gen_andi_tl(tmp, cpu_sar, 31);
1676 save_gpr(ctx, rt, tmp);
1677 break;
1679 #endif
1680 save_gpr(ctx, rt, cpu_sar);
1681 break;
1682 case 16: /* Interval Timer */
1683 tmp = dest_gpr(ctx, rt);
1684 tcg_gen_movi_tl(tmp, 0); /* FIXME */
1685 save_gpr(ctx, rt, tmp);
1686 break;
1687 case 26:
1688 save_gpr(ctx, rt, cpu_cr26);
1689 break;
1690 case 27:
1691 save_gpr(ctx, rt, cpu_cr27);
1692 break;
1693 default:
1694 /* All other control registers are privileged. */
1695 return gen_illegal(ctx);
1698 cond_free(&ctx->null_cond);
1699 return DISAS_NEXT;
1702 static DisasJumpType trans_mtctl(DisasContext *ctx, uint32_t insn,
1703 const DisasInsn *di)
1705 unsigned rin = extract32(insn, 16, 5);
1706 unsigned ctl = extract32(insn, 21, 5);
1707 TCGv tmp;
1709 if (ctl == 11) { /* SAR */
1710 tmp = tcg_temp_new();
1711 tcg_gen_andi_tl(tmp, load_gpr(ctx, rin), TARGET_LONG_BITS - 1);
1712 save_or_nullify(ctx, cpu_sar, tmp);
1713 tcg_temp_free(tmp);
1714 } else {
1715 /* All other control registers are privileged or read-only. */
1716 return gen_illegal(ctx);
1719 cond_free(&ctx->null_cond);
1720 return DISAS_NEXT;
1723 static DisasJumpType trans_mtsarcm(DisasContext *ctx, uint32_t insn,
1724 const DisasInsn *di)
1726 unsigned rin = extract32(insn, 16, 5);
1727 TCGv tmp = tcg_temp_new();
1729 tcg_gen_not_tl(tmp, load_gpr(ctx, rin));
1730 tcg_gen_andi_tl(tmp, tmp, TARGET_LONG_BITS - 1);
1731 save_or_nullify(ctx, cpu_sar, tmp);
1732 tcg_temp_free(tmp);
1734 cond_free(&ctx->null_cond);
1735 return DISAS_NEXT;
1738 static DisasJumpType trans_ldsid(DisasContext *ctx, uint32_t insn,
1739 const DisasInsn *di)
1741 unsigned rt = extract32(insn, 0, 5);
1742 TCGv dest = dest_gpr(ctx, rt);
1744 /* Since we don't implement space registers, this returns zero. */
1745 tcg_gen_movi_tl(dest, 0);
1746 save_gpr(ctx, rt, dest);
1748 cond_free(&ctx->null_cond);
1749 return DISAS_NEXT;
1752 static const DisasInsn table_system[] = {
1753 { 0x00000000u, 0xfc001fe0u, trans_break },
1754 /* We don't implement space register, so MTSP is a nop. */
1755 { 0x00001820u, 0xffe01fffu, trans_nop },
1756 { 0x00001840u, 0xfc00ffffu, trans_mtctl },
1757 { 0x016018c0u, 0xffe0ffffu, trans_mtsarcm },
1758 { 0x000014a0u, 0xffffffe0u, trans_mfia },
1759 { 0x000004a0u, 0xffff1fe0u, trans_mfsp },
1760 { 0x000008a0u, 0xfc1fffe0u, trans_mfctl },
1761 { 0x00000400u, 0xffffffffu, trans_sync },
1762 { 0x000010a0u, 0xfc1f3fe0u, trans_ldsid },
1765 static DisasJumpType trans_base_idx_mod(DisasContext *ctx, uint32_t insn,
1766 const DisasInsn *di)
1768 unsigned rb = extract32(insn, 21, 5);
1769 unsigned rx = extract32(insn, 16, 5);
1770 TCGv dest = dest_gpr(ctx, rb);
1771 TCGv src1 = load_gpr(ctx, rb);
1772 TCGv src2 = load_gpr(ctx, rx);
1774 /* The only thing we need to do is the base register modification. */
1775 tcg_gen_add_tl(dest, src1, src2);
1776 save_gpr(ctx, rb, dest);
1778 cond_free(&ctx->null_cond);
1779 return DISAS_NEXT;
1782 static DisasJumpType trans_probe(DisasContext *ctx, uint32_t insn,
1783 const DisasInsn *di)
1785 unsigned rt = extract32(insn, 0, 5);
1786 unsigned rb = extract32(insn, 21, 5);
1787 unsigned is_write = extract32(insn, 6, 1);
1788 TCGv dest;
1790 nullify_over(ctx);
1792 /* ??? Do something with priv level operand. */
1793 dest = dest_gpr(ctx, rt);
1794 if (is_write) {
1795 gen_helper_probe_w(dest, load_gpr(ctx, rb));
1796 } else {
1797 gen_helper_probe_r(dest, load_gpr(ctx, rb));
1799 save_gpr(ctx, rt, dest);
1800 return nullify_end(ctx, DISAS_NEXT);
1803 static const DisasInsn table_mem_mgmt[] = {
1804 { 0x04003280u, 0xfc003fffu, trans_nop }, /* fdc, disp */
1805 { 0x04001280u, 0xfc003fffu, trans_nop }, /* fdc, index */
1806 { 0x040012a0u, 0xfc003fffu, trans_base_idx_mod }, /* fdc, index, base mod */
1807 { 0x040012c0u, 0xfc003fffu, trans_nop }, /* fdce */
1808 { 0x040012e0u, 0xfc003fffu, trans_base_idx_mod }, /* fdce, base mod */
1809 { 0x04000280u, 0xfc001fffu, trans_nop }, /* fic 0a */
1810 { 0x040002a0u, 0xfc001fffu, trans_base_idx_mod }, /* fic 0a, base mod */
1811 { 0x040013c0u, 0xfc003fffu, trans_nop }, /* fic 4f */
1812 { 0x040013e0u, 0xfc003fffu, trans_base_idx_mod }, /* fic 4f, base mod */
1813 { 0x040002c0u, 0xfc001fffu, trans_nop }, /* fice */
1814 { 0x040002e0u, 0xfc001fffu, trans_base_idx_mod }, /* fice, base mod */
1815 { 0x04002700u, 0xfc003fffu, trans_nop }, /* pdc */
1816 { 0x04002720u, 0xfc003fffu, trans_base_idx_mod }, /* pdc, base mod */
1817 { 0x04001180u, 0xfc003fa0u, trans_probe }, /* probe */
1818 { 0x04003180u, 0xfc003fa0u, trans_probe }, /* probei */
1821 static DisasJumpType trans_add(DisasContext *ctx, uint32_t insn,
1822 const DisasInsn *di)
1824 unsigned r2 = extract32(insn, 21, 5);
1825 unsigned r1 = extract32(insn, 16, 5);
1826 unsigned cf = extract32(insn, 12, 4);
1827 unsigned ext = extract32(insn, 8, 4);
1828 unsigned shift = extract32(insn, 6, 2);
1829 unsigned rt = extract32(insn, 0, 5);
1830 TCGv tcg_r1, tcg_r2;
1831 bool is_c = false;
1832 bool is_l = false;
1833 bool is_tc = false;
1834 bool is_tsv = false;
1835 DisasJumpType ret;
1837 switch (ext) {
1838 case 0x6: /* ADD, SHLADD */
1839 break;
1840 case 0xa: /* ADD,L, SHLADD,L */
1841 is_l = true;
1842 break;
1843 case 0xe: /* ADD,TSV, SHLADD,TSV (1) */
1844 is_tsv = true;
1845 break;
1846 case 0x7: /* ADD,C */
1847 is_c = true;
1848 break;
1849 case 0xf: /* ADD,C,TSV */
1850 is_c = is_tsv = true;
1851 break;
1852 default:
1853 return gen_illegal(ctx);
1856 if (cf) {
1857 nullify_over(ctx);
1859 tcg_r1 = load_gpr(ctx, r1);
1860 tcg_r2 = load_gpr(ctx, r2);
1861 ret = do_add(ctx, rt, tcg_r1, tcg_r2, shift, is_l, is_tsv, is_tc, is_c, cf);
1862 return nullify_end(ctx, ret);
1865 static DisasJumpType trans_sub(DisasContext *ctx, uint32_t insn,
1866 const DisasInsn *di)
1868 unsigned r2 = extract32(insn, 21, 5);
1869 unsigned r1 = extract32(insn, 16, 5);
1870 unsigned cf = extract32(insn, 12, 4);
1871 unsigned ext = extract32(insn, 6, 6);
1872 unsigned rt = extract32(insn, 0, 5);
1873 TCGv tcg_r1, tcg_r2;
1874 bool is_b = false;
1875 bool is_tc = false;
1876 bool is_tsv = false;
1877 DisasJumpType ret;
1879 switch (ext) {
1880 case 0x10: /* SUB */
1881 break;
1882 case 0x30: /* SUB,TSV */
1883 is_tsv = true;
1884 break;
1885 case 0x14: /* SUB,B */
1886 is_b = true;
1887 break;
1888 case 0x34: /* SUB,B,TSV */
1889 is_b = is_tsv = true;
1890 break;
1891 case 0x13: /* SUB,TC */
1892 is_tc = true;
1893 break;
1894 case 0x33: /* SUB,TSV,TC */
1895 is_tc = is_tsv = true;
1896 break;
1897 default:
1898 return gen_illegal(ctx);
1901 if (cf) {
1902 nullify_over(ctx);
1904 tcg_r1 = load_gpr(ctx, r1);
1905 tcg_r2 = load_gpr(ctx, r2);
1906 ret = do_sub(ctx, rt, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, cf);
1907 return nullify_end(ctx, ret);
1910 static DisasJumpType trans_log(DisasContext *ctx, uint32_t insn,
1911 const DisasInsn *di)
1913 unsigned r2 = extract32(insn, 21, 5);
1914 unsigned r1 = extract32(insn, 16, 5);
1915 unsigned cf = extract32(insn, 12, 4);
1916 unsigned rt = extract32(insn, 0, 5);
1917 TCGv tcg_r1, tcg_r2;
1918 DisasJumpType ret;
1920 if (cf) {
1921 nullify_over(ctx);
1923 tcg_r1 = load_gpr(ctx, r1);
1924 tcg_r2 = load_gpr(ctx, r2);
1925 ret = do_log(ctx, rt, tcg_r1, tcg_r2, cf, di->f.ttt);
1926 return nullify_end(ctx, ret);
1929 /* OR r,0,t -> COPY (according to gas) */
1930 static DisasJumpType trans_copy(DisasContext *ctx, uint32_t insn,
1931 const DisasInsn *di)
1933 unsigned r1 = extract32(insn, 16, 5);
1934 unsigned rt = extract32(insn, 0, 5);
1936 if (r1 == 0) {
1937 TCGv dest = dest_gpr(ctx, rt);
1938 tcg_gen_movi_tl(dest, 0);
1939 save_gpr(ctx, rt, dest);
1940 } else {
1941 save_gpr(ctx, rt, cpu_gr[r1]);
1943 cond_free(&ctx->null_cond);
1944 return DISAS_NEXT;
1947 static DisasJumpType trans_cmpclr(DisasContext *ctx, uint32_t insn,
1948 const DisasInsn *di)
1950 unsigned r2 = extract32(insn, 21, 5);
1951 unsigned r1 = extract32(insn, 16, 5);
1952 unsigned cf = extract32(insn, 12, 4);
1953 unsigned rt = extract32(insn, 0, 5);
1954 TCGv tcg_r1, tcg_r2;
1955 DisasJumpType ret;
1957 if (cf) {
1958 nullify_over(ctx);
1960 tcg_r1 = load_gpr(ctx, r1);
1961 tcg_r2 = load_gpr(ctx, r2);
1962 ret = do_cmpclr(ctx, rt, tcg_r1, tcg_r2, cf);
1963 return nullify_end(ctx, ret);
1966 static DisasJumpType trans_uxor(DisasContext *ctx, uint32_t insn,
1967 const DisasInsn *di)
1969 unsigned r2 = extract32(insn, 21, 5);
1970 unsigned r1 = extract32(insn, 16, 5);
1971 unsigned cf = extract32(insn, 12, 4);
1972 unsigned rt = extract32(insn, 0, 5);
1973 TCGv tcg_r1, tcg_r2;
1974 DisasJumpType ret;
1976 if (cf) {
1977 nullify_over(ctx);
1979 tcg_r1 = load_gpr(ctx, r1);
1980 tcg_r2 = load_gpr(ctx, r2);
1981 ret = do_unit(ctx, rt, tcg_r1, tcg_r2, cf, false, tcg_gen_xor_tl);
1982 return nullify_end(ctx, ret);
1985 static DisasJumpType trans_uaddcm(DisasContext *ctx, uint32_t insn,
1986 const DisasInsn *di)
1988 unsigned r2 = extract32(insn, 21, 5);
1989 unsigned r1 = extract32(insn, 16, 5);
1990 unsigned cf = extract32(insn, 12, 4);
1991 unsigned is_tc = extract32(insn, 6, 1);
1992 unsigned rt = extract32(insn, 0, 5);
1993 TCGv tcg_r1, tcg_r2, tmp;
1994 DisasJumpType ret;
1996 if (cf) {
1997 nullify_over(ctx);
1999 tcg_r1 = load_gpr(ctx, r1);
2000 tcg_r2 = load_gpr(ctx, r2);
2001 tmp = get_temp(ctx);
2002 tcg_gen_not_tl(tmp, tcg_r2);
2003 ret = do_unit(ctx, rt, tcg_r1, tmp, cf, is_tc, tcg_gen_add_tl);
2004 return nullify_end(ctx, ret);
2007 static DisasJumpType trans_dcor(DisasContext *ctx, uint32_t insn,
2008 const DisasInsn *di)
2010 unsigned r2 = extract32(insn, 21, 5);
2011 unsigned cf = extract32(insn, 12, 4);
2012 unsigned is_i = extract32(insn, 6, 1);
2013 unsigned rt = extract32(insn, 0, 5);
2014 TCGv tmp;
2015 DisasJumpType ret;
2017 nullify_over(ctx);
2019 tmp = get_temp(ctx);
2020 tcg_gen_shri_tl(tmp, cpu_psw_cb, 3);
2021 if (!is_i) {
2022 tcg_gen_not_tl(tmp, tmp);
2024 tcg_gen_andi_tl(tmp, tmp, 0x11111111);
2025 tcg_gen_muli_tl(tmp, tmp, 6);
2026 ret = do_unit(ctx, rt, tmp, load_gpr(ctx, r2), cf, false,
2027 is_i ? tcg_gen_add_tl : tcg_gen_sub_tl);
2029 return nullify_end(ctx, ret);
2032 static DisasJumpType trans_ds(DisasContext *ctx, uint32_t insn,
2033 const DisasInsn *di)
2035 unsigned r2 = extract32(insn, 21, 5);
2036 unsigned r1 = extract32(insn, 16, 5);
2037 unsigned cf = extract32(insn, 12, 4);
2038 unsigned rt = extract32(insn, 0, 5);
2039 TCGv dest, add1, add2, addc, zero, in1, in2;
2041 nullify_over(ctx);
2043 in1 = load_gpr(ctx, r1);
2044 in2 = load_gpr(ctx, r2);
2046 add1 = tcg_temp_new();
2047 add2 = tcg_temp_new();
2048 addc = tcg_temp_new();
2049 dest = tcg_temp_new();
2050 zero = tcg_const_tl(0);
2052 /* Form R1 << 1 | PSW[CB]{8}. */
2053 tcg_gen_add_tl(add1, in1, in1);
2054 tcg_gen_add_tl(add1, add1, cpu_psw_cb_msb);
2056 /* Add or subtract R2, depending on PSW[V]. Proper computation of
2057 carry{8} requires that we subtract via + ~R2 + 1, as described in
2058 the manual. By extracting and masking V, we can produce the
2059 proper inputs to the addition without movcond. */
2060 tcg_gen_sari_tl(addc, cpu_psw_v, TARGET_LONG_BITS - 1);
2061 tcg_gen_xor_tl(add2, in2, addc);
2062 tcg_gen_andi_tl(addc, addc, 1);
2063 /* ??? This is only correct for 32-bit. */
2064 tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
2065 tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
2067 tcg_temp_free(addc);
2068 tcg_temp_free(zero);
2070 /* Write back the result register. */
2071 save_gpr(ctx, rt, dest);
2073 /* Write back PSW[CB]. */
2074 tcg_gen_xor_tl(cpu_psw_cb, add1, add2);
2075 tcg_gen_xor_tl(cpu_psw_cb, cpu_psw_cb, dest);
2077 /* Write back PSW[V] for the division step. */
2078 tcg_gen_neg_tl(cpu_psw_v, cpu_psw_cb_msb);
2079 tcg_gen_xor_tl(cpu_psw_v, cpu_psw_v, in2);
2081 /* Install the new nullification. */
2082 if (cf) {
2083 TCGv sv;
2084 TCGV_UNUSED(sv);
2085 if (cf >> 1 == 6) {
2086 /* ??? The lshift is supposed to contribute to overflow. */
2087 sv = do_add_sv(ctx, dest, add1, add2);
2089 ctx->null_cond = do_cond(cf, dest, cpu_psw_cb_msb, sv);
2092 tcg_temp_free(add1);
2093 tcg_temp_free(add2);
2094 tcg_temp_free(dest);
2096 return nullify_end(ctx, DISAS_NEXT);
2099 static const DisasInsn table_arith_log[] = {
2100 { 0x08000240u, 0xfc00ffffu, trans_nop }, /* or x,y,0 */
2101 { 0x08000240u, 0xffe0ffe0u, trans_copy }, /* or x,0,t */
2102 { 0x08000000u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_andc_tl },
2103 { 0x08000200u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_and_tl },
2104 { 0x08000240u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_or_tl },
2105 { 0x08000280u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_xor_tl },
2106 { 0x08000880u, 0xfc000fe0u, trans_cmpclr },
2107 { 0x08000380u, 0xfc000fe0u, trans_uxor },
2108 { 0x08000980u, 0xfc000fa0u, trans_uaddcm },
2109 { 0x08000b80u, 0xfc1f0fa0u, trans_dcor },
2110 { 0x08000440u, 0xfc000fe0u, trans_ds },
2111 { 0x08000700u, 0xfc0007e0u, trans_add }, /* add */
2112 { 0x08000400u, 0xfc0006e0u, trans_sub }, /* sub; sub,b; sub,tsv */
2113 { 0x080004c0u, 0xfc0007e0u, trans_sub }, /* sub,tc; sub,tsv,tc */
2114 { 0x08000200u, 0xfc000320u, trans_add }, /* shladd */
2117 static DisasJumpType trans_addi(DisasContext *ctx, uint32_t insn)
2119 target_long im = low_sextract(insn, 0, 11);
2120 unsigned e1 = extract32(insn, 11, 1);
2121 unsigned cf = extract32(insn, 12, 4);
2122 unsigned rt = extract32(insn, 16, 5);
2123 unsigned r2 = extract32(insn, 21, 5);
2124 unsigned o1 = extract32(insn, 26, 1);
2125 TCGv tcg_im, tcg_r2;
2126 DisasJumpType ret;
2128 if (cf) {
2129 nullify_over(ctx);
2132 tcg_im = load_const(ctx, im);
2133 tcg_r2 = load_gpr(ctx, r2);
2134 ret = do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf);
2136 return nullify_end(ctx, ret);
2139 static DisasJumpType trans_subi(DisasContext *ctx, uint32_t insn)
2141 target_long im = low_sextract(insn, 0, 11);
2142 unsigned e1 = extract32(insn, 11, 1);
2143 unsigned cf = extract32(insn, 12, 4);
2144 unsigned rt = extract32(insn, 16, 5);
2145 unsigned r2 = extract32(insn, 21, 5);
2146 TCGv tcg_im, tcg_r2;
2147 DisasJumpType ret;
2149 if (cf) {
2150 nullify_over(ctx);
2153 tcg_im = load_const(ctx, im);
2154 tcg_r2 = load_gpr(ctx, r2);
2155 ret = do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf);
2157 return nullify_end(ctx, ret);
2160 static DisasJumpType trans_cmpiclr(DisasContext *ctx, uint32_t insn)
2162 target_long im = low_sextract(insn, 0, 11);
2163 unsigned cf = extract32(insn, 12, 4);
2164 unsigned rt = extract32(insn, 16, 5);
2165 unsigned r2 = extract32(insn, 21, 5);
2166 TCGv tcg_im, tcg_r2;
2167 DisasJumpType ret;
2169 if (cf) {
2170 nullify_over(ctx);
2173 tcg_im = load_const(ctx, im);
2174 tcg_r2 = load_gpr(ctx, r2);
2175 ret = do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf);
2177 return nullify_end(ctx, ret);
2180 static DisasJumpType trans_ld_idx_i(DisasContext *ctx, uint32_t insn,
2181 const DisasInsn *di)
2183 unsigned rt = extract32(insn, 0, 5);
2184 unsigned m = extract32(insn, 5, 1);
2185 unsigned sz = extract32(insn, 6, 2);
2186 unsigned a = extract32(insn, 13, 1);
2187 int disp = low_sextract(insn, 16, 5);
2188 unsigned rb = extract32(insn, 21, 5);
2189 int modify = (m ? (a ? -1 : 1) : 0);
2190 TCGMemOp mop = MO_TE | sz;
2192 return do_load(ctx, rt, rb, 0, 0, disp, modify, mop);
2195 static DisasJumpType trans_ld_idx_x(DisasContext *ctx, uint32_t insn,
2196 const DisasInsn *di)
2198 unsigned rt = extract32(insn, 0, 5);
2199 unsigned m = extract32(insn, 5, 1);
2200 unsigned sz = extract32(insn, 6, 2);
2201 unsigned u = extract32(insn, 13, 1);
2202 unsigned rx = extract32(insn, 16, 5);
2203 unsigned rb = extract32(insn, 21, 5);
2204 TCGMemOp mop = MO_TE | sz;
2206 return do_load(ctx, rt, rb, rx, u ? sz : 0, 0, m, mop);
2209 static DisasJumpType trans_st_idx_i(DisasContext *ctx, uint32_t insn,
2210 const DisasInsn *di)
2212 int disp = low_sextract(insn, 0, 5);
2213 unsigned m = extract32(insn, 5, 1);
2214 unsigned sz = extract32(insn, 6, 2);
2215 unsigned a = extract32(insn, 13, 1);
2216 unsigned rr = extract32(insn, 16, 5);
2217 unsigned rb = extract32(insn, 21, 5);
2218 int modify = (m ? (a ? -1 : 1) : 0);
2219 TCGMemOp mop = MO_TE | sz;
2221 return do_store(ctx, rr, rb, disp, modify, mop);
2224 static DisasJumpType trans_ldcw(DisasContext *ctx, uint32_t insn,
2225 const DisasInsn *di)
2227 unsigned rt = extract32(insn, 0, 5);
2228 unsigned m = extract32(insn, 5, 1);
2229 unsigned i = extract32(insn, 12, 1);
2230 unsigned au = extract32(insn, 13, 1);
2231 unsigned rx = extract32(insn, 16, 5);
2232 unsigned rb = extract32(insn, 21, 5);
2233 TCGMemOp mop = MO_TEUL | MO_ALIGN_16;
2234 TCGv zero, addr, base, dest;
2235 int modify, disp = 0, scale = 0;
2237 nullify_over(ctx);
2239 /* ??? Share more code with do_load and do_load_{32,64}. */
2241 if (i) {
2242 modify = (m ? (au ? -1 : 1) : 0);
2243 disp = low_sextract(rx, 0, 5);
2244 rx = 0;
2245 } else {
2246 modify = m;
2247 if (au) {
2248 scale = mop & MO_SIZE;
2251 if (modify) {
2252 /* Base register modification. Make sure if RT == RB, we see
2253 the result of the load. */
2254 dest = get_temp(ctx);
2255 } else {
2256 dest = dest_gpr(ctx, rt);
2259 addr = tcg_temp_new();
2260 base = load_gpr(ctx, rb);
2261 if (rx) {
2262 tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
2263 tcg_gen_add_tl(addr, addr, base);
2264 } else {
2265 tcg_gen_addi_tl(addr, base, disp);
2268 zero = tcg_const_tl(0);
2269 tcg_gen_atomic_xchg_tl(dest, (modify <= 0 ? addr : base),
2270 zero, MMU_USER_IDX, mop);
2271 if (modify) {
2272 save_gpr(ctx, rb, addr);
2274 save_gpr(ctx, rt, dest);
2276 return nullify_end(ctx, DISAS_NEXT);
2279 static DisasJumpType trans_stby(DisasContext *ctx, uint32_t insn,
2280 const DisasInsn *di)
2282 target_long disp = low_sextract(insn, 0, 5);
2283 unsigned m = extract32(insn, 5, 1);
2284 unsigned a = extract32(insn, 13, 1);
2285 unsigned rt = extract32(insn, 16, 5);
2286 unsigned rb = extract32(insn, 21, 5);
2287 TCGv addr, val;
2289 nullify_over(ctx);
2291 addr = tcg_temp_new();
2292 if (m || disp == 0) {
2293 tcg_gen_mov_tl(addr, load_gpr(ctx, rb));
2294 } else {
2295 tcg_gen_addi_tl(addr, load_gpr(ctx, rb), disp);
2297 val = load_gpr(ctx, rt);
2299 if (a) {
2300 gen_helper_stby_e(cpu_env, addr, val);
2301 } else {
2302 gen_helper_stby_b(cpu_env, addr, val);
2305 if (m) {
2306 tcg_gen_addi_tl(addr, addr, disp);
2307 tcg_gen_andi_tl(addr, addr, ~3);
2308 save_gpr(ctx, rb, addr);
2310 tcg_temp_free(addr);
2312 return nullify_end(ctx, DISAS_NEXT);
2315 static const DisasInsn table_index_mem[] = {
2316 { 0x0c001000u, 0xfc001300, trans_ld_idx_i }, /* LD[BHWD], im */
2317 { 0x0c000000u, 0xfc001300, trans_ld_idx_x }, /* LD[BHWD], rx */
2318 { 0x0c001200u, 0xfc001300, trans_st_idx_i }, /* ST[BHWD] */
2319 { 0x0c0001c0u, 0xfc0003c0, trans_ldcw },
2320 { 0x0c001300u, 0xfc0013c0, trans_stby },
2323 static DisasJumpType trans_ldil(DisasContext *ctx, uint32_t insn)
2325 unsigned rt = extract32(insn, 21, 5);
2326 target_long i = assemble_21(insn);
2327 TCGv tcg_rt = dest_gpr(ctx, rt);
2329 tcg_gen_movi_tl(tcg_rt, i);
2330 save_gpr(ctx, rt, tcg_rt);
2331 cond_free(&ctx->null_cond);
2333 return DISAS_NEXT;
2336 static DisasJumpType trans_addil(DisasContext *ctx, uint32_t insn)
2338 unsigned rt = extract32(insn, 21, 5);
2339 target_long i = assemble_21(insn);
2340 TCGv tcg_rt = load_gpr(ctx, rt);
2341 TCGv tcg_r1 = dest_gpr(ctx, 1);
2343 tcg_gen_addi_tl(tcg_r1, tcg_rt, i);
2344 save_gpr(ctx, 1, tcg_r1);
2345 cond_free(&ctx->null_cond);
2347 return DISAS_NEXT;
2350 static DisasJumpType trans_ldo(DisasContext *ctx, uint32_t insn)
2352 unsigned rb = extract32(insn, 21, 5);
2353 unsigned rt = extract32(insn, 16, 5);
2354 target_long i = assemble_16(insn);
2355 TCGv tcg_rt = dest_gpr(ctx, rt);
2357 /* Special case rb == 0, for the LDI pseudo-op.
2358 The COPY pseudo-op is handled for free within tcg_gen_addi_tl. */
2359 if (rb == 0) {
2360 tcg_gen_movi_tl(tcg_rt, i);
2361 } else {
2362 tcg_gen_addi_tl(tcg_rt, cpu_gr[rb], i);
2364 save_gpr(ctx, rt, tcg_rt);
2365 cond_free(&ctx->null_cond);
2367 return DISAS_NEXT;
2370 static DisasJumpType trans_load(DisasContext *ctx, uint32_t insn,
2371 bool is_mod, TCGMemOp mop)
2373 unsigned rb = extract32(insn, 21, 5);
2374 unsigned rt = extract32(insn, 16, 5);
2375 target_long i = assemble_16(insn);
2377 return do_load(ctx, rt, rb, 0, 0, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
2380 static DisasJumpType trans_load_w(DisasContext *ctx, uint32_t insn)
2382 unsigned rb = extract32(insn, 21, 5);
2383 unsigned rt = extract32(insn, 16, 5);
2384 target_long i = assemble_16a(insn);
2385 unsigned ext2 = extract32(insn, 1, 2);
2387 switch (ext2) {
2388 case 0:
2389 case 1:
2390 /* FLDW without modification. */
2391 return do_floadw(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
2392 case 2:
2393 /* LDW with modification. Note that the sign of I selects
2394 post-dec vs pre-inc. */
2395 return do_load(ctx, rt, rb, 0, 0, i, (i < 0 ? 1 : -1), MO_TEUL);
2396 default:
2397 return gen_illegal(ctx);
2401 static DisasJumpType trans_fload_mod(DisasContext *ctx, uint32_t insn)
2403 target_long i = assemble_16a(insn);
2404 unsigned t1 = extract32(insn, 1, 1);
2405 unsigned a = extract32(insn, 2, 1);
2406 unsigned t0 = extract32(insn, 16, 5);
2407 unsigned rb = extract32(insn, 21, 5);
2409 /* FLDW with modification. */
2410 return do_floadw(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
2413 static DisasJumpType trans_store(DisasContext *ctx, uint32_t insn,
2414 bool is_mod, TCGMemOp mop)
2416 unsigned rb = extract32(insn, 21, 5);
2417 unsigned rt = extract32(insn, 16, 5);
2418 target_long i = assemble_16(insn);
2420 return do_store(ctx, rt, rb, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
2423 static DisasJumpType trans_store_w(DisasContext *ctx, uint32_t insn)
2425 unsigned rb = extract32(insn, 21, 5);
2426 unsigned rt = extract32(insn, 16, 5);
2427 target_long i = assemble_16a(insn);
2428 unsigned ext2 = extract32(insn, 1, 2);
2430 switch (ext2) {
2431 case 0:
2432 case 1:
2433 /* FSTW without modification. */
2434 return do_fstorew(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
2435 case 2:
2436 /* LDW with modification. */
2437 return do_store(ctx, rt, rb, i, (i < 0 ? 1 : -1), MO_TEUL);
2438 default:
2439 return gen_illegal(ctx);
2443 static DisasJumpType trans_fstore_mod(DisasContext *ctx, uint32_t insn)
2445 target_long i = assemble_16a(insn);
2446 unsigned t1 = extract32(insn, 1, 1);
2447 unsigned a = extract32(insn, 2, 1);
2448 unsigned t0 = extract32(insn, 16, 5);
2449 unsigned rb = extract32(insn, 21, 5);
2451 /* FSTW with modification. */
2452 return do_fstorew(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
2455 static DisasJumpType trans_copr_w(DisasContext *ctx, uint32_t insn)
2457 unsigned t0 = extract32(insn, 0, 5);
2458 unsigned m = extract32(insn, 5, 1);
2459 unsigned t1 = extract32(insn, 6, 1);
2460 unsigned ext3 = extract32(insn, 7, 3);
2461 /* unsigned cc = extract32(insn, 10, 2); */
2462 unsigned i = extract32(insn, 12, 1);
2463 unsigned ua = extract32(insn, 13, 1);
2464 unsigned rx = extract32(insn, 16, 5);
2465 unsigned rb = extract32(insn, 21, 5);
2466 unsigned rt = t1 * 32 + t0;
2467 int modify = (m ? (ua ? -1 : 1) : 0);
2468 int disp, scale;
2470 if (i == 0) {
2471 scale = (ua ? 2 : 0);
2472 disp = 0;
2473 modify = m;
2474 } else {
2475 disp = low_sextract(rx, 0, 5);
2476 scale = 0;
2477 rx = 0;
2478 modify = (m ? (ua ? -1 : 1) : 0);
2481 switch (ext3) {
2482 case 0: /* FLDW */
2483 return do_floadw(ctx, rt, rb, rx, scale, disp, modify);
2484 case 4: /* FSTW */
2485 return do_fstorew(ctx, rt, rb, rx, scale, disp, modify);
2487 return gen_illegal(ctx);
2490 static DisasJumpType trans_copr_dw(DisasContext *ctx, uint32_t insn)
2492 unsigned rt = extract32(insn, 0, 5);
2493 unsigned m = extract32(insn, 5, 1);
2494 unsigned ext4 = extract32(insn, 6, 4);
2495 /* unsigned cc = extract32(insn, 10, 2); */
2496 unsigned i = extract32(insn, 12, 1);
2497 unsigned ua = extract32(insn, 13, 1);
2498 unsigned rx = extract32(insn, 16, 5);
2499 unsigned rb = extract32(insn, 21, 5);
2500 int modify = (m ? (ua ? -1 : 1) : 0);
2501 int disp, scale;
2503 if (i == 0) {
2504 scale = (ua ? 3 : 0);
2505 disp = 0;
2506 modify = m;
2507 } else {
2508 disp = low_sextract(rx, 0, 5);
2509 scale = 0;
2510 rx = 0;
2511 modify = (m ? (ua ? -1 : 1) : 0);
2514 switch (ext4) {
2515 case 0: /* FLDD */
2516 return do_floadd(ctx, rt, rb, rx, scale, disp, modify);
2517 case 8: /* FSTD */
2518 return do_fstored(ctx, rt, rb, rx, scale, disp, modify);
2519 default:
2520 return gen_illegal(ctx);
2524 static DisasJumpType trans_cmpb(DisasContext *ctx, uint32_t insn,
2525 bool is_true, bool is_imm, bool is_dw)
2527 target_long disp = assemble_12(insn) * 4;
2528 unsigned n = extract32(insn, 1, 1);
2529 unsigned c = extract32(insn, 13, 3);
2530 unsigned r = extract32(insn, 21, 5);
2531 unsigned cf = c * 2 + !is_true;
2532 TCGv dest, in1, in2, sv;
2533 DisasCond cond;
2535 nullify_over(ctx);
2537 if (is_imm) {
2538 in1 = load_const(ctx, low_sextract(insn, 16, 5));
2539 } else {
2540 in1 = load_gpr(ctx, extract32(insn, 16, 5));
2542 in2 = load_gpr(ctx, r);
2543 dest = get_temp(ctx);
2545 tcg_gen_sub_tl(dest, in1, in2);
2547 TCGV_UNUSED(sv);
2548 if (c == 6) {
2549 sv = do_sub_sv(ctx, dest, in1, in2);
2552 cond = do_sub_cond(cf, dest, in1, in2, sv);
2553 return do_cbranch(ctx, disp, n, &cond);
2556 static DisasJumpType trans_addb(DisasContext *ctx, uint32_t insn,
2557 bool is_true, bool is_imm)
2559 target_long disp = assemble_12(insn) * 4;
2560 unsigned n = extract32(insn, 1, 1);
2561 unsigned c = extract32(insn, 13, 3);
2562 unsigned r = extract32(insn, 21, 5);
2563 unsigned cf = c * 2 + !is_true;
2564 TCGv dest, in1, in2, sv, cb_msb;
2565 DisasCond cond;
2567 nullify_over(ctx);
2569 if (is_imm) {
2570 in1 = load_const(ctx, low_sextract(insn, 16, 5));
2571 } else {
2572 in1 = load_gpr(ctx, extract32(insn, 16, 5));
2574 in2 = load_gpr(ctx, r);
2575 dest = dest_gpr(ctx, r);
2576 TCGV_UNUSED(sv);
2577 TCGV_UNUSED(cb_msb);
2579 switch (c) {
2580 default:
2581 tcg_gen_add_tl(dest, in1, in2);
2582 break;
2583 case 4: case 5:
2584 cb_msb = get_temp(ctx);
2585 tcg_gen_movi_tl(cb_msb, 0);
2586 tcg_gen_add2_tl(dest, cb_msb, in1, cb_msb, in2, cb_msb);
2587 break;
2588 case 6:
2589 tcg_gen_add_tl(dest, in1, in2);
2590 sv = do_add_sv(ctx, dest, in1, in2);
2591 break;
2594 cond = do_cond(cf, dest, cb_msb, sv);
2595 return do_cbranch(ctx, disp, n, &cond);
2598 static DisasJumpType trans_bb(DisasContext *ctx, uint32_t insn)
2600 target_long disp = assemble_12(insn) * 4;
2601 unsigned n = extract32(insn, 1, 1);
2602 unsigned c = extract32(insn, 15, 1);
2603 unsigned r = extract32(insn, 16, 5);
2604 unsigned p = extract32(insn, 21, 5);
2605 unsigned i = extract32(insn, 26, 1);
2606 TCGv tmp, tcg_r;
2607 DisasCond cond;
2609 nullify_over(ctx);
2611 tmp = tcg_temp_new();
2612 tcg_r = load_gpr(ctx, r);
2613 if (i) {
2614 tcg_gen_shli_tl(tmp, tcg_r, p);
2615 } else {
2616 tcg_gen_shl_tl(tmp, tcg_r, cpu_sar);
2619 cond = cond_make_0(c ? TCG_COND_GE : TCG_COND_LT, tmp);
2620 tcg_temp_free(tmp);
2621 return do_cbranch(ctx, disp, n, &cond);
2624 static DisasJumpType trans_movb(DisasContext *ctx, uint32_t insn, bool is_imm)
2626 target_long disp = assemble_12(insn) * 4;
2627 unsigned n = extract32(insn, 1, 1);
2628 unsigned c = extract32(insn, 13, 3);
2629 unsigned t = extract32(insn, 16, 5);
2630 unsigned r = extract32(insn, 21, 5);
2631 TCGv dest;
2632 DisasCond cond;
2634 nullify_over(ctx);
2636 dest = dest_gpr(ctx, r);
2637 if (is_imm) {
2638 tcg_gen_movi_tl(dest, low_sextract(t, 0, 5));
2639 } else if (t == 0) {
2640 tcg_gen_movi_tl(dest, 0);
2641 } else {
2642 tcg_gen_mov_tl(dest, cpu_gr[t]);
2645 cond = do_sed_cond(c, dest);
2646 return do_cbranch(ctx, disp, n, &cond);
2649 static DisasJumpType trans_shrpw_sar(DisasContext *ctx, uint32_t insn,
2650 const DisasInsn *di)
2652 unsigned rt = extract32(insn, 0, 5);
2653 unsigned c = extract32(insn, 13, 3);
2654 unsigned r1 = extract32(insn, 16, 5);
2655 unsigned r2 = extract32(insn, 21, 5);
2656 TCGv dest;
2658 if (c) {
2659 nullify_over(ctx);
2662 dest = dest_gpr(ctx, rt);
2663 if (r1 == 0) {
2664 tcg_gen_ext32u_tl(dest, load_gpr(ctx, r2));
2665 tcg_gen_shr_tl(dest, dest, cpu_sar);
2666 } else if (r1 == r2) {
2667 TCGv_i32 t32 = tcg_temp_new_i32();
2668 tcg_gen_trunc_tl_i32(t32, load_gpr(ctx, r2));
2669 tcg_gen_rotr_i32(t32, t32, cpu_sar);
2670 tcg_gen_extu_i32_tl(dest, t32);
2671 tcg_temp_free_i32(t32);
2672 } else {
2673 TCGv_i64 t = tcg_temp_new_i64();
2674 TCGv_i64 s = tcg_temp_new_i64();
2676 tcg_gen_concat_tl_i64(t, load_gpr(ctx, r2), load_gpr(ctx, r1));
2677 tcg_gen_extu_tl_i64(s, cpu_sar);
2678 tcg_gen_shr_i64(t, t, s);
2679 tcg_gen_trunc_i64_tl(dest, t);
2681 tcg_temp_free_i64(t);
2682 tcg_temp_free_i64(s);
2684 save_gpr(ctx, rt, dest);
2686 /* Install the new nullification. */
2687 cond_free(&ctx->null_cond);
2688 if (c) {
2689 ctx->null_cond = do_sed_cond(c, dest);
2691 return nullify_end(ctx, DISAS_NEXT);
2694 static DisasJumpType trans_shrpw_imm(DisasContext *ctx, uint32_t insn,
2695 const DisasInsn *di)
2697 unsigned rt = extract32(insn, 0, 5);
2698 unsigned cpos = extract32(insn, 5, 5);
2699 unsigned c = extract32(insn, 13, 3);
2700 unsigned r1 = extract32(insn, 16, 5);
2701 unsigned r2 = extract32(insn, 21, 5);
2702 unsigned sa = 31 - cpos;
2703 TCGv dest, t2;
2705 if (c) {
2706 nullify_over(ctx);
2709 dest = dest_gpr(ctx, rt);
2710 t2 = load_gpr(ctx, r2);
2711 if (r1 == r2) {
2712 TCGv_i32 t32 = tcg_temp_new_i32();
2713 tcg_gen_trunc_tl_i32(t32, t2);
2714 tcg_gen_rotri_i32(t32, t32, sa);
2715 tcg_gen_extu_i32_tl(dest, t32);
2716 tcg_temp_free_i32(t32);
2717 } else if (r1 == 0) {
2718 tcg_gen_extract_tl(dest, t2, sa, 32 - sa);
2719 } else {
2720 TCGv t0 = tcg_temp_new();
2721 tcg_gen_extract_tl(t0, t2, sa, 32 - sa);
2722 tcg_gen_deposit_tl(dest, t0, cpu_gr[r1], 32 - sa, sa);
2723 tcg_temp_free(t0);
2725 save_gpr(ctx, rt, dest);
2727 /* Install the new nullification. */
2728 cond_free(&ctx->null_cond);
2729 if (c) {
2730 ctx->null_cond = do_sed_cond(c, dest);
2732 return nullify_end(ctx, DISAS_NEXT);
2735 static DisasJumpType trans_extrw_sar(DisasContext *ctx, uint32_t insn,
2736 const DisasInsn *di)
2738 unsigned clen = extract32(insn, 0, 5);
2739 unsigned is_se = extract32(insn, 10, 1);
2740 unsigned c = extract32(insn, 13, 3);
2741 unsigned rt = extract32(insn, 16, 5);
2742 unsigned rr = extract32(insn, 21, 5);
2743 unsigned len = 32 - clen;
2744 TCGv dest, src, tmp;
2746 if (c) {
2747 nullify_over(ctx);
2750 dest = dest_gpr(ctx, rt);
2751 src = load_gpr(ctx, rr);
2752 tmp = tcg_temp_new();
2754 /* Recall that SAR is using big-endian bit numbering. */
2755 tcg_gen_xori_tl(tmp, cpu_sar, TARGET_LONG_BITS - 1);
2756 if (is_se) {
2757 tcg_gen_sar_tl(dest, src, tmp);
2758 tcg_gen_sextract_tl(dest, dest, 0, len);
2759 } else {
2760 tcg_gen_shr_tl(dest, src, tmp);
2761 tcg_gen_extract_tl(dest, dest, 0, len);
2763 tcg_temp_free(tmp);
2764 save_gpr(ctx, rt, dest);
2766 /* Install the new nullification. */
2767 cond_free(&ctx->null_cond);
2768 if (c) {
2769 ctx->null_cond = do_sed_cond(c, dest);
2771 return nullify_end(ctx, DISAS_NEXT);
2774 static DisasJumpType trans_extrw_imm(DisasContext *ctx, uint32_t insn,
2775 const DisasInsn *di)
2777 unsigned clen = extract32(insn, 0, 5);
2778 unsigned pos = extract32(insn, 5, 5);
2779 unsigned is_se = extract32(insn, 10, 1);
2780 unsigned c = extract32(insn, 13, 3);
2781 unsigned rt = extract32(insn, 16, 5);
2782 unsigned rr = extract32(insn, 21, 5);
2783 unsigned len = 32 - clen;
2784 unsigned cpos = 31 - pos;
2785 TCGv dest, src;
2787 if (c) {
2788 nullify_over(ctx);
2791 dest = dest_gpr(ctx, rt);
2792 src = load_gpr(ctx, rr);
2793 if (is_se) {
2794 tcg_gen_sextract_tl(dest, src, cpos, len);
2795 } else {
2796 tcg_gen_extract_tl(dest, src, cpos, len);
2798 save_gpr(ctx, rt, dest);
2800 /* Install the new nullification. */
2801 cond_free(&ctx->null_cond);
2802 if (c) {
2803 ctx->null_cond = do_sed_cond(c, dest);
2805 return nullify_end(ctx, DISAS_NEXT);
2808 static const DisasInsn table_sh_ex[] = {
2809 { 0xd0000000u, 0xfc001fe0u, trans_shrpw_sar },
2810 { 0xd0000800u, 0xfc001c00u, trans_shrpw_imm },
2811 { 0xd0001000u, 0xfc001be0u, trans_extrw_sar },
2812 { 0xd0001800u, 0xfc001800u, trans_extrw_imm },
2815 static DisasJumpType trans_depw_imm_c(DisasContext *ctx, uint32_t insn,
2816 const DisasInsn *di)
2818 unsigned clen = extract32(insn, 0, 5);
2819 unsigned cpos = extract32(insn, 5, 5);
2820 unsigned nz = extract32(insn, 10, 1);
2821 unsigned c = extract32(insn, 13, 3);
2822 target_long val = low_sextract(insn, 16, 5);
2823 unsigned rt = extract32(insn, 21, 5);
2824 unsigned len = 32 - clen;
2825 target_long mask0, mask1;
2826 TCGv dest;
2828 if (c) {
2829 nullify_over(ctx);
2831 if (cpos + len > 32) {
2832 len = 32 - cpos;
2835 dest = dest_gpr(ctx, rt);
2836 mask0 = deposit64(0, cpos, len, val);
2837 mask1 = deposit64(-1, cpos, len, val);
2839 if (nz) {
2840 TCGv src = load_gpr(ctx, rt);
2841 if (mask1 != -1) {
2842 tcg_gen_andi_tl(dest, src, mask1);
2843 src = dest;
2845 tcg_gen_ori_tl(dest, src, mask0);
2846 } else {
2847 tcg_gen_movi_tl(dest, mask0);
2849 save_gpr(ctx, rt, dest);
2851 /* Install the new nullification. */
2852 cond_free(&ctx->null_cond);
2853 if (c) {
2854 ctx->null_cond = do_sed_cond(c, dest);
2856 return nullify_end(ctx, DISAS_NEXT);
2859 static DisasJumpType trans_depw_imm(DisasContext *ctx, uint32_t insn,
2860 const DisasInsn *di)
2862 unsigned clen = extract32(insn, 0, 5);
2863 unsigned cpos = extract32(insn, 5, 5);
2864 unsigned nz = extract32(insn, 10, 1);
2865 unsigned c = extract32(insn, 13, 3);
2866 unsigned rr = extract32(insn, 16, 5);
2867 unsigned rt = extract32(insn, 21, 5);
2868 unsigned rs = nz ? rt : 0;
2869 unsigned len = 32 - clen;
2870 TCGv dest, val;
2872 if (c) {
2873 nullify_over(ctx);
2875 if (cpos + len > 32) {
2876 len = 32 - cpos;
2879 dest = dest_gpr(ctx, rt);
2880 val = load_gpr(ctx, rr);
2881 if (rs == 0) {
2882 tcg_gen_deposit_z_tl(dest, val, cpos, len);
2883 } else {
2884 tcg_gen_deposit_tl(dest, cpu_gr[rs], val, cpos, len);
2886 save_gpr(ctx, rt, dest);
2888 /* Install the new nullification. */
2889 cond_free(&ctx->null_cond);
2890 if (c) {
2891 ctx->null_cond = do_sed_cond(c, dest);
2893 return nullify_end(ctx, DISAS_NEXT);
2896 static DisasJumpType trans_depw_sar(DisasContext *ctx, uint32_t insn,
2897 const DisasInsn *di)
2899 unsigned clen = extract32(insn, 0, 5);
2900 unsigned nz = extract32(insn, 10, 1);
2901 unsigned i = extract32(insn, 12, 1);
2902 unsigned c = extract32(insn, 13, 3);
2903 unsigned rt = extract32(insn, 21, 5);
2904 unsigned rs = nz ? rt : 0;
2905 unsigned len = 32 - clen;
2906 TCGv val, mask, tmp, shift, dest;
2907 unsigned msb = 1U << (len - 1);
2909 if (c) {
2910 nullify_over(ctx);
2913 if (i) {
2914 val = load_const(ctx, low_sextract(insn, 16, 5));
2915 } else {
2916 val = load_gpr(ctx, extract32(insn, 16, 5));
2918 dest = dest_gpr(ctx, rt);
2919 shift = tcg_temp_new();
2920 tmp = tcg_temp_new();
2922 /* Convert big-endian bit numbering in SAR to left-shift. */
2923 tcg_gen_xori_tl(shift, cpu_sar, TARGET_LONG_BITS - 1);
2925 mask = tcg_const_tl(msb + (msb - 1));
2926 tcg_gen_and_tl(tmp, val, mask);
2927 if (rs) {
2928 tcg_gen_shl_tl(mask, mask, shift);
2929 tcg_gen_shl_tl(tmp, tmp, shift);
2930 tcg_gen_andc_tl(dest, cpu_gr[rs], mask);
2931 tcg_gen_or_tl(dest, dest, tmp);
2932 } else {
2933 tcg_gen_shl_tl(dest, tmp, shift);
2935 tcg_temp_free(shift);
2936 tcg_temp_free(mask);
2937 tcg_temp_free(tmp);
2938 save_gpr(ctx, rt, dest);
2940 /* Install the new nullification. */
2941 cond_free(&ctx->null_cond);
2942 if (c) {
2943 ctx->null_cond = do_sed_cond(c, dest);
2945 return nullify_end(ctx, DISAS_NEXT);
2948 static const DisasInsn table_depw[] = {
2949 { 0xd4000000u, 0xfc000be0u, trans_depw_sar },
2950 { 0xd4000800u, 0xfc001800u, trans_depw_imm },
2951 { 0xd4001800u, 0xfc001800u, trans_depw_imm_c },
2954 static DisasJumpType trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
2956 unsigned n = extract32(insn, 1, 1);
2957 unsigned b = extract32(insn, 21, 5);
2958 target_long disp = assemble_17(insn);
2960 /* unsigned s = low_uextract(insn, 13, 3); */
2961 /* ??? It seems like there should be a good way of using
2962 "be disp(sr2, r0)", the canonical gateway entry mechanism
2963 to our advantage. But that appears to be inconvenient to
2964 manage along side branch delay slots. Therefore we handle
2965 entry into the gateway page via absolute address. */
2967 /* Since we don't implement spaces, just branch. Do notice the special
2968 case of "be disp(*,r0)" using a direct branch to disp, so that we can
2969 goto_tb to the TB containing the syscall. */
2970 if (b == 0) {
2971 return do_dbranch(ctx, disp, is_l ? 31 : 0, n);
2972 } else {
2973 TCGv tmp = get_temp(ctx);
2974 tcg_gen_addi_tl(tmp, load_gpr(ctx, b), disp);
2975 return do_ibranch(ctx, tmp, is_l ? 31 : 0, n);
2979 static DisasJumpType trans_bl(DisasContext *ctx, uint32_t insn,
2980 const DisasInsn *di)
2982 unsigned n = extract32(insn, 1, 1);
2983 unsigned link = extract32(insn, 21, 5);
2984 target_long disp = assemble_17(insn);
2986 return do_dbranch(ctx, iaoq_dest(ctx, disp), link, n);
2989 static DisasJumpType trans_bl_long(DisasContext *ctx, uint32_t insn,
2990 const DisasInsn *di)
2992 unsigned n = extract32(insn, 1, 1);
2993 target_long disp = assemble_22(insn);
2995 return do_dbranch(ctx, iaoq_dest(ctx, disp), 2, n);
2998 static DisasJumpType trans_blr(DisasContext *ctx, uint32_t insn,
2999 const DisasInsn *di)
3001 unsigned n = extract32(insn, 1, 1);
3002 unsigned rx = extract32(insn, 16, 5);
3003 unsigned link = extract32(insn, 21, 5);
3004 TCGv tmp = get_temp(ctx);
3006 tcg_gen_shli_tl(tmp, load_gpr(ctx, rx), 3);
3007 tcg_gen_addi_tl(tmp, tmp, ctx->iaoq_f + 8);
3008 return do_ibranch(ctx, tmp, link, n);
3011 static DisasJumpType trans_bv(DisasContext *ctx, uint32_t insn,
3012 const DisasInsn *di)
3014 unsigned n = extract32(insn, 1, 1);
3015 unsigned rx = extract32(insn, 16, 5);
3016 unsigned rb = extract32(insn, 21, 5);
3017 TCGv dest;
3019 if (rx == 0) {
3020 dest = load_gpr(ctx, rb);
3021 } else {
3022 dest = get_temp(ctx);
3023 tcg_gen_shli_tl(dest, load_gpr(ctx, rx), 3);
3024 tcg_gen_add_tl(dest, dest, load_gpr(ctx, rb));
3026 return do_ibranch(ctx, dest, 0, n);
3029 static DisasJumpType trans_bve(DisasContext *ctx, uint32_t insn,
3030 const DisasInsn *di)
3032 unsigned n = extract32(insn, 1, 1);
3033 unsigned rb = extract32(insn, 21, 5);
3034 unsigned link = extract32(insn, 13, 1) ? 2 : 0;
3036 return do_ibranch(ctx, load_gpr(ctx, rb), link, n);
3039 static const DisasInsn table_branch[] = {
3040 { 0xe8000000u, 0xfc006000u, trans_bl }, /* B,L and B,L,PUSH */
3041 { 0xe800a000u, 0xfc00e000u, trans_bl_long },
3042 { 0xe8004000u, 0xfc00fffdu, trans_blr },
3043 { 0xe800c000u, 0xfc00fffdu, trans_bv },
3044 { 0xe800d000u, 0xfc00dffcu, trans_bve },
3047 static DisasJumpType trans_fop_wew_0c(DisasContext *ctx, uint32_t insn,
3048 const DisasInsn *di)
3050 unsigned rt = extract32(insn, 0, 5);
3051 unsigned ra = extract32(insn, 21, 5);
3052 return do_fop_wew(ctx, rt, ra, di->f.wew);
3055 static DisasJumpType trans_fop_wew_0e(DisasContext *ctx, uint32_t insn,
3056 const DisasInsn *di)
3058 unsigned rt = assemble_rt64(insn);
3059 unsigned ra = assemble_ra64(insn);
3060 return do_fop_wew(ctx, rt, ra, di->f.wew);
3063 static DisasJumpType trans_fop_ded(DisasContext *ctx, uint32_t insn,
3064 const DisasInsn *di)
3066 unsigned rt = extract32(insn, 0, 5);
3067 unsigned ra = extract32(insn, 21, 5);
3068 return do_fop_ded(ctx, rt, ra, di->f.ded);
3071 static DisasJumpType trans_fop_wed_0c(DisasContext *ctx, uint32_t insn,
3072 const DisasInsn *di)
3074 unsigned rt = extract32(insn, 0, 5);
3075 unsigned ra = extract32(insn, 21, 5);
3076 return do_fop_wed(ctx, rt, ra, di->f.wed);
3079 static DisasJumpType trans_fop_wed_0e(DisasContext *ctx, uint32_t insn,
3080 const DisasInsn *di)
3082 unsigned rt = assemble_rt64(insn);
3083 unsigned ra = extract32(insn, 21, 5);
3084 return do_fop_wed(ctx, rt, ra, di->f.wed);
3087 static DisasJumpType trans_fop_dew_0c(DisasContext *ctx, uint32_t insn,
3088 const DisasInsn *di)
3090 unsigned rt = extract32(insn, 0, 5);
3091 unsigned ra = extract32(insn, 21, 5);
3092 return do_fop_dew(ctx, rt, ra, di->f.dew);
3095 static DisasJumpType trans_fop_dew_0e(DisasContext *ctx, uint32_t insn,
3096 const DisasInsn *di)
3098 unsigned rt = extract32(insn, 0, 5);
3099 unsigned ra = assemble_ra64(insn);
3100 return do_fop_dew(ctx, rt, ra, di->f.dew);
3103 static DisasJumpType trans_fop_weww_0c(DisasContext *ctx, uint32_t insn,
3104 const DisasInsn *di)
3106 unsigned rt = extract32(insn, 0, 5);
3107 unsigned rb = extract32(insn, 16, 5);
3108 unsigned ra = extract32(insn, 21, 5);
3109 return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
3112 static DisasJumpType trans_fop_weww_0e(DisasContext *ctx, uint32_t insn,
3113 const DisasInsn *di)
3115 unsigned rt = assemble_rt64(insn);
3116 unsigned rb = assemble_rb64(insn);
3117 unsigned ra = assemble_ra64(insn);
3118 return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
3121 static DisasJumpType trans_fop_dedd(DisasContext *ctx, uint32_t insn,
3122 const DisasInsn *di)
3124 unsigned rt = extract32(insn, 0, 5);
3125 unsigned rb = extract32(insn, 16, 5);
3126 unsigned ra = extract32(insn, 21, 5);
3127 return do_fop_dedd(ctx, rt, ra, rb, di->f.dedd);
3130 static void gen_fcpy_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3132 tcg_gen_mov_i32(dst, src);
3135 static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3137 tcg_gen_mov_i64(dst, src);
3140 static void gen_fabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3142 tcg_gen_andi_i32(dst, src, INT32_MAX);
3145 static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3147 tcg_gen_andi_i64(dst, src, INT64_MAX);
3150 static void gen_fneg_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3152 tcg_gen_xori_i32(dst, src, INT32_MIN);
3155 static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3157 tcg_gen_xori_i64(dst, src, INT64_MIN);
3160 static void gen_fnegabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3162 tcg_gen_ori_i32(dst, src, INT32_MIN);
3165 static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3167 tcg_gen_ori_i64(dst, src, INT64_MIN);
3170 static DisasJumpType do_fcmp_s(DisasContext *ctx, unsigned ra, unsigned rb,
3171 unsigned y, unsigned c)
3173 TCGv_i32 ta, tb, tc, ty;
3175 nullify_over(ctx);
3177 ta = load_frw0_i32(ra);
3178 tb = load_frw0_i32(rb);
3179 ty = tcg_const_i32(y);
3180 tc = tcg_const_i32(c);
3182 gen_helper_fcmp_s(cpu_env, ta, tb, ty, tc);
3184 tcg_temp_free_i32(ta);
3185 tcg_temp_free_i32(tb);
3186 tcg_temp_free_i32(ty);
3187 tcg_temp_free_i32(tc);
3189 return nullify_end(ctx, DISAS_NEXT);
3192 static DisasJumpType trans_fcmp_s_0c(DisasContext *ctx, uint32_t insn,
3193 const DisasInsn *di)
3195 unsigned c = extract32(insn, 0, 5);
3196 unsigned y = extract32(insn, 13, 3);
3197 unsigned rb = extract32(insn, 16, 5);
3198 unsigned ra = extract32(insn, 21, 5);
3199 return do_fcmp_s(ctx, ra, rb, y, c);
3202 static DisasJumpType trans_fcmp_s_0e(DisasContext *ctx, uint32_t insn,
3203 const DisasInsn *di)
3205 unsigned c = extract32(insn, 0, 5);
3206 unsigned y = extract32(insn, 13, 3);
3207 unsigned rb = assemble_rb64(insn);
3208 unsigned ra = assemble_ra64(insn);
3209 return do_fcmp_s(ctx, ra, rb, y, c);
3212 static DisasJumpType trans_fcmp_d(DisasContext *ctx, uint32_t insn,
3213 const DisasInsn *di)
3215 unsigned c = extract32(insn, 0, 5);
3216 unsigned y = extract32(insn, 13, 3);
3217 unsigned rb = extract32(insn, 16, 5);
3218 unsigned ra = extract32(insn, 21, 5);
3219 TCGv_i64 ta, tb;
3220 TCGv_i32 tc, ty;
3222 nullify_over(ctx);
3224 ta = load_frd0(ra);
3225 tb = load_frd0(rb);
3226 ty = tcg_const_i32(y);
3227 tc = tcg_const_i32(c);
3229 gen_helper_fcmp_d(cpu_env, ta, tb, ty, tc);
3231 tcg_temp_free_i64(ta);
3232 tcg_temp_free_i64(tb);
3233 tcg_temp_free_i32(ty);
3234 tcg_temp_free_i32(tc);
3236 return nullify_end(ctx, DISAS_NEXT);
3239 static DisasJumpType trans_ftest_t(DisasContext *ctx, uint32_t insn,
3240 const DisasInsn *di)
3242 unsigned y = extract32(insn, 13, 3);
3243 unsigned cbit = (y ^ 1) - 1;
3244 TCGv t;
3246 nullify_over(ctx);
3248 t = tcg_temp_new();
3249 tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
3250 tcg_gen_extract_tl(t, t, 21 - cbit, 1);
3251 ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3252 tcg_temp_free(t);
3254 return nullify_end(ctx, DISAS_NEXT);
3257 static DisasJumpType trans_ftest_q(DisasContext *ctx, uint32_t insn,
3258 const DisasInsn *di)
3260 unsigned c = extract32(insn, 0, 5);
3261 int mask;
3262 bool inv = false;
3263 TCGv t;
3265 nullify_over(ctx);
3267 t = tcg_temp_new();
3268 tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
3270 switch (c) {
3271 case 0: /* simple */
3272 tcg_gen_andi_tl(t, t, 0x4000000);
3273 ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3274 goto done;
3275 case 2: /* rej */
3276 inv = true;
3277 /* fallthru */
3278 case 1: /* acc */
3279 mask = 0x43ff800;
3280 break;
3281 case 6: /* rej8 */
3282 inv = true;
3283 /* fallthru */
3284 case 5: /* acc8 */
3285 mask = 0x43f8000;
3286 break;
3287 case 9: /* acc6 */
3288 mask = 0x43e0000;
3289 break;
3290 case 13: /* acc4 */
3291 mask = 0x4380000;
3292 break;
3293 case 17: /* acc2 */
3294 mask = 0x4200000;
3295 break;
3296 default:
3297 return gen_illegal(ctx);
3299 if (inv) {
3300 TCGv c = load_const(ctx, mask);
3301 tcg_gen_or_tl(t, t, c);
3302 ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
3303 } else {
3304 tcg_gen_andi_tl(t, t, mask);
3305 ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
3307 done:
3308 return nullify_end(ctx, DISAS_NEXT);
3311 static DisasJumpType trans_xmpyu(DisasContext *ctx, uint32_t insn,
3312 const DisasInsn *di)
3314 unsigned rt = extract32(insn, 0, 5);
3315 unsigned rb = assemble_rb64(insn);
3316 unsigned ra = assemble_ra64(insn);
3317 TCGv_i64 a, b;
3319 nullify_over(ctx);
3321 a = load_frw0_i64(ra);
3322 b = load_frw0_i64(rb);
3323 tcg_gen_mul_i64(a, a, b);
3324 save_frd(rt, a);
3325 tcg_temp_free_i64(a);
3326 tcg_temp_free_i64(b);
3328 return nullify_end(ctx, DISAS_NEXT);
3331 #define FOP_DED trans_fop_ded, .f.ded
3332 #define FOP_DEDD trans_fop_dedd, .f.dedd
3334 #define FOP_WEW trans_fop_wew_0c, .f.wew
3335 #define FOP_DEW trans_fop_dew_0c, .f.dew
3336 #define FOP_WED trans_fop_wed_0c, .f.wed
3337 #define FOP_WEWW trans_fop_weww_0c, .f.weww
3339 static const DisasInsn table_float_0c[] = {
3340 /* floating point class zero */
3341 { 0x30004000, 0xfc1fffe0, FOP_WEW = gen_fcpy_s },
3342 { 0x30006000, 0xfc1fffe0, FOP_WEW = gen_fabs_s },
3343 { 0x30008000, 0xfc1fffe0, FOP_WEW = gen_helper_fsqrt_s },
3344 { 0x3000a000, 0xfc1fffe0, FOP_WEW = gen_helper_frnd_s },
3345 { 0x3000c000, 0xfc1fffe0, FOP_WEW = gen_fneg_s },
3346 { 0x3000e000, 0xfc1fffe0, FOP_WEW = gen_fnegabs_s },
3348 { 0x30004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
3349 { 0x30006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
3350 { 0x30008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
3351 { 0x3000a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
3352 { 0x3000c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
3353 { 0x3000e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
3355 /* floating point class three */
3356 { 0x30000600, 0xfc00ffe0, FOP_WEWW = gen_helper_fadd_s },
3357 { 0x30002600, 0xfc00ffe0, FOP_WEWW = gen_helper_fsub_s },
3358 { 0x30004600, 0xfc00ffe0, FOP_WEWW = gen_helper_fmpy_s },
3359 { 0x30006600, 0xfc00ffe0, FOP_WEWW = gen_helper_fdiv_s },
3361 { 0x30000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
3362 { 0x30002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
3363 { 0x30004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
3364 { 0x30006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
3366 /* floating point class one */
3367 /* float/float */
3368 { 0x30000a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_s },
3369 { 0x30002200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_d },
3370 /* int/float */
3371 { 0x30008200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_w_s },
3372 { 0x30008a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_dw_s },
3373 { 0x3000a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_w_d },
3374 { 0x3000aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
3375 /* float/int */
3376 { 0x30010200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_w },
3377 { 0x30010a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_w },
3378 { 0x30012200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_dw },
3379 { 0x30012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
3380 /* float/int truncate */
3381 { 0x30018200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_w },
3382 { 0x30018a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_w },
3383 { 0x3001a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_dw },
3384 { 0x3001aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
3385 /* uint/float */
3386 { 0x30028200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_uw_s },
3387 { 0x30028a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_udw_s },
3388 { 0x3002a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_uw_d },
3389 { 0x3002aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
3390 /* float/uint */
3391 { 0x30030200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_uw },
3392 { 0x30030a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_uw },
3393 { 0x30032200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_udw },
3394 { 0x30032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
3395 /* float/uint truncate */
3396 { 0x30038200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_uw },
3397 { 0x30038a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_uw },
3398 { 0x3003a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_udw },
3399 { 0x3003aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
3401 /* floating point class two */
3402 { 0x30000400, 0xfc001fe0, trans_fcmp_s_0c },
3403 { 0x30000c00, 0xfc001fe0, trans_fcmp_d },
3404 { 0x30002420, 0xffffffe0, trans_ftest_q },
3405 { 0x30000420, 0xffff1fff, trans_ftest_t },
3407 /* FID. Note that ra == rt == 0, which via fcpy puts 0 into fr0.
3408 This is machine/revision == 0, which is reserved for simulator. */
3409 { 0x30000000, 0xffffffff, FOP_WEW = gen_fcpy_s },
3412 #undef FOP_WEW
3413 #undef FOP_DEW
3414 #undef FOP_WED
3415 #undef FOP_WEWW
3416 #define FOP_WEW trans_fop_wew_0e, .f.wew
3417 #define FOP_DEW trans_fop_dew_0e, .f.dew
3418 #define FOP_WED trans_fop_wed_0e, .f.wed
3419 #define FOP_WEWW trans_fop_weww_0e, .f.weww
3421 static const DisasInsn table_float_0e[] = {
3422 /* floating point class zero */
3423 { 0x38004000, 0xfc1fff20, FOP_WEW = gen_fcpy_s },
3424 { 0x38006000, 0xfc1fff20, FOP_WEW = gen_fabs_s },
3425 { 0x38008000, 0xfc1fff20, FOP_WEW = gen_helper_fsqrt_s },
3426 { 0x3800a000, 0xfc1fff20, FOP_WEW = gen_helper_frnd_s },
3427 { 0x3800c000, 0xfc1fff20, FOP_WEW = gen_fneg_s },
3428 { 0x3800e000, 0xfc1fff20, FOP_WEW = gen_fnegabs_s },
3430 { 0x38004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
3431 { 0x38006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
3432 { 0x38008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
3433 { 0x3800a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
3434 { 0x3800c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
3435 { 0x3800e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
3437 /* floating point class three */
3438 { 0x38000600, 0xfc00ef20, FOP_WEWW = gen_helper_fadd_s },
3439 { 0x38002600, 0xfc00ef20, FOP_WEWW = gen_helper_fsub_s },
3440 { 0x38004600, 0xfc00ef20, FOP_WEWW = gen_helper_fmpy_s },
3441 { 0x38006600, 0xfc00ef20, FOP_WEWW = gen_helper_fdiv_s },
3443 { 0x38000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
3444 { 0x38002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
3445 { 0x38004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
3446 { 0x38006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
3448 { 0x38004700, 0xfc00ef60, trans_xmpyu },
3450 /* floating point class one */
3451 /* float/float */
3452 { 0x38000a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_s },
3453 { 0x38002200, 0xfc1fffc0, FOP_DEW = gen_helper_fcnv_s_d },
3454 /* int/float */
3455 { 0x38008200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_w_s },
3456 { 0x38008a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_dw_s },
3457 { 0x3800a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_w_d },
3458 { 0x3800aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
3459 /* float/int */
3460 { 0x38010200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_w },
3461 { 0x38010a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_w },
3462 { 0x38012200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_dw },
3463 { 0x38012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
3464 /* float/int truncate */
3465 { 0x38018200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_w },
3466 { 0x38018a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_w },
3467 { 0x3801a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_dw },
3468 { 0x3801aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
3469 /* uint/float */
3470 { 0x38028200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_uw_s },
3471 { 0x38028a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_udw_s },
3472 { 0x3802a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_uw_d },
3473 { 0x3802aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
3474 /* float/uint */
3475 { 0x38030200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_uw },
3476 { 0x38030a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_uw },
3477 { 0x38032200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_udw },
3478 { 0x38032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
3479 /* float/uint truncate */
3480 { 0x38038200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_uw },
3481 { 0x38038a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_uw },
3482 { 0x3803a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_udw },
3483 { 0x3803aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
3485 /* floating point class two */
3486 { 0x38000400, 0xfc000f60, trans_fcmp_s_0e },
3487 { 0x38000c00, 0xfc001fe0, trans_fcmp_d },
3490 #undef FOP_WEW
3491 #undef FOP_DEW
3492 #undef FOP_WED
3493 #undef FOP_WEWW
3494 #undef FOP_DED
3495 #undef FOP_DEDD
3497 /* Convert the fmpyadd single-precision register encodings to standard. */
3498 static inline int fmpyadd_s_reg(unsigned r)
3500 return (r & 16) * 2 + 16 + (r & 15);
3503 static DisasJumpType trans_fmpyadd(DisasContext *ctx,
3504 uint32_t insn, bool is_sub)
3506 unsigned tm = extract32(insn, 0, 5);
3507 unsigned f = extract32(insn, 5, 1);
3508 unsigned ra = extract32(insn, 6, 5);
3509 unsigned ta = extract32(insn, 11, 5);
3510 unsigned rm2 = extract32(insn, 16, 5);
3511 unsigned rm1 = extract32(insn, 21, 5);
3513 nullify_over(ctx);
3515 /* Independent multiply & add/sub, with undefined behaviour
3516 if outputs overlap inputs. */
3517 if (f == 0) {
3518 tm = fmpyadd_s_reg(tm);
3519 ra = fmpyadd_s_reg(ra);
3520 ta = fmpyadd_s_reg(ta);
3521 rm2 = fmpyadd_s_reg(rm2);
3522 rm1 = fmpyadd_s_reg(rm1);
3523 do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
3524 do_fop_weww(ctx, ta, ta, ra,
3525 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
3526 } else {
3527 do_fop_dedd(ctx, tm, rm1, rm2, gen_helper_fmpy_d);
3528 do_fop_dedd(ctx, ta, ta, ra,
3529 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
3532 return nullify_end(ctx, DISAS_NEXT);
3535 static DisasJumpType trans_fmpyfadd_s(DisasContext *ctx, uint32_t insn,
3536 const DisasInsn *di)
3538 unsigned rt = assemble_rt64(insn);
3539 unsigned neg = extract32(insn, 5, 1);
3540 unsigned rm1 = assemble_ra64(insn);
3541 unsigned rm2 = assemble_rb64(insn);
3542 unsigned ra3 = assemble_rc64(insn);
3543 TCGv_i32 a, b, c;
3545 nullify_over(ctx);
3546 a = load_frw0_i32(rm1);
3547 b = load_frw0_i32(rm2);
3548 c = load_frw0_i32(ra3);
3550 if (neg) {
3551 gen_helper_fmpynfadd_s(a, cpu_env, a, b, c);
3552 } else {
3553 gen_helper_fmpyfadd_s(a, cpu_env, a, b, c);
3556 tcg_temp_free_i32(b);
3557 tcg_temp_free_i32(c);
3558 save_frw_i32(rt, a);
3559 tcg_temp_free_i32(a);
3560 return nullify_end(ctx, DISAS_NEXT);
3563 static DisasJumpType trans_fmpyfadd_d(DisasContext *ctx, uint32_t insn,
3564 const DisasInsn *di)
3566 unsigned rt = extract32(insn, 0, 5);
3567 unsigned neg = extract32(insn, 5, 1);
3568 unsigned rm1 = extract32(insn, 21, 5);
3569 unsigned rm2 = extract32(insn, 16, 5);
3570 unsigned ra3 = assemble_rc64(insn);
3571 TCGv_i64 a, b, c;
3573 nullify_over(ctx);
3574 a = load_frd0(rm1);
3575 b = load_frd0(rm2);
3576 c = load_frd0(ra3);
3578 if (neg) {
3579 gen_helper_fmpynfadd_d(a, cpu_env, a, b, c);
3580 } else {
3581 gen_helper_fmpyfadd_d(a, cpu_env, a, b, c);
3584 tcg_temp_free_i64(b);
3585 tcg_temp_free_i64(c);
3586 save_frd(rt, a);
3587 tcg_temp_free_i64(a);
3588 return nullify_end(ctx, DISAS_NEXT);
3591 static const DisasInsn table_fp_fused[] = {
3592 { 0xb8000000u, 0xfc000800u, trans_fmpyfadd_s },
3593 { 0xb8000800u, 0xfc0019c0u, trans_fmpyfadd_d }
3596 static DisasJumpType translate_table_int(DisasContext *ctx, uint32_t insn,
3597 const DisasInsn table[], size_t n)
3599 size_t i;
3600 for (i = 0; i < n; ++i) {
3601 if ((insn & table[i].mask) == table[i].insn) {
3602 return table[i].trans(ctx, insn, &table[i]);
3605 return gen_illegal(ctx);
3608 #define translate_table(ctx, insn, table) \
3609 translate_table_int(ctx, insn, table, ARRAY_SIZE(table))
3611 static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
3613 uint32_t opc = extract32(insn, 26, 6);
3615 switch (opc) {
3616 case 0x00: /* system op */
3617 return translate_table(ctx, insn, table_system);
3618 case 0x01:
3619 return translate_table(ctx, insn, table_mem_mgmt);
3620 case 0x02:
3621 return translate_table(ctx, insn, table_arith_log);
3622 case 0x03:
3623 return translate_table(ctx, insn, table_index_mem);
3624 case 0x06:
3625 return trans_fmpyadd(ctx, insn, false);
3626 case 0x08:
3627 return trans_ldil(ctx, insn);
3628 case 0x09:
3629 return trans_copr_w(ctx, insn);
3630 case 0x0A:
3631 return trans_addil(ctx, insn);
3632 case 0x0B:
3633 return trans_copr_dw(ctx, insn);
3634 case 0x0C:
3635 return translate_table(ctx, insn, table_float_0c);
3636 case 0x0D:
3637 return trans_ldo(ctx, insn);
3638 case 0x0E:
3639 return translate_table(ctx, insn, table_float_0e);
3641 case 0x10:
3642 return trans_load(ctx, insn, false, MO_UB);
3643 case 0x11:
3644 return trans_load(ctx, insn, false, MO_TEUW);
3645 case 0x12:
3646 return trans_load(ctx, insn, false, MO_TEUL);
3647 case 0x13:
3648 return trans_load(ctx, insn, true, MO_TEUL);
3649 case 0x16:
3650 return trans_fload_mod(ctx, insn);
3651 case 0x17:
3652 return trans_load_w(ctx, insn);
3653 case 0x18:
3654 return trans_store(ctx, insn, false, MO_UB);
3655 case 0x19:
3656 return trans_store(ctx, insn, false, MO_TEUW);
3657 case 0x1A:
3658 return trans_store(ctx, insn, false, MO_TEUL);
3659 case 0x1B:
3660 return trans_store(ctx, insn, true, MO_TEUL);
3661 case 0x1E:
3662 return trans_fstore_mod(ctx, insn);
3663 case 0x1F:
3664 return trans_store_w(ctx, insn);
3666 case 0x20:
3667 return trans_cmpb(ctx, insn, true, false, false);
3668 case 0x21:
3669 return trans_cmpb(ctx, insn, true, true, false);
3670 case 0x22:
3671 return trans_cmpb(ctx, insn, false, false, false);
3672 case 0x23:
3673 return trans_cmpb(ctx, insn, false, true, false);
3674 case 0x24:
3675 return trans_cmpiclr(ctx, insn);
3676 case 0x25:
3677 return trans_subi(ctx, insn);
3678 case 0x26:
3679 return trans_fmpyadd(ctx, insn, true);
3680 case 0x27:
3681 return trans_cmpb(ctx, insn, true, false, true);
3682 case 0x28:
3683 return trans_addb(ctx, insn, true, false);
3684 case 0x29:
3685 return trans_addb(ctx, insn, true, true);
3686 case 0x2A:
3687 return trans_addb(ctx, insn, false, false);
3688 case 0x2B:
3689 return trans_addb(ctx, insn, false, true);
3690 case 0x2C:
3691 case 0x2D:
3692 return trans_addi(ctx, insn);
3693 case 0x2E:
3694 return translate_table(ctx, insn, table_fp_fused);
3695 case 0x2F:
3696 return trans_cmpb(ctx, insn, false, false, true);
3698 case 0x30:
3699 case 0x31:
3700 return trans_bb(ctx, insn);
3701 case 0x32:
3702 return trans_movb(ctx, insn, false);
3703 case 0x33:
3704 return trans_movb(ctx, insn, true);
3705 case 0x34:
3706 return translate_table(ctx, insn, table_sh_ex);
3707 case 0x35:
3708 return translate_table(ctx, insn, table_depw);
3709 case 0x38:
3710 return trans_be(ctx, insn, false);
3711 case 0x39:
3712 return trans_be(ctx, insn, true);
3713 case 0x3A:
3714 return translate_table(ctx, insn, table_branch);
3716 case 0x04: /* spopn */
3717 case 0x05: /* diag */
3718 case 0x0F: /* product specific */
3719 break;
3721 case 0x07: /* unassigned */
3722 case 0x15: /* unassigned */
3723 case 0x1D: /* unassigned */
3724 case 0x37: /* unassigned */
3725 case 0x3F: /* unassigned */
3726 default:
3727 break;
3729 return gen_illegal(ctx);
3732 static int hppa_tr_init_disas_context(DisasContextBase *dcbase,
3733 CPUState *cs, int max_insns)
3735 DisasContext *ctx = container_of(dcbase, DisasContext, base);
3736 TranslationBlock *tb = ctx->base.tb;
3737 int i, bound;
3739 ctx->cs = cs;
3740 ctx->iaoq_f = tb->pc;
3741 ctx->iaoq_b = tb->cs_base;
3742 ctx->iaoq_n = -1;
3743 TCGV_UNUSED(ctx->iaoq_n_var);
3745 ctx->ntemps = 0;
3746 for (i = 0; i < ARRAY_SIZE(ctx->temps); ++i) {
3747 TCGV_UNUSED(ctx->temps[i]);
3750 bound = -(tb->pc | TARGET_PAGE_MASK) / 4;
3751 return MIN(max_insns, bound);
3754 static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
3756 DisasContext *ctx = container_of(dcbase, DisasContext, base);
3758 /* Seed the nullification status from PSW[N], as shown in TB->FLAGS. */
3759 ctx->null_cond = cond_make_f();
3760 ctx->psw_n_nonzero = false;
3761 if (ctx->base.tb->flags & 1) {
3762 ctx->null_cond.c = TCG_COND_ALWAYS;
3763 ctx->psw_n_nonzero = true;
3765 ctx->null_lab = NULL;
3768 static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
3770 DisasContext *ctx = container_of(dcbase, DisasContext, base);
3772 tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b);
3775 static bool hppa_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
3776 const CPUBreakpoint *bp)
3778 DisasContext *ctx = container_of(dcbase, DisasContext, base);
3780 ctx->base.is_jmp = gen_excp(ctx, EXCP_DEBUG);
3781 ctx->base.pc_next = ctx->iaoq_f + 4;
3782 return true;
3785 static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
3787 DisasContext *ctx = container_of(dcbase, DisasContext, base);
3788 CPUHPPAState *env = cs->env_ptr;
3789 DisasJumpType ret;
3790 int i, n;
3792 /* Execute one insn. */
3793 if (ctx->iaoq_f < TARGET_PAGE_SIZE) {
3794 ret = do_page_zero(ctx);
3795 assert(ret != DISAS_NEXT);
3796 } else {
3797 /* Always fetch the insn, even if nullified, so that we check
3798 the page permissions for execute. */
3799 uint32_t insn = cpu_ldl_code(env, ctx->iaoq_f);
3801 /* Set up the IA queue for the next insn.
3802 This will be overwritten by a branch. */
3803 if (ctx->iaoq_b == -1) {
3804 ctx->iaoq_n = -1;
3805 ctx->iaoq_n_var = get_temp(ctx);
3806 tcg_gen_addi_tl(ctx->iaoq_n_var, cpu_iaoq_b, 4);
3807 } else {
3808 ctx->iaoq_n = ctx->iaoq_b + 4;
3809 TCGV_UNUSED(ctx->iaoq_n_var);
3812 if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
3813 ctx->null_cond.c = TCG_COND_NEVER;
3814 ret = DISAS_NEXT;
3815 } else {
3816 ret = translate_one(ctx, insn);
3817 assert(ctx->null_lab == NULL);
3821 /* Free any temporaries allocated. */
3822 for (i = 0, n = ctx->ntemps; i < n; ++i) {
3823 tcg_temp_free(ctx->temps[i]);
3824 TCGV_UNUSED(ctx->temps[i]);
3826 ctx->ntemps = 0;
3828 /* Advance the insn queue. */
3829 /* ??? The non-linear instruction restriction is purely due to
3830 the debugging dump. Otherwise we *could* follow unconditional
3831 branches within the same page. */
3832 if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
3833 if (ctx->null_cond.c == TCG_COND_NEVER
3834 || ctx->null_cond.c == TCG_COND_ALWAYS) {
3835 nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
3836 gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
3837 ret = DISAS_NORETURN;
3838 } else {
3839 ret = DISAS_IAQ_N_STALE;
3842 ctx->iaoq_f = ctx->iaoq_b;
3843 ctx->iaoq_b = ctx->iaoq_n;
3844 ctx->base.is_jmp = ret;
3846 if (ret == DISAS_NORETURN || ret == DISAS_IAQ_N_UPDATED) {
3847 return;
3849 if (ctx->iaoq_f == -1) {
3850 tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b);
3851 copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
3852 nullify_save(ctx);
3853 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
3854 } else if (ctx->iaoq_b == -1) {
3855 tcg_gen_mov_tl(cpu_iaoq_b, ctx->iaoq_n_var);
3859 static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
3861 DisasContext *ctx = container_of(dcbase, DisasContext, base);
3863 switch (ctx->base.is_jmp) {
3864 case DISAS_NORETURN:
3865 break;
3866 case DISAS_TOO_MANY:
3867 case DISAS_IAQ_N_STALE:
3868 copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
3869 copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
3870 nullify_save(ctx);
3871 /* FALLTHRU */
3872 case DISAS_IAQ_N_UPDATED:
3873 if (ctx->base.singlestep_enabled) {
3874 gen_excp_1(EXCP_DEBUG);
3875 } else {
3876 tcg_gen_lookup_and_goto_ptr();
3878 break;
3879 default:
3880 g_assert_not_reached();
3883 /* We don't actually use this during normal translation,
3884 but we should interact with the generic main loop. */
3885 ctx->base.pc_next = ctx->base.tb->pc + 4 * ctx->base.num_insns;
3888 static void hppa_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs)
3890 TranslationBlock *tb = dcbase->tb;
3892 switch (tb->pc) {
3893 case 0x00:
3894 qemu_log("IN:\n0x00000000: (null)\n");
3895 break;
3896 case 0xb0:
3897 qemu_log("IN:\n0x000000b0: light-weight-syscall\n");
3898 break;
3899 case 0xe0:
3900 qemu_log("IN:\n0x000000e0: set-thread-pointer-syscall\n");
3901 break;
3902 case 0x100:
3903 qemu_log("IN:\n0x00000100: syscall\n");
3904 break;
3905 default:
3906 qemu_log("IN: %s\n", lookup_symbol(tb->pc));
3907 log_target_disas(cs, tb->pc, tb->size, 1);
3908 break;
3912 static const TranslatorOps hppa_tr_ops = {
3913 .init_disas_context = hppa_tr_init_disas_context,
3914 .tb_start = hppa_tr_tb_start,
3915 .insn_start = hppa_tr_insn_start,
3916 .breakpoint_check = hppa_tr_breakpoint_check,
3917 .translate_insn = hppa_tr_translate_insn,
3918 .tb_stop = hppa_tr_tb_stop,
3919 .disas_log = hppa_tr_disas_log,
3922 void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
3925 DisasContext ctx;
3926 translator_loop(&hppa_tr_ops, &ctx.base, cs, tb);
3929 void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb,
3930 target_ulong *data)
3932 env->iaoq_f = data[0];
3933 if (data[1] != -1) {
3934 env->iaoq_b = data[1];
3936 /* Since we were executing the instruction at IAOQ_F, and took some
3937 sort of action that provoked the cpu_restore_state, we can infer
3938 that the instruction was not nullified. */
3939 env->psw_n = 0;