xref: /openbmc/qemu/target/hppa/translate.c (revision 4c42fd0d4e543aaf8981c737f971d27e7c9d4df0)
161766fe9SRichard Henderson /*
261766fe9SRichard Henderson  * HPPA emulation cpu translation for qemu.
361766fe9SRichard Henderson  *
461766fe9SRichard Henderson  * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
561766fe9SRichard Henderson  *
661766fe9SRichard Henderson  * This library is free software; you can redistribute it and/or
761766fe9SRichard Henderson  * modify it under the terms of the GNU Lesser General Public
861766fe9SRichard Henderson  * License as published by the Free Software Foundation; either
9d6ea4236SChetan Pant  * version 2.1 of the License, or (at your option) any later version.
1061766fe9SRichard Henderson  *
1161766fe9SRichard Henderson  * This library is distributed in the hope that it will be useful,
1261766fe9SRichard Henderson  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1361766fe9SRichard Henderson  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1461766fe9SRichard Henderson  * Lesser General Public License for more details.
1561766fe9SRichard Henderson  *
1661766fe9SRichard Henderson  * You should have received a copy of the GNU Lesser General Public
1761766fe9SRichard Henderson  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1861766fe9SRichard Henderson  */
1961766fe9SRichard Henderson 
2061766fe9SRichard Henderson #include "qemu/osdep.h"
2161766fe9SRichard Henderson #include "cpu.h"
2261766fe9SRichard Henderson #include "disas/disas.h"
2361766fe9SRichard Henderson #include "qemu/host-utils.h"
2461766fe9SRichard Henderson #include "exec/exec-all.h"
2574781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h"
26dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
270843563fSRichard Henderson #include "tcg/tcg-op-gvec.h"
2861766fe9SRichard Henderson #include "exec/helper-proto.h"
2961766fe9SRichard Henderson #include "exec/helper-gen.h"
30869051eaSRichard Henderson #include "exec/translator.h"
3161766fe9SRichard Henderson #include "exec/log.h"
3261766fe9SRichard Henderson 
33d53106c9SRichard Henderson #define HELPER_H "helper.h"
34d53106c9SRichard Henderson #include "exec/helper-info.c.inc"
35d53106c9SRichard Henderson #undef  HELPER_H
36d53106c9SRichard Henderson 
37aac0f603SRichard Henderson /* Choose to use explicit sizes within this file. */
38aac0f603SRichard Henderson #undef tcg_temp_new
39d53106c9SRichard Henderson 
4061766fe9SRichard Henderson typedef struct DisasCond {
4161766fe9SRichard Henderson     TCGCond c;
426fd0c7bcSRichard Henderson     TCGv_i64 a0, a1;
4361766fe9SRichard Henderson } DisasCond;
4461766fe9SRichard Henderson 
45bc921866SRichard Henderson typedef struct DisasIAQE {
46bc921866SRichard Henderson     /* IASQ; may be null for no change from TB. */
47bc921866SRichard Henderson     TCGv_i64 space;
480d89cb7cSRichard Henderson     /* IAOQ base; may be null for relative address. */
49bc921866SRichard Henderson     TCGv_i64 base;
500d89cb7cSRichard Henderson     /* IAOQ addend; if base is null, relative to ctx->iaoq_first. */
51bc921866SRichard Henderson     int64_t disp;
52bc921866SRichard Henderson } DisasIAQE;
53bc921866SRichard Henderson 
5461766fe9SRichard Henderson typedef struct DisasContext {
55d01a3625SRichard Henderson     DisasContextBase base;
5661766fe9SRichard Henderson     CPUState *cs;
5761766fe9SRichard Henderson 
58bc921866SRichard Henderson     /* IAQ_Front, IAQ_Back. */
59bc921866SRichard Henderson     DisasIAQE iaq_f, iaq_b;
60bc921866SRichard Henderson     /* IAQ_Next, for jumps, otherwise null for simple advance. */
61bc921866SRichard Henderson     DisasIAQE iaq_j, *iaq_n;
6261766fe9SRichard Henderson 
630d89cb7cSRichard Henderson     /* IAOQ_Front at entry to TB. */
640d89cb7cSRichard Henderson     uint64_t iaoq_first;
650d89cb7cSRichard Henderson 
6661766fe9SRichard Henderson     DisasCond null_cond;
6761766fe9SRichard Henderson     TCGLabel *null_lab;
6861766fe9SRichard Henderson 
69a4db4a78SRichard Henderson     TCGv_i64 zero;
70a4db4a78SRichard Henderson 
711a19da0dSRichard Henderson     uint32_t insn;
72494737b7SRichard Henderson     uint32_t tb_flags;
733d68ee7bSRichard Henderson     int mmu_idx;
743d68ee7bSRichard Henderson     int privilege;
7561766fe9SRichard Henderson     bool psw_n_nonzero;
76bd6243a3SRichard Henderson     bool is_pa20;
7724638bd1SRichard Henderson     bool insn_start_updated;
78217d1a5eSRichard Henderson 
79217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
80217d1a5eSRichard Henderson     MemOp unalign;
81217d1a5eSRichard Henderson #endif
8261766fe9SRichard Henderson } DisasContext;
8361766fe9SRichard Henderson 
84217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
85217d1a5eSRichard Henderson #define UNALIGN(C)       (C)->unalign
8617fe594cSRichard Henderson #define MMU_DISABLED(C)  false
87217d1a5eSRichard Henderson #else
882d4afb03SRichard Henderson #define UNALIGN(C)       MO_ALIGN
8917fe594cSRichard Henderson #define MMU_DISABLED(C)  MMU_IDX_MMU_DISABLED((C)->mmu_idx)
90217d1a5eSRichard Henderson #endif
91217d1a5eSRichard Henderson 
92e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently.  */
93451e4ffdSRichard Henderson static int expand_sm_imm(DisasContext *ctx, int val)
94e36f27efSRichard Henderson {
95881d1073SHelge Deller     /* Keep unimplemented bits disabled -- see cpu_hppa_put_psw. */
96881d1073SHelge Deller     if (ctx->is_pa20) {
97e36f27efSRichard Henderson         if (val & PSW_SM_W) {
98881d1073SHelge Deller             val |= PSW_W;
99881d1073SHelge Deller         }
100881d1073SHelge Deller         val &= ~(PSW_SM_W | PSW_SM_E | PSW_G);
101881d1073SHelge Deller     } else {
102881d1073SHelge Deller         val &= ~(PSW_SM_W | PSW_SM_E | PSW_O);
103e36f27efSRichard Henderson     }
104e36f27efSRichard Henderson     return val;
105e36f27efSRichard Henderson }
106e36f27efSRichard Henderson 
107deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base.  */
108451e4ffdSRichard Henderson static int expand_sr3x(DisasContext *ctx, int val)
109deee69a1SRichard Henderson {
110deee69a1SRichard Henderson     return ~val;
111deee69a1SRichard Henderson }
112deee69a1SRichard Henderson 
1131cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value
1141cd012a5SRichard Henderson    we use for the final M.  */
115451e4ffdSRichard Henderson static int ma_to_m(DisasContext *ctx, int val)
1161cd012a5SRichard Henderson {
1171cd012a5SRichard Henderson     return val & 2 ? (val & 1 ? -1 : 1) : 0;
1181cd012a5SRichard Henderson }
1191cd012a5SRichard Henderson 
120740038d7SRichard Henderson /* Convert the sign of the displacement to a pre or post-modify.  */
121451e4ffdSRichard Henderson static int pos_to_m(DisasContext *ctx, int val)
122740038d7SRichard Henderson {
123740038d7SRichard Henderson     return val ? 1 : -1;
124740038d7SRichard Henderson }
125740038d7SRichard Henderson 
126451e4ffdSRichard Henderson static int neg_to_m(DisasContext *ctx, int val)
127740038d7SRichard Henderson {
128740038d7SRichard Henderson     return val ? -1 : 1;
129740038d7SRichard Henderson }
130740038d7SRichard Henderson 
131740038d7SRichard Henderson /* Used for branch targets and fp memory ops.  */
132451e4ffdSRichard Henderson static int expand_shl2(DisasContext *ctx, int val)
13301afb7beSRichard Henderson {
13401afb7beSRichard Henderson     return val << 2;
13501afb7beSRichard Henderson }
13601afb7beSRichard Henderson 
1370588e061SRichard Henderson /* Used for assemble_21.  */
138451e4ffdSRichard Henderson static int expand_shl11(DisasContext *ctx, int val)
1390588e061SRichard Henderson {
1400588e061SRichard Henderson     return val << 11;
1410588e061SRichard Henderson }
1420588e061SRichard Henderson 
14372ae4f2bSRichard Henderson static int assemble_6(DisasContext *ctx, int val)
14472ae4f2bSRichard Henderson {
14572ae4f2bSRichard Henderson     /*
14672ae4f2bSRichard Henderson      * Officially, 32 * x + 32 - y.
14772ae4f2bSRichard Henderson      * Here, x is already in bit 5, and y is [4:0].
14872ae4f2bSRichard Henderson      * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1,
14972ae4f2bSRichard Henderson      * with the overflow from bit 4 summing with x.
15072ae4f2bSRichard Henderson      */
15172ae4f2bSRichard Henderson     return (val ^ 31) + 1;
15272ae4f2bSRichard Henderson }
15372ae4f2bSRichard Henderson 
1544768c28eSRichard Henderson /* Expander for assemble_16a(s,cat(im10a,0),i). */
1554768c28eSRichard Henderson static int expand_11a(DisasContext *ctx, int val)
1564768c28eSRichard Henderson {
1574768c28eSRichard Henderson     /*
1584768c28eSRichard Henderson      * @val is bit 0 and bits [4:15].
1594768c28eSRichard Henderson      * Swizzle thing around depending on PSW.W.
1604768c28eSRichard Henderson      */
1614768c28eSRichard Henderson     int im10a = extract32(val, 1, 10);
1624768c28eSRichard Henderson     int s = extract32(val, 11, 2);
1634768c28eSRichard Henderson     int i = (-(val & 1) << 13) | (im10a << 3);
1644768c28eSRichard Henderson 
1654768c28eSRichard Henderson     if (ctx->tb_flags & PSW_W) {
1664768c28eSRichard Henderson         i ^= s << 13;
1674768c28eSRichard Henderson     }
1684768c28eSRichard Henderson     return i;
1694768c28eSRichard Henderson }
1704768c28eSRichard Henderson 
17146174e14SRichard Henderson /* Expander for assemble_16a(s,im11a,i). */
17246174e14SRichard Henderson static int expand_12a(DisasContext *ctx, int val)
17346174e14SRichard Henderson {
17446174e14SRichard Henderson     /*
17546174e14SRichard Henderson      * @val is bit 0 and bits [3:15].
17646174e14SRichard Henderson      * Swizzle thing around depending on PSW.W.
17746174e14SRichard Henderson      */
17846174e14SRichard Henderson     int im11a = extract32(val, 1, 11);
17946174e14SRichard Henderson     int s = extract32(val, 12, 2);
18046174e14SRichard Henderson     int i = (-(val & 1) << 13) | (im11a << 2);
18146174e14SRichard Henderson 
18246174e14SRichard Henderson     if (ctx->tb_flags & PSW_W) {
18346174e14SRichard Henderson         i ^= s << 13;
18446174e14SRichard Henderson     }
18546174e14SRichard Henderson     return i;
18646174e14SRichard Henderson }
18746174e14SRichard Henderson 
18872bace2dSRichard Henderson /* Expander for assemble_16(s,im14). */
18972bace2dSRichard Henderson static int expand_16(DisasContext *ctx, int val)
19072bace2dSRichard Henderson {
19172bace2dSRichard Henderson     /*
19272bace2dSRichard Henderson      * @val is bits [0:15], containing both im14 and s.
19372bace2dSRichard Henderson      * Swizzle thing around depending on PSW.W.
19472bace2dSRichard Henderson      */
19572bace2dSRichard Henderson     int s = extract32(val, 14, 2);
19672bace2dSRichard Henderson     int i = (-(val & 1) << 13) | extract32(val, 1, 13);
19772bace2dSRichard Henderson 
19872bace2dSRichard Henderson     if (ctx->tb_flags & PSW_W) {
19972bace2dSRichard Henderson         i ^= s << 13;
20072bace2dSRichard Henderson     }
20172bace2dSRichard Henderson     return i;
20272bace2dSRichard Henderson }
20372bace2dSRichard Henderson 
20472bace2dSRichard Henderson /* The sp field is only present with !PSW_W. */
20572bace2dSRichard Henderson static int sp0_if_wide(DisasContext *ctx, int sp)
20672bace2dSRichard Henderson {
20772bace2dSRichard Henderson     return ctx->tb_flags & PSW_W ? 0 : sp;
20872bace2dSRichard Henderson }
20972bace2dSRichard Henderson 
210c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */
211c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val)
212c65c3ee1SRichard Henderson {
213c65c3ee1SRichard Henderson     return val ? val : 4; /* 0 == "*<<" */
214c65c3ee1SRichard Henderson }
215c65c3ee1SRichard Henderson 
21682d0c831SRichard Henderson /*
21782d0c831SRichard Henderson  * In many places pa1.x did not decode the bit that later became
21882d0c831SRichard Henderson  * the pa2.0 D bit.  Suppress D unless the cpu is pa2.0.
21982d0c831SRichard Henderson  */
22082d0c831SRichard Henderson static int pa20_d(DisasContext *ctx, int val)
22182d0c831SRichard Henderson {
22282d0c831SRichard Henderson     return ctx->is_pa20 & val;
22382d0c831SRichard Henderson }
22401afb7beSRichard Henderson 
22540f9f908SRichard Henderson /* Include the auto-generated decoder.  */
226abff1abfSPaolo Bonzini #include "decode-insns.c.inc"
22740f9f908SRichard Henderson 
22861766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated
22961766fe9SRichard Henderson    the iaq (for whatever reason), so don't do it again on exit.  */
230869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED  DISAS_TARGET_0
23161766fe9SRichard Henderson 
23261766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor
23361766fe9SRichard Henderson    updated the iaq for the next instruction to be executed.  */
234869051eaSRichard Henderson #define DISAS_IAQ_N_STALE    DISAS_TARGET_1
23561766fe9SRichard Henderson 
236e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately
237e1b5a5edSRichard Henderson    to recognize unmasked interrupts.  */
238e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT      DISAS_TARGET_2
239c5d0aec2SRichard Henderson #define DISAS_EXIT                  DISAS_TARGET_3
240e1b5a5edSRichard Henderson 
24161766fe9SRichard Henderson /* global register indexes */
2426fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32];
24333423472SRichard Henderson static TCGv_i64 cpu_sr[4];
244494737b7SRichard Henderson static TCGv_i64 cpu_srH;
2456fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f;
2466fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b;
247c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f;
248c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b;
2496fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar;
2506fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n;
2516fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v;
2526fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb;
2536fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb;
25461766fe9SRichard Henderson 
25561766fe9SRichard Henderson void hppa_translate_init(void)
25661766fe9SRichard Henderson {
25761766fe9SRichard Henderson #define DEF_VAR(V)  { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
25861766fe9SRichard Henderson 
2596fd0c7bcSRichard Henderson     typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar;
26061766fe9SRichard Henderson     static const GlobalVar vars[] = {
26135136a77SRichard Henderson         { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) },
26261766fe9SRichard Henderson         DEF_VAR(psw_n),
26361766fe9SRichard Henderson         DEF_VAR(psw_v),
26461766fe9SRichard Henderson         DEF_VAR(psw_cb),
26561766fe9SRichard Henderson         DEF_VAR(psw_cb_msb),
26661766fe9SRichard Henderson         DEF_VAR(iaoq_f),
26761766fe9SRichard Henderson         DEF_VAR(iaoq_b),
26861766fe9SRichard Henderson     };
26961766fe9SRichard Henderson 
27061766fe9SRichard Henderson #undef DEF_VAR
27161766fe9SRichard Henderson 
27261766fe9SRichard Henderson     /* Use the symbolic register names that match the disassembler.  */
27361766fe9SRichard Henderson     static const char gr_names[32][4] = {
27461766fe9SRichard Henderson         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
27561766fe9SRichard Henderson         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
27661766fe9SRichard Henderson         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
27761766fe9SRichard Henderson         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
27861766fe9SRichard Henderson     };
27933423472SRichard Henderson     /* SR[4-7] are not global registers so that we can index them.  */
280494737b7SRichard Henderson     static const char sr_names[5][4] = {
281494737b7SRichard Henderson         "sr0", "sr1", "sr2", "sr3", "srH"
28233423472SRichard Henderson     };
28361766fe9SRichard Henderson 
28461766fe9SRichard Henderson     int i;
28561766fe9SRichard Henderson 
286f764718dSRichard Henderson     cpu_gr[0] = NULL;
28761766fe9SRichard Henderson     for (i = 1; i < 32; i++) {
288ad75a51eSRichard Henderson         cpu_gr[i] = tcg_global_mem_new(tcg_env,
28961766fe9SRichard Henderson                                        offsetof(CPUHPPAState, gr[i]),
29061766fe9SRichard Henderson                                        gr_names[i]);
29161766fe9SRichard Henderson     }
29233423472SRichard Henderson     for (i = 0; i < 4; i++) {
293ad75a51eSRichard Henderson         cpu_sr[i] = tcg_global_mem_new_i64(tcg_env,
29433423472SRichard Henderson                                            offsetof(CPUHPPAState, sr[i]),
29533423472SRichard Henderson                                            sr_names[i]);
29633423472SRichard Henderson     }
297ad75a51eSRichard Henderson     cpu_srH = tcg_global_mem_new_i64(tcg_env,
298494737b7SRichard Henderson                                      offsetof(CPUHPPAState, sr[4]),
299494737b7SRichard Henderson                                      sr_names[4]);
30061766fe9SRichard Henderson 
30161766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(vars); ++i) {
30261766fe9SRichard Henderson         const GlobalVar *v = &vars[i];
303ad75a51eSRichard Henderson         *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name);
30461766fe9SRichard Henderson     }
305c301f34eSRichard Henderson 
306ad75a51eSRichard Henderson     cpu_iasq_f = tcg_global_mem_new_i64(tcg_env,
307c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_f),
308c301f34eSRichard Henderson                                         "iasq_f");
309ad75a51eSRichard Henderson     cpu_iasq_b = tcg_global_mem_new_i64(tcg_env,
310c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_b),
311c301f34eSRichard Henderson                                         "iasq_b");
31261766fe9SRichard Henderson }
31361766fe9SRichard Henderson 
314f5b5c857SRichard Henderson static void set_insn_breg(DisasContext *ctx, int breg)
315f5b5c857SRichard Henderson {
31624638bd1SRichard Henderson     assert(!ctx->insn_start_updated);
31724638bd1SRichard Henderson     ctx->insn_start_updated = true;
31824638bd1SRichard Henderson     tcg_set_insn_start_param(ctx->base.insn_start, 2, breg);
319f5b5c857SRichard Henderson }
320f5b5c857SRichard Henderson 
321129e9cc3SRichard Henderson static DisasCond cond_make_f(void)
322129e9cc3SRichard Henderson {
323f764718dSRichard Henderson     return (DisasCond){
324f764718dSRichard Henderson         .c = TCG_COND_NEVER,
325f764718dSRichard Henderson         .a0 = NULL,
326f764718dSRichard Henderson         .a1 = NULL,
327f764718dSRichard Henderson     };
328129e9cc3SRichard Henderson }
329129e9cc3SRichard Henderson 
330df0232feSRichard Henderson static DisasCond cond_make_t(void)
331df0232feSRichard Henderson {
332df0232feSRichard Henderson     return (DisasCond){
333df0232feSRichard Henderson         .c = TCG_COND_ALWAYS,
334df0232feSRichard Henderson         .a0 = NULL,
335df0232feSRichard Henderson         .a1 = NULL,
336df0232feSRichard Henderson     };
337df0232feSRichard Henderson }
338df0232feSRichard Henderson 
339129e9cc3SRichard Henderson static DisasCond cond_make_n(void)
340129e9cc3SRichard Henderson {
341f764718dSRichard Henderson     return (DisasCond){
342f764718dSRichard Henderson         .c = TCG_COND_NE,
343f764718dSRichard Henderson         .a0 = cpu_psw_n,
3446fd0c7bcSRichard Henderson         .a1 = tcg_constant_i64(0)
345f764718dSRichard Henderson     };
346129e9cc3SRichard Henderson }
347129e9cc3SRichard Henderson 
348*4c42fd0dSRichard Henderson static DisasCond cond_make_tt(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
349b47a4a02SSven Schnelle {
350b47a4a02SSven Schnelle     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
3514fe9533aSRichard Henderson     return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 };
3524fe9533aSRichard Henderson }
3534fe9533aSRichard Henderson 
354*4c42fd0dSRichard Henderson static DisasCond cond_make_ti(TCGCond c, TCGv_i64 a0, uint64_t imm)
3554fe9533aSRichard Henderson {
356*4c42fd0dSRichard Henderson     return cond_make_tt(c, a0, tcg_constant_i64(imm));
357b47a4a02SSven Schnelle }
358b47a4a02SSven Schnelle 
359*4c42fd0dSRichard Henderson static DisasCond cond_make_vi(TCGCond c, TCGv_i64 a0, uint64_t imm)
360129e9cc3SRichard Henderson {
361aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3626fd0c7bcSRichard Henderson     tcg_gen_mov_i64(tmp, a0);
363*4c42fd0dSRichard Henderson     return cond_make_ti(c, tmp, imm);
364129e9cc3SRichard Henderson }
365129e9cc3SRichard Henderson 
366*4c42fd0dSRichard Henderson static DisasCond cond_make_vv(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
367129e9cc3SRichard Henderson {
368aac0f603SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
369aac0f603SRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
370129e9cc3SRichard Henderson 
3716fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t0, a0);
3726fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t1, a1);
373*4c42fd0dSRichard Henderson     return cond_make_tt(c, t0, t1);
374129e9cc3SRichard Henderson }
375129e9cc3SRichard Henderson 
376129e9cc3SRichard Henderson static void cond_free(DisasCond *cond)
377129e9cc3SRichard Henderson {
378129e9cc3SRichard Henderson     switch (cond->c) {
379129e9cc3SRichard Henderson     default:
380f764718dSRichard Henderson         cond->a0 = NULL;
381f764718dSRichard Henderson         cond->a1 = NULL;
382129e9cc3SRichard Henderson         /* fallthru */
383129e9cc3SRichard Henderson     case TCG_COND_ALWAYS:
384129e9cc3SRichard Henderson         cond->c = TCG_COND_NEVER;
385129e9cc3SRichard Henderson         break;
386129e9cc3SRichard Henderson     case TCG_COND_NEVER:
387129e9cc3SRichard Henderson         break;
388129e9cc3SRichard Henderson     }
389129e9cc3SRichard Henderson }
390129e9cc3SRichard Henderson 
3916fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg)
39261766fe9SRichard Henderson {
39361766fe9SRichard Henderson     if (reg == 0) {
394bc3da3cfSRichard Henderson         return ctx->zero;
39561766fe9SRichard Henderson     } else {
39661766fe9SRichard Henderson         return cpu_gr[reg];
39761766fe9SRichard Henderson     }
39861766fe9SRichard Henderson }
39961766fe9SRichard Henderson 
4006fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg)
40161766fe9SRichard Henderson {
402129e9cc3SRichard Henderson     if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
403aac0f603SRichard Henderson         return tcg_temp_new_i64();
40461766fe9SRichard Henderson     } else {
40561766fe9SRichard Henderson         return cpu_gr[reg];
40661766fe9SRichard Henderson     }
40761766fe9SRichard Henderson }
40861766fe9SRichard Henderson 
4096fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t)
410129e9cc3SRichard Henderson {
411129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
4126fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0,
413129e9cc3SRichard Henderson                             ctx->null_cond.a1, dest, t);
414129e9cc3SRichard Henderson     } else {
4156fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, t);
416129e9cc3SRichard Henderson     }
417129e9cc3SRichard Henderson }
418129e9cc3SRichard Henderson 
4196fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t)
420129e9cc3SRichard Henderson {
421129e9cc3SRichard Henderson     if (reg != 0) {
422129e9cc3SRichard Henderson         save_or_nullify(ctx, cpu_gr[reg], t);
423129e9cc3SRichard Henderson     }
424129e9cc3SRichard Henderson }
425129e9cc3SRichard Henderson 
426e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
42796d6407fSRichard Henderson # define HI_OFS  0
42896d6407fSRichard Henderson # define LO_OFS  4
42996d6407fSRichard Henderson #else
43096d6407fSRichard Henderson # define HI_OFS  4
43196d6407fSRichard Henderson # define LO_OFS  0
43296d6407fSRichard Henderson #endif
43396d6407fSRichard Henderson 
43496d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt)
43596d6407fSRichard Henderson {
43696d6407fSRichard Henderson     TCGv_i32 ret = tcg_temp_new_i32();
437ad75a51eSRichard Henderson     tcg_gen_ld_i32(ret, tcg_env,
43896d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
43996d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
44096d6407fSRichard Henderson     return ret;
44196d6407fSRichard Henderson }
44296d6407fSRichard Henderson 
443ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt)
444ebe9383cSRichard Henderson {
445ebe9383cSRichard Henderson     if (rt == 0) {
4460992a930SRichard Henderson         TCGv_i32 ret = tcg_temp_new_i32();
4470992a930SRichard Henderson         tcg_gen_movi_i32(ret, 0);
4480992a930SRichard Henderson         return ret;
449ebe9383cSRichard Henderson     } else {
450ebe9383cSRichard Henderson         return load_frw_i32(rt);
451ebe9383cSRichard Henderson     }
452ebe9383cSRichard Henderson }
453ebe9383cSRichard Henderson 
454ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt)
455ebe9383cSRichard Henderson {
456ebe9383cSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
4570992a930SRichard Henderson     if (rt == 0) {
4580992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
4590992a930SRichard Henderson     } else {
460ad75a51eSRichard Henderson         tcg_gen_ld32u_i64(ret, tcg_env,
461ebe9383cSRichard Henderson                           offsetof(CPUHPPAState, fr[rt & 31])
462ebe9383cSRichard Henderson                           + (rt & 32 ? LO_OFS : HI_OFS));
463ebe9383cSRichard Henderson     }
4640992a930SRichard Henderson     return ret;
465ebe9383cSRichard Henderson }
466ebe9383cSRichard Henderson 
46796d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val)
46896d6407fSRichard Henderson {
469ad75a51eSRichard Henderson     tcg_gen_st_i32(val, tcg_env,
47096d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
47196d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
47296d6407fSRichard Henderson }
47396d6407fSRichard Henderson 
47496d6407fSRichard Henderson #undef HI_OFS
47596d6407fSRichard Henderson #undef LO_OFS
47696d6407fSRichard Henderson 
47796d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt)
47896d6407fSRichard Henderson {
47996d6407fSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
480ad75a51eSRichard Henderson     tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt]));
48196d6407fSRichard Henderson     return ret;
48296d6407fSRichard Henderson }
48396d6407fSRichard Henderson 
484ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt)
485ebe9383cSRichard Henderson {
486ebe9383cSRichard Henderson     if (rt == 0) {
4870992a930SRichard Henderson         TCGv_i64 ret = tcg_temp_new_i64();
4880992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
4890992a930SRichard Henderson         return ret;
490ebe9383cSRichard Henderson     } else {
491ebe9383cSRichard Henderson         return load_frd(rt);
492ebe9383cSRichard Henderson     }
493ebe9383cSRichard Henderson }
494ebe9383cSRichard Henderson 
49596d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val)
49696d6407fSRichard Henderson {
497ad75a51eSRichard Henderson     tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt]));
49896d6407fSRichard Henderson }
49996d6407fSRichard Henderson 
50033423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg)
50133423472SRichard Henderson {
50233423472SRichard Henderson #ifdef CONFIG_USER_ONLY
50333423472SRichard Henderson     tcg_gen_movi_i64(dest, 0);
50433423472SRichard Henderson #else
50533423472SRichard Henderson     if (reg < 4) {
50633423472SRichard Henderson         tcg_gen_mov_i64(dest, cpu_sr[reg]);
507494737b7SRichard Henderson     } else if (ctx->tb_flags & TB_FLAG_SR_SAME) {
508494737b7SRichard Henderson         tcg_gen_mov_i64(dest, cpu_srH);
50933423472SRichard Henderson     } else {
510ad75a51eSRichard Henderson         tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg]));
51133423472SRichard Henderson     }
51233423472SRichard Henderson #endif
51333423472SRichard Henderson }
51433423472SRichard Henderson 
515129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified.
516129e9cc3SRichard Henderson    Use this when the insn is too complex for a conditional move.  */
517129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx)
518129e9cc3SRichard Henderson {
519129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
520129e9cc3SRichard Henderson         /* The always condition should have been handled in the main loop.  */
521129e9cc3SRichard Henderson         assert(ctx->null_cond.c != TCG_COND_ALWAYS);
522129e9cc3SRichard Henderson 
523129e9cc3SRichard Henderson         ctx->null_lab = gen_new_label();
524129e9cc3SRichard Henderson 
525129e9cc3SRichard Henderson         /* If we're using PSW[N], copy it to a temp because... */
5266e94937aSRichard Henderson         if (ctx->null_cond.a0 == cpu_psw_n) {
527aac0f603SRichard Henderson             ctx->null_cond.a0 = tcg_temp_new_i64();
5286fd0c7bcSRichard Henderson             tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n);
529129e9cc3SRichard Henderson         }
530129e9cc3SRichard Henderson         /* ... we clear it before branching over the implementation,
531129e9cc3SRichard Henderson            so that (1) it's clear after nullifying this insn and
532129e9cc3SRichard Henderson            (2) if this insn nullifies the next, PSW[N] is valid.  */
533129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
534129e9cc3SRichard Henderson             ctx->psw_n_nonzero = false;
5356fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
536129e9cc3SRichard Henderson         }
537129e9cc3SRichard Henderson 
5386fd0c7bcSRichard Henderson         tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0,
539129e9cc3SRichard Henderson                            ctx->null_cond.a1, ctx->null_lab);
540129e9cc3SRichard Henderson         cond_free(&ctx->null_cond);
541129e9cc3SRichard Henderson     }
542129e9cc3SRichard Henderson }
543129e9cc3SRichard Henderson 
544129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N].  */
545129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx)
546129e9cc3SRichard Henderson {
547129e9cc3SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
548129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
5496fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
550129e9cc3SRichard Henderson         }
551129e9cc3SRichard Henderson         return;
552129e9cc3SRichard Henderson     }
5536e94937aSRichard Henderson     if (ctx->null_cond.a0 != cpu_psw_n) {
5546fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n,
555129e9cc3SRichard Henderson                             ctx->null_cond.a0, ctx->null_cond.a1);
556129e9cc3SRichard Henderson         ctx->psw_n_nonzero = true;
557129e9cc3SRichard Henderson     }
558129e9cc3SRichard Henderson     cond_free(&ctx->null_cond);
559129e9cc3SRichard Henderson }
560129e9cc3SRichard Henderson 
561129e9cc3SRichard Henderson /* Set a PSW[N] to X.  The intention is that this is used immediately
562129e9cc3SRichard Henderson    before a goto_tb/exit_tb, so that there is no fallthru path to other
563129e9cc3SRichard Henderson    code within the TB.  Therefore we do not update psw_n_nonzero.  */
564129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x)
565129e9cc3SRichard Henderson {
566129e9cc3SRichard Henderson     if (ctx->psw_n_nonzero || x) {
5676fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, x);
568129e9cc3SRichard Henderson     }
569129e9cc3SRichard Henderson }
570129e9cc3SRichard Henderson 
571129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified.
57240f9f908SRichard Henderson    This is the pair to nullify_over.  Always returns true so that
57340f9f908SRichard Henderson    it may be tail-called from a translate function.  */
57431234768SRichard Henderson static bool nullify_end(DisasContext *ctx)
575129e9cc3SRichard Henderson {
576129e9cc3SRichard Henderson     TCGLabel *null_lab = ctx->null_lab;
57731234768SRichard Henderson     DisasJumpType status = ctx->base.is_jmp;
578129e9cc3SRichard Henderson 
579f49b3537SRichard Henderson     /* For NEXT, NORETURN, STALE, we can easily continue (or exit).
580f49b3537SRichard Henderson        For UPDATED, we cannot update on the nullified path.  */
581f49b3537SRichard Henderson     assert(status != DISAS_IAQ_N_UPDATED);
582f49b3537SRichard Henderson 
583129e9cc3SRichard Henderson     if (likely(null_lab == NULL)) {
584129e9cc3SRichard Henderson         /* The current insn wasn't conditional or handled the condition
585129e9cc3SRichard Henderson            applied to it without a branch, so the (new) setting of
586129e9cc3SRichard Henderson            NULL_COND can be applied directly to the next insn.  */
58731234768SRichard Henderson         return true;
588129e9cc3SRichard Henderson     }
589129e9cc3SRichard Henderson     ctx->null_lab = NULL;
590129e9cc3SRichard Henderson 
591129e9cc3SRichard Henderson     if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
592129e9cc3SRichard Henderson         /* The next instruction will be unconditional,
593129e9cc3SRichard Henderson            and NULL_COND already reflects that.  */
594129e9cc3SRichard Henderson         gen_set_label(null_lab);
595129e9cc3SRichard Henderson     } else {
596129e9cc3SRichard Henderson         /* The insn that we just executed is itself nullifying the next
597129e9cc3SRichard Henderson            instruction.  Store the condition in the PSW[N] global.
598129e9cc3SRichard Henderson            We asserted PSW[N] = 0 in nullify_over, so that after the
599129e9cc3SRichard Henderson            label we have the proper value in place.  */
600129e9cc3SRichard Henderson         nullify_save(ctx);
601129e9cc3SRichard Henderson         gen_set_label(null_lab);
602129e9cc3SRichard Henderson         ctx->null_cond = cond_make_n();
603129e9cc3SRichard Henderson     }
604869051eaSRichard Henderson     if (status == DISAS_NORETURN) {
60531234768SRichard Henderson         ctx->base.is_jmp = DISAS_NEXT;
606129e9cc3SRichard Henderson     }
60731234768SRichard Henderson     return true;
608129e9cc3SRichard Henderson }
609129e9cc3SRichard Henderson 
610bc921866SRichard Henderson static bool iaqe_variable(const DisasIAQE *e)
611bc921866SRichard Henderson {
612bc921866SRichard Henderson     return e->base || e->space;
613bc921866SRichard Henderson }
614bc921866SRichard Henderson 
615bc921866SRichard Henderson static DisasIAQE iaqe_incr(const DisasIAQE *e, int64_t disp)
616bc921866SRichard Henderson {
617bc921866SRichard Henderson     return (DisasIAQE){
618bc921866SRichard Henderson         .space = e->space,
619bc921866SRichard Henderson         .base = e->base,
620bc921866SRichard Henderson         .disp = e->disp + disp,
621bc921866SRichard Henderson     };
622bc921866SRichard Henderson }
623bc921866SRichard Henderson 
624bc921866SRichard Henderson static DisasIAQE iaqe_branchi(DisasContext *ctx, int64_t disp)
625bc921866SRichard Henderson {
626bc921866SRichard Henderson     return (DisasIAQE){
627bc921866SRichard Henderson         .space = ctx->iaq_b.space,
628bc921866SRichard Henderson         .disp = ctx->iaq_f.disp + 8 + disp,
629bc921866SRichard Henderson     };
630bc921866SRichard Henderson }
631bc921866SRichard Henderson 
632bc921866SRichard Henderson static DisasIAQE iaqe_next_absv(DisasContext *ctx, TCGv_i64 var)
633bc921866SRichard Henderson {
634bc921866SRichard Henderson     return (DisasIAQE){
635bc921866SRichard Henderson         .space = ctx->iaq_b.space,
636bc921866SRichard Henderson         .base = var,
637bc921866SRichard Henderson     };
638bc921866SRichard Henderson }
639bc921866SRichard Henderson 
6406fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest,
641bc921866SRichard Henderson                             const DisasIAQE *src)
64261766fe9SRichard Henderson {
6437d50b696SSven Schnelle     uint64_t mask = gva_offset_mask(ctx->tb_flags);
644f13bf343SRichard Henderson 
645bc921866SRichard Henderson     if (src->base == NULL) {
6460d89cb7cSRichard Henderson         tcg_gen_movi_i64(dest, (ctx->iaoq_first + src->disp) & mask);
647bc921866SRichard Henderson     } else if (src->disp == 0) {
648bc921866SRichard Henderson         tcg_gen_andi_i64(dest, src->base, mask);
64961766fe9SRichard Henderson     } else {
650bc921866SRichard Henderson         tcg_gen_addi_i64(dest, src->base, src->disp);
651bc921866SRichard Henderson         tcg_gen_andi_i64(dest, dest, mask);
65261766fe9SRichard Henderson     }
65361766fe9SRichard Henderson }
65461766fe9SRichard Henderson 
655bc921866SRichard Henderson static void install_iaq_entries(DisasContext *ctx, const DisasIAQE *f,
656bc921866SRichard Henderson                                 const DisasIAQE *b)
65785e6cda0SRichard Henderson {
658bc921866SRichard Henderson     DisasIAQE b_next;
65985e6cda0SRichard Henderson 
660bc921866SRichard Henderson     if (b == NULL) {
661bc921866SRichard Henderson         b_next = iaqe_incr(f, 4);
662bc921866SRichard Henderson         b = &b_next;
66385e6cda0SRichard Henderson     }
664bc921866SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, f);
665bc921866SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, b);
666bc921866SRichard Henderson     if (f->space) {
667bc921866SRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, f->space);
668588deedaSRichard Henderson     }
669bc921866SRichard Henderson     if (b->space || f->space) {
670bc921866SRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, b->space ? : f->space);
671588deedaSRichard Henderson     }
67285e6cda0SRichard Henderson }
67385e6cda0SRichard Henderson 
67443541db0SRichard Henderson static void install_link(DisasContext *ctx, unsigned link, bool with_sr0)
67543541db0SRichard Henderson {
67643541db0SRichard Henderson     tcg_debug_assert(ctx->null_cond.c == TCG_COND_NEVER);
67743541db0SRichard Henderson     if (!link) {
67843541db0SRichard Henderson         return;
67943541db0SRichard Henderson     }
6800d89cb7cSRichard Henderson     DisasIAQE next = iaqe_incr(&ctx->iaq_b, 4);
6810d89cb7cSRichard Henderson     copy_iaoq_entry(ctx, cpu_gr[link], &next);
68243541db0SRichard Henderson #ifndef CONFIG_USER_ONLY
68343541db0SRichard Henderson     if (with_sr0) {
68443541db0SRichard Henderson         tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_b);
68543541db0SRichard Henderson     }
68643541db0SRichard Henderson #endif
68743541db0SRichard Henderson }
68843541db0SRichard Henderson 
68961766fe9SRichard Henderson static void gen_excp_1(int exception)
69061766fe9SRichard Henderson {
691ad75a51eSRichard Henderson     gen_helper_excp(tcg_env, tcg_constant_i32(exception));
69261766fe9SRichard Henderson }
69361766fe9SRichard Henderson 
69431234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception)
69561766fe9SRichard Henderson {
696bc921866SRichard Henderson     install_iaq_entries(ctx, &ctx->iaq_f, &ctx->iaq_b);
697129e9cc3SRichard Henderson     nullify_save(ctx);
69861766fe9SRichard Henderson     gen_excp_1(exception);
69931234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
70061766fe9SRichard Henderson }
70161766fe9SRichard Henderson 
70231234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc)
7031a19da0dSRichard Henderson {
70431234768SRichard Henderson     nullify_over(ctx);
7056fd0c7bcSRichard Henderson     tcg_gen_st_i64(tcg_constant_i64(ctx->insn),
706ad75a51eSRichard Henderson                    tcg_env, offsetof(CPUHPPAState, cr[CR_IIR]));
70731234768SRichard Henderson     gen_excp(ctx, exc);
70831234768SRichard Henderson     return nullify_end(ctx);
7091a19da0dSRichard Henderson }
7101a19da0dSRichard Henderson 
71131234768SRichard Henderson static bool gen_illegal(DisasContext *ctx)
71261766fe9SRichard Henderson {
71331234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_ILL);
71461766fe9SRichard Henderson }
71561766fe9SRichard Henderson 
71640f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY
71740f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
71840f9f908SRichard Henderson     return gen_excp_iir(ctx, EXCP)
71940f9f908SRichard Henderson #else
720e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
721e1b5a5edSRichard Henderson     do {                                     \
722e1b5a5edSRichard Henderson         if (ctx->privilege != 0) {           \
72331234768SRichard Henderson             return gen_excp_iir(ctx, EXCP);  \
724e1b5a5edSRichard Henderson         }                                    \
725e1b5a5edSRichard Henderson     } while (0)
72640f9f908SRichard Henderson #endif
727e1b5a5edSRichard Henderson 
728bc921866SRichard Henderson static bool use_goto_tb(DisasContext *ctx, const DisasIAQE *f,
729bc921866SRichard Henderson                         const DisasIAQE *b)
73061766fe9SRichard Henderson {
731bc921866SRichard Henderson     return (!iaqe_variable(f) &&
732bc921866SRichard Henderson             (b == NULL || !iaqe_variable(b)) &&
7330d89cb7cSRichard Henderson             translator_use_goto_tb(&ctx->base, ctx->iaoq_first + f->disp));
73461766fe9SRichard Henderson }
73561766fe9SRichard Henderson 
736129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page,
737129e9cc3SRichard Henderson    and we're not attempting to set a breakpoint on it, then we can
738129e9cc3SRichard Henderson    totally skip the nullified insn.  This avoids creating and
739129e9cc3SRichard Henderson    executing a TB that merely branches to the next TB.  */
740129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx)
741129e9cc3SRichard Henderson {
742f9b11bc2SRichard Henderson     return (!(tb_cflags(ctx->base.tb) & CF_BP_PAGE)
743bc921866SRichard Henderson             && !iaqe_variable(&ctx->iaq_b)
7440d89cb7cSRichard Henderson             && (((ctx->iaoq_first + ctx->iaq_b.disp) ^ ctx->iaoq_first)
7450d89cb7cSRichard Henderson                 & TARGET_PAGE_MASK) == 0);
746129e9cc3SRichard Henderson }
747129e9cc3SRichard Henderson 
74861766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which,
749bc921866SRichard Henderson                         const DisasIAQE *f, const DisasIAQE *b)
75061766fe9SRichard Henderson {
751bc921866SRichard Henderson     if (use_goto_tb(ctx, f, b)) {
75261766fe9SRichard Henderson         tcg_gen_goto_tb(which);
753bc921866SRichard Henderson         install_iaq_entries(ctx, f, b);
75407ea28b4SRichard Henderson         tcg_gen_exit_tb(ctx->base.tb, which);
75561766fe9SRichard Henderson     } else {
756bc921866SRichard Henderson         install_iaq_entries(ctx, f, b);
7577f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
75861766fe9SRichard Henderson     }
75961766fe9SRichard Henderson }
76061766fe9SRichard Henderson 
761b47a4a02SSven Schnelle static bool cond_need_sv(int c)
762b47a4a02SSven Schnelle {
763b47a4a02SSven Schnelle     return c == 2 || c == 3 || c == 6;
764b47a4a02SSven Schnelle }
765b47a4a02SSven Schnelle 
766b47a4a02SSven Schnelle static bool cond_need_cb(int c)
767b47a4a02SSven Schnelle {
768b47a4a02SSven Schnelle     return c == 4 || c == 5;
769b47a4a02SSven Schnelle }
770b47a4a02SSven Schnelle 
771b47a4a02SSven Schnelle /*
772b47a4a02SSven Schnelle  * Compute conditional for arithmetic.  See Page 5-3, Table 5-1, of
773b47a4a02SSven Schnelle  * the Parisc 1.1 Architecture Reference Manual for details.
774b47a4a02SSven Schnelle  */
775b2167459SRichard Henderson 
776a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d,
777fe2d066aSRichard Henderson                          TCGv_i64 res, TCGv_i64 uv, TCGv_i64 sv)
778b2167459SRichard Henderson {
779b2167459SRichard Henderson     DisasCond cond;
7806fd0c7bcSRichard Henderson     TCGv_i64 tmp;
781b2167459SRichard Henderson 
782b2167459SRichard Henderson     switch (cf >> 1) {
783b47a4a02SSven Schnelle     case 0: /* Never / TR    (0 / 1) */
784b2167459SRichard Henderson         cond = cond_make_f();
785b2167459SRichard Henderson         break;
786b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
78782d0c831SRichard Henderson         if (!d) {
788aac0f603SRichard Henderson             tmp = tcg_temp_new_i64();
7896fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
790a751eb31SRichard Henderson             res = tmp;
791a751eb31SRichard Henderson         }
792*4c42fd0dSRichard Henderson         cond = cond_make_vi(TCG_COND_EQ, res, 0);
793b2167459SRichard Henderson         break;
794b47a4a02SSven Schnelle     case 2: /* < / >=        (N ^ V / !(N ^ V) */
795aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
7966fd0c7bcSRichard Henderson         tcg_gen_xor_i64(tmp, res, sv);
79782d0c831SRichard Henderson         if (!d) {
7986fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, tmp);
799a751eb31SRichard Henderson         }
800*4c42fd0dSRichard Henderson         cond = cond_make_ti(TCG_COND_LT, tmp, 0);
801b2167459SRichard Henderson         break;
802b47a4a02SSven Schnelle     case 3: /* <= / >        (N ^ V) | Z / !((N ^ V) | Z) */
803b47a4a02SSven Schnelle         /*
804b47a4a02SSven Schnelle          * Simplify:
805b47a4a02SSven Schnelle          *   (N ^ V) | Z
806b47a4a02SSven Schnelle          *   ((res < 0) ^ (sv < 0)) | !res
807b47a4a02SSven Schnelle          *   ((res ^ sv) < 0) | !res
808b47a4a02SSven Schnelle          *   (~(res ^ sv) >= 0) | !res
809b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31) | !res
810b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31 & res)
811b47a4a02SSven Schnelle          */
812aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
8136fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(tmp, res, sv);
81482d0c831SRichard Henderson         if (!d) {
8156fd0c7bcSRichard Henderson             tcg_gen_sextract_i64(tmp, tmp, 31, 1);
8166fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
8176fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
818a751eb31SRichard Henderson         } else {
8196fd0c7bcSRichard Henderson             tcg_gen_sari_i64(tmp, tmp, 63);
8206fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
821a751eb31SRichard Henderson         }
822*4c42fd0dSRichard Henderson         cond = cond_make_ti(TCG_COND_EQ, tmp, 0);
823b2167459SRichard Henderson         break;
824fe2d066aSRichard Henderson     case 4: /* NUV / UV      (!UV / UV) */
825*4c42fd0dSRichard Henderson         cond = cond_make_vi(TCG_COND_EQ, uv, 0);
826b2167459SRichard Henderson         break;
827fe2d066aSRichard Henderson     case 5: /* ZNV / VNZ     (!UV | Z / UV & !Z) */
828aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
829fe2d066aSRichard Henderson         tcg_gen_movcond_i64(TCG_COND_EQ, tmp, uv, ctx->zero, ctx->zero, res);
83082d0c831SRichard Henderson         if (!d) {
8316fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
832a751eb31SRichard Henderson         }
833*4c42fd0dSRichard Henderson         cond = cond_make_ti(TCG_COND_EQ, tmp, 0);
834b2167459SRichard Henderson         break;
835b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
83682d0c831SRichard Henderson         if (!d) {
837aac0f603SRichard Henderson             tmp = tcg_temp_new_i64();
8386fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, sv);
839a751eb31SRichard Henderson             sv = tmp;
840a751eb31SRichard Henderson         }
841*4c42fd0dSRichard Henderson         cond = cond_make_ti(TCG_COND_LT, sv, 0);
842b2167459SRichard Henderson         break;
843b2167459SRichard Henderson     case 7: /* OD / EV */
844aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
8456fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, res, 1);
846*4c42fd0dSRichard Henderson         cond = cond_make_ti(TCG_COND_NE, tmp, 0);
847b2167459SRichard Henderson         break;
848b2167459SRichard Henderson     default:
849b2167459SRichard Henderson         g_assert_not_reached();
850b2167459SRichard Henderson     }
851b2167459SRichard Henderson     if (cf & 1) {
852b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
853b2167459SRichard Henderson     }
854b2167459SRichard Henderson 
855b2167459SRichard Henderson     return cond;
856b2167459SRichard Henderson }
857b2167459SRichard Henderson 
858b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
859b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
860b2167459SRichard Henderson    deleted as unused.  */
861b2167459SRichard Henderson 
8624fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d,
8636fd0c7bcSRichard Henderson                              TCGv_i64 res, TCGv_i64 in1,
8646fd0c7bcSRichard Henderson                              TCGv_i64 in2, TCGv_i64 sv)
865b2167459SRichard Henderson {
8664fe9533aSRichard Henderson     TCGCond tc;
8674fe9533aSRichard Henderson     bool ext_uns;
868b2167459SRichard Henderson 
869b2167459SRichard Henderson     switch (cf >> 1) {
870b2167459SRichard Henderson     case 1: /* = / <> */
8714fe9533aSRichard Henderson         tc = TCG_COND_EQ;
8724fe9533aSRichard Henderson         ext_uns = true;
873b2167459SRichard Henderson         break;
874b2167459SRichard Henderson     case 2: /* < / >= */
8754fe9533aSRichard Henderson         tc = TCG_COND_LT;
8764fe9533aSRichard Henderson         ext_uns = false;
877b2167459SRichard Henderson         break;
878b2167459SRichard Henderson     case 3: /* <= / > */
8794fe9533aSRichard Henderson         tc = TCG_COND_LE;
8804fe9533aSRichard Henderson         ext_uns = false;
881b2167459SRichard Henderson         break;
882b2167459SRichard Henderson     case 4: /* << / >>= */
8834fe9533aSRichard Henderson         tc = TCG_COND_LTU;
8844fe9533aSRichard Henderson         ext_uns = true;
885b2167459SRichard Henderson         break;
886b2167459SRichard Henderson     case 5: /* <<= / >> */
8874fe9533aSRichard Henderson         tc = TCG_COND_LEU;
8884fe9533aSRichard Henderson         ext_uns = true;
889b2167459SRichard Henderson         break;
890b2167459SRichard Henderson     default:
891a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, sv);
892b2167459SRichard Henderson     }
893b2167459SRichard Henderson 
8944fe9533aSRichard Henderson     if (cf & 1) {
8954fe9533aSRichard Henderson         tc = tcg_invert_cond(tc);
8964fe9533aSRichard Henderson     }
89782d0c831SRichard Henderson     if (!d) {
898aac0f603SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
899aac0f603SRichard Henderson         TCGv_i64 t2 = tcg_temp_new_i64();
9004fe9533aSRichard Henderson 
9014fe9533aSRichard Henderson         if (ext_uns) {
9026fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t1, in1);
9036fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t2, in2);
9044fe9533aSRichard Henderson         } else {
9056fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t1, in1);
9066fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t2, in2);
9074fe9533aSRichard Henderson         }
908*4c42fd0dSRichard Henderson         return cond_make_tt(tc, t1, t2);
9094fe9533aSRichard Henderson     }
910*4c42fd0dSRichard Henderson     return cond_make_vv(tc, in1, in2);
911b2167459SRichard Henderson }
912b2167459SRichard Henderson 
913df0232feSRichard Henderson /*
914df0232feSRichard Henderson  * Similar, but for logicals, where the carry and overflow bits are not
915df0232feSRichard Henderson  * computed, and use of them is undefined.
916df0232feSRichard Henderson  *
917df0232feSRichard Henderson  * Undefined or not, hardware does not trap.  It seems reasonable to
918df0232feSRichard Henderson  * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's
919df0232feSRichard Henderson  * how cases c={2,3} are treated.
920df0232feSRichard Henderson  */
921b2167459SRichard Henderson 
922b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d,
9236fd0c7bcSRichard Henderson                              TCGv_i64 res)
924b2167459SRichard Henderson {
925b5af8423SRichard Henderson     TCGCond tc;
926b5af8423SRichard Henderson     bool ext_uns;
927a751eb31SRichard Henderson 
928df0232feSRichard Henderson     switch (cf) {
929df0232feSRichard Henderson     case 0:  /* never */
930df0232feSRichard Henderson     case 9:  /* undef, C */
931df0232feSRichard Henderson     case 11: /* undef, C & !Z */
932df0232feSRichard Henderson     case 12: /* undef, V */
933df0232feSRichard Henderson         return cond_make_f();
934df0232feSRichard Henderson 
935df0232feSRichard Henderson     case 1:  /* true */
936df0232feSRichard Henderson     case 8:  /* undef, !C */
937df0232feSRichard Henderson     case 10: /* undef, !C | Z */
938df0232feSRichard Henderson     case 13: /* undef, !V */
939df0232feSRichard Henderson         return cond_make_t();
940df0232feSRichard Henderson 
941df0232feSRichard Henderson     case 2:  /* == */
942b5af8423SRichard Henderson         tc = TCG_COND_EQ;
943b5af8423SRichard Henderson         ext_uns = true;
944b5af8423SRichard Henderson         break;
945df0232feSRichard Henderson     case 3:  /* <> */
946b5af8423SRichard Henderson         tc = TCG_COND_NE;
947b5af8423SRichard Henderson         ext_uns = true;
948b5af8423SRichard Henderson         break;
949df0232feSRichard Henderson     case 4:  /* < */
950b5af8423SRichard Henderson         tc = TCG_COND_LT;
951b5af8423SRichard Henderson         ext_uns = false;
952b5af8423SRichard Henderson         break;
953df0232feSRichard Henderson     case 5:  /* >= */
954b5af8423SRichard Henderson         tc = TCG_COND_GE;
955b5af8423SRichard Henderson         ext_uns = false;
956b5af8423SRichard Henderson         break;
957df0232feSRichard Henderson     case 6:  /* <= */
958b5af8423SRichard Henderson         tc = TCG_COND_LE;
959b5af8423SRichard Henderson         ext_uns = false;
960b5af8423SRichard Henderson         break;
961df0232feSRichard Henderson     case 7:  /* > */
962b5af8423SRichard Henderson         tc = TCG_COND_GT;
963b5af8423SRichard Henderson         ext_uns = false;
964b5af8423SRichard Henderson         break;
965df0232feSRichard Henderson 
966df0232feSRichard Henderson     case 14: /* OD */
967df0232feSRichard Henderson     case 15: /* EV */
968a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, NULL);
969df0232feSRichard Henderson 
970df0232feSRichard Henderson     default:
971df0232feSRichard Henderson         g_assert_not_reached();
972b2167459SRichard Henderson     }
973b5af8423SRichard Henderson 
97482d0c831SRichard Henderson     if (!d) {
975aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
976b5af8423SRichard Henderson 
977b5af8423SRichard Henderson         if (ext_uns) {
9786fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
979b5af8423SRichard Henderson         } else {
9806fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, res);
981b5af8423SRichard Henderson         }
982*4c42fd0dSRichard Henderson         return cond_make_ti(tc, tmp, 0);
983b5af8423SRichard Henderson     }
984*4c42fd0dSRichard Henderson     return cond_make_vi(tc, res, 0);
985b2167459SRichard Henderson }
986b2167459SRichard Henderson 
98798cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
98898cd9ca7SRichard Henderson 
9894fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d,
9906fd0c7bcSRichard Henderson                              TCGv_i64 res)
99198cd9ca7SRichard Henderson {
99298cd9ca7SRichard Henderson     unsigned c, f;
99398cd9ca7SRichard Henderson 
99498cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
99598cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
99698cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
99798cd9ca7SRichard Henderson     c = orig & 3;
99898cd9ca7SRichard Henderson     if (c == 3) {
99998cd9ca7SRichard Henderson         c = 7;
100098cd9ca7SRichard Henderson     }
100198cd9ca7SRichard Henderson     f = (orig & 4) / 4;
100298cd9ca7SRichard Henderson 
1003b5af8423SRichard Henderson     return do_log_cond(ctx, c * 2 + f, d, res);
100498cd9ca7SRichard Henderson }
100598cd9ca7SRichard Henderson 
100646bb3d46SRichard Henderson /* Similar, but for unit zero conditions.  */
100746bb3d46SRichard Henderson static DisasCond do_unit_zero_cond(unsigned cf, bool d, TCGv_i64 res)
1008b2167459SRichard Henderson {
100946bb3d46SRichard Henderson     TCGv_i64 tmp;
1010c53e401eSRichard Henderson     uint64_t d_repl = d ? 0x0000000100000001ull : 1;
101146bb3d46SRichard Henderson     uint64_t ones = 0, sgns = 0;
1012b2167459SRichard Henderson 
1013b2167459SRichard Henderson     switch (cf >> 1) {
1014578b8132SSven Schnelle     case 1: /* SBW / NBW */
1015578b8132SSven Schnelle         if (d) {
101646bb3d46SRichard Henderson             ones = d_repl;
101746bb3d46SRichard Henderson             sgns = d_repl << 31;
1018578b8132SSven Schnelle         }
1019578b8132SSven Schnelle         break;
1020b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
102146bb3d46SRichard Henderson         ones = d_repl * 0x01010101u;
102246bb3d46SRichard Henderson         sgns = ones << 7;
102346bb3d46SRichard Henderson         break;
102446bb3d46SRichard Henderson     case 3: /* SHZ / NHZ */
102546bb3d46SRichard Henderson         ones = d_repl * 0x00010001u;
102646bb3d46SRichard Henderson         sgns = ones << 15;
102746bb3d46SRichard Henderson         break;
102846bb3d46SRichard Henderson     }
102946bb3d46SRichard Henderson     if (ones == 0) {
103046bb3d46SRichard Henderson         /* Undefined, or 0/1 (never/always). */
103146bb3d46SRichard Henderson         return cf & 1 ? cond_make_t() : cond_make_f();
103246bb3d46SRichard Henderson     }
103346bb3d46SRichard Henderson 
103446bb3d46SRichard Henderson     /*
103546bb3d46SRichard Henderson      * See hasless(v,1) from
1036b2167459SRichard Henderson      * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
1037b2167459SRichard Henderson      */
1038aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
103946bb3d46SRichard Henderson     tcg_gen_subi_i64(tmp, res, ones);
10406fd0c7bcSRichard Henderson     tcg_gen_andc_i64(tmp, tmp, res);
104146bb3d46SRichard Henderson     tcg_gen_andi_i64(tmp, tmp, sgns);
1042b2167459SRichard Henderson 
1043*4c42fd0dSRichard Henderson     return cond_make_ti(cf & 1 ? TCG_COND_EQ : TCG_COND_NE, tmp, 0);
1044b2167459SRichard Henderson }
1045b2167459SRichard Henderson 
10466fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d,
10476fd0c7bcSRichard Henderson                           TCGv_i64 cb, TCGv_i64 cb_msb)
104872ca8753SRichard Henderson {
104982d0c831SRichard Henderson     if (!d) {
1050aac0f603SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
10516fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, cb, 32, 1);
105272ca8753SRichard Henderson         return t;
105372ca8753SRichard Henderson     }
105472ca8753SRichard Henderson     return cb_msb;
105572ca8753SRichard Henderson }
105672ca8753SRichard Henderson 
10576fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d)
105872ca8753SRichard Henderson {
105972ca8753SRichard Henderson     return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb);
106072ca8753SRichard Henderson }
106172ca8753SRichard Henderson 
1062b2167459SRichard Henderson /* Compute signed overflow for addition.  */
10636fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res,
1064f8f5986eSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2,
1065f8f5986eSRichard Henderson                           TCGv_i64 orig_in1, int shift, bool d)
1066b2167459SRichard Henderson {
1067aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
1068aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
1069b2167459SRichard Henderson 
10706fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
10716fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
10726fd0c7bcSRichard Henderson     tcg_gen_andc_i64(sv, sv, tmp);
1073b2167459SRichard Henderson 
1074f8f5986eSRichard Henderson     switch (shift) {
1075f8f5986eSRichard Henderson     case 0:
1076f8f5986eSRichard Henderson         break;
1077f8f5986eSRichard Henderson     case 1:
1078f8f5986eSRichard Henderson         /* Shift left by one and compare the sign. */
1079f8f5986eSRichard Henderson         tcg_gen_add_i64(tmp, orig_in1, orig_in1);
1080f8f5986eSRichard Henderson         tcg_gen_xor_i64(tmp, tmp, orig_in1);
1081f8f5986eSRichard Henderson         /* Incorporate into the overflow. */
1082f8f5986eSRichard Henderson         tcg_gen_or_i64(sv, sv, tmp);
1083f8f5986eSRichard Henderson         break;
1084f8f5986eSRichard Henderson     default:
1085f8f5986eSRichard Henderson         {
1086f8f5986eSRichard Henderson             int sign_bit = d ? 63 : 31;
1087f8f5986eSRichard Henderson 
1088f8f5986eSRichard Henderson             /* Compare the sign against all lower bits. */
1089f8f5986eSRichard Henderson             tcg_gen_sextract_i64(tmp, orig_in1, sign_bit, 1);
1090f8f5986eSRichard Henderson             tcg_gen_xor_i64(tmp, tmp, orig_in1);
1091f8f5986eSRichard Henderson             /*
1092f8f5986eSRichard Henderson              * If one of the bits shifting into or through the sign
1093f8f5986eSRichard Henderson              * differs, then we have overflow.
1094f8f5986eSRichard Henderson              */
1095f8f5986eSRichard Henderson             tcg_gen_extract_i64(tmp, tmp, sign_bit - shift, shift);
1096f8f5986eSRichard Henderson             tcg_gen_movcond_i64(TCG_COND_NE, sv, tmp, ctx->zero,
1097f8f5986eSRichard Henderson                                 tcg_constant_i64(-1), sv);
1098f8f5986eSRichard Henderson         }
1099f8f5986eSRichard Henderson     }
1100b2167459SRichard Henderson     return sv;
1101b2167459SRichard Henderson }
1102b2167459SRichard Henderson 
1103f8f5986eSRichard Henderson /* Compute unsigned overflow for addition.  */
1104f8f5986eSRichard Henderson static TCGv_i64 do_add_uv(DisasContext *ctx, TCGv_i64 cb, TCGv_i64 cb_msb,
1105f8f5986eSRichard Henderson                           TCGv_i64 in1, int shift, bool d)
1106f8f5986eSRichard Henderson {
1107f8f5986eSRichard Henderson     if (shift == 0) {
1108f8f5986eSRichard Henderson         return get_carry(ctx, d, cb, cb_msb);
1109f8f5986eSRichard Henderson     } else {
1110f8f5986eSRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
1111f8f5986eSRichard Henderson         tcg_gen_extract_i64(tmp, in1, (d ? 63 : 31) - shift, shift);
1112f8f5986eSRichard Henderson         tcg_gen_or_i64(tmp, tmp, get_carry(ctx, d, cb, cb_msb));
1113f8f5986eSRichard Henderson         return tmp;
1114f8f5986eSRichard Henderson     }
1115f8f5986eSRichard Henderson }
1116f8f5986eSRichard Henderson 
1117b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
11186fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res,
11196fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
1120b2167459SRichard Henderson {
1121aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
1122aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
1123b2167459SRichard Henderson 
11246fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
11256fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
11266fd0c7bcSRichard Henderson     tcg_gen_and_i64(sv, sv, tmp);
1127b2167459SRichard Henderson 
1128b2167459SRichard Henderson     return sv;
1129b2167459SRichard Henderson }
1130b2167459SRichard Henderson 
1131f8f5986eSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 orig_in1,
11326fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned shift, bool is_l,
1133faf97ba1SRichard Henderson                    bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d)
1134b2167459SRichard Henderson {
1135f8f5986eSRichard Henderson     TCGv_i64 dest, cb, cb_msb, in1, uv, sv, tmp;
1136b2167459SRichard Henderson     unsigned c = cf >> 1;
1137b2167459SRichard Henderson     DisasCond cond;
1138b2167459SRichard Henderson 
1139aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1140f764718dSRichard Henderson     cb = NULL;
1141f764718dSRichard Henderson     cb_msb = NULL;
1142b2167459SRichard Henderson 
1143f8f5986eSRichard Henderson     in1 = orig_in1;
1144b2167459SRichard Henderson     if (shift) {
1145aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
11466fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, in1, shift);
1147b2167459SRichard Henderson         in1 = tmp;
1148b2167459SRichard Henderson     }
1149b2167459SRichard Henderson 
1150b47a4a02SSven Schnelle     if (!is_l || cond_need_cb(c)) {
1151aac0f603SRichard Henderson         cb_msb = tcg_temp_new_i64();
1152aac0f603SRichard Henderson         cb = tcg_temp_new_i64();
1153bdcccc17SRichard Henderson 
1154a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero);
1155b2167459SRichard Henderson         if (is_c) {
11566fd0c7bcSRichard Henderson             tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb,
1157a4db4a78SRichard Henderson                              get_psw_carry(ctx, d), ctx->zero);
1158b2167459SRichard Henderson         }
11596fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
11606fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1161b2167459SRichard Henderson     } else {
11626fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
1163b2167459SRichard Henderson         if (is_c) {
11646fd0c7bcSRichard Henderson             tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d));
1165b2167459SRichard Henderson         }
1166b2167459SRichard Henderson     }
1167b2167459SRichard Henderson 
1168b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1169f764718dSRichard Henderson     sv = NULL;
1170b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1171f8f5986eSRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2, orig_in1, shift, d);
1172b2167459SRichard Henderson         if (is_tsv) {
1173bd1ad92cSSven Schnelle             if (!d) {
1174bd1ad92cSSven Schnelle                 tcg_gen_ext32s_i64(sv, sv);
1175bd1ad92cSSven Schnelle             }
1176ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1177b2167459SRichard Henderson         }
1178b2167459SRichard Henderson     }
1179b2167459SRichard Henderson 
1180f8f5986eSRichard Henderson     /* Compute unsigned overflow if required.  */
1181f8f5986eSRichard Henderson     uv = NULL;
1182f8f5986eSRichard Henderson     if (cond_need_cb(c)) {
1183f8f5986eSRichard Henderson         uv = do_add_uv(ctx, cb, cb_msb, orig_in1, shift, d);
1184f8f5986eSRichard Henderson     }
1185f8f5986eSRichard Henderson 
1186b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1187f8f5986eSRichard Henderson     cond = do_cond(ctx, cf, d, dest, uv, sv);
1188b2167459SRichard Henderson     if (is_tc) {
1189aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
11906fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1191ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1192b2167459SRichard Henderson     }
1193b2167459SRichard Henderson 
1194b2167459SRichard Henderson     /* Write back the result.  */
1195b2167459SRichard Henderson     if (!is_l) {
1196b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
1197b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1198b2167459SRichard Henderson     }
1199b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1200b2167459SRichard Henderson 
1201b2167459SRichard Henderson     /* Install the new nullification.  */
1202b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1203b2167459SRichard Henderson     ctx->null_cond = cond;
1204b2167459SRichard Henderson }
1205b2167459SRichard Henderson 
1206faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a,
12070c982a28SRichard Henderson                        bool is_l, bool is_tsv, bool is_tc, bool is_c)
12080c982a28SRichard Henderson {
12096fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
12100c982a28SRichard Henderson 
12110c982a28SRichard Henderson     if (a->cf) {
12120c982a28SRichard Henderson         nullify_over(ctx);
12130c982a28SRichard Henderson     }
12140c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
12150c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1216faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l,
1217faf97ba1SRichard Henderson            is_tsv, is_tc, is_c, a->cf, a->d);
12180c982a28SRichard Henderson     return nullify_end(ctx);
12190c982a28SRichard Henderson }
12200c982a28SRichard Henderson 
12210588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a,
12220588e061SRichard Henderson                        bool is_tsv, bool is_tc)
12230588e061SRichard Henderson {
12246fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
12250588e061SRichard Henderson 
12260588e061SRichard Henderson     if (a->cf) {
12270588e061SRichard Henderson         nullify_over(ctx);
12280588e061SRichard Henderson     }
12296fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
12300588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
1231faf97ba1SRichard Henderson     /* All ADDI conditions are 32-bit. */
1232faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false);
12330588e061SRichard Henderson     return nullify_end(ctx);
12340588e061SRichard Henderson }
12350588e061SRichard Henderson 
12366fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12376fd0c7bcSRichard Henderson                    TCGv_i64 in2, bool is_tsv, bool is_b,
123863c427c6SRichard Henderson                    bool is_tc, unsigned cf, bool d)
1239b2167459SRichard Henderson {
1240a4db4a78SRichard Henderson     TCGv_i64 dest, sv, cb, cb_msb, tmp;
1241b2167459SRichard Henderson     unsigned c = cf >> 1;
1242b2167459SRichard Henderson     DisasCond cond;
1243b2167459SRichard Henderson 
1244aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1245aac0f603SRichard Henderson     cb = tcg_temp_new_i64();
1246aac0f603SRichard Henderson     cb_msb = tcg_temp_new_i64();
1247b2167459SRichard Henderson 
1248b2167459SRichard Henderson     if (is_b) {
1249b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
12506fd0c7bcSRichard Henderson         tcg_gen_not_i64(cb, in2);
1251a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero,
1252a4db4a78SRichard Henderson                          get_psw_carry(ctx, d), ctx->zero);
1253a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero);
12546fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, in1);
12556fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1256b2167459SRichard Henderson     } else {
1257bdcccc17SRichard Henderson         /*
1258bdcccc17SRichard Henderson          * DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
1259bdcccc17SRichard Henderson          * operations by seeding the high word with 1 and subtracting.
1260bdcccc17SRichard Henderson          */
12616fd0c7bcSRichard Henderson         TCGv_i64 one = tcg_constant_i64(1);
1262a4db4a78SRichard Henderson         tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero);
12636fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(cb, in1, in2);
12646fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1265b2167459SRichard Henderson     }
1266b2167459SRichard Henderson 
1267b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1268f764718dSRichard Henderson     sv = NULL;
1269b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1270b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1271b2167459SRichard Henderson         if (is_tsv) {
1272bd1ad92cSSven Schnelle             if (!d) {
1273bd1ad92cSSven Schnelle                 tcg_gen_ext32s_i64(sv, sv);
1274bd1ad92cSSven Schnelle             }
1275ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1276b2167459SRichard Henderson         }
1277b2167459SRichard Henderson     }
1278b2167459SRichard Henderson 
1279b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
1280b2167459SRichard Henderson     if (!is_b) {
12814fe9533aSRichard Henderson         cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1282b2167459SRichard Henderson     } else {
1283a751eb31SRichard Henderson         cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv);
1284b2167459SRichard Henderson     }
1285b2167459SRichard Henderson 
1286b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1287b2167459SRichard Henderson     if (is_tc) {
1288aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
12896fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1290ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1291b2167459SRichard Henderson     }
1292b2167459SRichard Henderson 
1293b2167459SRichard Henderson     /* Write back the result.  */
1294b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
1295b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1296b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1297b2167459SRichard Henderson 
1298b2167459SRichard Henderson     /* Install the new nullification.  */
1299b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1300b2167459SRichard Henderson     ctx->null_cond = cond;
1301b2167459SRichard Henderson }
1302b2167459SRichard Henderson 
130363c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a,
13040c982a28SRichard Henderson                        bool is_tsv, bool is_b, bool is_tc)
13050c982a28SRichard Henderson {
13066fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
13070c982a28SRichard Henderson 
13080c982a28SRichard Henderson     if (a->cf) {
13090c982a28SRichard Henderson         nullify_over(ctx);
13100c982a28SRichard Henderson     }
13110c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
13120c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
131363c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d);
13140c982a28SRichard Henderson     return nullify_end(ctx);
13150c982a28SRichard Henderson }
13160c982a28SRichard Henderson 
13170588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv)
13180588e061SRichard Henderson {
13196fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
13200588e061SRichard Henderson 
13210588e061SRichard Henderson     if (a->cf) {
13220588e061SRichard Henderson         nullify_over(ctx);
13230588e061SRichard Henderson     }
13246fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
13250588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
132663c427c6SRichard Henderson     /* All SUBI conditions are 32-bit. */
132763c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false);
13280588e061SRichard Henderson     return nullify_end(ctx);
13290588e061SRichard Henderson }
13300588e061SRichard Henderson 
13316fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
13326fd0c7bcSRichard Henderson                       TCGv_i64 in2, unsigned cf, bool d)
1333b2167459SRichard Henderson {
13346fd0c7bcSRichard Henderson     TCGv_i64 dest, sv;
1335b2167459SRichard Henderson     DisasCond cond;
1336b2167459SRichard Henderson 
1337aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
13386fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
1339b2167459SRichard Henderson 
1340b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1341f764718dSRichard Henderson     sv = NULL;
1342b47a4a02SSven Schnelle     if (cond_need_sv(cf >> 1)) {
1343b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1344b2167459SRichard Henderson     }
1345b2167459SRichard Henderson 
1346b2167459SRichard Henderson     /* Form the condition for the compare.  */
13474fe9533aSRichard Henderson     cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1348b2167459SRichard Henderson 
1349b2167459SRichard Henderson     /* Clear.  */
13506fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
1351b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1352b2167459SRichard Henderson 
1353b2167459SRichard Henderson     /* Install the new nullification.  */
1354b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1355b2167459SRichard Henderson     ctx->null_cond = cond;
1356b2167459SRichard Henderson }
1357b2167459SRichard Henderson 
13586fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
13596fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned cf, bool d,
13606fd0c7bcSRichard Henderson                    void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1361b2167459SRichard Henderson {
13626fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, rt);
1363b2167459SRichard Henderson 
1364b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
1365b2167459SRichard Henderson     fn(dest, in1, in2);
1366b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1367b2167459SRichard Henderson 
1368b2167459SRichard Henderson     /* Install the new nullification.  */
1369b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1370b2167459SRichard Henderson     if (cf) {
1371b5af8423SRichard Henderson         ctx->null_cond = do_log_cond(ctx, cf, d, dest);
1372b2167459SRichard Henderson     }
1373b2167459SRichard Henderson }
1374b2167459SRichard Henderson 
1375fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a,
13766fd0c7bcSRichard Henderson                        void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
13770c982a28SRichard Henderson {
13786fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
13790c982a28SRichard Henderson 
13800c982a28SRichard Henderson     if (a->cf) {
13810c982a28SRichard Henderson         nullify_over(ctx);
13820c982a28SRichard Henderson     }
13830c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
13840c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1385fa8e3bedSRichard Henderson     do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn);
13860c982a28SRichard Henderson     return nullify_end(ctx);
13870c982a28SRichard Henderson }
13880c982a28SRichard Henderson 
138946bb3d46SRichard Henderson static void do_unit_addsub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
139046bb3d46SRichard Henderson                            TCGv_i64 in2, unsigned cf, bool d,
139146bb3d46SRichard Henderson                            bool is_tc, bool is_add)
1392b2167459SRichard Henderson {
139346bb3d46SRichard Henderson     TCGv_i64 dest = tcg_temp_new_i64();
139446bb3d46SRichard Henderson     uint64_t test_cb = 0;
1395b2167459SRichard Henderson     DisasCond cond;
1396b2167459SRichard Henderson 
139746bb3d46SRichard Henderson     /* Select which carry-out bits to test. */
139846bb3d46SRichard Henderson     switch (cf >> 1) {
139946bb3d46SRichard Henderson     case 4: /* NDC / SDC -- 4-bit carries */
140046bb3d46SRichard Henderson         test_cb = dup_const(MO_8, 0x88);
140146bb3d46SRichard Henderson         break;
140246bb3d46SRichard Henderson     case 5: /* NWC / SWC -- 32-bit carries */
140346bb3d46SRichard Henderson         if (d) {
140446bb3d46SRichard Henderson             test_cb = dup_const(MO_32, INT32_MIN);
1405b2167459SRichard Henderson         } else {
140646bb3d46SRichard Henderson             cf &= 1; /* undefined -- map to never/always */
140746bb3d46SRichard Henderson         }
140846bb3d46SRichard Henderson         break;
140946bb3d46SRichard Henderson     case 6: /* NBC / SBC -- 8-bit carries */
141046bb3d46SRichard Henderson         test_cb = dup_const(MO_8, INT8_MIN);
141146bb3d46SRichard Henderson         break;
141246bb3d46SRichard Henderson     case 7: /* NHC / SHC -- 16-bit carries */
141346bb3d46SRichard Henderson         test_cb = dup_const(MO_16, INT16_MIN);
141446bb3d46SRichard Henderson         break;
141546bb3d46SRichard Henderson     }
141646bb3d46SRichard Henderson     if (!d) {
141746bb3d46SRichard Henderson         test_cb = (uint32_t)test_cb;
141846bb3d46SRichard Henderson     }
1419b2167459SRichard Henderson 
142046bb3d46SRichard Henderson     if (!test_cb) {
142146bb3d46SRichard Henderson         /* No need to compute carries if we don't need to test them. */
142246bb3d46SRichard Henderson         if (is_add) {
142346bb3d46SRichard Henderson             tcg_gen_add_i64(dest, in1, in2);
142446bb3d46SRichard Henderson         } else {
142546bb3d46SRichard Henderson             tcg_gen_sub_i64(dest, in1, in2);
142646bb3d46SRichard Henderson         }
142746bb3d46SRichard Henderson         cond = do_unit_zero_cond(cf, d, dest);
142846bb3d46SRichard Henderson     } else {
142946bb3d46SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
143046bb3d46SRichard Henderson 
143146bb3d46SRichard Henderson         if (d) {
143246bb3d46SRichard Henderson             TCGv_i64 cb_msb = tcg_temp_new_i64();
143346bb3d46SRichard Henderson             if (is_add) {
143446bb3d46SRichard Henderson                 tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero);
143546bb3d46SRichard Henderson                 tcg_gen_xor_i64(cb, in1, in2);
143646bb3d46SRichard Henderson             } else {
143746bb3d46SRichard Henderson                 /* See do_sub, !is_b. */
143846bb3d46SRichard Henderson                 TCGv_i64 one = tcg_constant_i64(1);
143946bb3d46SRichard Henderson                 tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero);
144046bb3d46SRichard Henderson                 tcg_gen_eqv_i64(cb, in1, in2);
144146bb3d46SRichard Henderson             }
144246bb3d46SRichard Henderson             tcg_gen_xor_i64(cb, cb, dest);
144346bb3d46SRichard Henderson             tcg_gen_extract2_i64(cb, cb, cb_msb, 1);
144446bb3d46SRichard Henderson         } else {
144546bb3d46SRichard Henderson             if (is_add) {
144646bb3d46SRichard Henderson                 tcg_gen_add_i64(dest, in1, in2);
144746bb3d46SRichard Henderson                 tcg_gen_xor_i64(cb, in1, in2);
144846bb3d46SRichard Henderson             } else {
144946bb3d46SRichard Henderson                 tcg_gen_sub_i64(dest, in1, in2);
145046bb3d46SRichard Henderson                 tcg_gen_eqv_i64(cb, in1, in2);
145146bb3d46SRichard Henderson             }
145246bb3d46SRichard Henderson             tcg_gen_xor_i64(cb, cb, dest);
145346bb3d46SRichard Henderson             tcg_gen_shri_i64(cb, cb, 1);
145446bb3d46SRichard Henderson         }
145546bb3d46SRichard Henderson 
145646bb3d46SRichard Henderson         tcg_gen_andi_i64(cb, cb, test_cb);
1457*4c42fd0dSRichard Henderson         cond = cond_make_ti(cf & 1 ? TCG_COND_EQ : TCG_COND_NE, cb, 0);
145846bb3d46SRichard Henderson     }
1459b2167459SRichard Henderson 
1460b2167459SRichard Henderson     if (is_tc) {
1461aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
14626fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1463ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1464b2167459SRichard Henderson     }
1465b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1466b2167459SRichard Henderson 
1467b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1468b2167459SRichard Henderson     ctx->null_cond = cond;
1469b2167459SRichard Henderson }
1470b2167459SRichard Henderson 
147186f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY
14728d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space
14738d6ae7fbSRichard Henderson    from the top 2 bits of the base register.  There are a few system
14748d6ae7fbSRichard Henderson    instructions that have a 3-bit space specifier, for which SR0 is
14758d6ae7fbSRichard Henderson    not special.  To handle this, pass ~SP.  */
14766fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base)
147786f8d05fSRichard Henderson {
147886f8d05fSRichard Henderson     TCGv_ptr ptr;
14796fd0c7bcSRichard Henderson     TCGv_i64 tmp;
148086f8d05fSRichard Henderson     TCGv_i64 spc;
148186f8d05fSRichard Henderson 
148286f8d05fSRichard Henderson     if (sp != 0) {
14838d6ae7fbSRichard Henderson         if (sp < 0) {
14848d6ae7fbSRichard Henderson             sp = ~sp;
14858d6ae7fbSRichard Henderson         }
14866fd0c7bcSRichard Henderson         spc = tcg_temp_new_i64();
14878d6ae7fbSRichard Henderson         load_spr(ctx, spc, sp);
14888d6ae7fbSRichard Henderson         return spc;
148986f8d05fSRichard Henderson     }
1490494737b7SRichard Henderson     if (ctx->tb_flags & TB_FLAG_SR_SAME) {
1491494737b7SRichard Henderson         return cpu_srH;
1492494737b7SRichard Henderson     }
149386f8d05fSRichard Henderson 
149486f8d05fSRichard Henderson     ptr = tcg_temp_new_ptr();
1495aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
14966fd0c7bcSRichard Henderson     spc = tcg_temp_new_i64();
149786f8d05fSRichard Henderson 
1498698240d1SRichard Henderson     /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */
14996fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5);
15006fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, 030);
15016fd0c7bcSRichard Henderson     tcg_gen_trunc_i64_ptr(ptr, tmp);
150286f8d05fSRichard Henderson 
1503ad75a51eSRichard Henderson     tcg_gen_add_ptr(ptr, ptr, tcg_env);
150486f8d05fSRichard Henderson     tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4]));
150586f8d05fSRichard Henderson 
150686f8d05fSRichard Henderson     return spc;
150786f8d05fSRichard Henderson }
150886f8d05fSRichard Henderson #endif
150986f8d05fSRichard Henderson 
15106fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
1511c53e401eSRichard Henderson                      unsigned rb, unsigned rx, int scale, int64_t disp,
151286f8d05fSRichard Henderson                      unsigned sp, int modify, bool is_phys)
151386f8d05fSRichard Henderson {
15146fd0c7bcSRichard Henderson     TCGv_i64 base = load_gpr(ctx, rb);
15156fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15166fd0c7bcSRichard Henderson     TCGv_i64 addr;
151786f8d05fSRichard Henderson 
1518f5b5c857SRichard Henderson     set_insn_breg(ctx, rb);
1519f5b5c857SRichard Henderson 
152086f8d05fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
152186f8d05fSRichard Henderson     if (rx) {
1522aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
15236fd0c7bcSRichard Henderson         tcg_gen_shli_i64(ofs, cpu_gr[rx], scale);
15246fd0c7bcSRichard Henderson         tcg_gen_add_i64(ofs, ofs, base);
152586f8d05fSRichard Henderson     } else if (disp || modify) {
1526aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
15276fd0c7bcSRichard Henderson         tcg_gen_addi_i64(ofs, base, disp);
152886f8d05fSRichard Henderson     } else {
152986f8d05fSRichard Henderson         ofs = base;
153086f8d05fSRichard Henderson     }
153186f8d05fSRichard Henderson 
153286f8d05fSRichard Henderson     *pofs = ofs;
15336fd0c7bcSRichard Henderson     *pgva = addr = tcg_temp_new_i64();
15347d50b696SSven Schnelle     tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base,
15357d50b696SSven Schnelle                      gva_offset_mask(ctx->tb_flags));
1536698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY
153786f8d05fSRichard Henderson     if (!is_phys) {
1538d265360fSRichard Henderson         tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base));
153986f8d05fSRichard Henderson     }
154086f8d05fSRichard Henderson #endif
154186f8d05fSRichard Henderson }
154286f8d05fSRichard Henderson 
154396d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
154496d6407fSRichard Henderson  * < 0 for pre-modify,
154596d6407fSRichard Henderson  * > 0 for post-modify,
154696d6407fSRichard Henderson  * = 0 for no base register update.
154796d6407fSRichard Henderson  */
154896d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1549c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
155014776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
155196d6407fSRichard Henderson {
15526fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15536fd0c7bcSRichard Henderson     TCGv_i64 addr;
155496d6407fSRichard Henderson 
155596d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
155696d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
155796d6407fSRichard Henderson 
155886f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
155917fe594cSRichard Henderson              MMU_DISABLED(ctx));
1560c1f55d97SRichard Henderson     tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
156186f8d05fSRichard Henderson     if (modify) {
156286f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
156396d6407fSRichard Henderson     }
156496d6407fSRichard Henderson }
156596d6407fSRichard Henderson 
156696d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1567c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
156814776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
156996d6407fSRichard Henderson {
15706fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15716fd0c7bcSRichard Henderson     TCGv_i64 addr;
157296d6407fSRichard Henderson 
157396d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
157496d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
157596d6407fSRichard Henderson 
157686f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
157717fe594cSRichard Henderson              MMU_DISABLED(ctx));
1578217d1a5eSRichard Henderson     tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
157986f8d05fSRichard Henderson     if (modify) {
158086f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
158196d6407fSRichard Henderson     }
158296d6407fSRichard Henderson }
158396d6407fSRichard Henderson 
158496d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1585c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
158614776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
158796d6407fSRichard Henderson {
15886fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15896fd0c7bcSRichard Henderson     TCGv_i64 addr;
159096d6407fSRichard Henderson 
159196d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
159296d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
159396d6407fSRichard Henderson 
159486f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
159517fe594cSRichard Henderson              MMU_DISABLED(ctx));
1596217d1a5eSRichard Henderson     tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
159786f8d05fSRichard Henderson     if (modify) {
159886f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
159996d6407fSRichard Henderson     }
160096d6407fSRichard Henderson }
160196d6407fSRichard Henderson 
160296d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1603c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
160414776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
160596d6407fSRichard Henderson {
16066fd0c7bcSRichard Henderson     TCGv_i64 ofs;
16076fd0c7bcSRichard Henderson     TCGv_i64 addr;
160896d6407fSRichard Henderson 
160996d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
161096d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
161196d6407fSRichard Henderson 
161286f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
161317fe594cSRichard Henderson              MMU_DISABLED(ctx));
1614217d1a5eSRichard Henderson     tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
161586f8d05fSRichard Henderson     if (modify) {
161686f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
161796d6407fSRichard Henderson     }
161896d6407fSRichard Henderson }
161996d6407fSRichard Henderson 
16201cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1621c53e401eSRichard Henderson                     unsigned rx, int scale, int64_t disp,
162214776ab5STony Nguyen                     unsigned sp, int modify, MemOp mop)
162396d6407fSRichard Henderson {
16246fd0c7bcSRichard Henderson     TCGv_i64 dest;
162596d6407fSRichard Henderson 
162696d6407fSRichard Henderson     nullify_over(ctx);
162796d6407fSRichard Henderson 
162896d6407fSRichard Henderson     if (modify == 0) {
162996d6407fSRichard Henderson         /* No base register update.  */
163096d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
163196d6407fSRichard Henderson     } else {
163296d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
1633aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
163496d6407fSRichard Henderson     }
16356fd0c7bcSRichard Henderson     do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
163696d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
163796d6407fSRichard Henderson 
16381cd012a5SRichard Henderson     return nullify_end(ctx);
163996d6407fSRichard Henderson }
164096d6407fSRichard Henderson 
1641740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
1642c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
164386f8d05fSRichard Henderson                       unsigned sp, int modify)
164496d6407fSRichard Henderson {
164596d6407fSRichard Henderson     TCGv_i32 tmp;
164696d6407fSRichard Henderson 
164796d6407fSRichard Henderson     nullify_over(ctx);
164896d6407fSRichard Henderson 
164996d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
165086f8d05fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
165196d6407fSRichard Henderson     save_frw_i32(rt, tmp);
165296d6407fSRichard Henderson 
165396d6407fSRichard Henderson     if (rt == 0) {
1654ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
165596d6407fSRichard Henderson     }
165696d6407fSRichard Henderson 
1657740038d7SRichard Henderson     return nullify_end(ctx);
165896d6407fSRichard Henderson }
165996d6407fSRichard Henderson 
1660740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a)
1661740038d7SRichard Henderson {
1662740038d7SRichard Henderson     return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1663740038d7SRichard Henderson                      a->disp, a->sp, a->m);
1664740038d7SRichard Henderson }
1665740038d7SRichard Henderson 
1666740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1667c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
166886f8d05fSRichard Henderson                       unsigned sp, int modify)
166996d6407fSRichard Henderson {
167096d6407fSRichard Henderson     TCGv_i64 tmp;
167196d6407fSRichard Henderson 
167296d6407fSRichard Henderson     nullify_over(ctx);
167396d6407fSRichard Henderson 
167496d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
1675fc313c64SFrédéric Pétrot     do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
167696d6407fSRichard Henderson     save_frd(rt, tmp);
167796d6407fSRichard Henderson 
167896d6407fSRichard Henderson     if (rt == 0) {
1679ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
168096d6407fSRichard Henderson     }
168196d6407fSRichard Henderson 
1682740038d7SRichard Henderson     return nullify_end(ctx);
1683740038d7SRichard Henderson }
1684740038d7SRichard Henderson 
1685740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a)
1686740038d7SRichard Henderson {
1687740038d7SRichard Henderson     return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1688740038d7SRichard Henderson                      a->disp, a->sp, a->m);
168996d6407fSRichard Henderson }
169096d6407fSRichard Henderson 
16911cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb,
1692c53e401eSRichard Henderson                      int64_t disp, unsigned sp,
169314776ab5STony Nguyen                      int modify, MemOp mop)
169496d6407fSRichard Henderson {
169596d6407fSRichard Henderson     nullify_over(ctx);
16966fd0c7bcSRichard Henderson     do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
16971cd012a5SRichard Henderson     return nullify_end(ctx);
169896d6407fSRichard Henderson }
169996d6407fSRichard Henderson 
1700740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1701c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
170286f8d05fSRichard Henderson                        unsigned sp, int modify)
170396d6407fSRichard Henderson {
170496d6407fSRichard Henderson     TCGv_i32 tmp;
170596d6407fSRichard Henderson 
170696d6407fSRichard Henderson     nullify_over(ctx);
170796d6407fSRichard Henderson 
170896d6407fSRichard Henderson     tmp = load_frw_i32(rt);
170986f8d05fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
171096d6407fSRichard Henderson 
1711740038d7SRichard Henderson     return nullify_end(ctx);
171296d6407fSRichard Henderson }
171396d6407fSRichard Henderson 
1714740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a)
1715740038d7SRichard Henderson {
1716740038d7SRichard Henderson     return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1717740038d7SRichard Henderson                       a->disp, a->sp, a->m);
1718740038d7SRichard Henderson }
1719740038d7SRichard Henderson 
1720740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1721c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
172286f8d05fSRichard Henderson                        unsigned sp, int modify)
172396d6407fSRichard Henderson {
172496d6407fSRichard Henderson     TCGv_i64 tmp;
172596d6407fSRichard Henderson 
172696d6407fSRichard Henderson     nullify_over(ctx);
172796d6407fSRichard Henderson 
172896d6407fSRichard Henderson     tmp = load_frd(rt);
1729fc313c64SFrédéric Pétrot     do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
173096d6407fSRichard Henderson 
1731740038d7SRichard Henderson     return nullify_end(ctx);
1732740038d7SRichard Henderson }
1733740038d7SRichard Henderson 
1734740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a)
1735740038d7SRichard Henderson {
1736740038d7SRichard Henderson     return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1737740038d7SRichard Henderson                       a->disp, a->sp, a->m);
173896d6407fSRichard Henderson }
173996d6407fSRichard Henderson 
17401ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1741ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1742ebe9383cSRichard Henderson {
1743ebe9383cSRichard Henderson     TCGv_i32 tmp;
1744ebe9383cSRichard Henderson 
1745ebe9383cSRichard Henderson     nullify_over(ctx);
1746ebe9383cSRichard Henderson     tmp = load_frw0_i32(ra);
1747ebe9383cSRichard Henderson 
1748ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1749ebe9383cSRichard Henderson 
1750ebe9383cSRichard Henderson     save_frw_i32(rt, tmp);
17511ca74648SRichard Henderson     return nullify_end(ctx);
1752ebe9383cSRichard Henderson }
1753ebe9383cSRichard Henderson 
17541ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1755ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1756ebe9383cSRichard Henderson {
1757ebe9383cSRichard Henderson     TCGv_i32 dst;
1758ebe9383cSRichard Henderson     TCGv_i64 src;
1759ebe9383cSRichard Henderson 
1760ebe9383cSRichard Henderson     nullify_over(ctx);
1761ebe9383cSRichard Henderson     src = load_frd(ra);
1762ebe9383cSRichard Henderson     dst = tcg_temp_new_i32();
1763ebe9383cSRichard Henderson 
1764ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1765ebe9383cSRichard Henderson 
1766ebe9383cSRichard Henderson     save_frw_i32(rt, dst);
17671ca74648SRichard Henderson     return nullify_end(ctx);
1768ebe9383cSRichard Henderson }
1769ebe9383cSRichard Henderson 
17701ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1771ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1772ebe9383cSRichard Henderson {
1773ebe9383cSRichard Henderson     TCGv_i64 tmp;
1774ebe9383cSRichard Henderson 
1775ebe9383cSRichard Henderson     nullify_over(ctx);
1776ebe9383cSRichard Henderson     tmp = load_frd0(ra);
1777ebe9383cSRichard Henderson 
1778ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1779ebe9383cSRichard Henderson 
1780ebe9383cSRichard Henderson     save_frd(rt, tmp);
17811ca74648SRichard Henderson     return nullify_end(ctx);
1782ebe9383cSRichard Henderson }
1783ebe9383cSRichard Henderson 
17841ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1785ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1786ebe9383cSRichard Henderson {
1787ebe9383cSRichard Henderson     TCGv_i32 src;
1788ebe9383cSRichard Henderson     TCGv_i64 dst;
1789ebe9383cSRichard Henderson 
1790ebe9383cSRichard Henderson     nullify_over(ctx);
1791ebe9383cSRichard Henderson     src = load_frw0_i32(ra);
1792ebe9383cSRichard Henderson     dst = tcg_temp_new_i64();
1793ebe9383cSRichard Henderson 
1794ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1795ebe9383cSRichard Henderson 
1796ebe9383cSRichard Henderson     save_frd(rt, dst);
17971ca74648SRichard Henderson     return nullify_end(ctx);
1798ebe9383cSRichard Henderson }
1799ebe9383cSRichard Henderson 
18001ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt,
1801ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
180231234768SRichard Henderson                         void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
1803ebe9383cSRichard Henderson {
1804ebe9383cSRichard Henderson     TCGv_i32 a, b;
1805ebe9383cSRichard Henderson 
1806ebe9383cSRichard Henderson     nullify_over(ctx);
1807ebe9383cSRichard Henderson     a = load_frw0_i32(ra);
1808ebe9383cSRichard Henderson     b = load_frw0_i32(rb);
1809ebe9383cSRichard Henderson 
1810ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1811ebe9383cSRichard Henderson 
1812ebe9383cSRichard Henderson     save_frw_i32(rt, a);
18131ca74648SRichard Henderson     return nullify_end(ctx);
1814ebe9383cSRichard Henderson }
1815ebe9383cSRichard Henderson 
18161ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt,
1817ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
181831234768SRichard Henderson                         void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
1819ebe9383cSRichard Henderson {
1820ebe9383cSRichard Henderson     TCGv_i64 a, b;
1821ebe9383cSRichard Henderson 
1822ebe9383cSRichard Henderson     nullify_over(ctx);
1823ebe9383cSRichard Henderson     a = load_frd0(ra);
1824ebe9383cSRichard Henderson     b = load_frd0(rb);
1825ebe9383cSRichard Henderson 
1826ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1827ebe9383cSRichard Henderson 
1828ebe9383cSRichard Henderson     save_frd(rt, a);
18291ca74648SRichard Henderson     return nullify_end(ctx);
1830ebe9383cSRichard Henderson }
1831ebe9383cSRichard Henderson 
183298cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
183398cd9ca7SRichard Henderson    have already had nullification handled.  */
18342644f80bSRichard Henderson static bool do_dbranch(DisasContext *ctx, int64_t disp,
183598cd9ca7SRichard Henderson                        unsigned link, bool is_n)
183698cd9ca7SRichard Henderson {
1837bc921866SRichard Henderson     ctx->iaq_j = iaqe_branchi(ctx, disp);
18382644f80bSRichard Henderson 
183998cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
184043541db0SRichard Henderson         install_link(ctx, link, false);
184198cd9ca7SRichard Henderson         if (is_n) {
1842d08ad0e0SRichard Henderson             if (use_nullify_skip(ctx)) {
1843d08ad0e0SRichard Henderson                 nullify_set(ctx, 0);
1844bc921866SRichard Henderson                 gen_goto_tb(ctx, 0, &ctx->iaq_j, NULL);
1845d08ad0e0SRichard Henderson                 ctx->base.is_jmp = DISAS_NORETURN;
1846d08ad0e0SRichard Henderson                 return true;
1847d08ad0e0SRichard Henderson             }
184898cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
184998cd9ca7SRichard Henderson         }
1850bc921866SRichard Henderson         ctx->iaq_n = &ctx->iaq_j;
185198cd9ca7SRichard Henderson     } else {
185298cd9ca7SRichard Henderson         nullify_over(ctx);
185398cd9ca7SRichard Henderson 
185443541db0SRichard Henderson         install_link(ctx, link, false);
185598cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
185698cd9ca7SRichard Henderson             nullify_set(ctx, 0);
1857bc921866SRichard Henderson             gen_goto_tb(ctx, 0, &ctx->iaq_j, NULL);
185898cd9ca7SRichard Henderson         } else {
185998cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
1860bc921866SRichard Henderson             gen_goto_tb(ctx, 0, &ctx->iaq_b, &ctx->iaq_j);
186198cd9ca7SRichard Henderson         }
186231234768SRichard Henderson         nullify_end(ctx);
186398cd9ca7SRichard Henderson 
186498cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1865bc921866SRichard Henderson         gen_goto_tb(ctx, 1, &ctx->iaq_b, NULL);
186631234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
186798cd9ca7SRichard Henderson     }
186801afb7beSRichard Henderson     return true;
186998cd9ca7SRichard Henderson }
187098cd9ca7SRichard Henderson 
187198cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
187298cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
1873c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n,
187498cd9ca7SRichard Henderson                        DisasCond *cond)
187598cd9ca7SRichard Henderson {
1876bc921866SRichard Henderson     DisasIAQE next;
187798cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
187898cd9ca7SRichard Henderson     TCGCond c = cond->c;
187998cd9ca7SRichard Henderson     bool n;
188098cd9ca7SRichard Henderson 
188198cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
188298cd9ca7SRichard Henderson 
188398cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
188498cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
18852644f80bSRichard Henderson         return do_dbranch(ctx, disp, 0, is_n && disp >= 0);
188698cd9ca7SRichard Henderson     }
188798cd9ca7SRichard Henderson 
188898cd9ca7SRichard Henderson     taken = gen_new_label();
18896fd0c7bcSRichard Henderson     tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken);
189098cd9ca7SRichard Henderson     cond_free(cond);
189198cd9ca7SRichard Henderson 
189298cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
189398cd9ca7SRichard Henderson     n = is_n && disp < 0;
189498cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
189598cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1896bc921866SRichard Henderson         next = iaqe_incr(&ctx->iaq_b, 4);
1897bc921866SRichard Henderson         gen_goto_tb(ctx, 0, &next, NULL);
189898cd9ca7SRichard Henderson     } else {
189998cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
190098cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
190198cd9ca7SRichard Henderson             ctx->null_lab = NULL;
190298cd9ca7SRichard Henderson         }
190398cd9ca7SRichard Henderson         nullify_set(ctx, n);
1904bc921866SRichard Henderson         gen_goto_tb(ctx, 0, &ctx->iaq_b, NULL);
190598cd9ca7SRichard Henderson     }
190698cd9ca7SRichard Henderson 
190798cd9ca7SRichard Henderson     gen_set_label(taken);
190898cd9ca7SRichard Henderson 
190998cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
191098cd9ca7SRichard Henderson     n = is_n && disp >= 0;
1911bc921866SRichard Henderson 
1912bc921866SRichard Henderson     next = iaqe_branchi(ctx, disp);
191398cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
191498cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1915bc921866SRichard Henderson         gen_goto_tb(ctx, 1, &next, NULL);
191698cd9ca7SRichard Henderson     } else {
191798cd9ca7SRichard Henderson         nullify_set(ctx, n);
1918bc921866SRichard Henderson         gen_goto_tb(ctx, 1, &ctx->iaq_b, &next);
191998cd9ca7SRichard Henderson     }
192098cd9ca7SRichard Henderson 
192198cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
192298cd9ca7SRichard Henderson     if (ctx->null_lab) {
192398cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
192498cd9ca7SRichard Henderson         ctx->null_lab = NULL;
192531234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
192698cd9ca7SRichard Henderson     } else {
192731234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
192898cd9ca7SRichard Henderson     }
192901afb7beSRichard Henderson     return true;
193098cd9ca7SRichard Henderson }
193198cd9ca7SRichard Henderson 
1932bc921866SRichard Henderson /*
1933bc921866SRichard Henderson  * Emit an unconditional branch to an indirect target, in ctx->iaq_j.
1934bc921866SRichard Henderson  * This handles nullification of the branch itself.
1935bc921866SRichard Henderson  */
1936bc921866SRichard Henderson static bool do_ibranch(DisasContext *ctx, unsigned link,
1937bc921866SRichard Henderson                        bool with_sr0, bool is_n)
193898cd9ca7SRichard Henderson {
1939d582c1faSRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
1940019f4159SRichard Henderson         install_link(ctx, link, with_sr0);
194198cd9ca7SRichard Henderson         if (is_n) {
1942c301f34eSRichard Henderson             if (use_nullify_skip(ctx)) {
1943bc921866SRichard Henderson                 install_iaq_entries(ctx, &ctx->iaq_j, NULL);
1944c301f34eSRichard Henderson                 nullify_set(ctx, 0);
194531234768SRichard Henderson                 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
194601afb7beSRichard Henderson                 return true;
1947c301f34eSRichard Henderson             }
194898cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
194998cd9ca7SRichard Henderson         }
1950bc921866SRichard Henderson         ctx->iaq_n = &ctx->iaq_j;
1951d582c1faSRichard Henderson         return true;
1952d582c1faSRichard Henderson     }
195398cd9ca7SRichard Henderson 
1954d582c1faSRichard Henderson     nullify_over(ctx);
1955d582c1faSRichard Henderson 
1956019f4159SRichard Henderson     install_link(ctx, link, with_sr0);
1957d582c1faSRichard Henderson     if (is_n && use_nullify_skip(ctx)) {
1958bc921866SRichard Henderson         install_iaq_entries(ctx, &ctx->iaq_j, NULL);
1959d582c1faSRichard Henderson         nullify_set(ctx, 0);
1960d582c1faSRichard Henderson     } else {
1961bc921866SRichard Henderson         install_iaq_entries(ctx, &ctx->iaq_b, &ctx->iaq_j);
1962d582c1faSRichard Henderson         nullify_set(ctx, is_n);
1963d582c1faSRichard Henderson     }
1964d582c1faSRichard Henderson 
19657f11636dSEmilio G. Cota     tcg_gen_lookup_and_goto_ptr();
1966d582c1faSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
196701afb7beSRichard Henderson     return nullify_end(ctx);
196898cd9ca7SRichard Henderson }
196998cd9ca7SRichard Henderson 
1970660eefe1SRichard Henderson /* Implement
1971660eefe1SRichard Henderson  *    if (IAOQ_Front{30..31} < GR[b]{30..31})
1972660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← GR[b]{30..31};
1973660eefe1SRichard Henderson  *    else
1974660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← IAOQ_Front{30..31};
1975660eefe1SRichard Henderson  * which keeps the privilege level from being increased.
1976660eefe1SRichard Henderson  */
19776fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset)
1978660eefe1SRichard Henderson {
19791874e6c2SRichard Henderson     TCGv_i64 dest = tcg_temp_new_i64();
1980660eefe1SRichard Henderson     switch (ctx->privilege) {
1981660eefe1SRichard Henderson     case 0:
1982660eefe1SRichard Henderson         /* Privilege 0 is maximum and is allowed to decrease.  */
19831874e6c2SRichard Henderson         tcg_gen_mov_i64(dest, offset);
19841874e6c2SRichard Henderson         break;
1985660eefe1SRichard Henderson     case 3:
1986993119feSRichard Henderson         /* Privilege 3 is minimum and is never allowed to increase.  */
19876fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, offset, 3);
1988660eefe1SRichard Henderson         break;
1989660eefe1SRichard Henderson     default:
19906fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, offset, -4);
19916fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, ctx->privilege);
19920bb02029SRichard Henderson         tcg_gen_umax_i64(dest, dest, offset);
1993660eefe1SRichard Henderson         break;
1994660eefe1SRichard Henderson     }
1995660eefe1SRichard Henderson     return dest;
1996660eefe1SRichard Henderson }
1997660eefe1SRichard Henderson 
1998ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
19997ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
20007ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
20017ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
20027ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
20037ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
20047ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
20057ad439dfSRichard Henderson    aforementioned BE.  */
200631234768SRichard Henderson static void do_page_zero(DisasContext *ctx)
20077ad439dfSRichard Henderson {
20080d89cb7cSRichard Henderson     assert(ctx->iaq_f.disp == 0);
20090d89cb7cSRichard Henderson 
20107ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
20117ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
20128b81968cSMichael Tokarev        next insn within the privileged page.  */
20137ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
20147ad439dfSRichard Henderson     case TCG_COND_NEVER:
20157ad439dfSRichard Henderson         break;
20167ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
20176fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, 0);
20187ad439dfSRichard Henderson         goto do_sigill;
20197ad439dfSRichard Henderson     default:
20207ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
20217ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
20227ad439dfSRichard Henderson         g_assert_not_reached();
20237ad439dfSRichard Henderson     }
20247ad439dfSRichard Henderson 
20257ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
20267ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
20277ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
20287ad439dfSRichard Henderson        under such conditions.  */
20290d89cb7cSRichard Henderson     if (iaqe_variable(&ctx->iaq_b) || ctx->iaq_b.disp != 4) {
20307ad439dfSRichard Henderson         goto do_sigill;
20317ad439dfSRichard Henderson     }
20327ad439dfSRichard Henderson 
20330d89cb7cSRichard Henderson     switch (ctx->base.pc_first) {
20347ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
20352986721dSRichard Henderson         gen_excp_1(EXCP_IMP);
203631234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
203731234768SRichard Henderson         break;
20387ad439dfSRichard Henderson 
20397ad439dfSRichard Henderson     case 0xb0: /* LWS */
20407ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
204131234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
204231234768SRichard Henderson         break;
20437ad439dfSRichard Henderson 
20447ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
2045bc921866SRichard Henderson         {
2046bc921866SRichard Henderson             DisasIAQE next = { .base = tcg_temp_new_i64() };
2047bc921866SRichard Henderson 
2048bc921866SRichard Henderson             tcg_gen_st_i64(cpu_gr[26], tcg_env,
2049bc921866SRichard Henderson                            offsetof(CPUHPPAState, cr[27]));
2050bc921866SRichard Henderson             tcg_gen_ori_i64(next.base, cpu_gr[31], 3);
2051bc921866SRichard Henderson             install_iaq_entries(ctx, &next, NULL);
205231234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
2053bc921866SRichard Henderson         }
205431234768SRichard Henderson         break;
20557ad439dfSRichard Henderson 
20567ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
20577ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
205831234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
205931234768SRichard Henderson         break;
20607ad439dfSRichard Henderson 
20617ad439dfSRichard Henderson     default:
20627ad439dfSRichard Henderson     do_sigill:
20632986721dSRichard Henderson         gen_excp_1(EXCP_ILL);
206431234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
206531234768SRichard Henderson         break;
20667ad439dfSRichard Henderson     }
20677ad439dfSRichard Henderson }
2068ba1d0b44SRichard Henderson #endif
20697ad439dfSRichard Henderson 
2070deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a)
2071b2167459SRichard Henderson {
2072b2167459SRichard Henderson     cond_free(&ctx->null_cond);
207331234768SRichard Henderson     return true;
2074b2167459SRichard Henderson }
2075b2167459SRichard Henderson 
207640f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a)
207798a9cb79SRichard Henderson {
207831234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_BREAK);
207998a9cb79SRichard Henderson }
208098a9cb79SRichard Henderson 
2081e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a)
208298a9cb79SRichard Henderson {
208398a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
208498a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
208598a9cb79SRichard Henderson 
208698a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
208731234768SRichard Henderson     return true;
208898a9cb79SRichard Henderson }
208998a9cb79SRichard Henderson 
2090c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a)
209198a9cb79SRichard Henderson {
2092bc921866SRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
209398a9cb79SRichard Henderson 
2094bc921866SRichard Henderson     copy_iaoq_entry(ctx, dest, &ctx->iaq_f);
2095bc921866SRichard Henderson     tcg_gen_andi_i64(dest, dest, -4);
2096bc921866SRichard Henderson 
2097bc921866SRichard Henderson     save_gpr(ctx, a->t, dest);
209898a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
209931234768SRichard Henderson     return true;
210098a9cb79SRichard Henderson }
210198a9cb79SRichard Henderson 
2102c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a)
210398a9cb79SRichard Henderson {
2104c603e14aSRichard Henderson     unsigned rt = a->t;
2105c603e14aSRichard Henderson     unsigned rs = a->sp;
210633423472SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
210798a9cb79SRichard Henderson 
210833423472SRichard Henderson     load_spr(ctx, t0, rs);
210933423472SRichard Henderson     tcg_gen_shri_i64(t0, t0, 32);
211033423472SRichard Henderson 
2111967662cdSRichard Henderson     save_gpr(ctx, rt, t0);
211298a9cb79SRichard Henderson 
211398a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
211431234768SRichard Henderson     return true;
211598a9cb79SRichard Henderson }
211698a9cb79SRichard Henderson 
2117c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a)
211898a9cb79SRichard Henderson {
2119c603e14aSRichard Henderson     unsigned rt = a->t;
2120c603e14aSRichard Henderson     unsigned ctl = a->r;
21216fd0c7bcSRichard Henderson     TCGv_i64 tmp;
212298a9cb79SRichard Henderson 
212398a9cb79SRichard Henderson     switch (ctl) {
212435136a77SRichard Henderson     case CR_SAR:
2125c603e14aSRichard Henderson         if (a->e == 0) {
212698a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
212798a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
21286fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
212998a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
213035136a77SRichard Henderson             goto done;
213198a9cb79SRichard Henderson         }
213298a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
213335136a77SRichard Henderson         goto done;
213435136a77SRichard Henderson     case CR_IT: /* Interval Timer */
213535136a77SRichard Henderson         /* FIXME: Respect PSW_S bit.  */
213635136a77SRichard Henderson         nullify_over(ctx);
213798a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
2138dfd1b812SRichard Henderson         if (translator_io_start(&ctx->base)) {
213931234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
214049c29d6cSRichard Henderson         }
21410c58c1bcSRichard Henderson         gen_helper_read_interval_timer(tmp);
214298a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
214331234768SRichard Henderson         return nullify_end(ctx);
214498a9cb79SRichard Henderson     case 26:
214598a9cb79SRichard Henderson     case 27:
214698a9cb79SRichard Henderson         break;
214798a9cb79SRichard Henderson     default:
214898a9cb79SRichard Henderson         /* All other control registers are privileged.  */
214935136a77SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
215035136a77SRichard Henderson         break;
215198a9cb79SRichard Henderson     }
215298a9cb79SRichard Henderson 
2153aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
21546fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
215535136a77SRichard Henderson     save_gpr(ctx, rt, tmp);
215635136a77SRichard Henderson 
215735136a77SRichard Henderson  done:
215898a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
215931234768SRichard Henderson     return true;
216098a9cb79SRichard Henderson }
216198a9cb79SRichard Henderson 
2162c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
216333423472SRichard Henderson {
2164c603e14aSRichard Henderson     unsigned rr = a->r;
2165c603e14aSRichard Henderson     unsigned rs = a->sp;
2166967662cdSRichard Henderson     TCGv_i64 tmp;
216733423472SRichard Henderson 
216833423472SRichard Henderson     if (rs >= 5) {
216933423472SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
217033423472SRichard Henderson     }
217133423472SRichard Henderson     nullify_over(ctx);
217233423472SRichard Henderson 
2173967662cdSRichard Henderson     tmp = tcg_temp_new_i64();
2174967662cdSRichard Henderson     tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32);
217533423472SRichard Henderson 
217633423472SRichard Henderson     if (rs >= 4) {
2177967662cdSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs]));
2178494737b7SRichard Henderson         ctx->tb_flags &= ~TB_FLAG_SR_SAME;
217933423472SRichard Henderson     } else {
2180967662cdSRichard Henderson         tcg_gen_mov_i64(cpu_sr[rs], tmp);
218133423472SRichard Henderson     }
218233423472SRichard Henderson 
218331234768SRichard Henderson     return nullify_end(ctx);
218433423472SRichard Henderson }
218533423472SRichard Henderson 
2186c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
218798a9cb79SRichard Henderson {
2188c603e14aSRichard Henderson     unsigned ctl = a->t;
21896fd0c7bcSRichard Henderson     TCGv_i64 reg;
21906fd0c7bcSRichard Henderson     TCGv_i64 tmp;
219198a9cb79SRichard Henderson 
219235136a77SRichard Henderson     if (ctl == CR_SAR) {
21934845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
2194aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
21956fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31);
219698a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
219798a9cb79SRichard Henderson 
219898a9cb79SRichard Henderson         cond_free(&ctx->null_cond);
219931234768SRichard Henderson         return true;
220098a9cb79SRichard Henderson     }
220198a9cb79SRichard Henderson 
220235136a77SRichard Henderson     /* All other control registers are privileged or read-only.  */
220335136a77SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
220435136a77SRichard Henderson 
2205c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
220635136a77SRichard Henderson     nullify_over(ctx);
22074c34bab0SHelge Deller 
22084c34bab0SHelge Deller     if (ctx->is_pa20) {
22094845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
22104c34bab0SHelge Deller     } else {
22114c34bab0SHelge Deller         reg = tcg_temp_new_i64();
22124c34bab0SHelge Deller         tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r));
22134c34bab0SHelge Deller     }
22144845f015SSven Schnelle 
221535136a77SRichard Henderson     switch (ctl) {
221635136a77SRichard Henderson     case CR_IT:
2217104281c1SRichard Henderson         if (translator_io_start(&ctx->base)) {
2218104281c1SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2219104281c1SRichard Henderson         }
2220ad75a51eSRichard Henderson         gen_helper_write_interval_timer(tcg_env, reg);
222135136a77SRichard Henderson         break;
22224f5f2548SRichard Henderson     case CR_EIRR:
22236ebebea7SRichard Henderson         /* Helper modifies interrupt lines and is therefore IO. */
22246ebebea7SRichard Henderson         translator_io_start(&ctx->base);
2225ad75a51eSRichard Henderson         gen_helper_write_eirr(tcg_env, reg);
22266ebebea7SRichard Henderson         /* Exit to re-evaluate interrupts in the main loop. */
222731234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
22284f5f2548SRichard Henderson         break;
22294f5f2548SRichard Henderson 
223035136a77SRichard Henderson     case CR_IIASQ:
223135136a77SRichard Henderson     case CR_IIAOQ:
223235136a77SRichard Henderson         /* FIXME: Respect PSW_Q bit */
223335136a77SRichard Henderson         /* The write advances the queue and stores to the back element.  */
2234aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
22356fd0c7bcSRichard Henderson         tcg_gen_ld_i64(tmp, tcg_env,
223635136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
22376fd0c7bcSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
22386fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env,
223935136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
224035136a77SRichard Henderson         break;
224135136a77SRichard Henderson 
2242d5de20bdSSven Schnelle     case CR_PID1:
2243d5de20bdSSven Schnelle     case CR_PID2:
2244d5de20bdSSven Schnelle     case CR_PID3:
2245d5de20bdSSven Schnelle     case CR_PID4:
22466fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
2247d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY
2248ad75a51eSRichard Henderson         gen_helper_change_prot_id(tcg_env);
2249d5de20bdSSven Schnelle #endif
2250d5de20bdSSven Schnelle         break;
2251d5de20bdSSven Schnelle 
22526ebebea7SRichard Henderson     case CR_EIEM:
22536ebebea7SRichard Henderson         /* Exit to re-evaluate interrupts in the main loop. */
22546ebebea7SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
22556ebebea7SRichard Henderson         /* FALLTHRU */
225635136a77SRichard Henderson     default:
22576fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
225835136a77SRichard Henderson         break;
225935136a77SRichard Henderson     }
226031234768SRichard Henderson     return nullify_end(ctx);
22614f5f2548SRichard Henderson #endif
226235136a77SRichard Henderson }
226335136a77SRichard Henderson 
2264c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
226598a9cb79SRichard Henderson {
2266aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
226798a9cb79SRichard Henderson 
22686fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, load_gpr(ctx, a->r));
22696fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31);
227098a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
227198a9cb79SRichard Henderson 
227298a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
227331234768SRichard Henderson     return true;
227498a9cb79SRichard Henderson }
227598a9cb79SRichard Henderson 
2276e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a)
227798a9cb79SRichard Henderson {
22786fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
227998a9cb79SRichard Henderson 
22802330504cSHelge Deller #ifdef CONFIG_USER_ONLY
22812330504cSHelge Deller     /* We don't implement space registers in user mode. */
22826fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
22832330504cSHelge Deller #else
2284967662cdSRichard Henderson     tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
2285967662cdSRichard Henderson     tcg_gen_shri_i64(dest, dest, 32);
22862330504cSHelge Deller #endif
2287e36f27efSRichard Henderson     save_gpr(ctx, a->t, dest);
228898a9cb79SRichard Henderson 
228998a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
229031234768SRichard Henderson     return true;
229198a9cb79SRichard Henderson }
229298a9cb79SRichard Henderson 
2293e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a)
2294e36f27efSRichard Henderson {
22957b2d70a1SHelge Deller #ifdef CONFIG_USER_ONLY
2296e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
22977b2d70a1SHelge Deller #else
22986fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2299e1b5a5edSRichard Henderson 
23007b2d70a1SHelge Deller     /* HP-UX 11i and HP ODE use rsm for read-access to PSW */
23017b2d70a1SHelge Deller     if (a->i) {
23027b2d70a1SHelge Deller         CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
23037b2d70a1SHelge Deller     }
23047b2d70a1SHelge Deller 
2305e1b5a5edSRichard Henderson     nullify_over(ctx);
2306e1b5a5edSRichard Henderson 
2307aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
23086fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
23096fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ~a->i);
2310ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2311e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2312e1b5a5edSRichard Henderson 
2313e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_M.  */
231431234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
231531234768SRichard Henderson     return nullify_end(ctx);
2316e36f27efSRichard Henderson #endif
2317e1b5a5edSRichard Henderson }
2318e1b5a5edSRichard Henderson 
2319e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
2320e1b5a5edSRichard Henderson {
2321e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2322e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
23236fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2324e1b5a5edSRichard Henderson 
2325e1b5a5edSRichard Henderson     nullify_over(ctx);
2326e1b5a5edSRichard Henderson 
2327aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
23286fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
23296fd0c7bcSRichard Henderson     tcg_gen_ori_i64(tmp, tmp, a->i);
2330ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2331e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2332e1b5a5edSRichard Henderson 
2333e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_I.  */
233431234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
233531234768SRichard Henderson     return nullify_end(ctx);
2336e36f27efSRichard Henderson #endif
2337e1b5a5edSRichard Henderson }
2338e1b5a5edSRichard Henderson 
2339c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
2340e1b5a5edSRichard Henderson {
2341e1b5a5edSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2342c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
23436fd0c7bcSRichard Henderson     TCGv_i64 tmp, reg;
2344e1b5a5edSRichard Henderson     nullify_over(ctx);
2345e1b5a5edSRichard Henderson 
2346c603e14aSRichard Henderson     reg = load_gpr(ctx, a->r);
2347aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2348ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, reg);
2349e1b5a5edSRichard Henderson 
2350e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts.  */
235131234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
235231234768SRichard Henderson     return nullify_end(ctx);
2353c603e14aSRichard Henderson #endif
2354e1b5a5edSRichard Henderson }
2355f49b3537SRichard Henderson 
2356e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r)
2357f49b3537SRichard Henderson {
2358f49b3537SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2359e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
2360f49b3537SRichard Henderson     nullify_over(ctx);
2361f49b3537SRichard Henderson 
2362e36f27efSRichard Henderson     if (rfi_r) {
2363ad75a51eSRichard Henderson         gen_helper_rfi_r(tcg_env);
2364f49b3537SRichard Henderson     } else {
2365ad75a51eSRichard Henderson         gen_helper_rfi(tcg_env);
2366f49b3537SRichard Henderson     }
236731234768SRichard Henderson     /* Exit the TB to recognize new interrupts.  */
236807ea28b4SRichard Henderson     tcg_gen_exit_tb(NULL, 0);
236931234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
2370f49b3537SRichard Henderson 
237131234768SRichard Henderson     return nullify_end(ctx);
2372e36f27efSRichard Henderson #endif
2373f49b3537SRichard Henderson }
23746210db05SHelge Deller 
2375e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a)
2376e36f27efSRichard Henderson {
2377e36f27efSRichard Henderson     return do_rfi(ctx, false);
2378e36f27efSRichard Henderson }
2379e36f27efSRichard Henderson 
2380e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a)
2381e36f27efSRichard Henderson {
2382e36f27efSRichard Henderson     return do_rfi(ctx, true);
2383e36f27efSRichard Henderson }
2384e36f27efSRichard Henderson 
238596927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a)
23866210db05SHelge Deller {
23876210db05SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
238896927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
23896210db05SHelge Deller     nullify_over(ctx);
2390ad75a51eSRichard Henderson     gen_helper_halt(tcg_env);
239131234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
239231234768SRichard Henderson     return nullify_end(ctx);
239396927adbSRichard Henderson #endif
23946210db05SHelge Deller }
239596927adbSRichard Henderson 
239696927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a)
239796927adbSRichard Henderson {
239896927adbSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
239996927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
240096927adbSRichard Henderson     nullify_over(ctx);
2401ad75a51eSRichard Henderson     gen_helper_reset(tcg_env);
240296927adbSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
240396927adbSRichard Henderson     return nullify_end(ctx);
240496927adbSRichard Henderson #endif
240596927adbSRichard Henderson }
2406e1b5a5edSRichard Henderson 
2407558c09beSRichard Henderson static bool do_getshadowregs(DisasContext *ctx)
24084a4554c6SHelge Deller {
24094a4554c6SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24104a4554c6SHelge Deller     nullify_over(ctx);
2411558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0]));
2412558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1]));
2413558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2]));
2414558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3]));
2415558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4]));
2416558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5]));
2417558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6]));
24184a4554c6SHelge Deller     return nullify_end(ctx);
2419558c09beSRichard Henderson }
2420558c09beSRichard Henderson 
24213bdf2081SHelge Deller static bool do_putshadowregs(DisasContext *ctx)
24223bdf2081SHelge Deller {
24233bdf2081SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24243bdf2081SHelge Deller     nullify_over(ctx);
24253bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0]));
24263bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1]));
24273bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2]));
24283bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3]));
24293bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4]));
24303bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5]));
24313bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6]));
24323bdf2081SHelge Deller     return nullify_end(ctx);
24333bdf2081SHelge Deller }
24343bdf2081SHelge Deller 
2435558c09beSRichard Henderson static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
2436558c09beSRichard Henderson {
2437558c09beSRichard Henderson     return do_getshadowregs(ctx);
24384a4554c6SHelge Deller }
24394a4554c6SHelge Deller 
2440deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
244198a9cb79SRichard Henderson {
2442deee69a1SRichard Henderson     if (a->m) {
24436fd0c7bcSRichard Henderson         TCGv_i64 dest = dest_gpr(ctx, a->b);
24446fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->b);
24456fd0c7bcSRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->x);
244698a9cb79SRichard Henderson 
244798a9cb79SRichard Henderson         /* The only thing we need to do is the base register modification.  */
24486fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, src1, src2);
2449deee69a1SRichard Henderson         save_gpr(ctx, a->b, dest);
2450deee69a1SRichard Henderson     }
245198a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
245231234768SRichard Henderson     return true;
245398a9cb79SRichard Henderson }
245498a9cb79SRichard Henderson 
2455ad1fdacdSSven Schnelle static bool trans_fic(DisasContext *ctx, arg_ldst *a)
2456ad1fdacdSSven Schnelle {
2457ad1fdacdSSven Schnelle     /* End TB for flush instruction cache, so we pick up new insns. */
2458ad1fdacdSSven Schnelle     ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2459ad1fdacdSSven Schnelle     return trans_nop_addrx(ctx, a);
2460ad1fdacdSSven Schnelle }
2461ad1fdacdSSven Schnelle 
2462deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a)
246398a9cb79SRichard Henderson {
24646fd0c7bcSRichard Henderson     TCGv_i64 dest, ofs;
2465eed14219SRichard Henderson     TCGv_i32 level, want;
24666fd0c7bcSRichard Henderson     TCGv_i64 addr;
246798a9cb79SRichard Henderson 
246898a9cb79SRichard Henderson     nullify_over(ctx);
246998a9cb79SRichard Henderson 
2470deee69a1SRichard Henderson     dest = dest_gpr(ctx, a->t);
2471deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2472eed14219SRichard Henderson 
2473deee69a1SRichard Henderson     if (a->imm) {
2474e5d487c9SRichard Henderson         level = tcg_constant_i32(a->ri & 3);
247598a9cb79SRichard Henderson     } else {
2476eed14219SRichard Henderson         level = tcg_temp_new_i32();
24776fd0c7bcSRichard Henderson         tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri));
2478eed14219SRichard Henderson         tcg_gen_andi_i32(level, level, 3);
247998a9cb79SRichard Henderson     }
248029dd6f64SRichard Henderson     want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ);
2481eed14219SRichard Henderson 
2482ad75a51eSRichard Henderson     gen_helper_probe(dest, tcg_env, addr, level, want);
2483eed14219SRichard Henderson 
2484deee69a1SRichard Henderson     save_gpr(ctx, a->t, dest);
248531234768SRichard Henderson     return nullify_end(ctx);
248698a9cb79SRichard Henderson }
248798a9cb79SRichard Henderson 
2488deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
24898d6ae7fbSRichard Henderson {
24908577f354SRichard Henderson     if (ctx->is_pa20) {
24918577f354SRichard Henderson         return false;
24928577f354SRichard Henderson     }
2493deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2494deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
24956fd0c7bcSRichard Henderson     TCGv_i64 addr;
24966fd0c7bcSRichard Henderson     TCGv_i64 ofs, reg;
24978d6ae7fbSRichard Henderson 
24988d6ae7fbSRichard Henderson     nullify_over(ctx);
24998d6ae7fbSRichard Henderson 
2500deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2501deee69a1SRichard Henderson     reg = load_gpr(ctx, a->r);
2502deee69a1SRichard Henderson     if (a->addr) {
25038577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
25048d6ae7fbSRichard Henderson     } else {
25058577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
25068d6ae7fbSRichard Henderson     }
25078d6ae7fbSRichard Henderson 
250832dc7569SSven Schnelle     /* Exit TB for TLB change if mmu is enabled.  */
250932dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
251031234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
251131234768SRichard Henderson     }
251231234768SRichard Henderson     return nullify_end(ctx);
2513deee69a1SRichard Henderson #endif
25148d6ae7fbSRichard Henderson }
251563300a00SRichard Henderson 
2516eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local)
251763300a00SRichard Henderson {
2518deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2519deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
25206fd0c7bcSRichard Henderson     TCGv_i64 addr;
25216fd0c7bcSRichard Henderson     TCGv_i64 ofs;
252263300a00SRichard Henderson 
252363300a00SRichard Henderson     nullify_over(ctx);
252463300a00SRichard Henderson 
2525deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2526eb25d10fSHelge Deller 
2527eb25d10fSHelge Deller     /*
2528eb25d10fSHelge Deller      * Page align now, rather than later, so that we can add in the
2529eb25d10fSHelge Deller      * page_size field from pa2.0 from the low 4 bits of GR[b].
2530eb25d10fSHelge Deller      */
2531eb25d10fSHelge Deller     tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK);
2532eb25d10fSHelge Deller     if (ctx->is_pa20) {
2533eb25d10fSHelge Deller         tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4);
253463300a00SRichard Henderson     }
2535eb25d10fSHelge Deller 
2536eb25d10fSHelge Deller     if (local) {
2537eb25d10fSHelge Deller         gen_helper_ptlb_l(tcg_env, addr);
253863300a00SRichard Henderson     } else {
2539ad75a51eSRichard Henderson         gen_helper_ptlb(tcg_env, addr);
254063300a00SRichard Henderson     }
254163300a00SRichard Henderson 
2542eb25d10fSHelge Deller     if (a->m) {
2543eb25d10fSHelge Deller         save_gpr(ctx, a->b, ofs);
2544eb25d10fSHelge Deller     }
2545eb25d10fSHelge Deller 
2546eb25d10fSHelge Deller     /* Exit TB for TLB change if mmu is enabled.  */
2547eb25d10fSHelge Deller     if (ctx->tb_flags & PSW_C) {
2548eb25d10fSHelge Deller         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2549eb25d10fSHelge Deller     }
2550eb25d10fSHelge Deller     return nullify_end(ctx);
2551eb25d10fSHelge Deller #endif
2552eb25d10fSHelge Deller }
2553eb25d10fSHelge Deller 
2554eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a)
2555eb25d10fSHelge Deller {
2556eb25d10fSHelge Deller     return do_pxtlb(ctx, a, false);
2557eb25d10fSHelge Deller }
2558eb25d10fSHelge Deller 
2559eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a)
2560eb25d10fSHelge Deller {
2561eb25d10fSHelge Deller     return ctx->is_pa20 && do_pxtlb(ctx, a, true);
2562eb25d10fSHelge Deller }
2563eb25d10fSHelge Deller 
2564eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a)
2565eb25d10fSHelge Deller {
2566eb25d10fSHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2567eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY
2568eb25d10fSHelge Deller     nullify_over(ctx);
2569eb25d10fSHelge Deller 
2570eb25d10fSHelge Deller     trans_nop_addrx(ctx, a);
2571eb25d10fSHelge Deller     gen_helper_ptlbe(tcg_env);
2572eb25d10fSHelge Deller 
257363300a00SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
257432dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
257531234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
257631234768SRichard Henderson     }
257731234768SRichard Henderson     return nullify_end(ctx);
2578deee69a1SRichard Henderson #endif
257963300a00SRichard Henderson }
25802dfcca9fSRichard Henderson 
25816797c315SNick Hudson /*
25826797c315SNick Hudson  * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
25836797c315SNick Hudson  * See
25846797c315SNick Hudson  *     https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
25856797c315SNick Hudson  *     page 13-9 (195/206)
25866797c315SNick Hudson  */
25876797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
25886797c315SNick Hudson {
25898577f354SRichard Henderson     if (ctx->is_pa20) {
25908577f354SRichard Henderson         return false;
25918577f354SRichard Henderson     }
25926797c315SNick Hudson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
25936797c315SNick Hudson #ifndef CONFIG_USER_ONLY
25946fd0c7bcSRichard Henderson     TCGv_i64 addr, atl, stl;
25956fd0c7bcSRichard Henderson     TCGv_i64 reg;
25966797c315SNick Hudson 
25976797c315SNick Hudson     nullify_over(ctx);
25986797c315SNick Hudson 
25996797c315SNick Hudson     /*
26006797c315SNick Hudson      * FIXME:
26016797c315SNick Hudson      *  if (not (pcxl or pcxl2))
26026797c315SNick Hudson      *    return gen_illegal(ctx);
26036797c315SNick Hudson      */
26046797c315SNick Hudson 
26056fd0c7bcSRichard Henderson     atl = tcg_temp_new_i64();
26066fd0c7bcSRichard Henderson     stl = tcg_temp_new_i64();
26076fd0c7bcSRichard Henderson     addr = tcg_temp_new_i64();
26086797c315SNick Hudson 
2609ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(stl, tcg_env,
26106797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
26116797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIASQ]));
2612ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(atl, tcg_env,
26136797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
26146797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIAOQ]));
26156797c315SNick Hudson     tcg_gen_shli_i64(stl, stl, 32);
2616d265360fSRichard Henderson     tcg_gen_or_i64(addr, atl, stl);
26176797c315SNick Hudson 
26186797c315SNick Hudson     reg = load_gpr(ctx, a->r);
26196797c315SNick Hudson     if (a->addr) {
26208577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
26216797c315SNick Hudson     } else {
26228577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
26236797c315SNick Hudson     }
26246797c315SNick Hudson 
26256797c315SNick Hudson     /* Exit TB for TLB change if mmu is enabled.  */
26266797c315SNick Hudson     if (ctx->tb_flags & PSW_C) {
26276797c315SNick Hudson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
26286797c315SNick Hudson     }
26296797c315SNick Hudson     return nullify_end(ctx);
26306797c315SNick Hudson #endif
26316797c315SNick Hudson }
26326797c315SNick Hudson 
26338577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
26348577f354SRichard Henderson {
26358577f354SRichard Henderson     if (!ctx->is_pa20) {
26368577f354SRichard Henderson         return false;
26378577f354SRichard Henderson     }
26388577f354SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
26398577f354SRichard Henderson #ifndef CONFIG_USER_ONLY
26408577f354SRichard Henderson     nullify_over(ctx);
26418577f354SRichard Henderson     {
26428577f354SRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
26438577f354SRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->r2);
26448577f354SRichard Henderson 
26458577f354SRichard Henderson         if (a->data) {
26468577f354SRichard Henderson             gen_helper_idtlbt_pa20(tcg_env, src1, src2);
26478577f354SRichard Henderson         } else {
26488577f354SRichard Henderson             gen_helper_iitlbt_pa20(tcg_env, src1, src2);
26498577f354SRichard Henderson         }
26508577f354SRichard Henderson     }
26518577f354SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
26528577f354SRichard Henderson     if (ctx->tb_flags & PSW_C) {
26538577f354SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
26548577f354SRichard Henderson     }
26558577f354SRichard Henderson     return nullify_end(ctx);
26568577f354SRichard Henderson #endif
26578577f354SRichard Henderson }
26588577f354SRichard Henderson 
2659deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
26602dfcca9fSRichard Henderson {
2661deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2662deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
26636fd0c7bcSRichard Henderson     TCGv_i64 vaddr;
26646fd0c7bcSRichard Henderson     TCGv_i64 ofs, paddr;
26652dfcca9fSRichard Henderson 
26662dfcca9fSRichard Henderson     nullify_over(ctx);
26672dfcca9fSRichard Henderson 
2668deee69a1SRichard Henderson     form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
26692dfcca9fSRichard Henderson 
2670aac0f603SRichard Henderson     paddr = tcg_temp_new_i64();
2671ad75a51eSRichard Henderson     gen_helper_lpa(paddr, tcg_env, vaddr);
26722dfcca9fSRichard Henderson 
26732dfcca9fSRichard Henderson     /* Note that physical address result overrides base modification.  */
2674deee69a1SRichard Henderson     if (a->m) {
2675deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
26762dfcca9fSRichard Henderson     }
2677deee69a1SRichard Henderson     save_gpr(ctx, a->t, paddr);
26782dfcca9fSRichard Henderson 
267931234768SRichard Henderson     return nullify_end(ctx);
2680deee69a1SRichard Henderson #endif
26812dfcca9fSRichard Henderson }
268243a97b81SRichard Henderson 
2683deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a)
268443a97b81SRichard Henderson {
268543a97b81SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
268643a97b81SRichard Henderson 
268743a97b81SRichard Henderson     /* The Coherence Index is an implementation-defined function of the
268843a97b81SRichard Henderson        physical address.  Two addresses with the same CI have a coherent
268943a97b81SRichard Henderson        view of the cache.  Our implementation is to return 0 for all,
269043a97b81SRichard Henderson        since the entire address space is coherent.  */
2691a4db4a78SRichard Henderson     save_gpr(ctx, a->t, ctx->zero);
269243a97b81SRichard Henderson 
269331234768SRichard Henderson     cond_free(&ctx->null_cond);
269431234768SRichard Henderson     return true;
269543a97b81SRichard Henderson }
269698a9cb79SRichard Henderson 
2697faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2698b2167459SRichard Henderson {
26990c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, false);
2700b2167459SRichard Henderson }
2701b2167459SRichard Henderson 
2702faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2703b2167459SRichard Henderson {
27040c982a28SRichard Henderson     return do_add_reg(ctx, a, true, false, false, false);
2705b2167459SRichard Henderson }
2706b2167459SRichard Henderson 
2707faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2708b2167459SRichard Henderson {
27090c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, false);
2710b2167459SRichard Henderson }
2711b2167459SRichard Henderson 
2712faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2713b2167459SRichard Henderson {
27140c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, true);
27150c982a28SRichard Henderson }
2716b2167459SRichard Henderson 
2717faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
27180c982a28SRichard Henderson {
27190c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, true);
27200c982a28SRichard Henderson }
27210c982a28SRichard Henderson 
272263c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
27230c982a28SRichard Henderson {
27240c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, false);
27250c982a28SRichard Henderson }
27260c982a28SRichard Henderson 
272763c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
27280c982a28SRichard Henderson {
27290c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, false);
27300c982a28SRichard Henderson }
27310c982a28SRichard Henderson 
273263c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
27330c982a28SRichard Henderson {
27340c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, true);
27350c982a28SRichard Henderson }
27360c982a28SRichard Henderson 
273763c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
27380c982a28SRichard Henderson {
27390c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, true);
27400c982a28SRichard Henderson }
27410c982a28SRichard Henderson 
274263c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
27430c982a28SRichard Henderson {
27440c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, true, false);
27450c982a28SRichard Henderson }
27460c982a28SRichard Henderson 
274763c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
27480c982a28SRichard Henderson {
27490c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, true, false);
27500c982a28SRichard Henderson }
27510c982a28SRichard Henderson 
2752fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
27530c982a28SRichard Henderson {
27546fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_andc_i64);
27550c982a28SRichard Henderson }
27560c982a28SRichard Henderson 
2757fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
27580c982a28SRichard Henderson {
27596fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_and_i64);
27600c982a28SRichard Henderson }
27610c982a28SRichard Henderson 
2762fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
27630c982a28SRichard Henderson {
27640c982a28SRichard Henderson     if (a->cf == 0) {
27650c982a28SRichard Henderson         unsigned r2 = a->r2;
27660c982a28SRichard Henderson         unsigned r1 = a->r1;
27670c982a28SRichard Henderson         unsigned rt = a->t;
27680c982a28SRichard Henderson 
27697aee8189SRichard Henderson         if (rt == 0) { /* NOP */
27707aee8189SRichard Henderson             cond_free(&ctx->null_cond);
27717aee8189SRichard Henderson             return true;
27727aee8189SRichard Henderson         }
27737aee8189SRichard Henderson         if (r2 == 0) { /* COPY */
2774b2167459SRichard Henderson             if (r1 == 0) {
27756fd0c7bcSRichard Henderson                 TCGv_i64 dest = dest_gpr(ctx, rt);
27766fd0c7bcSRichard Henderson                 tcg_gen_movi_i64(dest, 0);
2777b2167459SRichard Henderson                 save_gpr(ctx, rt, dest);
2778b2167459SRichard Henderson             } else {
2779b2167459SRichard Henderson                 save_gpr(ctx, rt, cpu_gr[r1]);
2780b2167459SRichard Henderson             }
2781b2167459SRichard Henderson             cond_free(&ctx->null_cond);
278231234768SRichard Henderson             return true;
2783b2167459SRichard Henderson         }
27847aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY
27857aee8189SRichard Henderson         /* These are QEMU extensions and are nops in the real architecture:
27867aee8189SRichard Henderson          *
27877aee8189SRichard Henderson          * or %r10,%r10,%r10 -- idle loop; wait for interrupt
27887aee8189SRichard Henderson          * or %r31,%r31,%r31 -- death loop; offline cpu
27897aee8189SRichard Henderson          *                      currently implemented as idle.
27907aee8189SRichard Henderson          */
27917aee8189SRichard Henderson         if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
27927aee8189SRichard Henderson             /* No need to check for supervisor, as userland can only pause
27937aee8189SRichard Henderson                until the next timer interrupt.  */
27947aee8189SRichard Henderson             nullify_over(ctx);
27957aee8189SRichard Henderson 
27967aee8189SRichard Henderson             /* Advance the instruction queue.  */
2797bc921866SRichard Henderson             install_iaq_entries(ctx, &ctx->iaq_b, NULL);
27987aee8189SRichard Henderson             nullify_set(ctx, 0);
27997aee8189SRichard Henderson 
28007aee8189SRichard Henderson             /* Tell the qemu main loop to halt until this cpu has work.  */
2801ad75a51eSRichard Henderson             tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
280229dd6f64SRichard Henderson                            offsetof(CPUState, halted) - offsetof(HPPACPU, env));
28037aee8189SRichard Henderson             gen_excp_1(EXCP_HALTED);
28047aee8189SRichard Henderson             ctx->base.is_jmp = DISAS_NORETURN;
28057aee8189SRichard Henderson 
28067aee8189SRichard Henderson             return nullify_end(ctx);
28077aee8189SRichard Henderson         }
28087aee8189SRichard Henderson #endif
28097aee8189SRichard Henderson     }
28106fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_or_i64);
28117aee8189SRichard Henderson }
2812b2167459SRichard Henderson 
2813fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
2814b2167459SRichard Henderson {
28156fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_xor_i64);
28160c982a28SRichard Henderson }
28170c982a28SRichard Henderson 
2818345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
28190c982a28SRichard Henderson {
28206fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2821b2167459SRichard Henderson 
28220c982a28SRichard Henderson     if (a->cf) {
2823b2167459SRichard Henderson         nullify_over(ctx);
2824b2167459SRichard Henderson     }
28250c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
28260c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2827345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
282831234768SRichard Henderson     return nullify_end(ctx);
2829b2167459SRichard Henderson }
2830b2167459SRichard Henderson 
2831af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
2832b2167459SRichard Henderson {
283346bb3d46SRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, dest;
2834b2167459SRichard Henderson 
28350c982a28SRichard Henderson     if (a->cf) {
2836b2167459SRichard Henderson         nullify_over(ctx);
2837b2167459SRichard Henderson     }
283846bb3d46SRichard Henderson 
28390c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
28400c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
284146bb3d46SRichard Henderson     dest = dest_gpr(ctx, a->t);
284246bb3d46SRichard Henderson 
284346bb3d46SRichard Henderson     tcg_gen_xor_i64(dest, tcg_r1, tcg_r2);
284446bb3d46SRichard Henderson     save_gpr(ctx, a->t, dest);
284546bb3d46SRichard Henderson 
284646bb3d46SRichard Henderson     cond_free(&ctx->null_cond);
284746bb3d46SRichard Henderson     if (a->cf) {
284846bb3d46SRichard Henderson         ctx->null_cond = do_unit_zero_cond(a->cf, a->d, dest);
284946bb3d46SRichard Henderson     }
285046bb3d46SRichard Henderson 
285131234768SRichard Henderson     return nullify_end(ctx);
2852b2167459SRichard Henderson }
2853b2167459SRichard Henderson 
2854af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
2855b2167459SRichard Henderson {
28566fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, tmp;
2857b2167459SRichard Henderson 
2858ababac16SRichard Henderson     if (a->cf == 0) {
2859ababac16SRichard Henderson         tcg_r2 = load_gpr(ctx, a->r2);
2860ababac16SRichard Henderson         tmp = dest_gpr(ctx, a->t);
2861ababac16SRichard Henderson 
2862ababac16SRichard Henderson         if (a->r1 == 0) {
2863ababac16SRichard Henderson             /* UADDCM r0,src,dst is the common idiom for dst = ~src. */
2864ababac16SRichard Henderson             tcg_gen_not_i64(tmp, tcg_r2);
2865ababac16SRichard Henderson         } else {
2866ababac16SRichard Henderson             /*
2867ababac16SRichard Henderson              * Recall that r1 - r2 == r1 + ~r2 + 1.
2868ababac16SRichard Henderson              * Thus r1 + ~r2 == r1 - r2 - 1,
2869ababac16SRichard Henderson              * which does not require an extra temporary.
2870ababac16SRichard Henderson              */
2871ababac16SRichard Henderson             tcg_r1 = load_gpr(ctx, a->r1);
2872ababac16SRichard Henderson             tcg_gen_sub_i64(tmp, tcg_r1, tcg_r2);
2873ababac16SRichard Henderson             tcg_gen_subi_i64(tmp, tmp, 1);
2874b2167459SRichard Henderson         }
2875ababac16SRichard Henderson         save_gpr(ctx, a->t, tmp);
2876ababac16SRichard Henderson         cond_free(&ctx->null_cond);
2877ababac16SRichard Henderson         return true;
2878ababac16SRichard Henderson     }
2879ababac16SRichard Henderson 
2880ababac16SRichard Henderson     nullify_over(ctx);
28810c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
28820c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2883aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
28846fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, tcg_r2);
288546bb3d46SRichard Henderson     do_unit_addsub(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, true);
288631234768SRichard Henderson     return nullify_end(ctx);
2887b2167459SRichard Henderson }
2888b2167459SRichard Henderson 
2889af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
2890b2167459SRichard Henderson {
28910c982a28SRichard Henderson     return do_uaddcm(ctx, a, false);
28920c982a28SRichard Henderson }
28930c982a28SRichard Henderson 
2894af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
28950c982a28SRichard Henderson {
28960c982a28SRichard Henderson     return do_uaddcm(ctx, a, true);
28970c982a28SRichard Henderson }
28980c982a28SRichard Henderson 
2899af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
29000c982a28SRichard Henderson {
29016fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2902b2167459SRichard Henderson 
2903b2167459SRichard Henderson     nullify_over(ctx);
2904b2167459SRichard Henderson 
2905aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2906d0ae87a2SRichard Henderson     tcg_gen_extract2_i64(tmp, cpu_psw_cb, cpu_psw_cb_msb, 4);
2907b2167459SRichard Henderson     if (!is_i) {
29086fd0c7bcSRichard Henderson         tcg_gen_not_i64(tmp, tmp);
2909b2167459SRichard Henderson     }
29106fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
29116fd0c7bcSRichard Henderson     tcg_gen_muli_i64(tmp, tmp, 6);
291246bb3d46SRichard Henderson     do_unit_addsub(ctx, a->t, load_gpr(ctx, a->r), tmp,
291346bb3d46SRichard Henderson                    a->cf, a->d, false, is_i);
291431234768SRichard Henderson     return nullify_end(ctx);
2915b2167459SRichard Henderson }
2916b2167459SRichard Henderson 
2917af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
2918b2167459SRichard Henderson {
29190c982a28SRichard Henderson     return do_dcor(ctx, a, false);
29200c982a28SRichard Henderson }
29210c982a28SRichard Henderson 
2922af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
29230c982a28SRichard Henderson {
29240c982a28SRichard Henderson     return do_dcor(ctx, a, true);
29250c982a28SRichard Henderson }
29260c982a28SRichard Henderson 
29270c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
29280c982a28SRichard Henderson {
2929a4db4a78SRichard Henderson     TCGv_i64 dest, add1, add2, addc, in1, in2;
2930b2167459SRichard Henderson 
2931b2167459SRichard Henderson     nullify_over(ctx);
2932b2167459SRichard Henderson 
29330c982a28SRichard Henderson     in1 = load_gpr(ctx, a->r1);
29340c982a28SRichard Henderson     in2 = load_gpr(ctx, a->r2);
2935b2167459SRichard Henderson 
2936aac0f603SRichard Henderson     add1 = tcg_temp_new_i64();
2937aac0f603SRichard Henderson     add2 = tcg_temp_new_i64();
2938aac0f603SRichard Henderson     addc = tcg_temp_new_i64();
2939aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
2940b2167459SRichard Henderson 
2941b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
29426fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, in1, in1);
29436fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
2944b2167459SRichard Henderson 
294572ca8753SRichard Henderson     /*
294672ca8753SRichard Henderson      * Add or subtract R2, depending on PSW[V].  Proper computation of
294772ca8753SRichard Henderson      * carry requires that we subtract via + ~R2 + 1, as described in
294872ca8753SRichard Henderson      * the manual.  By extracting and masking V, we can produce the
294972ca8753SRichard Henderson      * proper inputs to the addition without movcond.
295072ca8753SRichard Henderson      */
29516fd0c7bcSRichard Henderson     tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
29526fd0c7bcSRichard Henderson     tcg_gen_xor_i64(add2, in2, addc);
29536fd0c7bcSRichard Henderson     tcg_gen_andi_i64(addc, addc, 1);
295472ca8753SRichard Henderson 
2955a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero);
2956a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb,
2957a4db4a78SRichard Henderson                      addc, ctx->zero);
2958b2167459SRichard Henderson 
2959b2167459SRichard Henderson     /* Write back the result register.  */
29600c982a28SRichard Henderson     save_gpr(ctx, a->t, dest);
2961b2167459SRichard Henderson 
2962b2167459SRichard Henderson     /* Write back PSW[CB].  */
29636fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
29646fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
2965b2167459SRichard Henderson 
2966f8f5986eSRichard Henderson     /*
2967f8f5986eSRichard Henderson      * Write back PSW[V] for the division step.
2968f8f5986eSRichard Henderson      * Shift cb{8} from where it lives in bit 32 to bit 31,
2969f8f5986eSRichard Henderson      * so that it overlaps r2{32} in bit 31.
2970f8f5986eSRichard Henderson      */
2971f8f5986eSRichard Henderson     tcg_gen_shri_i64(cpu_psw_v, cpu_psw_cb, 1);
29726fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
2973b2167459SRichard Henderson 
2974b2167459SRichard Henderson     /* Install the new nullification.  */
29750c982a28SRichard Henderson     if (a->cf) {
2976f8f5986eSRichard Henderson         TCGv_i64 sv = NULL, uv = NULL;
2977b47a4a02SSven Schnelle         if (cond_need_sv(a->cf >> 1)) {
2978f8f5986eSRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2, in1, 1, false);
2979f8f5986eSRichard Henderson         } else if (cond_need_cb(a->cf >> 1)) {
2980f8f5986eSRichard Henderson             uv = do_add_uv(ctx, cpu_psw_cb, NULL, in1, 1, false);
2981b2167459SRichard Henderson         }
2982f8f5986eSRichard Henderson         ctx->null_cond = do_cond(ctx, a->cf, false, dest, uv, sv);
2983b2167459SRichard Henderson     }
2984b2167459SRichard Henderson 
298531234768SRichard Henderson     return nullify_end(ctx);
2986b2167459SRichard Henderson }
2987b2167459SRichard Henderson 
29880588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a)
2989b2167459SRichard Henderson {
29900588e061SRichard Henderson     return do_add_imm(ctx, a, false, false);
29910588e061SRichard Henderson }
29920588e061SRichard Henderson 
29930588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a)
29940588e061SRichard Henderson {
29950588e061SRichard Henderson     return do_add_imm(ctx, a, true, false);
29960588e061SRichard Henderson }
29970588e061SRichard Henderson 
29980588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a)
29990588e061SRichard Henderson {
30000588e061SRichard Henderson     return do_add_imm(ctx, a, false, true);
30010588e061SRichard Henderson }
30020588e061SRichard Henderson 
30030588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a)
30040588e061SRichard Henderson {
30050588e061SRichard Henderson     return do_add_imm(ctx, a, true, true);
30060588e061SRichard Henderson }
30070588e061SRichard Henderson 
30080588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a)
30090588e061SRichard Henderson {
30100588e061SRichard Henderson     return do_sub_imm(ctx, a, false);
30110588e061SRichard Henderson }
30120588e061SRichard Henderson 
30130588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
30140588e061SRichard Henderson {
30150588e061SRichard Henderson     return do_sub_imm(ctx, a, true);
30160588e061SRichard Henderson }
30170588e061SRichard Henderson 
3018345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
30190588e061SRichard Henderson {
30206fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
3021b2167459SRichard Henderson 
30220588e061SRichard Henderson     if (a->cf) {
3023b2167459SRichard Henderson         nullify_over(ctx);
3024b2167459SRichard Henderson     }
3025b2167459SRichard Henderson 
30266fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
30270588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
3028345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
3029b2167459SRichard Henderson 
303031234768SRichard Henderson     return nullify_end(ctx);
3031b2167459SRichard Henderson }
3032b2167459SRichard Henderson 
30330843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a,
30340843563fSRichard Henderson                           void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
30350843563fSRichard Henderson {
30360843563fSRichard Henderson     TCGv_i64 r1, r2, dest;
30370843563fSRichard Henderson 
30380843563fSRichard Henderson     if (!ctx->is_pa20) {
30390843563fSRichard Henderson         return false;
30400843563fSRichard Henderson     }
30410843563fSRichard Henderson 
30420843563fSRichard Henderson     nullify_over(ctx);
30430843563fSRichard Henderson 
30440843563fSRichard Henderson     r1 = load_gpr(ctx, a->r1);
30450843563fSRichard Henderson     r2 = load_gpr(ctx, a->r2);
30460843563fSRichard Henderson     dest = dest_gpr(ctx, a->t);
30470843563fSRichard Henderson 
30480843563fSRichard Henderson     fn(dest, r1, r2);
30490843563fSRichard Henderson     save_gpr(ctx, a->t, dest);
30500843563fSRichard Henderson 
30510843563fSRichard Henderson     return nullify_end(ctx);
30520843563fSRichard Henderson }
30530843563fSRichard Henderson 
3054151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a,
3055151f309bSRichard Henderson                              void (*fn)(TCGv_i64, TCGv_i64, int64_t))
3056151f309bSRichard Henderson {
3057151f309bSRichard Henderson     TCGv_i64 r, dest;
3058151f309bSRichard Henderson 
3059151f309bSRichard Henderson     if (!ctx->is_pa20) {
3060151f309bSRichard Henderson         return false;
3061151f309bSRichard Henderson     }
3062151f309bSRichard Henderson 
3063151f309bSRichard Henderson     nullify_over(ctx);
3064151f309bSRichard Henderson 
3065151f309bSRichard Henderson     r = load_gpr(ctx, a->r);
3066151f309bSRichard Henderson     dest = dest_gpr(ctx, a->t);
3067151f309bSRichard Henderson 
3068151f309bSRichard Henderson     fn(dest, r, a->i);
3069151f309bSRichard Henderson     save_gpr(ctx, a->t, dest);
3070151f309bSRichard Henderson 
3071151f309bSRichard Henderson     return nullify_end(ctx);
3072151f309bSRichard Henderson }
3073151f309bSRichard Henderson 
30743bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a,
30753bbb8e48SRichard Henderson                                 void (*fn)(TCGv_i64, TCGv_i64,
30763bbb8e48SRichard Henderson                                            TCGv_i64, TCGv_i32))
30773bbb8e48SRichard Henderson {
30783bbb8e48SRichard Henderson     TCGv_i64 r1, r2, dest;
30793bbb8e48SRichard Henderson 
30803bbb8e48SRichard Henderson     if (!ctx->is_pa20) {
30813bbb8e48SRichard Henderson         return false;
30823bbb8e48SRichard Henderson     }
30833bbb8e48SRichard Henderson 
30843bbb8e48SRichard Henderson     nullify_over(ctx);
30853bbb8e48SRichard Henderson 
30863bbb8e48SRichard Henderson     r1 = load_gpr(ctx, a->r1);
30873bbb8e48SRichard Henderson     r2 = load_gpr(ctx, a->r2);
30883bbb8e48SRichard Henderson     dest = dest_gpr(ctx, a->t);
30893bbb8e48SRichard Henderson 
30903bbb8e48SRichard Henderson     fn(dest, r1, r2, tcg_constant_i32(a->sh));
30913bbb8e48SRichard Henderson     save_gpr(ctx, a->t, dest);
30923bbb8e48SRichard Henderson 
30933bbb8e48SRichard Henderson     return nullify_end(ctx);
30943bbb8e48SRichard Henderson }
30953bbb8e48SRichard Henderson 
30960843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a)
30970843563fSRichard Henderson {
30980843563fSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_add16_i64);
30990843563fSRichard Henderson }
31000843563fSRichard Henderson 
31010843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a)
31020843563fSRichard Henderson {
31030843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_ss);
31040843563fSRichard Henderson }
31050843563fSRichard Henderson 
31060843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a)
31070843563fSRichard Henderson {
31080843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_us);
31090843563fSRichard Henderson }
31100843563fSRichard Henderson 
31111b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a)
31121b3cb7c8SRichard Henderson {
31131b3cb7c8SRichard Henderson     return do_multimedia(ctx, a, gen_helper_havg);
31141b3cb7c8SRichard Henderson }
31151b3cb7c8SRichard Henderson 
3116151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a)
3117151f309bSRichard Henderson {
3118151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64);
3119151f309bSRichard Henderson }
3120151f309bSRichard Henderson 
3121151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a)
3122151f309bSRichard Henderson {
3123151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64);
3124151f309bSRichard Henderson }
3125151f309bSRichard Henderson 
3126151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a)
3127151f309bSRichard Henderson {
3128151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64);
3129151f309bSRichard Henderson }
3130151f309bSRichard Henderson 
31313bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a)
31323bbb8e48SRichard Henderson {
31333bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshladd);
31343bbb8e48SRichard Henderson }
31353bbb8e48SRichard Henderson 
31363bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a)
31373bbb8e48SRichard Henderson {
31383bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshradd);
31393bbb8e48SRichard Henderson }
31403bbb8e48SRichard Henderson 
314110c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a)
314210c9e58dSRichard Henderson {
314310c9e58dSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64);
314410c9e58dSRichard Henderson }
314510c9e58dSRichard Henderson 
314610c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a)
314710c9e58dSRichard Henderson {
314810c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_ss);
314910c9e58dSRichard Henderson }
315010c9e58dSRichard Henderson 
315110c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a)
315210c9e58dSRichard Henderson {
315310c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_us);
315410c9e58dSRichard Henderson }
315510c9e58dSRichard Henderson 
3156c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3157c2a7ee3fSRichard Henderson {
3158c2a7ee3fSRichard Henderson     uint64_t mask = 0xffff0000ffff0000ull;
3159c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3160c2a7ee3fSRichard Henderson 
3161c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r2, mask);
3162c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r1, mask);
3163c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, tmp, 16);
3164c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
3165c2a7ee3fSRichard Henderson }
3166c2a7ee3fSRichard Henderson 
3167c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a)
3168c2a7ee3fSRichard Henderson {
3169c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_l);
3170c2a7ee3fSRichard Henderson }
3171c2a7ee3fSRichard Henderson 
3172c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3173c2a7ee3fSRichard Henderson {
3174c2a7ee3fSRichard Henderson     uint64_t mask = 0x0000ffff0000ffffull;
3175c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3176c2a7ee3fSRichard Henderson 
3177c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r1, mask);
3178c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r2, mask);
3179c2a7ee3fSRichard Henderson     tcg_gen_shli_i64(tmp, tmp, 16);
3180c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
3181c2a7ee3fSRichard Henderson }
3182c2a7ee3fSRichard Henderson 
3183c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a)
3184c2a7ee3fSRichard Henderson {
3185c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_r);
3186c2a7ee3fSRichard Henderson }
3187c2a7ee3fSRichard Henderson 
3188c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3189c2a7ee3fSRichard Henderson {
3190c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3191c2a7ee3fSRichard Henderson 
3192c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, r2, 32);
3193c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r1, tmp, 0, 32);
3194c2a7ee3fSRichard Henderson }
3195c2a7ee3fSRichard Henderson 
3196c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a)
3197c2a7ee3fSRichard Henderson {
3198c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_l);
3199c2a7ee3fSRichard Henderson }
3200c2a7ee3fSRichard Henderson 
3201c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3202c2a7ee3fSRichard Henderson {
3203c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r2, r1, 32, 32);
3204c2a7ee3fSRichard Henderson }
3205c2a7ee3fSRichard Henderson 
3206c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a)
3207c2a7ee3fSRichard Henderson {
3208c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_r);
3209c2a7ee3fSRichard Henderson }
3210c2a7ee3fSRichard Henderson 
32114e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a)
32124e7abdb1SRichard Henderson {
32134e7abdb1SRichard Henderson     TCGv_i64 r, t0, t1, t2, t3;
32144e7abdb1SRichard Henderson 
32154e7abdb1SRichard Henderson     if (!ctx->is_pa20) {
32164e7abdb1SRichard Henderson         return false;
32174e7abdb1SRichard Henderson     }
32184e7abdb1SRichard Henderson 
32194e7abdb1SRichard Henderson     nullify_over(ctx);
32204e7abdb1SRichard Henderson 
32214e7abdb1SRichard Henderson     r = load_gpr(ctx, a->r1);
32224e7abdb1SRichard Henderson     t0 = tcg_temp_new_i64();
32234e7abdb1SRichard Henderson     t1 = tcg_temp_new_i64();
32244e7abdb1SRichard Henderson     t2 = tcg_temp_new_i64();
32254e7abdb1SRichard Henderson     t3 = tcg_temp_new_i64();
32264e7abdb1SRichard Henderson 
32274e7abdb1SRichard Henderson     tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16);
32284e7abdb1SRichard Henderson     tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16);
32294e7abdb1SRichard Henderson     tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16);
32304e7abdb1SRichard Henderson     tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16);
32314e7abdb1SRichard Henderson 
32324e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t1, t0, 16, 48);
32334e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t2, t3, t2, 16, 48);
32344e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t2, t0, 32, 32);
32354e7abdb1SRichard Henderson 
32364e7abdb1SRichard Henderson     save_gpr(ctx, a->t, t0);
32374e7abdb1SRichard Henderson     return nullify_end(ctx);
32384e7abdb1SRichard Henderson }
32394e7abdb1SRichard Henderson 
32401cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a)
324196d6407fSRichard Henderson {
3242b5caa17cSRichard Henderson     if (ctx->is_pa20) {
3243b5caa17cSRichard Henderson        /*
3244b5caa17cSRichard Henderson         * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches.
3245b5caa17cSRichard Henderson         * Any base modification still occurs.
3246b5caa17cSRichard Henderson         */
3247b5caa17cSRichard Henderson         if (a->t == 0) {
3248b5caa17cSRichard Henderson             return trans_nop_addrx(ctx, a);
3249b5caa17cSRichard Henderson         }
3250b5caa17cSRichard Henderson     } else if (a->size > MO_32) {
32510786a3b6SHelge Deller         return gen_illegal(ctx);
3252c53e401eSRichard Henderson     }
32531cd012a5SRichard Henderson     return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
32541cd012a5SRichard Henderson                    a->disp, a->sp, a->m, a->size | MO_TE);
325596d6407fSRichard Henderson }
325696d6407fSRichard Henderson 
32571cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a)
325896d6407fSRichard Henderson {
32591cd012a5SRichard Henderson     assert(a->x == 0 && a->scale == 0);
3260c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
32610786a3b6SHelge Deller         return gen_illegal(ctx);
326296d6407fSRichard Henderson     }
3263c53e401eSRichard Henderson     return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
32640786a3b6SHelge Deller }
326596d6407fSRichard Henderson 
32661cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
326796d6407fSRichard Henderson {
3268b1af755cSRichard Henderson     MemOp mop = MO_TE | MO_ALIGN | a->size;
3269a4db4a78SRichard Henderson     TCGv_i64 dest, ofs;
32706fd0c7bcSRichard Henderson     TCGv_i64 addr;
327196d6407fSRichard Henderson 
3272c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
327351416c4eSRichard Henderson         return gen_illegal(ctx);
327451416c4eSRichard Henderson     }
327551416c4eSRichard Henderson 
327696d6407fSRichard Henderson     nullify_over(ctx);
327796d6407fSRichard Henderson 
32781cd012a5SRichard Henderson     if (a->m) {
327986f8d05fSRichard Henderson         /* Base register modification.  Make sure if RT == RB,
328086f8d05fSRichard Henderson            we see the result of the load.  */
3281aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
328296d6407fSRichard Henderson     } else {
32831cd012a5SRichard Henderson         dest = dest_gpr(ctx, a->t);
328496d6407fSRichard Henderson     }
328596d6407fSRichard Henderson 
3286c3ea1996SSven Schnelle     form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? 3 : 0,
328717fe594cSRichard Henderson              a->disp, a->sp, a->m, MMU_DISABLED(ctx));
3288b1af755cSRichard Henderson 
3289b1af755cSRichard Henderson     /*
3290b1af755cSRichard Henderson      * For hppa1.1, LDCW is undefined unless aligned mod 16.
3291b1af755cSRichard Henderson      * However actual hardware succeeds with aligned mod 4.
3292b1af755cSRichard Henderson      * Detect this case and log a GUEST_ERROR.
3293b1af755cSRichard Henderson      *
3294b1af755cSRichard Henderson      * TODO: HPPA64 relaxes the over-alignment requirement
3295b1af755cSRichard Henderson      * with the ,co completer.
3296b1af755cSRichard Henderson      */
3297b1af755cSRichard Henderson     gen_helper_ldc_check(addr);
3298b1af755cSRichard Henderson 
3299a4db4a78SRichard Henderson     tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop);
3300b1af755cSRichard Henderson 
33011cd012a5SRichard Henderson     if (a->m) {
33021cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
330396d6407fSRichard Henderson     }
33041cd012a5SRichard Henderson     save_gpr(ctx, a->t, dest);
330596d6407fSRichard Henderson 
330631234768SRichard Henderson     return nullify_end(ctx);
330796d6407fSRichard Henderson }
330896d6407fSRichard Henderson 
33091cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a)
331096d6407fSRichard Henderson {
33116fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
33126fd0c7bcSRichard Henderson     TCGv_i64 addr;
331396d6407fSRichard Henderson 
331496d6407fSRichard Henderson     nullify_over(ctx);
331596d6407fSRichard Henderson 
33161cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
331717fe594cSRichard Henderson              MMU_DISABLED(ctx));
33181cd012a5SRichard Henderson     val = load_gpr(ctx, a->r);
33191cd012a5SRichard Henderson     if (a->a) {
3320f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3321ad75a51eSRichard Henderson             gen_helper_stby_e_parallel(tcg_env, addr, val);
3322f9f46db4SEmilio G. Cota         } else {
3323ad75a51eSRichard Henderson             gen_helper_stby_e(tcg_env, addr, val);
3324f9f46db4SEmilio G. Cota         }
3325f9f46db4SEmilio G. Cota     } else {
3326f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3327ad75a51eSRichard Henderson             gen_helper_stby_b_parallel(tcg_env, addr, val);
332896d6407fSRichard Henderson         } else {
3329ad75a51eSRichard Henderson             gen_helper_stby_b(tcg_env, addr, val);
333096d6407fSRichard Henderson         }
3331f9f46db4SEmilio G. Cota     }
33321cd012a5SRichard Henderson     if (a->m) {
33336fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~3);
33341cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
333596d6407fSRichard Henderson     }
333696d6407fSRichard Henderson 
333731234768SRichard Henderson     return nullify_end(ctx);
333896d6407fSRichard Henderson }
333996d6407fSRichard Henderson 
334025460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a)
334125460fc5SRichard Henderson {
33426fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
33436fd0c7bcSRichard Henderson     TCGv_i64 addr;
334425460fc5SRichard Henderson 
334525460fc5SRichard Henderson     if (!ctx->is_pa20) {
334625460fc5SRichard Henderson         return false;
334725460fc5SRichard Henderson     }
334825460fc5SRichard Henderson     nullify_over(ctx);
334925460fc5SRichard Henderson 
335025460fc5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
335117fe594cSRichard Henderson              MMU_DISABLED(ctx));
335225460fc5SRichard Henderson     val = load_gpr(ctx, a->r);
335325460fc5SRichard Henderson     if (a->a) {
335425460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
335525460fc5SRichard Henderson             gen_helper_stdby_e_parallel(tcg_env, addr, val);
335625460fc5SRichard Henderson         } else {
335725460fc5SRichard Henderson             gen_helper_stdby_e(tcg_env, addr, val);
335825460fc5SRichard Henderson         }
335925460fc5SRichard Henderson     } else {
336025460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
336125460fc5SRichard Henderson             gen_helper_stdby_b_parallel(tcg_env, addr, val);
336225460fc5SRichard Henderson         } else {
336325460fc5SRichard Henderson             gen_helper_stdby_b(tcg_env, addr, val);
336425460fc5SRichard Henderson         }
336525460fc5SRichard Henderson     }
336625460fc5SRichard Henderson     if (a->m) {
33676fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~7);
336825460fc5SRichard Henderson         save_gpr(ctx, a->b, ofs);
336925460fc5SRichard Henderson     }
337025460fc5SRichard Henderson 
337125460fc5SRichard Henderson     return nullify_end(ctx);
337225460fc5SRichard Henderson }
337325460fc5SRichard Henderson 
33741cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a)
3375d0a851ccSRichard Henderson {
3376d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3377d0a851ccSRichard Henderson 
3378d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3379451d993dSRichard Henderson     ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX;
33801cd012a5SRichard Henderson     trans_ld(ctx, a);
3381d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
338231234768SRichard Henderson     return true;
3383d0a851ccSRichard Henderson }
3384d0a851ccSRichard Henderson 
33851cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a)
3386d0a851ccSRichard Henderson {
3387d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3388d0a851ccSRichard Henderson 
3389d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3390451d993dSRichard Henderson     ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX;
33911cd012a5SRichard Henderson     trans_st(ctx, a);
3392d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
339331234768SRichard Henderson     return true;
3394d0a851ccSRichard Henderson }
339595412a61SRichard Henderson 
33960588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
3397b2167459SRichard Henderson {
33986fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3399b2167459SRichard Henderson 
34006fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tcg_rt, a->i);
34010588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3402b2167459SRichard Henderson     cond_free(&ctx->null_cond);
340331234768SRichard Henderson     return true;
3404b2167459SRichard Henderson }
3405b2167459SRichard Henderson 
34060588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a)
3407b2167459SRichard Henderson {
34086fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
34096fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
3410b2167459SRichard Henderson 
34116fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
3412b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
3413b2167459SRichard Henderson     cond_free(&ctx->null_cond);
341431234768SRichard Henderson     return true;
3415b2167459SRichard Henderson }
3416b2167459SRichard Henderson 
34170588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
3418b2167459SRichard Henderson {
34196fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3420b2167459SRichard Henderson 
3421b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
3422d265360fSRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_i64.  */
34230588e061SRichard Henderson     if (a->b == 0) {
34246fd0c7bcSRichard Henderson         tcg_gen_movi_i64(tcg_rt, a->i);
3425b2167459SRichard Henderson     } else {
34266fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
3427b2167459SRichard Henderson     }
34280588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3429b2167459SRichard Henderson     cond_free(&ctx->null_cond);
343031234768SRichard Henderson     return true;
3431b2167459SRichard Henderson }
3432b2167459SRichard Henderson 
34336fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
3434e9efd4bcSRichard Henderson                     unsigned c, unsigned f, bool d, unsigned n, int disp)
343598cd9ca7SRichard Henderson {
34366fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv;
343798cd9ca7SRichard Henderson     DisasCond cond;
343898cd9ca7SRichard Henderson 
343998cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3440aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
344198cd9ca7SRichard Henderson 
34426fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
344398cd9ca7SRichard Henderson 
3444f764718dSRichard Henderson     sv = NULL;
3445b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
344698cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
344798cd9ca7SRichard Henderson     }
344898cd9ca7SRichard Henderson 
34494fe9533aSRichard Henderson     cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
345001afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
345198cd9ca7SRichard Henderson }
345298cd9ca7SRichard Henderson 
345301afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
345498cd9ca7SRichard Henderson {
3455e9efd4bcSRichard Henderson     if (!ctx->is_pa20 && a->d) {
3456e9efd4bcSRichard Henderson         return false;
3457e9efd4bcSRichard Henderson     }
345801afb7beSRichard Henderson     nullify_over(ctx);
3459e9efd4bcSRichard Henderson     return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
3460e9efd4bcSRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
346101afb7beSRichard Henderson }
346201afb7beSRichard Henderson 
346301afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
346401afb7beSRichard Henderson {
3465c65c3ee1SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3466c65c3ee1SRichard Henderson         return false;
3467c65c3ee1SRichard Henderson     }
346801afb7beSRichard Henderson     nullify_over(ctx);
34696fd0c7bcSRichard Henderson     return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
3470c65c3ee1SRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
347101afb7beSRichard Henderson }
347201afb7beSRichard Henderson 
34736fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
347401afb7beSRichard Henderson                     unsigned c, unsigned f, unsigned n, int disp)
347501afb7beSRichard Henderson {
34766fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv, cb_cond;
347798cd9ca7SRichard Henderson     DisasCond cond;
3478bdcccc17SRichard Henderson     bool d = false;
347998cd9ca7SRichard Henderson 
3480f25d3160SRichard Henderson     /*
3481f25d3160SRichard Henderson      * For hppa64, the ADDB conditions change with PSW.W,
3482f25d3160SRichard Henderson      * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3483f25d3160SRichard Henderson      */
3484f25d3160SRichard Henderson     if (ctx->tb_flags & PSW_W) {
3485f25d3160SRichard Henderson         d = c >= 5;
3486f25d3160SRichard Henderson         if (d) {
3487f25d3160SRichard Henderson             c &= 3;
3488f25d3160SRichard Henderson         }
3489f25d3160SRichard Henderson     }
3490f25d3160SRichard Henderson 
349198cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3492aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
3493f764718dSRichard Henderson     sv = NULL;
3494bdcccc17SRichard Henderson     cb_cond = NULL;
349598cd9ca7SRichard Henderson 
3496b47a4a02SSven Schnelle     if (cond_need_cb(c)) {
3497aac0f603SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
3498aac0f603SRichard Henderson         TCGv_i64 cb_msb = tcg_temp_new_i64();
3499bdcccc17SRichard Henderson 
35006fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cb_msb, 0);
35016fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
35026fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
35036fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
3504bdcccc17SRichard Henderson         cb_cond = get_carry(ctx, d, cb, cb_msb);
3505b47a4a02SSven Schnelle     } else {
35066fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
3507b47a4a02SSven Schnelle     }
3508b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
3509f8f5986eSRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2, in1, 0, d);
351098cd9ca7SRichard Henderson     }
351198cd9ca7SRichard Henderson 
3512a751eb31SRichard Henderson     cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
351343675d20SSven Schnelle     save_gpr(ctx, r, dest);
351401afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
351598cd9ca7SRichard Henderson }
351698cd9ca7SRichard Henderson 
351701afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a)
351898cd9ca7SRichard Henderson {
351901afb7beSRichard Henderson     nullify_over(ctx);
352001afb7beSRichard Henderson     return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
352101afb7beSRichard Henderson }
352201afb7beSRichard Henderson 
352301afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
352401afb7beSRichard Henderson {
352501afb7beSRichard Henderson     nullify_over(ctx);
35266fd0c7bcSRichard Henderson     return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
352701afb7beSRichard Henderson }
352801afb7beSRichard Henderson 
352901afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
353001afb7beSRichard Henderson {
35316fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
353298cd9ca7SRichard Henderson     DisasCond cond;
353398cd9ca7SRichard Henderson 
353498cd9ca7SRichard Henderson     nullify_over(ctx);
353598cd9ca7SRichard Henderson 
3536aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
353701afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
353882d0c831SRichard Henderson     if (a->d) {
353982d0c831SRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
354082d0c831SRichard Henderson     } else {
35411e9ab9fbSRichard Henderson         /* Force shift into [32,63] */
35426fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_sar, 32);
35436fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, tmp);
35441e9ab9fbSRichard Henderson     }
354598cd9ca7SRichard Henderson 
3546*4c42fd0dSRichard Henderson     cond = cond_make_ti(a->c ? TCG_COND_GE : TCG_COND_LT, tmp, 0);
354701afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
354898cd9ca7SRichard Henderson }
354998cd9ca7SRichard Henderson 
355001afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
355198cd9ca7SRichard Henderson {
35526fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
355301afb7beSRichard Henderson     DisasCond cond;
35541e9ab9fbSRichard Henderson     int p;
355501afb7beSRichard Henderson 
355601afb7beSRichard Henderson     nullify_over(ctx);
355701afb7beSRichard Henderson 
3558aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
355901afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
356082d0c831SRichard Henderson     p = a->p | (a->d ? 0 : 32);
35616fd0c7bcSRichard Henderson     tcg_gen_shli_i64(tmp, tcg_r, p);
356201afb7beSRichard Henderson 
3563*4c42fd0dSRichard Henderson     cond = cond_make_ti(a->c ? TCG_COND_GE : TCG_COND_LT, tmp, 0);
356401afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
356501afb7beSRichard Henderson }
356601afb7beSRichard Henderson 
356701afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a)
356801afb7beSRichard Henderson {
35696fd0c7bcSRichard Henderson     TCGv_i64 dest;
357098cd9ca7SRichard Henderson     DisasCond cond;
357198cd9ca7SRichard Henderson 
357298cd9ca7SRichard Henderson     nullify_over(ctx);
357398cd9ca7SRichard Henderson 
357401afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r2);
357501afb7beSRichard Henderson     if (a->r1 == 0) {
35766fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, 0);
357798cd9ca7SRichard Henderson     } else {
35786fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
357998cd9ca7SRichard Henderson     }
358098cd9ca7SRichard Henderson 
35814fa52edfSRichard Henderson     /* All MOVB conditions are 32-bit. */
35824fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
358301afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
358401afb7beSRichard Henderson }
358501afb7beSRichard Henderson 
358601afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
358701afb7beSRichard Henderson {
35886fd0c7bcSRichard Henderson     TCGv_i64 dest;
358901afb7beSRichard Henderson     DisasCond cond;
359001afb7beSRichard Henderson 
359101afb7beSRichard Henderson     nullify_over(ctx);
359201afb7beSRichard Henderson 
359301afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r);
35946fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, a->i);
359501afb7beSRichard Henderson 
35964fa52edfSRichard Henderson     /* All MOVBI conditions are 32-bit. */
35974fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
359801afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
359998cd9ca7SRichard Henderson }
360098cd9ca7SRichard Henderson 
3601f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
36020b1347d2SRichard Henderson {
36036fd0c7bcSRichard Henderson     TCGv_i64 dest, src2;
36040b1347d2SRichard Henderson 
3605f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3606f7b775a9SRichard Henderson         return false;
3607f7b775a9SRichard Henderson     }
360830878590SRichard Henderson     if (a->c) {
36090b1347d2SRichard Henderson         nullify_over(ctx);
36100b1347d2SRichard Henderson     }
36110b1347d2SRichard Henderson 
361230878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
3613f7b775a9SRichard Henderson     src2 = load_gpr(ctx, a->r2);
361430878590SRichard Henderson     if (a->r1 == 0) {
3615f7b775a9SRichard Henderson         if (a->d) {
36166fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src2, cpu_sar);
3617f7b775a9SRichard Henderson         } else {
3618aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
3619f7b775a9SRichard Henderson 
36206fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src2);
36216fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
36226fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, dest, tmp);
3623f7b775a9SRichard Henderson         }
362430878590SRichard Henderson     } else if (a->r1 == a->r2) {
3625f7b775a9SRichard Henderson         if (a->d) {
36266fd0c7bcSRichard Henderson             tcg_gen_rotr_i64(dest, src2, cpu_sar);
3627f7b775a9SRichard Henderson         } else {
36280b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
3629e1d635e8SRichard Henderson             TCGv_i32 s32 = tcg_temp_new_i32();
3630e1d635e8SRichard Henderson 
36316fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, src2);
36326fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(s32, cpu_sar);
3633f7b775a9SRichard Henderson             tcg_gen_andi_i32(s32, s32, 31);
3634e1d635e8SRichard Henderson             tcg_gen_rotr_i32(t32, t32, s32);
36356fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
3636f7b775a9SRichard Henderson         }
3637f7b775a9SRichard Henderson     } else {
36386fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
3639f7b775a9SRichard Henderson 
3640f7b775a9SRichard Henderson         if (a->d) {
3641aac0f603SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
3642aac0f603SRichard Henderson             TCGv_i64 n = tcg_temp_new_i64();
3643f7b775a9SRichard Henderson 
36446fd0c7bcSRichard Henderson             tcg_gen_xori_i64(n, cpu_sar, 63);
3645a01491a2SHelge Deller             tcg_gen_shl_i64(t, src1, n);
36466fd0c7bcSRichard Henderson             tcg_gen_shli_i64(t, t, 1);
3647a01491a2SHelge Deller             tcg_gen_shr_i64(dest, src2, cpu_sar);
36486fd0c7bcSRichard Henderson             tcg_gen_or_i64(dest, dest, t);
36490b1347d2SRichard Henderson         } else {
36500b1347d2SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
36510b1347d2SRichard Henderson             TCGv_i64 s = tcg_temp_new_i64();
36520b1347d2SRichard Henderson 
36536fd0c7bcSRichard Henderson             tcg_gen_concat32_i64(t, src2, src1);
3654967662cdSRichard Henderson             tcg_gen_andi_i64(s, cpu_sar, 31);
3655967662cdSRichard Henderson             tcg_gen_shr_i64(dest, t, s);
36560b1347d2SRichard Henderson         }
3657f7b775a9SRichard Henderson     }
365830878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36590b1347d2SRichard Henderson 
36600b1347d2SRichard Henderson     /* Install the new nullification.  */
36610b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
366230878590SRichard Henderson     if (a->c) {
3663d37fad0aSSven Schnelle         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
36640b1347d2SRichard Henderson     }
366531234768SRichard Henderson     return nullify_end(ctx);
36660b1347d2SRichard Henderson }
36670b1347d2SRichard Henderson 
3668f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
36690b1347d2SRichard Henderson {
3670f7b775a9SRichard Henderson     unsigned width, sa;
36716fd0c7bcSRichard Henderson     TCGv_i64 dest, t2;
36720b1347d2SRichard Henderson 
3673f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3674f7b775a9SRichard Henderson         return false;
3675f7b775a9SRichard Henderson     }
367630878590SRichard Henderson     if (a->c) {
36770b1347d2SRichard Henderson         nullify_over(ctx);
36780b1347d2SRichard Henderson     }
36790b1347d2SRichard Henderson 
3680f7b775a9SRichard Henderson     width = a->d ? 64 : 32;
3681f7b775a9SRichard Henderson     sa = width - 1 - a->cpos;
3682f7b775a9SRichard Henderson 
368330878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
368430878590SRichard Henderson     t2 = load_gpr(ctx, a->r2);
368505bfd4dbSRichard Henderson     if (a->r1 == 0) {
36866fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, t2, sa, width - sa);
3687c53e401eSRichard Henderson     } else if (width == TARGET_LONG_BITS) {
36886fd0c7bcSRichard Henderson         tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
3689f7b775a9SRichard Henderson     } else {
3690f7b775a9SRichard Henderson         assert(!a->d);
3691f7b775a9SRichard Henderson         if (a->r1 == a->r2) {
36920b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
36936fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, t2);
36940b1347d2SRichard Henderson             tcg_gen_rotri_i32(t32, t32, sa);
36956fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
36960b1347d2SRichard Henderson         } else {
3697967662cdSRichard Henderson             tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]);
3698967662cdSRichard Henderson             tcg_gen_extract_i64(dest, dest, sa, 32);
36990b1347d2SRichard Henderson         }
3700f7b775a9SRichard Henderson     }
370130878590SRichard Henderson     save_gpr(ctx, a->t, dest);
37020b1347d2SRichard Henderson 
37030b1347d2SRichard Henderson     /* Install the new nullification.  */
37040b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
370530878590SRichard Henderson     if (a->c) {
3706d37fad0aSSven Schnelle         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
37070b1347d2SRichard Henderson     }
370831234768SRichard Henderson     return nullify_end(ctx);
37090b1347d2SRichard Henderson }
37100b1347d2SRichard Henderson 
3711bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
37120b1347d2SRichard Henderson {
3713bd792da3SRichard Henderson     unsigned widthm1 = a->d ? 63 : 31;
37146fd0c7bcSRichard Henderson     TCGv_i64 dest, src, tmp;
37150b1347d2SRichard Henderson 
3716bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3717bd792da3SRichard Henderson         return false;
3718bd792da3SRichard Henderson     }
371930878590SRichard Henderson     if (a->c) {
37200b1347d2SRichard Henderson         nullify_over(ctx);
37210b1347d2SRichard Henderson     }
37220b1347d2SRichard Henderson 
372330878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
372430878590SRichard Henderson     src = load_gpr(ctx, a->r);
3725aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
37260b1347d2SRichard Henderson 
37270b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
37286fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
37296fd0c7bcSRichard Henderson     tcg_gen_xori_i64(tmp, tmp, widthm1);
3730d781cb77SRichard Henderson 
373130878590SRichard Henderson     if (a->se) {
3732bd792da3SRichard Henderson         if (!a->d) {
37336fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(dest, src);
3734bd792da3SRichard Henderson             src = dest;
3735bd792da3SRichard Henderson         }
37366fd0c7bcSRichard Henderson         tcg_gen_sar_i64(dest, src, tmp);
37376fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, dest, 0, a->len);
37380b1347d2SRichard Henderson     } else {
3739bd792da3SRichard Henderson         if (!a->d) {
37406fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src);
3741bd792da3SRichard Henderson             src = dest;
3742bd792da3SRichard Henderson         }
37436fd0c7bcSRichard Henderson         tcg_gen_shr_i64(dest, src, tmp);
37446fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, dest, 0, a->len);
37450b1347d2SRichard Henderson     }
374630878590SRichard Henderson     save_gpr(ctx, a->t, dest);
37470b1347d2SRichard Henderson 
37480b1347d2SRichard Henderson     /* Install the new nullification.  */
37490b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
375030878590SRichard Henderson     if (a->c) {
3751bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
37520b1347d2SRichard Henderson     }
375331234768SRichard Henderson     return nullify_end(ctx);
37540b1347d2SRichard Henderson }
37550b1347d2SRichard Henderson 
3756bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
37570b1347d2SRichard Henderson {
3758bd792da3SRichard Henderson     unsigned len, cpos, width;
37596fd0c7bcSRichard Henderson     TCGv_i64 dest, src;
37600b1347d2SRichard Henderson 
3761bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3762bd792da3SRichard Henderson         return false;
3763bd792da3SRichard Henderson     }
376430878590SRichard Henderson     if (a->c) {
37650b1347d2SRichard Henderson         nullify_over(ctx);
37660b1347d2SRichard Henderson     }
37670b1347d2SRichard Henderson 
3768bd792da3SRichard Henderson     len = a->len;
3769bd792da3SRichard Henderson     width = a->d ? 64 : 32;
3770bd792da3SRichard Henderson     cpos = width - 1 - a->pos;
3771bd792da3SRichard Henderson     if (cpos + len > width) {
3772bd792da3SRichard Henderson         len = width - cpos;
3773bd792da3SRichard Henderson     }
3774bd792da3SRichard Henderson 
377530878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
377630878590SRichard Henderson     src = load_gpr(ctx, a->r);
377730878590SRichard Henderson     if (a->se) {
37786fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, src, cpos, len);
37790b1347d2SRichard Henderson     } else {
37806fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, src, cpos, len);
37810b1347d2SRichard Henderson     }
378230878590SRichard Henderson     save_gpr(ctx, a->t, dest);
37830b1347d2SRichard Henderson 
37840b1347d2SRichard Henderson     /* Install the new nullification.  */
37850b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
378630878590SRichard Henderson     if (a->c) {
3787bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
37880b1347d2SRichard Henderson     }
378931234768SRichard Henderson     return nullify_end(ctx);
37900b1347d2SRichard Henderson }
37910b1347d2SRichard Henderson 
379272ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
37930b1347d2SRichard Henderson {
379472ae4f2bSRichard Henderson     unsigned len, width;
3795c53e401eSRichard Henderson     uint64_t mask0, mask1;
37966fd0c7bcSRichard Henderson     TCGv_i64 dest;
37970b1347d2SRichard Henderson 
379872ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
379972ae4f2bSRichard Henderson         return false;
380072ae4f2bSRichard Henderson     }
380130878590SRichard Henderson     if (a->c) {
38020b1347d2SRichard Henderson         nullify_over(ctx);
38030b1347d2SRichard Henderson     }
380472ae4f2bSRichard Henderson 
380572ae4f2bSRichard Henderson     len = a->len;
380672ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
380772ae4f2bSRichard Henderson     if (a->cpos + len > width) {
380872ae4f2bSRichard Henderson         len = width - a->cpos;
38090b1347d2SRichard Henderson     }
38100b1347d2SRichard Henderson 
381130878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
381230878590SRichard Henderson     mask0 = deposit64(0, a->cpos, len, a->i);
381330878590SRichard Henderson     mask1 = deposit64(-1, a->cpos, len, a->i);
38140b1347d2SRichard Henderson 
381530878590SRichard Henderson     if (a->nz) {
38166fd0c7bcSRichard Henderson         TCGv_i64 src = load_gpr(ctx, a->t);
38176fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, src, mask1);
38186fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, mask0);
38190b1347d2SRichard Henderson     } else {
38206fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, mask0);
38210b1347d2SRichard Henderson     }
382230878590SRichard Henderson     save_gpr(ctx, a->t, dest);
38230b1347d2SRichard Henderson 
38240b1347d2SRichard Henderson     /* Install the new nullification.  */
38250b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
382630878590SRichard Henderson     if (a->c) {
382772ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
38280b1347d2SRichard Henderson     }
382931234768SRichard Henderson     return nullify_end(ctx);
38300b1347d2SRichard Henderson }
38310b1347d2SRichard Henderson 
383272ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
38330b1347d2SRichard Henderson {
383430878590SRichard Henderson     unsigned rs = a->nz ? a->t : 0;
383572ae4f2bSRichard Henderson     unsigned len, width;
38366fd0c7bcSRichard Henderson     TCGv_i64 dest, val;
38370b1347d2SRichard Henderson 
383872ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
383972ae4f2bSRichard Henderson         return false;
384072ae4f2bSRichard Henderson     }
384130878590SRichard Henderson     if (a->c) {
38420b1347d2SRichard Henderson         nullify_over(ctx);
38430b1347d2SRichard Henderson     }
384472ae4f2bSRichard Henderson 
384572ae4f2bSRichard Henderson     len = a->len;
384672ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
384772ae4f2bSRichard Henderson     if (a->cpos + len > width) {
384872ae4f2bSRichard Henderson         len = width - a->cpos;
38490b1347d2SRichard Henderson     }
38500b1347d2SRichard Henderson 
385130878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
385230878590SRichard Henderson     val = load_gpr(ctx, a->r);
38530b1347d2SRichard Henderson     if (rs == 0) {
38546fd0c7bcSRichard Henderson         tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
38550b1347d2SRichard Henderson     } else {
38566fd0c7bcSRichard Henderson         tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
38570b1347d2SRichard Henderson     }
385830878590SRichard Henderson     save_gpr(ctx, a->t, dest);
38590b1347d2SRichard Henderson 
38600b1347d2SRichard Henderson     /* Install the new nullification.  */
38610b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
386230878590SRichard Henderson     if (a->c) {
386372ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
38640b1347d2SRichard Henderson     }
386531234768SRichard Henderson     return nullify_end(ctx);
38660b1347d2SRichard Henderson }
38670b1347d2SRichard Henderson 
386872ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
38696fd0c7bcSRichard Henderson                        bool d, bool nz, unsigned len, TCGv_i64 val)
38700b1347d2SRichard Henderson {
38710b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
387272ae4f2bSRichard Henderson     unsigned widthm1 = d ? 63 : 31;
38736fd0c7bcSRichard Henderson     TCGv_i64 mask, tmp, shift, dest;
3874c53e401eSRichard Henderson     uint64_t msb = 1ULL << (len - 1);
38750b1347d2SRichard Henderson 
38760b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
3877aac0f603SRichard Henderson     shift = tcg_temp_new_i64();
3878aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
38790b1347d2SRichard Henderson 
38800b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
38816fd0c7bcSRichard Henderson     tcg_gen_andi_i64(shift, cpu_sar, widthm1);
38826fd0c7bcSRichard Henderson     tcg_gen_xori_i64(shift, shift, widthm1);
38830b1347d2SRichard Henderson 
3884aac0f603SRichard Henderson     mask = tcg_temp_new_i64();
38856fd0c7bcSRichard Henderson     tcg_gen_movi_i64(mask, msb + (msb - 1));
38866fd0c7bcSRichard Henderson     tcg_gen_and_i64(tmp, val, mask);
38870b1347d2SRichard Henderson     if (rs) {
38886fd0c7bcSRichard Henderson         tcg_gen_shl_i64(mask, mask, shift);
38896fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tmp, shift);
38906fd0c7bcSRichard Henderson         tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
38916fd0c7bcSRichard Henderson         tcg_gen_or_i64(dest, dest, tmp);
38920b1347d2SRichard Henderson     } else {
38936fd0c7bcSRichard Henderson         tcg_gen_shl_i64(dest, tmp, shift);
38940b1347d2SRichard Henderson     }
38950b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
38960b1347d2SRichard Henderson 
38970b1347d2SRichard Henderson     /* Install the new nullification.  */
38980b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
38990b1347d2SRichard Henderson     if (c) {
390072ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, c, d, dest);
39010b1347d2SRichard Henderson     }
390231234768SRichard Henderson     return nullify_end(ctx);
39030b1347d2SRichard Henderson }
39040b1347d2SRichard Henderson 
390572ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
390630878590SRichard Henderson {
390772ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
390872ae4f2bSRichard Henderson         return false;
390972ae4f2bSRichard Henderson     }
3910a6deecceSSven Schnelle     if (a->c) {
3911a6deecceSSven Schnelle         nullify_over(ctx);
3912a6deecceSSven Schnelle     }
391372ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
391472ae4f2bSRichard Henderson                       load_gpr(ctx, a->r));
391530878590SRichard Henderson }
391630878590SRichard Henderson 
391772ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
391830878590SRichard Henderson {
391972ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
392072ae4f2bSRichard Henderson         return false;
392172ae4f2bSRichard Henderson     }
3922a6deecceSSven Schnelle     if (a->c) {
3923a6deecceSSven Schnelle         nullify_over(ctx);
3924a6deecceSSven Schnelle     }
392572ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
39266fd0c7bcSRichard Henderson                       tcg_constant_i64(a->i));
392730878590SRichard Henderson }
39280b1347d2SRichard Henderson 
39298340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a)
393098cd9ca7SRichard Henderson {
3931019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY
3932bc921866SRichard Henderson     ctx->iaq_j.space = tcg_temp_new_i64();
3933bc921866SRichard Henderson     load_spr(ctx, ctx->iaq_j.space, a->sp);
3934c301f34eSRichard Henderson #endif
3935019f4159SRichard Henderson 
3936bc921866SRichard Henderson     ctx->iaq_j.base = tcg_temp_new_i64();
3937bc921866SRichard Henderson     ctx->iaq_j.disp = 0;
3938bc921866SRichard Henderson 
3939bc921866SRichard Henderson     tcg_gen_addi_i64(ctx->iaq_j.base, load_gpr(ctx, a->b), a->disp);
3940bc921866SRichard Henderson     ctx->iaq_j.base = do_ibranch_priv(ctx, ctx->iaq_j.base);
3941bc921866SRichard Henderson 
3942bc921866SRichard Henderson     return do_ibranch(ctx, a->l, true, a->n);
394398cd9ca7SRichard Henderson }
394498cd9ca7SRichard Henderson 
39458340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a)
394698cd9ca7SRichard Henderson {
39472644f80bSRichard Henderson     return do_dbranch(ctx, a->disp, a->l, a->n);
394898cd9ca7SRichard Henderson }
394998cd9ca7SRichard Henderson 
39508340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
395143e05652SRichard Henderson {
3952bc921866SRichard Henderson     int64_t disp = a->disp;
395343e05652SRichard Henderson 
39546e5f5300SSven Schnelle     nullify_over(ctx);
39556e5f5300SSven Schnelle 
395643e05652SRichard Henderson     /* Make sure the caller hasn't done something weird with the queue.
395743e05652SRichard Henderson      * ??? This is not quite the same as the PSW[B] bit, which would be
395843e05652SRichard Henderson      * expensive to track.  Real hardware will trap for
395943e05652SRichard Henderson      *    b  gateway
396043e05652SRichard Henderson      *    b  gateway+4  (in delay slot of first branch)
396143e05652SRichard Henderson      * However, checking for a non-sequential instruction queue *will*
396243e05652SRichard Henderson      * diagnose the security hole
396343e05652SRichard Henderson      *    b  gateway
396443e05652SRichard Henderson      *    b  evil
396543e05652SRichard Henderson      * in which instructions at evil would run with increased privs.
396643e05652SRichard Henderson      */
3967bc921866SRichard Henderson     if (iaqe_variable(&ctx->iaq_b) || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) {
396843e05652SRichard Henderson         return gen_illegal(ctx);
396943e05652SRichard Henderson     }
397043e05652SRichard Henderson 
397143e05652SRichard Henderson #ifndef CONFIG_USER_ONLY
397243e05652SRichard Henderson     if (ctx->tb_flags & PSW_C) {
397394956d7bSPhilippe Mathieu-Daudé         int type = hppa_artype_for_page(cpu_env(ctx->cs), ctx->base.pc_next);
397443e05652SRichard Henderson         /* If we could not find a TLB entry, then we need to generate an
397543e05652SRichard Henderson            ITLB miss exception so the kernel will provide it.
397643e05652SRichard Henderson            The resulting TLB fill operation will invalidate this TB and
397743e05652SRichard Henderson            we will re-translate, at which point we *will* be able to find
397843e05652SRichard Henderson            the TLB entry and determine if this is in fact a gateway page.  */
397943e05652SRichard Henderson         if (type < 0) {
398031234768SRichard Henderson             gen_excp(ctx, EXCP_ITLB_MISS);
398131234768SRichard Henderson             return true;
398243e05652SRichard Henderson         }
398343e05652SRichard Henderson         /* No change for non-gateway pages or for priv decrease.  */
398443e05652SRichard Henderson         if (type >= 4 && type - 4 < ctx->privilege) {
3985bc921866SRichard Henderson             disp -= ctx->privilege;
3986bc921866SRichard Henderson             disp += type - 4;
398743e05652SRichard Henderson         }
398843e05652SRichard Henderson     } else {
3989bc921866SRichard Henderson         disp -= ctx->privilege;  /* priv = 0 */
399043e05652SRichard Henderson     }
399143e05652SRichard Henderson #endif
399243e05652SRichard Henderson 
39936e5f5300SSven Schnelle     if (a->l) {
39946fd0c7bcSRichard Henderson         TCGv_i64 tmp = dest_gpr(ctx, a->l);
39956e5f5300SSven Schnelle         if (ctx->privilege < 3) {
39966fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, tmp, -4);
39976e5f5300SSven Schnelle         }
39986fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
39996e5f5300SSven Schnelle         save_gpr(ctx, a->l, tmp);
40006e5f5300SSven Schnelle     }
40016e5f5300SSven Schnelle 
4002bc921866SRichard Henderson     return do_dbranch(ctx, disp, 0, a->n);
400343e05652SRichard Henderson }
400443e05652SRichard Henderson 
40058340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a)
400698cd9ca7SRichard Henderson {
4007b35aec85SRichard Henderson     if (a->x) {
4008bc921866SRichard Henderson         DisasIAQE next = iaqe_incr(&ctx->iaq_f, 8);
4009bc921866SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
4010bc921866SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
4011bc921866SRichard Henderson 
4012660eefe1SRichard Henderson         /* The computation here never changes privilege level.  */
4013bc921866SRichard Henderson         copy_iaoq_entry(ctx, t0, &next);
4014bc921866SRichard Henderson         tcg_gen_shli_i64(t1, load_gpr(ctx, a->x), 3);
4015bc921866SRichard Henderson         tcg_gen_add_i64(t0, t0, t1);
4016bc921866SRichard Henderson 
4017bc921866SRichard Henderson         ctx->iaq_j = iaqe_next_absv(ctx, t0);
4018bc921866SRichard Henderson         return do_ibranch(ctx, a->l, false, a->n);
4019b35aec85SRichard Henderson     } else {
4020b35aec85SRichard Henderson         /* BLR R0,RX is a good way to load PC+8 into RX.  */
40212644f80bSRichard Henderson         return do_dbranch(ctx, 0, a->l, a->n);
4022b35aec85SRichard Henderson     }
402398cd9ca7SRichard Henderson }
402498cd9ca7SRichard Henderson 
40258340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a)
402698cd9ca7SRichard Henderson {
40276fd0c7bcSRichard Henderson     TCGv_i64 dest;
402898cd9ca7SRichard Henderson 
40298340f534SRichard Henderson     if (a->x == 0) {
40308340f534SRichard Henderson         dest = load_gpr(ctx, a->b);
403198cd9ca7SRichard Henderson     } else {
4032aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
40336fd0c7bcSRichard Henderson         tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
40346fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
403598cd9ca7SRichard Henderson     }
4036660eefe1SRichard Henderson     dest = do_ibranch_priv(ctx, dest);
4037bc921866SRichard Henderson     ctx->iaq_j = iaqe_next_absv(ctx, dest);
4038bc921866SRichard Henderson 
4039bc921866SRichard Henderson     return do_ibranch(ctx, 0, false, a->n);
404098cd9ca7SRichard Henderson }
404198cd9ca7SRichard Henderson 
40428340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a)
404398cd9ca7SRichard Henderson {
4044019f4159SRichard Henderson     TCGv_i64 b = load_gpr(ctx, a->b);
404598cd9ca7SRichard Henderson 
4046019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY
4047bc921866SRichard Henderson     ctx->iaq_j.space = space_select(ctx, 0, b);
4048c301f34eSRichard Henderson #endif
4049bc921866SRichard Henderson     ctx->iaq_j.base = do_ibranch_priv(ctx, b);
4050bc921866SRichard Henderson     ctx->iaq_j.disp = 0;
4051019f4159SRichard Henderson 
4052bc921866SRichard Henderson     return do_ibranch(ctx, a->l, false, a->n);
405398cd9ca7SRichard Henderson }
405498cd9ca7SRichard Henderson 
4055a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
4056a8966ba7SRichard Henderson {
4057a8966ba7SRichard Henderson     /* All branch target stack instructions implement as nop. */
4058a8966ba7SRichard Henderson     return ctx->is_pa20;
4059a8966ba7SRichard Henderson }
4060a8966ba7SRichard Henderson 
40611ca74648SRichard Henderson /*
40621ca74648SRichard Henderson  * Float class 0
40631ca74648SRichard Henderson  */
4064ebe9383cSRichard Henderson 
40651ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4066ebe9383cSRichard Henderson {
4067ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
4068ebe9383cSRichard Henderson }
4069ebe9383cSRichard Henderson 
407059f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
407159f8c04bSHelge Deller {
4072a300dad3SRichard Henderson     uint64_t ret;
4073a300dad3SRichard Henderson 
4074c53e401eSRichard Henderson     if (ctx->is_pa20) {
4075a300dad3SRichard Henderson         ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
4076a300dad3SRichard Henderson     } else {
4077a300dad3SRichard Henderson         ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
4078a300dad3SRichard Henderson     }
4079a300dad3SRichard Henderson 
408059f8c04bSHelge Deller     nullify_over(ctx);
4081a300dad3SRichard Henderson     save_frd(0, tcg_constant_i64(ret));
408259f8c04bSHelge Deller     return nullify_end(ctx);
408359f8c04bSHelge Deller }
408459f8c04bSHelge Deller 
40851ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a)
40861ca74648SRichard Henderson {
40871ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f);
40881ca74648SRichard Henderson }
40891ca74648SRichard Henderson 
4090ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4091ebe9383cSRichard Henderson {
4092ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
4093ebe9383cSRichard Henderson }
4094ebe9383cSRichard Henderson 
40951ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a)
40961ca74648SRichard Henderson {
40971ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d);
40981ca74648SRichard Henderson }
40991ca74648SRichard Henderson 
41001ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4101ebe9383cSRichard Henderson {
4102ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
4103ebe9383cSRichard Henderson }
4104ebe9383cSRichard Henderson 
41051ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a)
41061ca74648SRichard Henderson {
41071ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fabs_f);
41081ca74648SRichard Henderson }
41091ca74648SRichard Henderson 
4110ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4111ebe9383cSRichard Henderson {
4112ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
4113ebe9383cSRichard Henderson }
4114ebe9383cSRichard Henderson 
41151ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a)
41161ca74648SRichard Henderson {
41171ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fabs_d);
41181ca74648SRichard Henderson }
41191ca74648SRichard Henderson 
41201ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a)
41211ca74648SRichard Henderson {
41221ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s);
41231ca74648SRichard Henderson }
41241ca74648SRichard Henderson 
41251ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a)
41261ca74648SRichard Henderson {
41271ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d);
41281ca74648SRichard Henderson }
41291ca74648SRichard Henderson 
41301ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a)
41311ca74648SRichard Henderson {
41321ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s);
41331ca74648SRichard Henderson }
41341ca74648SRichard Henderson 
41351ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a)
41361ca74648SRichard Henderson {
41371ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d);
41381ca74648SRichard Henderson }
41391ca74648SRichard Henderson 
41401ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4141ebe9383cSRichard Henderson {
4142ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
4143ebe9383cSRichard Henderson }
4144ebe9383cSRichard Henderson 
41451ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a)
41461ca74648SRichard Henderson {
41471ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fneg_f);
41481ca74648SRichard Henderson }
41491ca74648SRichard Henderson 
4150ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4151ebe9383cSRichard Henderson {
4152ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
4153ebe9383cSRichard Henderson }
4154ebe9383cSRichard Henderson 
41551ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a)
41561ca74648SRichard Henderson {
41571ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fneg_d);
41581ca74648SRichard Henderson }
41591ca74648SRichard Henderson 
41601ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4161ebe9383cSRichard Henderson {
4162ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
4163ebe9383cSRichard Henderson }
4164ebe9383cSRichard Henderson 
41651ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a)
41661ca74648SRichard Henderson {
41671ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f);
41681ca74648SRichard Henderson }
41691ca74648SRichard Henderson 
4170ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4171ebe9383cSRichard Henderson {
4172ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
4173ebe9383cSRichard Henderson }
4174ebe9383cSRichard Henderson 
41751ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a)
41761ca74648SRichard Henderson {
41771ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d);
41781ca74648SRichard Henderson }
41791ca74648SRichard Henderson 
41801ca74648SRichard Henderson /*
41811ca74648SRichard Henderson  * Float class 1
41821ca74648SRichard Henderson  */
41831ca74648SRichard Henderson 
41841ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a)
41851ca74648SRichard Henderson {
41861ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s);
41871ca74648SRichard Henderson }
41881ca74648SRichard Henderson 
41891ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a)
41901ca74648SRichard Henderson {
41911ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d);
41921ca74648SRichard Henderson }
41931ca74648SRichard Henderson 
41941ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a)
41951ca74648SRichard Henderson {
41961ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s);
41971ca74648SRichard Henderson }
41981ca74648SRichard Henderson 
41991ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a)
42001ca74648SRichard Henderson {
42011ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s);
42021ca74648SRichard Henderson }
42031ca74648SRichard Henderson 
42041ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a)
42051ca74648SRichard Henderson {
42061ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d);
42071ca74648SRichard Henderson }
42081ca74648SRichard Henderson 
42091ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a)
42101ca74648SRichard Henderson {
42111ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d);
42121ca74648SRichard Henderson }
42131ca74648SRichard Henderson 
42141ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a)
42151ca74648SRichard Henderson {
42161ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w);
42171ca74648SRichard Henderson }
42181ca74648SRichard Henderson 
42191ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a)
42201ca74648SRichard Henderson {
42211ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w);
42221ca74648SRichard Henderson }
42231ca74648SRichard Henderson 
42241ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a)
42251ca74648SRichard Henderson {
42261ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw);
42271ca74648SRichard Henderson }
42281ca74648SRichard Henderson 
42291ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a)
42301ca74648SRichard Henderson {
42311ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw);
42321ca74648SRichard Henderson }
42331ca74648SRichard Henderson 
42341ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a)
42351ca74648SRichard Henderson {
42361ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w);
42371ca74648SRichard Henderson }
42381ca74648SRichard Henderson 
42391ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a)
42401ca74648SRichard Henderson {
42411ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w);
42421ca74648SRichard Henderson }
42431ca74648SRichard Henderson 
42441ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a)
42451ca74648SRichard Henderson {
42461ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw);
42471ca74648SRichard Henderson }
42481ca74648SRichard Henderson 
42491ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a)
42501ca74648SRichard Henderson {
42511ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw);
42521ca74648SRichard Henderson }
42531ca74648SRichard Henderson 
42541ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a)
42551ca74648SRichard Henderson {
42561ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s);
42571ca74648SRichard Henderson }
42581ca74648SRichard Henderson 
42591ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a)
42601ca74648SRichard Henderson {
42611ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s);
42621ca74648SRichard Henderson }
42631ca74648SRichard Henderson 
42641ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a)
42651ca74648SRichard Henderson {
42661ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d);
42671ca74648SRichard Henderson }
42681ca74648SRichard Henderson 
42691ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a)
42701ca74648SRichard Henderson {
42711ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d);
42721ca74648SRichard Henderson }
42731ca74648SRichard Henderson 
42741ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a)
42751ca74648SRichard Henderson {
42761ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw);
42771ca74648SRichard Henderson }
42781ca74648SRichard Henderson 
42791ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a)
42801ca74648SRichard Henderson {
42811ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw);
42821ca74648SRichard Henderson }
42831ca74648SRichard Henderson 
42841ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a)
42851ca74648SRichard Henderson {
42861ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw);
42871ca74648SRichard Henderson }
42881ca74648SRichard Henderson 
42891ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a)
42901ca74648SRichard Henderson {
42911ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw);
42921ca74648SRichard Henderson }
42931ca74648SRichard Henderson 
42941ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a)
42951ca74648SRichard Henderson {
42961ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw);
42971ca74648SRichard Henderson }
42981ca74648SRichard Henderson 
42991ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a)
43001ca74648SRichard Henderson {
43011ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw);
43021ca74648SRichard Henderson }
43031ca74648SRichard Henderson 
43041ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a)
43051ca74648SRichard Henderson {
43061ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw);
43071ca74648SRichard Henderson }
43081ca74648SRichard Henderson 
43091ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a)
43101ca74648SRichard Henderson {
43111ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw);
43121ca74648SRichard Henderson }
43131ca74648SRichard Henderson 
43141ca74648SRichard Henderson /*
43151ca74648SRichard Henderson  * Float class 2
43161ca74648SRichard Henderson  */
43171ca74648SRichard Henderson 
43181ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a)
4319ebe9383cSRichard Henderson {
4320ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
4321ebe9383cSRichard Henderson 
4322ebe9383cSRichard Henderson     nullify_over(ctx);
4323ebe9383cSRichard Henderson 
43241ca74648SRichard Henderson     ta = load_frw0_i32(a->r1);
43251ca74648SRichard Henderson     tb = load_frw0_i32(a->r2);
432629dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
432729dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4328ebe9383cSRichard Henderson 
4329ad75a51eSRichard Henderson     gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc);
4330ebe9383cSRichard Henderson 
43311ca74648SRichard Henderson     return nullify_end(ctx);
4332ebe9383cSRichard Henderson }
4333ebe9383cSRichard Henderson 
43341ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
4335ebe9383cSRichard Henderson {
4336ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
4337ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
4338ebe9383cSRichard Henderson 
4339ebe9383cSRichard Henderson     nullify_over(ctx);
4340ebe9383cSRichard Henderson 
43411ca74648SRichard Henderson     ta = load_frd0(a->r1);
43421ca74648SRichard Henderson     tb = load_frd0(a->r2);
434329dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
434429dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4345ebe9383cSRichard Henderson 
4346ad75a51eSRichard Henderson     gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc);
4347ebe9383cSRichard Henderson 
434831234768SRichard Henderson     return nullify_end(ctx);
4349ebe9383cSRichard Henderson }
4350ebe9383cSRichard Henderson 
43511ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
4352ebe9383cSRichard Henderson {
43536fd0c7bcSRichard Henderson     TCGv_i64 t;
4354ebe9383cSRichard Henderson 
4355ebe9383cSRichard Henderson     nullify_over(ctx);
4356ebe9383cSRichard Henderson 
4357aac0f603SRichard Henderson     t = tcg_temp_new_i64();
43586fd0c7bcSRichard Henderson     tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
4359ebe9383cSRichard Henderson 
43601ca74648SRichard Henderson     if (a->y == 1) {
4361ebe9383cSRichard Henderson         int mask;
4362ebe9383cSRichard Henderson         bool inv = false;
4363ebe9383cSRichard Henderson 
43641ca74648SRichard Henderson         switch (a->c) {
4365ebe9383cSRichard Henderson         case 0: /* simple */
43666fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, 0x4000000);
4367*4c42fd0dSRichard Henderson             ctx->null_cond = cond_make_ti(TCG_COND_NE, t, 0);
4368ebe9383cSRichard Henderson             goto done;
4369ebe9383cSRichard Henderson         case 2: /* rej */
4370ebe9383cSRichard Henderson             inv = true;
4371ebe9383cSRichard Henderson             /* fallthru */
4372ebe9383cSRichard Henderson         case 1: /* acc */
4373ebe9383cSRichard Henderson             mask = 0x43ff800;
4374ebe9383cSRichard Henderson             break;
4375ebe9383cSRichard Henderson         case 6: /* rej8 */
4376ebe9383cSRichard Henderson             inv = true;
4377ebe9383cSRichard Henderson             /* fallthru */
4378ebe9383cSRichard Henderson         case 5: /* acc8 */
4379ebe9383cSRichard Henderson             mask = 0x43f8000;
4380ebe9383cSRichard Henderson             break;
4381ebe9383cSRichard Henderson         case 9: /* acc6 */
4382ebe9383cSRichard Henderson             mask = 0x43e0000;
4383ebe9383cSRichard Henderson             break;
4384ebe9383cSRichard Henderson         case 13: /* acc4 */
4385ebe9383cSRichard Henderson             mask = 0x4380000;
4386ebe9383cSRichard Henderson             break;
4387ebe9383cSRichard Henderson         case 17: /* acc2 */
4388ebe9383cSRichard Henderson             mask = 0x4200000;
4389ebe9383cSRichard Henderson             break;
4390ebe9383cSRichard Henderson         default:
43911ca74648SRichard Henderson             gen_illegal(ctx);
43921ca74648SRichard Henderson             return true;
4393ebe9383cSRichard Henderson         }
4394ebe9383cSRichard Henderson         if (inv) {
43956fd0c7bcSRichard Henderson             TCGv_i64 c = tcg_constant_i64(mask);
43966fd0c7bcSRichard Henderson             tcg_gen_or_i64(t, t, c);
4397*4c42fd0dSRichard Henderson             ctx->null_cond = cond_make_tt(TCG_COND_EQ, t, c);
4398ebe9383cSRichard Henderson         } else {
43996fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, mask);
4400*4c42fd0dSRichard Henderson             ctx->null_cond = cond_make_ti(TCG_COND_EQ, t, 0);
4401ebe9383cSRichard Henderson         }
44021ca74648SRichard Henderson     } else {
44031ca74648SRichard Henderson         unsigned cbit = (a->y ^ 1) - 1;
44041ca74648SRichard Henderson 
44056fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, t, 21 - cbit, 1);
4406*4c42fd0dSRichard Henderson         ctx->null_cond = cond_make_ti(TCG_COND_NE, t, 0);
44071ca74648SRichard Henderson     }
44081ca74648SRichard Henderson 
4409ebe9383cSRichard Henderson  done:
441031234768SRichard Henderson     return nullify_end(ctx);
4411ebe9383cSRichard Henderson }
4412ebe9383cSRichard Henderson 
44131ca74648SRichard Henderson /*
44141ca74648SRichard Henderson  * Float class 2
44151ca74648SRichard Henderson  */
44161ca74648SRichard Henderson 
44171ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a)
4418ebe9383cSRichard Henderson {
44191ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s);
44201ca74648SRichard Henderson }
44211ca74648SRichard Henderson 
44221ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a)
44231ca74648SRichard Henderson {
44241ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d);
44251ca74648SRichard Henderson }
44261ca74648SRichard Henderson 
44271ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a)
44281ca74648SRichard Henderson {
44291ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s);
44301ca74648SRichard Henderson }
44311ca74648SRichard Henderson 
44321ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a)
44331ca74648SRichard Henderson {
44341ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d);
44351ca74648SRichard Henderson }
44361ca74648SRichard Henderson 
44371ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a)
44381ca74648SRichard Henderson {
44391ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s);
44401ca74648SRichard Henderson }
44411ca74648SRichard Henderson 
44421ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a)
44431ca74648SRichard Henderson {
44441ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d);
44451ca74648SRichard Henderson }
44461ca74648SRichard Henderson 
44471ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a)
44481ca74648SRichard Henderson {
44491ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s);
44501ca74648SRichard Henderson }
44511ca74648SRichard Henderson 
44521ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a)
44531ca74648SRichard Henderson {
44541ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d);
44551ca74648SRichard Henderson }
44561ca74648SRichard Henderson 
44571ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a)
44581ca74648SRichard Henderson {
44591ca74648SRichard Henderson     TCGv_i64 x, y;
4460ebe9383cSRichard Henderson 
4461ebe9383cSRichard Henderson     nullify_over(ctx);
4462ebe9383cSRichard Henderson 
44631ca74648SRichard Henderson     x = load_frw0_i64(a->r1);
44641ca74648SRichard Henderson     y = load_frw0_i64(a->r2);
44651ca74648SRichard Henderson     tcg_gen_mul_i64(x, x, y);
44661ca74648SRichard Henderson     save_frd(a->t, x);
4467ebe9383cSRichard Henderson 
446831234768SRichard Henderson     return nullify_end(ctx);
4469ebe9383cSRichard Henderson }
4470ebe9383cSRichard Henderson 
4471ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
4472ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
4473ebe9383cSRichard Henderson {
4474ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
4475ebe9383cSRichard Henderson }
4476ebe9383cSRichard Henderson 
4477b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4478ebe9383cSRichard Henderson {
4479b1e2af57SRichard Henderson     int tm = fmpyadd_s_reg(a->tm);
4480b1e2af57SRichard Henderson     int ra = fmpyadd_s_reg(a->ra);
4481b1e2af57SRichard Henderson     int ta = fmpyadd_s_reg(a->ta);
4482b1e2af57SRichard Henderson     int rm2 = fmpyadd_s_reg(a->rm2);
4483b1e2af57SRichard Henderson     int rm1 = fmpyadd_s_reg(a->rm1);
4484ebe9383cSRichard Henderson 
4485ebe9383cSRichard Henderson     nullify_over(ctx);
4486ebe9383cSRichard Henderson 
4487ebe9383cSRichard Henderson     do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4488ebe9383cSRichard Henderson     do_fop_weww(ctx, ta, ta, ra,
4489ebe9383cSRichard Henderson                 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
4490ebe9383cSRichard Henderson 
449131234768SRichard Henderson     return nullify_end(ctx);
4492ebe9383cSRichard Henderson }
4493ebe9383cSRichard Henderson 
4494b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4495b1e2af57SRichard Henderson {
4496b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, false);
4497b1e2af57SRichard Henderson }
4498b1e2af57SRichard Henderson 
4499b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4500b1e2af57SRichard Henderson {
4501b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, true);
4502b1e2af57SRichard Henderson }
4503b1e2af57SRichard Henderson 
4504b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4505b1e2af57SRichard Henderson {
4506b1e2af57SRichard Henderson     nullify_over(ctx);
4507b1e2af57SRichard Henderson 
4508b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4509b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4510b1e2af57SRichard Henderson                 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4511b1e2af57SRichard Henderson 
4512b1e2af57SRichard Henderson     return nullify_end(ctx);
4513b1e2af57SRichard Henderson }
4514b1e2af57SRichard Henderson 
4515b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4516b1e2af57SRichard Henderson {
4517b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, false);
4518b1e2af57SRichard Henderson }
4519b1e2af57SRichard Henderson 
4520b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4521b1e2af57SRichard Henderson {
4522b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, true);
4523b1e2af57SRichard Henderson }
4524b1e2af57SRichard Henderson 
4525c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a)
4526ebe9383cSRichard Henderson {
4527c3bad4f8SRichard Henderson     TCGv_i32 x, y, z;
4528ebe9383cSRichard Henderson 
4529ebe9383cSRichard Henderson     nullify_over(ctx);
4530c3bad4f8SRichard Henderson     x = load_frw0_i32(a->rm1);
4531c3bad4f8SRichard Henderson     y = load_frw0_i32(a->rm2);
4532c3bad4f8SRichard Henderson     z = load_frw0_i32(a->ra3);
4533ebe9383cSRichard Henderson 
4534c3bad4f8SRichard Henderson     if (a->neg) {
4535ad75a51eSRichard Henderson         gen_helper_fmpynfadd_s(x, tcg_env, x, y, z);
4536ebe9383cSRichard Henderson     } else {
4537ad75a51eSRichard Henderson         gen_helper_fmpyfadd_s(x, tcg_env, x, y, z);
4538ebe9383cSRichard Henderson     }
4539ebe9383cSRichard Henderson 
4540c3bad4f8SRichard Henderson     save_frw_i32(a->t, x);
454131234768SRichard Henderson     return nullify_end(ctx);
4542ebe9383cSRichard Henderson }
4543ebe9383cSRichard Henderson 
4544c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
4545ebe9383cSRichard Henderson {
4546c3bad4f8SRichard Henderson     TCGv_i64 x, y, z;
4547ebe9383cSRichard Henderson 
4548ebe9383cSRichard Henderson     nullify_over(ctx);
4549c3bad4f8SRichard Henderson     x = load_frd0(a->rm1);
4550c3bad4f8SRichard Henderson     y = load_frd0(a->rm2);
4551c3bad4f8SRichard Henderson     z = load_frd0(a->ra3);
4552ebe9383cSRichard Henderson 
4553c3bad4f8SRichard Henderson     if (a->neg) {
4554ad75a51eSRichard Henderson         gen_helper_fmpynfadd_d(x, tcg_env, x, y, z);
4555ebe9383cSRichard Henderson     } else {
4556ad75a51eSRichard Henderson         gen_helper_fmpyfadd_d(x, tcg_env, x, y, z);
4557ebe9383cSRichard Henderson     }
4558ebe9383cSRichard Henderson 
4559c3bad4f8SRichard Henderson     save_frd(a->t, x);
456031234768SRichard Henderson     return nullify_end(ctx);
4561ebe9383cSRichard Henderson }
4562ebe9383cSRichard Henderson 
456338193127SRichard Henderson /* Emulate PDC BTLB, called by SeaBIOS-hppa */
456438193127SRichard Henderson static bool trans_diag_btlb(DisasContext *ctx, arg_diag_btlb *a)
456515da177bSSven Schnelle {
4566cf6b28d4SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4567cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY
4568ad75a51eSRichard Henderson     nullify_over(ctx);
4569ad75a51eSRichard Henderson     gen_helper_diag_btlb(tcg_env);
4570cf6b28d4SHelge Deller     return nullify_end(ctx);
457138193127SRichard Henderson #endif
457215da177bSSven Schnelle }
457338193127SRichard Henderson 
457438193127SRichard Henderson /* Print char in %r26 to first serial console, used by SeaBIOS-hppa */
457538193127SRichard Henderson static bool trans_diag_cout(DisasContext *ctx, arg_diag_cout *a)
457638193127SRichard Henderson {
457738193127SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
457838193127SRichard Henderson #ifndef CONFIG_USER_ONLY
4579dbca0835SHelge Deller     nullify_over(ctx);
4580dbca0835SHelge Deller     gen_helper_diag_console_output(tcg_env);
4581dbca0835SHelge Deller     return nullify_end(ctx);
4582ad75a51eSRichard Henderson #endif
458338193127SRichard Henderson }
458438193127SRichard Henderson 
45853bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa1(DisasContext *ctx, arg_empty *a)
45863bdf2081SHelge Deller {
45873bdf2081SHelge Deller     return !ctx->is_pa20 && do_getshadowregs(ctx);
45883bdf2081SHelge Deller }
45893bdf2081SHelge Deller 
45903bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa2(DisasContext *ctx, arg_empty *a)
45913bdf2081SHelge Deller {
45923bdf2081SHelge Deller     return ctx->is_pa20 && do_getshadowregs(ctx);
45933bdf2081SHelge Deller }
45943bdf2081SHelge Deller 
45953bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa1(DisasContext *ctx, arg_empty *a)
45963bdf2081SHelge Deller {
45973bdf2081SHelge Deller     return !ctx->is_pa20 && do_putshadowregs(ctx);
45983bdf2081SHelge Deller }
45993bdf2081SHelge Deller 
46003bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa2(DisasContext *ctx, arg_empty *a)
46013bdf2081SHelge Deller {
46023bdf2081SHelge Deller     return ctx->is_pa20 && do_putshadowregs(ctx);
46033bdf2081SHelge Deller }
46043bdf2081SHelge Deller 
460538193127SRichard Henderson static bool trans_diag_unimp(DisasContext *ctx, arg_diag_unimp *a)
460638193127SRichard Henderson {
460738193127SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4608ad75a51eSRichard Henderson     qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i);
4609ad75a51eSRichard Henderson     return true;
4610ad75a51eSRichard Henderson }
461115da177bSSven Schnelle 
4612b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
461361766fe9SRichard Henderson {
461451b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4615f764718dSRichard Henderson     int bound;
461661766fe9SRichard Henderson 
461751b061fbSRichard Henderson     ctx->cs = cs;
4618494737b7SRichard Henderson     ctx->tb_flags = ctx->base.tb->flags;
4619bd6243a3SRichard Henderson     ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
46203d68ee7bSRichard Henderson 
46213d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY
4622c01e5dfbSHelge Deller     ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX);
46233d68ee7bSRichard Henderson     ctx->mmu_idx = MMU_USER_IDX;
46240d89cb7cSRichard Henderson     ctx->iaoq_first = ctx->base.pc_first | ctx->privilege;
46250d89cb7cSRichard Henderson     ctx->iaq_b.disp = ctx->base.tb->cs_base - ctx->base.pc_first;
4626217d1a5eSRichard Henderson     ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
4627c301f34eSRichard Henderson #else
4628494737b7SRichard Henderson     ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
4629bb67ec32SRichard Henderson     ctx->mmu_idx = (ctx->tb_flags & PSW_D
4630bb67ec32SRichard Henderson                     ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
4631451d993dSRichard Henderson                     : ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX);
46323d68ee7bSRichard Henderson 
4633c301f34eSRichard Henderson     /* Recover the IAOQ values from the GVA + PRIV.  */
4634c301f34eSRichard Henderson     uint64_t cs_base = ctx->base.tb->cs_base;
4635c301f34eSRichard Henderson     uint64_t iasq_f = cs_base & ~0xffffffffull;
4636c301f34eSRichard Henderson     int32_t diff = cs_base;
4637c301f34eSRichard Henderson 
46380d89cb7cSRichard Henderson     ctx->iaoq_first = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
46390d89cb7cSRichard Henderson 
4640bc921866SRichard Henderson     if (diff) {
46410d89cb7cSRichard Henderson         ctx->iaq_b.disp = diff;
4642bc921866SRichard Henderson     } else {
4643bc921866SRichard Henderson         ctx->iaq_b.base = cpu_iaoq_b;
4644bc921866SRichard Henderson         ctx->iaq_b.space = cpu_iasq_b;
4645bc921866SRichard Henderson     }
4646c301f34eSRichard Henderson #endif
464761766fe9SRichard Henderson 
4648a4db4a78SRichard Henderson     ctx->zero = tcg_constant_i64(0);
4649a4db4a78SRichard Henderson 
46503d68ee7bSRichard Henderson     /* Bound the number of instructions by those left on the page.  */
46513d68ee7bSRichard Henderson     bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
4652b542683dSEmilio G. Cota     ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
465361766fe9SRichard Henderson }
465461766fe9SRichard Henderson 
465551b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
465651b061fbSRichard Henderson {
465751b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
465861766fe9SRichard Henderson 
46593d68ee7bSRichard Henderson     /* Seed the nullification status from PSW[N], as saved in TB->FLAGS.  */
466051b061fbSRichard Henderson     ctx->null_cond = cond_make_f();
466151b061fbSRichard Henderson     ctx->psw_n_nonzero = false;
4662494737b7SRichard Henderson     if (ctx->tb_flags & PSW_N) {
466351b061fbSRichard Henderson         ctx->null_cond.c = TCG_COND_ALWAYS;
466451b061fbSRichard Henderson         ctx->psw_n_nonzero = true;
4665129e9cc3SRichard Henderson     }
466651b061fbSRichard Henderson     ctx->null_lab = NULL;
466761766fe9SRichard Henderson }
466861766fe9SRichard Henderson 
466951b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
467051b061fbSRichard Henderson {
467151b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
467251b061fbSRichard Henderson 
4673bc921866SRichard Henderson     tcg_debug_assert(!iaqe_variable(&ctx->iaq_f));
46740d89cb7cSRichard Henderson     tcg_gen_insn_start(ctx->iaoq_first + ctx->iaq_f.disp,
46750d89cb7cSRichard Henderson                        (iaqe_variable(&ctx->iaq_b) ? -1 :
46760d89cb7cSRichard Henderson                         ctx->iaoq_first + ctx->iaq_b.disp), 0);
467724638bd1SRichard Henderson     ctx->insn_start_updated = false;
467851b061fbSRichard Henderson }
467951b061fbSRichard Henderson 
468051b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
468151b061fbSRichard Henderson {
468251b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4683b77af26eSRichard Henderson     CPUHPPAState *env = cpu_env(cs);
468451b061fbSRichard Henderson     DisasJumpType ret;
468551b061fbSRichard Henderson 
468651b061fbSRichard Henderson     /* Execute one insn.  */
4687ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4688c301f34eSRichard Henderson     if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
468931234768SRichard Henderson         do_page_zero(ctx);
469031234768SRichard Henderson         ret = ctx->base.is_jmp;
4691869051eaSRichard Henderson         assert(ret != DISAS_NEXT);
4692ba1d0b44SRichard Henderson     } else
4693ba1d0b44SRichard Henderson #endif
4694ba1d0b44SRichard Henderson     {
469561766fe9SRichard Henderson         /* Always fetch the insn, even if nullified, so that we check
469661766fe9SRichard Henderson            the page permissions for execute.  */
46974e116893SIlya Leoshkevich         uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next);
469861766fe9SRichard Henderson 
4699bc921866SRichard Henderson         /*
4700bc921866SRichard Henderson          * Set up the IA queue for the next insn.
4701bc921866SRichard Henderson          * This will be overwritten by a branch.
4702bc921866SRichard Henderson          */
4703bc921866SRichard Henderson         ctx->iaq_n = NULL;
4704bc921866SRichard Henderson         memset(&ctx->iaq_j, 0, sizeof(ctx->iaq_j));
470561766fe9SRichard Henderson 
470651b061fbSRichard Henderson         if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
470751b061fbSRichard Henderson             ctx->null_cond.c = TCG_COND_NEVER;
4708869051eaSRichard Henderson             ret = DISAS_NEXT;
4709129e9cc3SRichard Henderson         } else {
47101a19da0dSRichard Henderson             ctx->insn = insn;
471131274b46SRichard Henderson             if (!decode(ctx, insn)) {
471231274b46SRichard Henderson                 gen_illegal(ctx);
471331274b46SRichard Henderson             }
471431234768SRichard Henderson             ret = ctx->base.is_jmp;
471551b061fbSRichard Henderson             assert(ctx->null_lab == NULL);
4716129e9cc3SRichard Henderson         }
471761766fe9SRichard Henderson     }
471861766fe9SRichard Henderson 
4719dbdccbdfSRichard Henderson     /* If the TranslationBlock must end, do so. */
4720dbdccbdfSRichard Henderson     ctx->base.pc_next += 4;
4721dbdccbdfSRichard Henderson     if (ret != DISAS_NEXT) {
4722dbdccbdfSRichard Henderson         return;
472361766fe9SRichard Henderson     }
4724dbdccbdfSRichard Henderson     /* Note this also detects a priority change. */
4725bc921866SRichard Henderson     if (iaqe_variable(&ctx->iaq_b)
4726bc921866SRichard Henderson         || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) {
4727dbdccbdfSRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
4728dbdccbdfSRichard Henderson         return;
4729129e9cc3SRichard Henderson     }
4730dbdccbdfSRichard Henderson 
4731dbdccbdfSRichard Henderson     /*
4732dbdccbdfSRichard Henderson      * Advance the insn queue.
4733dbdccbdfSRichard Henderson      * The only exit now is DISAS_TOO_MANY from the translator loop.
4734dbdccbdfSRichard Henderson      */
4735bc921866SRichard Henderson     ctx->iaq_f.disp = ctx->iaq_b.disp;
4736bc921866SRichard Henderson     if (!ctx->iaq_n) {
4737bc921866SRichard Henderson         ctx->iaq_b.disp += 4;
4738bc921866SRichard Henderson         return;
4739bc921866SRichard Henderson     }
4740bc921866SRichard Henderson     /*
4741bc921866SRichard Henderson      * If IAQ_Next is variable in any way, we need to copy into the
4742bc921866SRichard Henderson      * IAQ_Back globals, in case the next insn raises an exception.
4743bc921866SRichard Henderson      */
4744bc921866SRichard Henderson     if (ctx->iaq_n->base) {
4745bc921866SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaq_n);
4746bc921866SRichard Henderson         ctx->iaq_b.base = cpu_iaoq_b;
4747bc921866SRichard Henderson         ctx->iaq_b.disp = 0;
47480dcd6640SRichard Henderson     } else {
4749bc921866SRichard Henderson         ctx->iaq_b.disp = ctx->iaq_n->disp;
47500dcd6640SRichard Henderson     }
4751bc921866SRichard Henderson     if (ctx->iaq_n->space) {
4752bc921866SRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, ctx->iaq_n->space);
4753bc921866SRichard Henderson         ctx->iaq_b.space = cpu_iasq_b;
4754142faf5fSRichard Henderson     }
475561766fe9SRichard Henderson }
475661766fe9SRichard Henderson 
475751b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
475851b061fbSRichard Henderson {
475951b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4760e1b5a5edSRichard Henderson     DisasJumpType is_jmp = ctx->base.is_jmp;
4761dbdccbdfSRichard Henderson     /* Assume the insn queue has not been advanced. */
4762bc921866SRichard Henderson     DisasIAQE *f = &ctx->iaq_b;
4763bc921866SRichard Henderson     DisasIAQE *b = ctx->iaq_n;
476451b061fbSRichard Henderson 
4765e1b5a5edSRichard Henderson     switch (is_jmp) {
4766869051eaSRichard Henderson     case DISAS_NORETURN:
476761766fe9SRichard Henderson         break;
476851b061fbSRichard Henderson     case DISAS_TOO_MANY:
4769dbdccbdfSRichard Henderson         /* The insn queue has not been advanced. */
4770bc921866SRichard Henderson         f = &ctx->iaq_f;
4771bc921866SRichard Henderson         b = &ctx->iaq_b;
477261766fe9SRichard Henderson         /* FALLTHRU */
4773dbdccbdfSRichard Henderson     case DISAS_IAQ_N_STALE:
4774bc921866SRichard Henderson         if (use_goto_tb(ctx, f, b)
4775dbdccbdfSRichard Henderson             && (ctx->null_cond.c == TCG_COND_NEVER
4776dbdccbdfSRichard Henderson                 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
4777dbdccbdfSRichard Henderson             nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
4778bc921866SRichard Henderson             gen_goto_tb(ctx, 0, f, b);
47798532a14eSRichard Henderson             break;
478061766fe9SRichard Henderson         }
4781c5d0aec2SRichard Henderson         /* FALLTHRU */
4782dbdccbdfSRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
4783bc921866SRichard Henderson         install_iaq_entries(ctx, f, b);
4784dbdccbdfSRichard Henderson         nullify_save(ctx);
4785dbdccbdfSRichard Henderson         if (is_jmp == DISAS_IAQ_N_STALE_EXIT) {
4786dbdccbdfSRichard Henderson             tcg_gen_exit_tb(NULL, 0);
4787dbdccbdfSRichard Henderson             break;
4788dbdccbdfSRichard Henderson         }
4789dbdccbdfSRichard Henderson         /* FALLTHRU */
4790dbdccbdfSRichard Henderson     case DISAS_IAQ_N_UPDATED:
4791dbdccbdfSRichard Henderson         tcg_gen_lookup_and_goto_ptr();
4792dbdccbdfSRichard Henderson         break;
4793c5d0aec2SRichard Henderson     case DISAS_EXIT:
4794c5d0aec2SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
479561766fe9SRichard Henderson         break;
479661766fe9SRichard Henderson     default:
479751b061fbSRichard Henderson         g_assert_not_reached();
479861766fe9SRichard Henderson     }
479951b061fbSRichard Henderson }
480061766fe9SRichard Henderson 
48018eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase,
48028eb806a7SRichard Henderson                               CPUState *cs, FILE *logfile)
480351b061fbSRichard Henderson {
4804c301f34eSRichard Henderson     target_ulong pc = dcbase->pc_first;
480561766fe9SRichard Henderson 
4806ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4807ba1d0b44SRichard Henderson     switch (pc) {
48087ad439dfSRichard Henderson     case 0x00:
48098eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000000:  (null)\n");
4810ba1d0b44SRichard Henderson         return;
48117ad439dfSRichard Henderson     case 0xb0:
48128eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000b0:  light-weight-syscall\n");
4813ba1d0b44SRichard Henderson         return;
48147ad439dfSRichard Henderson     case 0xe0:
48158eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000e0:  set-thread-pointer-syscall\n");
4816ba1d0b44SRichard Henderson         return;
48177ad439dfSRichard Henderson     case 0x100:
48188eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000100:  syscall\n");
4819ba1d0b44SRichard Henderson         return;
48207ad439dfSRichard Henderson     }
4821ba1d0b44SRichard Henderson #endif
4822ba1d0b44SRichard Henderson 
48238eb806a7SRichard Henderson     fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
48248eb806a7SRichard Henderson     target_disas(logfile, cs, pc, dcbase->tb->size);
482561766fe9SRichard Henderson }
482651b061fbSRichard Henderson 
482751b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = {
482851b061fbSRichard Henderson     .init_disas_context = hppa_tr_init_disas_context,
482951b061fbSRichard Henderson     .tb_start           = hppa_tr_tb_start,
483051b061fbSRichard Henderson     .insn_start         = hppa_tr_insn_start,
483151b061fbSRichard Henderson     .translate_insn     = hppa_tr_translate_insn,
483251b061fbSRichard Henderson     .tb_stop            = hppa_tr_tb_stop,
483351b061fbSRichard Henderson     .disas_log          = hppa_tr_disas_log,
483451b061fbSRichard Henderson };
483551b061fbSRichard Henderson 
4836597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
483732f0c394SAnton Johansson                            vaddr pc, void *host_pc)
483851b061fbSRichard Henderson {
4839bc921866SRichard Henderson     DisasContext ctx = { };
4840306c8721SRichard Henderson     translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
484161766fe9SRichard Henderson }
4842