xref: /openbmc/qemu/target/hppa/translate.c (revision b041ec9d7173ec893c1a5bc0bfd25fe860b4fcb0)
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 
3484c42fd0dSRichard 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 
3544c42fd0dSRichard Henderson static DisasCond cond_make_ti(TCGCond c, TCGv_i64 a0, uint64_t imm)
3554fe9533aSRichard Henderson {
3564c42fd0dSRichard Henderson     return cond_make_tt(c, a0, tcg_constant_i64(imm));
357b47a4a02SSven Schnelle }
358b47a4a02SSven Schnelle 
3594c42fd0dSRichard 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);
3634c42fd0dSRichard Henderson     return cond_make_ti(c, tmp, imm);
364129e9cc3SRichard Henderson }
365129e9cc3SRichard Henderson 
3664c42fd0dSRichard 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);
3734c42fd0dSRichard 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 {
779d6d46be1SRichard Henderson     TCGCond sign_cond, zero_cond;
780d6d46be1SRichard Henderson     uint64_t sign_imm, zero_imm;
781b2167459SRichard Henderson     DisasCond cond;
7826fd0c7bcSRichard Henderson     TCGv_i64 tmp;
783b2167459SRichard Henderson 
784d6d46be1SRichard Henderson     if (d) {
785d6d46be1SRichard Henderson         /* 64-bit condition. */
786d6d46be1SRichard Henderson         sign_imm = 0;
787d6d46be1SRichard Henderson         sign_cond = TCG_COND_LT;
788d6d46be1SRichard Henderson         zero_imm = 0;
789d6d46be1SRichard Henderson         zero_cond = TCG_COND_EQ;
790d6d46be1SRichard Henderson     } else {
791d6d46be1SRichard Henderson         /* 32-bit condition. */
792d6d46be1SRichard Henderson         sign_imm = 1ull << 31;
793d6d46be1SRichard Henderson         sign_cond = TCG_COND_TSTNE;
794d6d46be1SRichard Henderson         zero_imm = UINT32_MAX;
795d6d46be1SRichard Henderson         zero_cond = TCG_COND_TSTEQ;
796d6d46be1SRichard Henderson     }
797d6d46be1SRichard Henderson 
798b2167459SRichard Henderson     switch (cf >> 1) {
799b47a4a02SSven Schnelle     case 0: /* Never / TR    (0 / 1) */
800b2167459SRichard Henderson         cond = cond_make_f();
801b2167459SRichard Henderson         break;
802b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
803d6d46be1SRichard Henderson         cond = cond_make_vi(zero_cond, res, zero_imm);
804b2167459SRichard Henderson         break;
805b47a4a02SSven Schnelle     case 2: /* < / >=        (N ^ V / !(N ^ V) */
806aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
8076fd0c7bcSRichard Henderson         tcg_gen_xor_i64(tmp, res, sv);
808d6d46be1SRichard Henderson         cond = cond_make_ti(sign_cond, tmp, sign_imm);
809b2167459SRichard Henderson         break;
810b47a4a02SSven Schnelle     case 3: /* <= / >        (N ^ V) | Z / !((N ^ V) | Z) */
811b47a4a02SSven Schnelle         /*
812b47a4a02SSven Schnelle          * Simplify:
813b47a4a02SSven Schnelle          *   (N ^ V) | Z
814b47a4a02SSven Schnelle          *   ((res < 0) ^ (sv < 0)) | !res
815b47a4a02SSven Schnelle          *   ((res ^ sv) < 0) | !res
816d6d46be1SRichard Henderson          *   ((res ^ sv) < 0 ? 1 : !res)
817d6d46be1SRichard Henderson          *   !((res ^ sv) < 0 ? 0 : res)
818b47a4a02SSven Schnelle          */
819aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
820d6d46be1SRichard Henderson         tcg_gen_xor_i64(tmp, res, sv);
821d6d46be1SRichard Henderson         tcg_gen_movcond_i64(sign_cond, tmp,
822d6d46be1SRichard Henderson                             tmp, tcg_constant_i64(sign_imm),
823d6d46be1SRichard Henderson                             ctx->zero, res);
824d6d46be1SRichard Henderson         cond = cond_make_ti(zero_cond, tmp, zero_imm);
825b2167459SRichard Henderson         break;
826fe2d066aSRichard Henderson     case 4: /* NUV / UV      (!UV / UV) */
8274c42fd0dSRichard Henderson         cond = cond_make_vi(TCG_COND_EQ, uv, 0);
828b2167459SRichard Henderson         break;
829fe2d066aSRichard Henderson     case 5: /* ZNV / VNZ     (!UV | Z / UV & !Z) */
830aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
831fe2d066aSRichard Henderson         tcg_gen_movcond_i64(TCG_COND_EQ, tmp, uv, ctx->zero, ctx->zero, res);
832d6d46be1SRichard Henderson         cond = cond_make_ti(zero_cond, tmp, zero_imm);
833b2167459SRichard Henderson         break;
834b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
835d6d46be1SRichard Henderson         cond = cond_make_vi(sign_cond, sv, sign_imm);
836b2167459SRichard Henderson         break;
837b2167459SRichard Henderson     case 7: /* OD / EV */
838d6d46be1SRichard Henderson         cond = cond_make_vi(TCG_COND_TSTNE, res, 1);
839b2167459SRichard Henderson         break;
840b2167459SRichard Henderson     default:
841b2167459SRichard Henderson         g_assert_not_reached();
842b2167459SRichard Henderson     }
843b2167459SRichard Henderson     if (cf & 1) {
844b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
845b2167459SRichard Henderson     }
846b2167459SRichard Henderson 
847b2167459SRichard Henderson     return cond;
848b2167459SRichard Henderson }
849b2167459SRichard Henderson 
850b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
851b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
852b2167459SRichard Henderson    deleted as unused.  */
853b2167459SRichard Henderson 
8544fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d,
8556fd0c7bcSRichard Henderson                              TCGv_i64 res, TCGv_i64 in1,
8566fd0c7bcSRichard Henderson                              TCGv_i64 in2, TCGv_i64 sv)
857b2167459SRichard Henderson {
8584fe9533aSRichard Henderson     TCGCond tc;
8594fe9533aSRichard Henderson     bool ext_uns;
860b2167459SRichard Henderson 
861b2167459SRichard Henderson     switch (cf >> 1) {
862b2167459SRichard Henderson     case 1: /* = / <> */
8634fe9533aSRichard Henderson         tc = TCG_COND_EQ;
8644fe9533aSRichard Henderson         ext_uns = true;
865b2167459SRichard Henderson         break;
866b2167459SRichard Henderson     case 2: /* < / >= */
8674fe9533aSRichard Henderson         tc = TCG_COND_LT;
8684fe9533aSRichard Henderson         ext_uns = false;
869b2167459SRichard Henderson         break;
870b2167459SRichard Henderson     case 3: /* <= / > */
8714fe9533aSRichard Henderson         tc = TCG_COND_LE;
8724fe9533aSRichard Henderson         ext_uns = false;
873b2167459SRichard Henderson         break;
874b2167459SRichard Henderson     case 4: /* << / >>= */
8754fe9533aSRichard Henderson         tc = TCG_COND_LTU;
8764fe9533aSRichard Henderson         ext_uns = true;
877b2167459SRichard Henderson         break;
878b2167459SRichard Henderson     case 5: /* <<= / >> */
8794fe9533aSRichard Henderson         tc = TCG_COND_LEU;
8804fe9533aSRichard Henderson         ext_uns = true;
881b2167459SRichard Henderson         break;
882b2167459SRichard Henderson     default:
883a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, sv);
884b2167459SRichard Henderson     }
885b2167459SRichard Henderson 
8864fe9533aSRichard Henderson     if (cf & 1) {
8874fe9533aSRichard Henderson         tc = tcg_invert_cond(tc);
8884fe9533aSRichard Henderson     }
88982d0c831SRichard Henderson     if (!d) {
890aac0f603SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
891aac0f603SRichard Henderson         TCGv_i64 t2 = tcg_temp_new_i64();
8924fe9533aSRichard Henderson 
8934fe9533aSRichard Henderson         if (ext_uns) {
8946fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t1, in1);
8956fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t2, in2);
8964fe9533aSRichard Henderson         } else {
8976fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t1, in1);
8986fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t2, in2);
8994fe9533aSRichard Henderson         }
9004c42fd0dSRichard Henderson         return cond_make_tt(tc, t1, t2);
9014fe9533aSRichard Henderson     }
9024c42fd0dSRichard Henderson     return cond_make_vv(tc, in1, in2);
903b2167459SRichard Henderson }
904b2167459SRichard Henderson 
905df0232feSRichard Henderson /*
906df0232feSRichard Henderson  * Similar, but for logicals, where the carry and overflow bits are not
907df0232feSRichard Henderson  * computed, and use of them is undefined.
908df0232feSRichard Henderson  *
909df0232feSRichard Henderson  * Undefined or not, hardware does not trap.  It seems reasonable to
910df0232feSRichard Henderson  * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's
911df0232feSRichard Henderson  * how cases c={2,3} are treated.
912df0232feSRichard Henderson  */
913b2167459SRichard Henderson 
914b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d,
9156fd0c7bcSRichard Henderson                              TCGv_i64 res)
916b2167459SRichard Henderson {
917b5af8423SRichard Henderson     TCGCond tc;
918fbe65c64SRichard Henderson     uint64_t imm;
919a751eb31SRichard Henderson 
920fbe65c64SRichard Henderson     switch (cf >> 1) {
921fbe65c64SRichard Henderson     case 0:  /* never / always */
922fbe65c64SRichard Henderson     case 4:  /* undef, C */
923fbe65c64SRichard Henderson     case 5:  /* undef, C & !Z */
924fbe65c64SRichard Henderson     case 6:  /* undef, V */
925fbe65c64SRichard Henderson         return cf & 1 ? cond_make_t() : cond_make_f();
926fbe65c64SRichard Henderson     case 1:  /* == / <> */
927fbe65c64SRichard Henderson         tc = d ? TCG_COND_EQ : TCG_COND_TSTEQ;
928fbe65c64SRichard Henderson         imm = d ? 0 : UINT32_MAX;
929b5af8423SRichard Henderson         break;
930fbe65c64SRichard Henderson     case 2:  /* < / >= */
931fbe65c64SRichard Henderson         tc = d ? TCG_COND_LT : TCG_COND_TSTNE;
932fbe65c64SRichard Henderson         imm = d ? 0 : 1ull << 31;
933b5af8423SRichard Henderson         break;
934fbe65c64SRichard Henderson     case 3:  /* <= / > */
935fbe65c64SRichard Henderson         tc = cf & 1 ? TCG_COND_GT : TCG_COND_LE;
93682d0c831SRichard Henderson         if (!d) {
937aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
9386fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, res);
9394c42fd0dSRichard Henderson             return cond_make_ti(tc, tmp, 0);
940b5af8423SRichard Henderson         }
9414c42fd0dSRichard Henderson         return cond_make_vi(tc, res, 0);
942fbe65c64SRichard Henderson     case 7: /* OD / EV */
943fbe65c64SRichard Henderson         tc = TCG_COND_TSTNE;
944fbe65c64SRichard Henderson         imm = 1;
945fbe65c64SRichard Henderson         break;
946fbe65c64SRichard Henderson     default:
947fbe65c64SRichard Henderson         g_assert_not_reached();
948fbe65c64SRichard Henderson     }
949fbe65c64SRichard Henderson     if (cf & 1) {
950fbe65c64SRichard Henderson         tc = tcg_invert_cond(tc);
951fbe65c64SRichard Henderson     }
952fbe65c64SRichard Henderson     return cond_make_vi(tc, res, imm);
953b2167459SRichard Henderson }
954b2167459SRichard Henderson 
95598cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
95698cd9ca7SRichard Henderson 
9574fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d,
9586fd0c7bcSRichard Henderson                              TCGv_i64 res)
95998cd9ca7SRichard Henderson {
96098cd9ca7SRichard Henderson     unsigned c, f;
96198cd9ca7SRichard Henderson 
96298cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
96398cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
96498cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
96598cd9ca7SRichard Henderson     c = orig & 3;
96698cd9ca7SRichard Henderson     if (c == 3) {
96798cd9ca7SRichard Henderson         c = 7;
96898cd9ca7SRichard Henderson     }
96998cd9ca7SRichard Henderson     f = (orig & 4) / 4;
97098cd9ca7SRichard Henderson 
971b5af8423SRichard Henderson     return do_log_cond(ctx, c * 2 + f, d, res);
97298cd9ca7SRichard Henderson }
97398cd9ca7SRichard Henderson 
97446bb3d46SRichard Henderson /* Similar, but for unit zero conditions.  */
97546bb3d46SRichard Henderson static DisasCond do_unit_zero_cond(unsigned cf, bool d, TCGv_i64 res)
976b2167459SRichard Henderson {
97746bb3d46SRichard Henderson     TCGv_i64 tmp;
978c53e401eSRichard Henderson     uint64_t d_repl = d ? 0x0000000100000001ull : 1;
97946bb3d46SRichard Henderson     uint64_t ones = 0, sgns = 0;
980b2167459SRichard Henderson 
981b2167459SRichard Henderson     switch (cf >> 1) {
982578b8132SSven Schnelle     case 1: /* SBW / NBW */
983578b8132SSven Schnelle         if (d) {
98446bb3d46SRichard Henderson             ones = d_repl;
98546bb3d46SRichard Henderson             sgns = d_repl << 31;
986578b8132SSven Schnelle         }
987578b8132SSven Schnelle         break;
988b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
98946bb3d46SRichard Henderson         ones = d_repl * 0x01010101u;
99046bb3d46SRichard Henderson         sgns = ones << 7;
99146bb3d46SRichard Henderson         break;
99246bb3d46SRichard Henderson     case 3: /* SHZ / NHZ */
99346bb3d46SRichard Henderson         ones = d_repl * 0x00010001u;
99446bb3d46SRichard Henderson         sgns = ones << 15;
99546bb3d46SRichard Henderson         break;
99646bb3d46SRichard Henderson     }
99746bb3d46SRichard Henderson     if (ones == 0) {
99846bb3d46SRichard Henderson         /* Undefined, or 0/1 (never/always). */
99946bb3d46SRichard Henderson         return cf & 1 ? cond_make_t() : cond_make_f();
100046bb3d46SRichard Henderson     }
100146bb3d46SRichard Henderson 
100246bb3d46SRichard Henderson     /*
100346bb3d46SRichard Henderson      * See hasless(v,1) from
1004b2167459SRichard Henderson      * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
1005b2167459SRichard Henderson      */
1006aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
100746bb3d46SRichard Henderson     tcg_gen_subi_i64(tmp, res, ones);
10086fd0c7bcSRichard Henderson     tcg_gen_andc_i64(tmp, tmp, res);
1009b2167459SRichard Henderson 
101025f97be7SRichard Henderson     return cond_make_ti(cf & 1 ? TCG_COND_TSTEQ : TCG_COND_TSTNE, tmp, sgns);
1011b2167459SRichard Henderson }
1012b2167459SRichard Henderson 
10136fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d,
10146fd0c7bcSRichard Henderson                           TCGv_i64 cb, TCGv_i64 cb_msb)
101572ca8753SRichard Henderson {
101682d0c831SRichard Henderson     if (!d) {
1017aac0f603SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
10186fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, cb, 32, 1);
101972ca8753SRichard Henderson         return t;
102072ca8753SRichard Henderson     }
102172ca8753SRichard Henderson     return cb_msb;
102272ca8753SRichard Henderson }
102372ca8753SRichard Henderson 
10246fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d)
102572ca8753SRichard Henderson {
102672ca8753SRichard Henderson     return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb);
102772ca8753SRichard Henderson }
102872ca8753SRichard Henderson 
1029b2167459SRichard Henderson /* Compute signed overflow for addition.  */
10306fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res,
1031f8f5986eSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2,
1032f8f5986eSRichard Henderson                           TCGv_i64 orig_in1, int shift, bool d)
1033b2167459SRichard Henderson {
1034aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
1035aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
1036b2167459SRichard Henderson 
10376fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
10386fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
10396fd0c7bcSRichard Henderson     tcg_gen_andc_i64(sv, sv, tmp);
1040b2167459SRichard Henderson 
1041f8f5986eSRichard Henderson     switch (shift) {
1042f8f5986eSRichard Henderson     case 0:
1043f8f5986eSRichard Henderson         break;
1044f8f5986eSRichard Henderson     case 1:
1045f8f5986eSRichard Henderson         /* Shift left by one and compare the sign. */
1046f8f5986eSRichard Henderson         tcg_gen_add_i64(tmp, orig_in1, orig_in1);
1047f8f5986eSRichard Henderson         tcg_gen_xor_i64(tmp, tmp, orig_in1);
1048f8f5986eSRichard Henderson         /* Incorporate into the overflow. */
1049f8f5986eSRichard Henderson         tcg_gen_or_i64(sv, sv, tmp);
1050f8f5986eSRichard Henderson         break;
1051f8f5986eSRichard Henderson     default:
1052f8f5986eSRichard Henderson         {
1053f8f5986eSRichard Henderson             int sign_bit = d ? 63 : 31;
1054f8f5986eSRichard Henderson 
1055f8f5986eSRichard Henderson             /* Compare the sign against all lower bits. */
1056f8f5986eSRichard Henderson             tcg_gen_sextract_i64(tmp, orig_in1, sign_bit, 1);
1057f8f5986eSRichard Henderson             tcg_gen_xor_i64(tmp, tmp, orig_in1);
1058f8f5986eSRichard Henderson             /*
1059f8f5986eSRichard Henderson              * If one of the bits shifting into or through the sign
1060f8f5986eSRichard Henderson              * differs, then we have overflow.
1061f8f5986eSRichard Henderson              */
1062f8f5986eSRichard Henderson             tcg_gen_extract_i64(tmp, tmp, sign_bit - shift, shift);
1063f8f5986eSRichard Henderson             tcg_gen_movcond_i64(TCG_COND_NE, sv, tmp, ctx->zero,
1064f8f5986eSRichard Henderson                                 tcg_constant_i64(-1), sv);
1065f8f5986eSRichard Henderson         }
1066f8f5986eSRichard Henderson     }
1067b2167459SRichard Henderson     return sv;
1068b2167459SRichard Henderson }
1069b2167459SRichard Henderson 
1070f8f5986eSRichard Henderson /* Compute unsigned overflow for addition.  */
1071f8f5986eSRichard Henderson static TCGv_i64 do_add_uv(DisasContext *ctx, TCGv_i64 cb, TCGv_i64 cb_msb,
1072f8f5986eSRichard Henderson                           TCGv_i64 in1, int shift, bool d)
1073f8f5986eSRichard Henderson {
1074f8f5986eSRichard Henderson     if (shift == 0) {
1075f8f5986eSRichard Henderson         return get_carry(ctx, d, cb, cb_msb);
1076f8f5986eSRichard Henderson     } else {
1077f8f5986eSRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
1078f8f5986eSRichard Henderson         tcg_gen_extract_i64(tmp, in1, (d ? 63 : 31) - shift, shift);
1079f8f5986eSRichard Henderson         tcg_gen_or_i64(tmp, tmp, get_carry(ctx, d, cb, cb_msb));
1080f8f5986eSRichard Henderson         return tmp;
1081f8f5986eSRichard Henderson     }
1082f8f5986eSRichard Henderson }
1083f8f5986eSRichard Henderson 
1084b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
10856fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res,
10866fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
1087b2167459SRichard Henderson {
1088aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
1089aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
1090b2167459SRichard Henderson 
10916fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
10926fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
10936fd0c7bcSRichard Henderson     tcg_gen_and_i64(sv, sv, tmp);
1094b2167459SRichard Henderson 
1095b2167459SRichard Henderson     return sv;
1096b2167459SRichard Henderson }
1097b2167459SRichard Henderson 
1098f8f5986eSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 orig_in1,
10996fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned shift, bool is_l,
1100faf97ba1SRichard Henderson                    bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d)
1101b2167459SRichard Henderson {
1102f8f5986eSRichard Henderson     TCGv_i64 dest, cb, cb_msb, in1, uv, sv, tmp;
1103b2167459SRichard Henderson     unsigned c = cf >> 1;
1104b2167459SRichard Henderson     DisasCond cond;
1105b2167459SRichard Henderson 
1106aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1107f764718dSRichard Henderson     cb = NULL;
1108f764718dSRichard Henderson     cb_msb = NULL;
1109b2167459SRichard Henderson 
1110f8f5986eSRichard Henderson     in1 = orig_in1;
1111b2167459SRichard Henderson     if (shift) {
1112aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
11136fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, in1, shift);
1114b2167459SRichard Henderson         in1 = tmp;
1115b2167459SRichard Henderson     }
1116b2167459SRichard Henderson 
1117b47a4a02SSven Schnelle     if (!is_l || cond_need_cb(c)) {
1118aac0f603SRichard Henderson         cb_msb = tcg_temp_new_i64();
1119aac0f603SRichard Henderson         cb = tcg_temp_new_i64();
1120bdcccc17SRichard Henderson 
1121a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero);
1122b2167459SRichard Henderson         if (is_c) {
11236fd0c7bcSRichard Henderson             tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb,
1124a4db4a78SRichard Henderson                              get_psw_carry(ctx, d), ctx->zero);
1125b2167459SRichard Henderson         }
11266fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
11276fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1128b2167459SRichard Henderson     } else {
11296fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
1130b2167459SRichard Henderson         if (is_c) {
11316fd0c7bcSRichard Henderson             tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d));
1132b2167459SRichard Henderson         }
1133b2167459SRichard Henderson     }
1134b2167459SRichard Henderson 
1135b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1136f764718dSRichard Henderson     sv = NULL;
1137b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1138f8f5986eSRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2, orig_in1, shift, d);
1139b2167459SRichard Henderson         if (is_tsv) {
1140bd1ad92cSSven Schnelle             if (!d) {
1141bd1ad92cSSven Schnelle                 tcg_gen_ext32s_i64(sv, sv);
1142bd1ad92cSSven Schnelle             }
1143ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1144b2167459SRichard Henderson         }
1145b2167459SRichard Henderson     }
1146b2167459SRichard Henderson 
1147f8f5986eSRichard Henderson     /* Compute unsigned overflow if required.  */
1148f8f5986eSRichard Henderson     uv = NULL;
1149f8f5986eSRichard Henderson     if (cond_need_cb(c)) {
1150f8f5986eSRichard Henderson         uv = do_add_uv(ctx, cb, cb_msb, orig_in1, shift, d);
1151f8f5986eSRichard Henderson     }
1152f8f5986eSRichard Henderson 
1153b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1154f8f5986eSRichard Henderson     cond = do_cond(ctx, cf, d, dest, uv, sv);
1155b2167459SRichard Henderson     if (is_tc) {
1156aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
11576fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1158ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1159b2167459SRichard Henderson     }
1160b2167459SRichard Henderson 
1161b2167459SRichard Henderson     /* Write back the result.  */
1162b2167459SRichard Henderson     if (!is_l) {
1163b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
1164b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1165b2167459SRichard Henderson     }
1166b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1167b2167459SRichard Henderson 
1168b2167459SRichard Henderson     /* Install the new nullification.  */
1169b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1170b2167459SRichard Henderson     ctx->null_cond = cond;
1171b2167459SRichard Henderson }
1172b2167459SRichard Henderson 
1173faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a,
11740c982a28SRichard Henderson                        bool is_l, bool is_tsv, bool is_tc, bool is_c)
11750c982a28SRichard Henderson {
11766fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
11770c982a28SRichard Henderson 
11780c982a28SRichard Henderson     if (a->cf) {
11790c982a28SRichard Henderson         nullify_over(ctx);
11800c982a28SRichard Henderson     }
11810c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
11820c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1183faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l,
1184faf97ba1SRichard Henderson            is_tsv, is_tc, is_c, a->cf, a->d);
11850c982a28SRichard Henderson     return nullify_end(ctx);
11860c982a28SRichard Henderson }
11870c982a28SRichard Henderson 
11880588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a,
11890588e061SRichard Henderson                        bool is_tsv, bool is_tc)
11900588e061SRichard Henderson {
11916fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
11920588e061SRichard Henderson 
11930588e061SRichard Henderson     if (a->cf) {
11940588e061SRichard Henderson         nullify_over(ctx);
11950588e061SRichard Henderson     }
11966fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
11970588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
1198faf97ba1SRichard Henderson     /* All ADDI conditions are 32-bit. */
1199faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false);
12000588e061SRichard Henderson     return nullify_end(ctx);
12010588e061SRichard Henderson }
12020588e061SRichard Henderson 
12036fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12046fd0c7bcSRichard Henderson                    TCGv_i64 in2, bool is_tsv, bool is_b,
120563c427c6SRichard Henderson                    bool is_tc, unsigned cf, bool d)
1206b2167459SRichard Henderson {
1207a4db4a78SRichard Henderson     TCGv_i64 dest, sv, cb, cb_msb, tmp;
1208b2167459SRichard Henderson     unsigned c = cf >> 1;
1209b2167459SRichard Henderson     DisasCond cond;
1210b2167459SRichard Henderson 
1211aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1212aac0f603SRichard Henderson     cb = tcg_temp_new_i64();
1213aac0f603SRichard Henderson     cb_msb = tcg_temp_new_i64();
1214b2167459SRichard Henderson 
1215b2167459SRichard Henderson     if (is_b) {
1216b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
12176fd0c7bcSRichard Henderson         tcg_gen_not_i64(cb, in2);
1218a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero,
1219a4db4a78SRichard Henderson                          get_psw_carry(ctx, d), ctx->zero);
1220a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero);
12216fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, in1);
12226fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1223b2167459SRichard Henderson     } else {
1224bdcccc17SRichard Henderson         /*
1225bdcccc17SRichard Henderson          * DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
1226bdcccc17SRichard Henderson          * operations by seeding the high word with 1 and subtracting.
1227bdcccc17SRichard Henderson          */
12286fd0c7bcSRichard Henderson         TCGv_i64 one = tcg_constant_i64(1);
1229a4db4a78SRichard Henderson         tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero);
12306fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(cb, in1, in2);
12316fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1232b2167459SRichard Henderson     }
1233b2167459SRichard Henderson 
1234b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1235f764718dSRichard Henderson     sv = NULL;
1236b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1237b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1238b2167459SRichard Henderson         if (is_tsv) {
1239bd1ad92cSSven Schnelle             if (!d) {
1240bd1ad92cSSven Schnelle                 tcg_gen_ext32s_i64(sv, sv);
1241bd1ad92cSSven Schnelle             }
1242ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1243b2167459SRichard Henderson         }
1244b2167459SRichard Henderson     }
1245b2167459SRichard Henderson 
1246b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
1247b2167459SRichard Henderson     if (!is_b) {
12484fe9533aSRichard Henderson         cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1249b2167459SRichard Henderson     } else {
1250a751eb31SRichard Henderson         cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv);
1251b2167459SRichard Henderson     }
1252b2167459SRichard Henderson 
1253b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1254b2167459SRichard Henderson     if (is_tc) {
1255aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
12566fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1257ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1258b2167459SRichard Henderson     }
1259b2167459SRichard Henderson 
1260b2167459SRichard Henderson     /* Write back the result.  */
1261b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
1262b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1263b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1264b2167459SRichard Henderson 
1265b2167459SRichard Henderson     /* Install the new nullification.  */
1266b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1267b2167459SRichard Henderson     ctx->null_cond = cond;
1268b2167459SRichard Henderson }
1269b2167459SRichard Henderson 
127063c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a,
12710c982a28SRichard Henderson                        bool is_tsv, bool is_b, bool is_tc)
12720c982a28SRichard Henderson {
12736fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
12740c982a28SRichard Henderson 
12750c982a28SRichard Henderson     if (a->cf) {
12760c982a28SRichard Henderson         nullify_over(ctx);
12770c982a28SRichard Henderson     }
12780c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
12790c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
128063c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d);
12810c982a28SRichard Henderson     return nullify_end(ctx);
12820c982a28SRichard Henderson }
12830c982a28SRichard Henderson 
12840588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv)
12850588e061SRichard Henderson {
12866fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
12870588e061SRichard Henderson 
12880588e061SRichard Henderson     if (a->cf) {
12890588e061SRichard Henderson         nullify_over(ctx);
12900588e061SRichard Henderson     }
12916fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
12920588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
129363c427c6SRichard Henderson     /* All SUBI conditions are 32-bit. */
129463c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false);
12950588e061SRichard Henderson     return nullify_end(ctx);
12960588e061SRichard Henderson }
12970588e061SRichard Henderson 
12986fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12996fd0c7bcSRichard Henderson                       TCGv_i64 in2, unsigned cf, bool d)
1300b2167459SRichard Henderson {
13016fd0c7bcSRichard Henderson     TCGv_i64 dest, sv;
1302b2167459SRichard Henderson     DisasCond cond;
1303b2167459SRichard Henderson 
1304aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
13056fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
1306b2167459SRichard Henderson 
1307b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1308f764718dSRichard Henderson     sv = NULL;
1309b47a4a02SSven Schnelle     if (cond_need_sv(cf >> 1)) {
1310b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1311b2167459SRichard Henderson     }
1312b2167459SRichard Henderson 
1313b2167459SRichard Henderson     /* Form the condition for the compare.  */
13144fe9533aSRichard Henderson     cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1315b2167459SRichard Henderson 
1316b2167459SRichard Henderson     /* Clear.  */
13176fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
1318b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1319b2167459SRichard Henderson 
1320b2167459SRichard Henderson     /* Install the new nullification.  */
1321b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1322b2167459SRichard Henderson     ctx->null_cond = cond;
1323b2167459SRichard Henderson }
1324b2167459SRichard Henderson 
13256fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
13266fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned cf, bool d,
13276fd0c7bcSRichard Henderson                    void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1328b2167459SRichard Henderson {
13296fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, rt);
1330b2167459SRichard Henderson 
1331b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
1332b2167459SRichard Henderson     fn(dest, in1, in2);
1333b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1334b2167459SRichard Henderson 
1335b2167459SRichard Henderson     /* Install the new nullification.  */
1336b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1337b2167459SRichard Henderson     if (cf) {
1338b5af8423SRichard Henderson         ctx->null_cond = do_log_cond(ctx, cf, d, dest);
1339b2167459SRichard Henderson     }
1340b2167459SRichard Henderson }
1341b2167459SRichard Henderson 
1342fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a,
13436fd0c7bcSRichard Henderson                        void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
13440c982a28SRichard Henderson {
13456fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
13460c982a28SRichard Henderson 
13470c982a28SRichard Henderson     if (a->cf) {
13480c982a28SRichard Henderson         nullify_over(ctx);
13490c982a28SRichard Henderson     }
13500c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
13510c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1352fa8e3bedSRichard Henderson     do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn);
13530c982a28SRichard Henderson     return nullify_end(ctx);
13540c982a28SRichard Henderson }
13550c982a28SRichard Henderson 
135646bb3d46SRichard Henderson static void do_unit_addsub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
135746bb3d46SRichard Henderson                            TCGv_i64 in2, unsigned cf, bool d,
135846bb3d46SRichard Henderson                            bool is_tc, bool is_add)
1359b2167459SRichard Henderson {
136046bb3d46SRichard Henderson     TCGv_i64 dest = tcg_temp_new_i64();
136146bb3d46SRichard Henderson     uint64_t test_cb = 0;
1362b2167459SRichard Henderson     DisasCond cond;
1363b2167459SRichard Henderson 
136446bb3d46SRichard Henderson     /* Select which carry-out bits to test. */
136546bb3d46SRichard Henderson     switch (cf >> 1) {
136646bb3d46SRichard Henderson     case 4: /* NDC / SDC -- 4-bit carries */
136746bb3d46SRichard Henderson         test_cb = dup_const(MO_8, 0x88);
136846bb3d46SRichard Henderson         break;
136946bb3d46SRichard Henderson     case 5: /* NWC / SWC -- 32-bit carries */
137046bb3d46SRichard Henderson         if (d) {
137146bb3d46SRichard Henderson             test_cb = dup_const(MO_32, INT32_MIN);
1372b2167459SRichard Henderson         } else {
137346bb3d46SRichard Henderson             cf &= 1; /* undefined -- map to never/always */
137446bb3d46SRichard Henderson         }
137546bb3d46SRichard Henderson         break;
137646bb3d46SRichard Henderson     case 6: /* NBC / SBC -- 8-bit carries */
137746bb3d46SRichard Henderson         test_cb = dup_const(MO_8, INT8_MIN);
137846bb3d46SRichard Henderson         break;
137946bb3d46SRichard Henderson     case 7: /* NHC / SHC -- 16-bit carries */
138046bb3d46SRichard Henderson         test_cb = dup_const(MO_16, INT16_MIN);
138146bb3d46SRichard Henderson         break;
138246bb3d46SRichard Henderson     }
138346bb3d46SRichard Henderson     if (!d) {
138446bb3d46SRichard Henderson         test_cb = (uint32_t)test_cb;
138546bb3d46SRichard Henderson     }
1386b2167459SRichard Henderson 
138746bb3d46SRichard Henderson     if (!test_cb) {
138846bb3d46SRichard Henderson         /* No need to compute carries if we don't need to test them. */
138946bb3d46SRichard Henderson         if (is_add) {
139046bb3d46SRichard Henderson             tcg_gen_add_i64(dest, in1, in2);
139146bb3d46SRichard Henderson         } else {
139246bb3d46SRichard Henderson             tcg_gen_sub_i64(dest, in1, in2);
139346bb3d46SRichard Henderson         }
139446bb3d46SRichard Henderson         cond = do_unit_zero_cond(cf, d, dest);
139546bb3d46SRichard Henderson     } else {
139646bb3d46SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
139746bb3d46SRichard Henderson 
139846bb3d46SRichard Henderson         if (d) {
139946bb3d46SRichard Henderson             TCGv_i64 cb_msb = tcg_temp_new_i64();
140046bb3d46SRichard Henderson             if (is_add) {
140146bb3d46SRichard Henderson                 tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero);
140246bb3d46SRichard Henderson                 tcg_gen_xor_i64(cb, in1, in2);
140346bb3d46SRichard Henderson             } else {
140446bb3d46SRichard Henderson                 /* See do_sub, !is_b. */
140546bb3d46SRichard Henderson                 TCGv_i64 one = tcg_constant_i64(1);
140646bb3d46SRichard Henderson                 tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero);
140746bb3d46SRichard Henderson                 tcg_gen_eqv_i64(cb, in1, in2);
140846bb3d46SRichard Henderson             }
140946bb3d46SRichard Henderson             tcg_gen_xor_i64(cb, cb, dest);
141046bb3d46SRichard Henderson             tcg_gen_extract2_i64(cb, cb, cb_msb, 1);
141146bb3d46SRichard Henderson         } else {
141246bb3d46SRichard Henderson             if (is_add) {
141346bb3d46SRichard Henderson                 tcg_gen_add_i64(dest, in1, in2);
141446bb3d46SRichard Henderson                 tcg_gen_xor_i64(cb, in1, in2);
141546bb3d46SRichard Henderson             } else {
141646bb3d46SRichard Henderson                 tcg_gen_sub_i64(dest, in1, in2);
141746bb3d46SRichard Henderson                 tcg_gen_eqv_i64(cb, in1, in2);
141846bb3d46SRichard Henderson             }
141946bb3d46SRichard Henderson             tcg_gen_xor_i64(cb, cb, dest);
142046bb3d46SRichard Henderson             tcg_gen_shri_i64(cb, cb, 1);
142146bb3d46SRichard Henderson         }
142246bb3d46SRichard Henderson 
14233289ea0eSRichard Henderson         cond = cond_make_ti(cf & 1 ? TCG_COND_TSTEQ : TCG_COND_TSTNE,
14243289ea0eSRichard Henderson                             cb, test_cb);
142546bb3d46SRichard Henderson     }
1426b2167459SRichard Henderson 
1427b2167459SRichard Henderson     if (is_tc) {
1428aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
14296fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1430ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1431b2167459SRichard Henderson     }
1432b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1433b2167459SRichard Henderson 
1434b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1435b2167459SRichard Henderson     ctx->null_cond = cond;
1436b2167459SRichard Henderson }
1437b2167459SRichard Henderson 
143886f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY
14398d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space
14408d6ae7fbSRichard Henderson    from the top 2 bits of the base register.  There are a few system
14418d6ae7fbSRichard Henderson    instructions that have a 3-bit space specifier, for which SR0 is
14428d6ae7fbSRichard Henderson    not special.  To handle this, pass ~SP.  */
14436fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base)
144486f8d05fSRichard Henderson {
144586f8d05fSRichard Henderson     TCGv_ptr ptr;
14466fd0c7bcSRichard Henderson     TCGv_i64 tmp;
144786f8d05fSRichard Henderson     TCGv_i64 spc;
144886f8d05fSRichard Henderson 
144986f8d05fSRichard Henderson     if (sp != 0) {
14508d6ae7fbSRichard Henderson         if (sp < 0) {
14518d6ae7fbSRichard Henderson             sp = ~sp;
14528d6ae7fbSRichard Henderson         }
14536fd0c7bcSRichard Henderson         spc = tcg_temp_new_i64();
14548d6ae7fbSRichard Henderson         load_spr(ctx, spc, sp);
14558d6ae7fbSRichard Henderson         return spc;
145686f8d05fSRichard Henderson     }
1457494737b7SRichard Henderson     if (ctx->tb_flags & TB_FLAG_SR_SAME) {
1458494737b7SRichard Henderson         return cpu_srH;
1459494737b7SRichard Henderson     }
146086f8d05fSRichard Henderson 
146186f8d05fSRichard Henderson     ptr = tcg_temp_new_ptr();
1462aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
14636fd0c7bcSRichard Henderson     spc = tcg_temp_new_i64();
146486f8d05fSRichard Henderson 
1465698240d1SRichard Henderson     /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */
14666fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5);
14676fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, 030);
14686fd0c7bcSRichard Henderson     tcg_gen_trunc_i64_ptr(ptr, tmp);
146986f8d05fSRichard Henderson 
1470ad75a51eSRichard Henderson     tcg_gen_add_ptr(ptr, ptr, tcg_env);
147186f8d05fSRichard Henderson     tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4]));
147286f8d05fSRichard Henderson 
147386f8d05fSRichard Henderson     return spc;
147486f8d05fSRichard Henderson }
147586f8d05fSRichard Henderson #endif
147686f8d05fSRichard Henderson 
14776fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
1478c53e401eSRichard Henderson                      unsigned rb, unsigned rx, int scale, int64_t disp,
147986f8d05fSRichard Henderson                      unsigned sp, int modify, bool is_phys)
148086f8d05fSRichard Henderson {
14816fd0c7bcSRichard Henderson     TCGv_i64 base = load_gpr(ctx, rb);
14826fd0c7bcSRichard Henderson     TCGv_i64 ofs;
14836fd0c7bcSRichard Henderson     TCGv_i64 addr;
148486f8d05fSRichard Henderson 
1485f5b5c857SRichard Henderson     set_insn_breg(ctx, rb);
1486f5b5c857SRichard Henderson 
148786f8d05fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
148886f8d05fSRichard Henderson     if (rx) {
1489aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
14906fd0c7bcSRichard Henderson         tcg_gen_shli_i64(ofs, cpu_gr[rx], scale);
14916fd0c7bcSRichard Henderson         tcg_gen_add_i64(ofs, ofs, base);
149286f8d05fSRichard Henderson     } else if (disp || modify) {
1493aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
14946fd0c7bcSRichard Henderson         tcg_gen_addi_i64(ofs, base, disp);
149586f8d05fSRichard Henderson     } else {
149686f8d05fSRichard Henderson         ofs = base;
149786f8d05fSRichard Henderson     }
149886f8d05fSRichard Henderson 
149986f8d05fSRichard Henderson     *pofs = ofs;
15006fd0c7bcSRichard Henderson     *pgva = addr = tcg_temp_new_i64();
15017d50b696SSven Schnelle     tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base,
15027d50b696SSven Schnelle                      gva_offset_mask(ctx->tb_flags));
1503698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY
150486f8d05fSRichard Henderson     if (!is_phys) {
1505d265360fSRichard Henderson         tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base));
150686f8d05fSRichard Henderson     }
150786f8d05fSRichard Henderson #endif
150886f8d05fSRichard Henderson }
150986f8d05fSRichard Henderson 
151096d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
151196d6407fSRichard Henderson  * < 0 for pre-modify,
151296d6407fSRichard Henderson  * > 0 for post-modify,
151396d6407fSRichard Henderson  * = 0 for no base register update.
151496d6407fSRichard Henderson  */
151596d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1516c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
151714776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
151896d6407fSRichard Henderson {
15196fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15206fd0c7bcSRichard Henderson     TCGv_i64 addr;
152196d6407fSRichard Henderson 
152296d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
152396d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
152496d6407fSRichard Henderson 
152586f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
152617fe594cSRichard Henderson              MMU_DISABLED(ctx));
1527c1f55d97SRichard Henderson     tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
152886f8d05fSRichard Henderson     if (modify) {
152986f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
153096d6407fSRichard Henderson     }
153196d6407fSRichard Henderson }
153296d6407fSRichard Henderson 
153396d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1534c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
153514776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
153696d6407fSRichard Henderson {
15376fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15386fd0c7bcSRichard Henderson     TCGv_i64 addr;
153996d6407fSRichard Henderson 
154096d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
154196d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
154296d6407fSRichard Henderson 
154386f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
154417fe594cSRichard Henderson              MMU_DISABLED(ctx));
1545217d1a5eSRichard Henderson     tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
154686f8d05fSRichard Henderson     if (modify) {
154786f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
154896d6407fSRichard Henderson     }
154996d6407fSRichard Henderson }
155096d6407fSRichard Henderson 
155196d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1552c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
155314776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
155496d6407fSRichard Henderson {
15556fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15566fd0c7bcSRichard Henderson     TCGv_i64 addr;
155796d6407fSRichard Henderson 
155896d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
155996d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
156096d6407fSRichard Henderson 
156186f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
156217fe594cSRichard Henderson              MMU_DISABLED(ctx));
1563217d1a5eSRichard Henderson     tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
156486f8d05fSRichard Henderson     if (modify) {
156586f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
156696d6407fSRichard Henderson     }
156796d6407fSRichard Henderson }
156896d6407fSRichard Henderson 
156996d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1570c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
157114776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
157296d6407fSRichard Henderson {
15736fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15746fd0c7bcSRichard Henderson     TCGv_i64 addr;
157596d6407fSRichard Henderson 
157696d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
157796d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
157896d6407fSRichard Henderson 
157986f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
158017fe594cSRichard Henderson              MMU_DISABLED(ctx));
1581217d1a5eSRichard Henderson     tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
158286f8d05fSRichard Henderson     if (modify) {
158386f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
158496d6407fSRichard Henderson     }
158596d6407fSRichard Henderson }
158696d6407fSRichard Henderson 
15871cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1588c53e401eSRichard Henderson                     unsigned rx, int scale, int64_t disp,
158914776ab5STony Nguyen                     unsigned sp, int modify, MemOp mop)
159096d6407fSRichard Henderson {
15916fd0c7bcSRichard Henderson     TCGv_i64 dest;
159296d6407fSRichard Henderson 
159396d6407fSRichard Henderson     nullify_over(ctx);
159496d6407fSRichard Henderson 
159596d6407fSRichard Henderson     if (modify == 0) {
159696d6407fSRichard Henderson         /* No base register update.  */
159796d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
159896d6407fSRichard Henderson     } else {
159996d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
1600aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
160196d6407fSRichard Henderson     }
16026fd0c7bcSRichard Henderson     do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
160396d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
160496d6407fSRichard Henderson 
16051cd012a5SRichard Henderson     return nullify_end(ctx);
160696d6407fSRichard Henderson }
160796d6407fSRichard Henderson 
1608740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
1609c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
161086f8d05fSRichard Henderson                       unsigned sp, int modify)
161196d6407fSRichard Henderson {
161296d6407fSRichard Henderson     TCGv_i32 tmp;
161396d6407fSRichard Henderson 
161496d6407fSRichard Henderson     nullify_over(ctx);
161596d6407fSRichard Henderson 
161696d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
161786f8d05fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
161896d6407fSRichard Henderson     save_frw_i32(rt, tmp);
161996d6407fSRichard Henderson 
162096d6407fSRichard Henderson     if (rt == 0) {
1621ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
162296d6407fSRichard Henderson     }
162396d6407fSRichard Henderson 
1624740038d7SRichard Henderson     return nullify_end(ctx);
162596d6407fSRichard Henderson }
162696d6407fSRichard Henderson 
1627740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a)
1628740038d7SRichard Henderson {
1629740038d7SRichard Henderson     return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1630740038d7SRichard Henderson                      a->disp, a->sp, a->m);
1631740038d7SRichard Henderson }
1632740038d7SRichard Henderson 
1633740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1634c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
163586f8d05fSRichard Henderson                       unsigned sp, int modify)
163696d6407fSRichard Henderson {
163796d6407fSRichard Henderson     TCGv_i64 tmp;
163896d6407fSRichard Henderson 
163996d6407fSRichard Henderson     nullify_over(ctx);
164096d6407fSRichard Henderson 
164196d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
1642fc313c64SFrédéric Pétrot     do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
164396d6407fSRichard Henderson     save_frd(rt, tmp);
164496d6407fSRichard Henderson 
164596d6407fSRichard Henderson     if (rt == 0) {
1646ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
164796d6407fSRichard Henderson     }
164896d6407fSRichard Henderson 
1649740038d7SRichard Henderson     return nullify_end(ctx);
1650740038d7SRichard Henderson }
1651740038d7SRichard Henderson 
1652740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a)
1653740038d7SRichard Henderson {
1654740038d7SRichard Henderson     return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1655740038d7SRichard Henderson                      a->disp, a->sp, a->m);
165696d6407fSRichard Henderson }
165796d6407fSRichard Henderson 
16581cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb,
1659c53e401eSRichard Henderson                      int64_t disp, unsigned sp,
166014776ab5STony Nguyen                      int modify, MemOp mop)
166196d6407fSRichard Henderson {
166296d6407fSRichard Henderson     nullify_over(ctx);
16636fd0c7bcSRichard Henderson     do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
16641cd012a5SRichard Henderson     return nullify_end(ctx);
166596d6407fSRichard Henderson }
166696d6407fSRichard Henderson 
1667740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1668c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
166986f8d05fSRichard Henderson                        unsigned sp, int modify)
167096d6407fSRichard Henderson {
167196d6407fSRichard Henderson     TCGv_i32 tmp;
167296d6407fSRichard Henderson 
167396d6407fSRichard Henderson     nullify_over(ctx);
167496d6407fSRichard Henderson 
167596d6407fSRichard Henderson     tmp = load_frw_i32(rt);
167686f8d05fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
167796d6407fSRichard Henderson 
1678740038d7SRichard Henderson     return nullify_end(ctx);
167996d6407fSRichard Henderson }
168096d6407fSRichard Henderson 
1681740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a)
1682740038d7SRichard Henderson {
1683740038d7SRichard Henderson     return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1684740038d7SRichard Henderson                       a->disp, a->sp, a->m);
1685740038d7SRichard Henderson }
1686740038d7SRichard Henderson 
1687740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1688c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
168986f8d05fSRichard Henderson                        unsigned sp, int modify)
169096d6407fSRichard Henderson {
169196d6407fSRichard Henderson     TCGv_i64 tmp;
169296d6407fSRichard Henderson 
169396d6407fSRichard Henderson     nullify_over(ctx);
169496d6407fSRichard Henderson 
169596d6407fSRichard Henderson     tmp = load_frd(rt);
1696fc313c64SFrédéric Pétrot     do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
169796d6407fSRichard Henderson 
1698740038d7SRichard Henderson     return nullify_end(ctx);
1699740038d7SRichard Henderson }
1700740038d7SRichard Henderson 
1701740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a)
1702740038d7SRichard Henderson {
1703740038d7SRichard Henderson     return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1704740038d7SRichard Henderson                       a->disp, a->sp, a->m);
170596d6407fSRichard Henderson }
170696d6407fSRichard Henderson 
17071ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1708ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1709ebe9383cSRichard Henderson {
1710ebe9383cSRichard Henderson     TCGv_i32 tmp;
1711ebe9383cSRichard Henderson 
1712ebe9383cSRichard Henderson     nullify_over(ctx);
1713ebe9383cSRichard Henderson     tmp = load_frw0_i32(ra);
1714ebe9383cSRichard Henderson 
1715ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1716ebe9383cSRichard Henderson 
1717ebe9383cSRichard Henderson     save_frw_i32(rt, tmp);
17181ca74648SRichard Henderson     return nullify_end(ctx);
1719ebe9383cSRichard Henderson }
1720ebe9383cSRichard Henderson 
17211ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1722ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1723ebe9383cSRichard Henderson {
1724ebe9383cSRichard Henderson     TCGv_i32 dst;
1725ebe9383cSRichard Henderson     TCGv_i64 src;
1726ebe9383cSRichard Henderson 
1727ebe9383cSRichard Henderson     nullify_over(ctx);
1728ebe9383cSRichard Henderson     src = load_frd(ra);
1729ebe9383cSRichard Henderson     dst = tcg_temp_new_i32();
1730ebe9383cSRichard Henderson 
1731ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1732ebe9383cSRichard Henderson 
1733ebe9383cSRichard Henderson     save_frw_i32(rt, dst);
17341ca74648SRichard Henderson     return nullify_end(ctx);
1735ebe9383cSRichard Henderson }
1736ebe9383cSRichard Henderson 
17371ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1738ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1739ebe9383cSRichard Henderson {
1740ebe9383cSRichard Henderson     TCGv_i64 tmp;
1741ebe9383cSRichard Henderson 
1742ebe9383cSRichard Henderson     nullify_over(ctx);
1743ebe9383cSRichard Henderson     tmp = load_frd0(ra);
1744ebe9383cSRichard Henderson 
1745ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1746ebe9383cSRichard Henderson 
1747ebe9383cSRichard Henderson     save_frd(rt, tmp);
17481ca74648SRichard Henderson     return nullify_end(ctx);
1749ebe9383cSRichard Henderson }
1750ebe9383cSRichard Henderson 
17511ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1752ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1753ebe9383cSRichard Henderson {
1754ebe9383cSRichard Henderson     TCGv_i32 src;
1755ebe9383cSRichard Henderson     TCGv_i64 dst;
1756ebe9383cSRichard Henderson 
1757ebe9383cSRichard Henderson     nullify_over(ctx);
1758ebe9383cSRichard Henderson     src = load_frw0_i32(ra);
1759ebe9383cSRichard Henderson     dst = tcg_temp_new_i64();
1760ebe9383cSRichard Henderson 
1761ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1762ebe9383cSRichard Henderson 
1763ebe9383cSRichard Henderson     save_frd(rt, dst);
17641ca74648SRichard Henderson     return nullify_end(ctx);
1765ebe9383cSRichard Henderson }
1766ebe9383cSRichard Henderson 
17671ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt,
1768ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
176931234768SRichard Henderson                         void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
1770ebe9383cSRichard Henderson {
1771ebe9383cSRichard Henderson     TCGv_i32 a, b;
1772ebe9383cSRichard Henderson 
1773ebe9383cSRichard Henderson     nullify_over(ctx);
1774ebe9383cSRichard Henderson     a = load_frw0_i32(ra);
1775ebe9383cSRichard Henderson     b = load_frw0_i32(rb);
1776ebe9383cSRichard Henderson 
1777ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1778ebe9383cSRichard Henderson 
1779ebe9383cSRichard Henderson     save_frw_i32(rt, a);
17801ca74648SRichard Henderson     return nullify_end(ctx);
1781ebe9383cSRichard Henderson }
1782ebe9383cSRichard Henderson 
17831ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt,
1784ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
178531234768SRichard Henderson                         void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
1786ebe9383cSRichard Henderson {
1787ebe9383cSRichard Henderson     TCGv_i64 a, b;
1788ebe9383cSRichard Henderson 
1789ebe9383cSRichard Henderson     nullify_over(ctx);
1790ebe9383cSRichard Henderson     a = load_frd0(ra);
1791ebe9383cSRichard Henderson     b = load_frd0(rb);
1792ebe9383cSRichard Henderson 
1793ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1794ebe9383cSRichard Henderson 
1795ebe9383cSRichard Henderson     save_frd(rt, a);
17961ca74648SRichard Henderson     return nullify_end(ctx);
1797ebe9383cSRichard Henderson }
1798ebe9383cSRichard Henderson 
179998cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
180098cd9ca7SRichard Henderson    have already had nullification handled.  */
18012644f80bSRichard Henderson static bool do_dbranch(DisasContext *ctx, int64_t disp,
180298cd9ca7SRichard Henderson                        unsigned link, bool is_n)
180398cd9ca7SRichard Henderson {
1804bc921866SRichard Henderson     ctx->iaq_j = iaqe_branchi(ctx, disp);
18052644f80bSRichard Henderson 
180698cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
180743541db0SRichard Henderson         install_link(ctx, link, false);
180898cd9ca7SRichard Henderson         if (is_n) {
1809d08ad0e0SRichard Henderson             if (use_nullify_skip(ctx)) {
1810d08ad0e0SRichard Henderson                 nullify_set(ctx, 0);
1811bc921866SRichard Henderson                 gen_goto_tb(ctx, 0, &ctx->iaq_j, NULL);
1812d08ad0e0SRichard Henderson                 ctx->base.is_jmp = DISAS_NORETURN;
1813d08ad0e0SRichard Henderson                 return true;
1814d08ad0e0SRichard Henderson             }
181598cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
181698cd9ca7SRichard Henderson         }
1817bc921866SRichard Henderson         ctx->iaq_n = &ctx->iaq_j;
181898cd9ca7SRichard Henderson     } else {
181998cd9ca7SRichard Henderson         nullify_over(ctx);
182098cd9ca7SRichard Henderson 
182143541db0SRichard Henderson         install_link(ctx, link, false);
182298cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
182398cd9ca7SRichard Henderson             nullify_set(ctx, 0);
1824bc921866SRichard Henderson             gen_goto_tb(ctx, 0, &ctx->iaq_j, NULL);
182598cd9ca7SRichard Henderson         } else {
182698cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
1827bc921866SRichard Henderson             gen_goto_tb(ctx, 0, &ctx->iaq_b, &ctx->iaq_j);
182898cd9ca7SRichard Henderson         }
182931234768SRichard Henderson         nullify_end(ctx);
183098cd9ca7SRichard Henderson 
183198cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1832bc921866SRichard Henderson         gen_goto_tb(ctx, 1, &ctx->iaq_b, NULL);
183331234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
183498cd9ca7SRichard Henderson     }
183501afb7beSRichard Henderson     return true;
183698cd9ca7SRichard Henderson }
183798cd9ca7SRichard Henderson 
183898cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
183998cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
1840c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n,
184198cd9ca7SRichard Henderson                        DisasCond *cond)
184298cd9ca7SRichard Henderson {
1843bc921866SRichard Henderson     DisasIAQE next;
184498cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
184598cd9ca7SRichard Henderson     TCGCond c = cond->c;
184698cd9ca7SRichard Henderson     bool n;
184798cd9ca7SRichard Henderson 
184898cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
184998cd9ca7SRichard Henderson 
185098cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
185198cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
18522644f80bSRichard Henderson         return do_dbranch(ctx, disp, 0, is_n && disp >= 0);
185398cd9ca7SRichard Henderson     }
185498cd9ca7SRichard Henderson 
185598cd9ca7SRichard Henderson     taken = gen_new_label();
18566fd0c7bcSRichard Henderson     tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken);
185798cd9ca7SRichard Henderson     cond_free(cond);
185898cd9ca7SRichard Henderson 
185998cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
186098cd9ca7SRichard Henderson     n = is_n && disp < 0;
186198cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
186298cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1863bc921866SRichard Henderson         next = iaqe_incr(&ctx->iaq_b, 4);
1864bc921866SRichard Henderson         gen_goto_tb(ctx, 0, &next, NULL);
186598cd9ca7SRichard Henderson     } else {
186698cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
186798cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
186898cd9ca7SRichard Henderson             ctx->null_lab = NULL;
186998cd9ca7SRichard Henderson         }
187098cd9ca7SRichard Henderson         nullify_set(ctx, n);
1871bc921866SRichard Henderson         gen_goto_tb(ctx, 0, &ctx->iaq_b, NULL);
187298cd9ca7SRichard Henderson     }
187398cd9ca7SRichard Henderson 
187498cd9ca7SRichard Henderson     gen_set_label(taken);
187598cd9ca7SRichard Henderson 
187698cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
187798cd9ca7SRichard Henderson     n = is_n && disp >= 0;
1878bc921866SRichard Henderson 
1879bc921866SRichard Henderson     next = iaqe_branchi(ctx, disp);
188098cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
188198cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1882bc921866SRichard Henderson         gen_goto_tb(ctx, 1, &next, NULL);
188398cd9ca7SRichard Henderson     } else {
188498cd9ca7SRichard Henderson         nullify_set(ctx, n);
1885bc921866SRichard Henderson         gen_goto_tb(ctx, 1, &ctx->iaq_b, &next);
188698cd9ca7SRichard Henderson     }
188798cd9ca7SRichard Henderson 
188898cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
188998cd9ca7SRichard Henderson     if (ctx->null_lab) {
189098cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
189198cd9ca7SRichard Henderson         ctx->null_lab = NULL;
189231234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
189398cd9ca7SRichard Henderson     } else {
189431234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
189598cd9ca7SRichard Henderson     }
189601afb7beSRichard Henderson     return true;
189798cd9ca7SRichard Henderson }
189898cd9ca7SRichard Henderson 
1899bc921866SRichard Henderson /*
1900bc921866SRichard Henderson  * Emit an unconditional branch to an indirect target, in ctx->iaq_j.
1901bc921866SRichard Henderson  * This handles nullification of the branch itself.
1902bc921866SRichard Henderson  */
1903bc921866SRichard Henderson static bool do_ibranch(DisasContext *ctx, unsigned link,
1904bc921866SRichard Henderson                        bool with_sr0, bool is_n)
190598cd9ca7SRichard Henderson {
1906d582c1faSRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
1907019f4159SRichard Henderson         install_link(ctx, link, with_sr0);
190898cd9ca7SRichard Henderson         if (is_n) {
1909c301f34eSRichard Henderson             if (use_nullify_skip(ctx)) {
1910bc921866SRichard Henderson                 install_iaq_entries(ctx, &ctx->iaq_j, NULL);
1911c301f34eSRichard Henderson                 nullify_set(ctx, 0);
191231234768SRichard Henderson                 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
191301afb7beSRichard Henderson                 return true;
1914c301f34eSRichard Henderson             }
191598cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
191698cd9ca7SRichard Henderson         }
1917bc921866SRichard Henderson         ctx->iaq_n = &ctx->iaq_j;
1918d582c1faSRichard Henderson         return true;
1919d582c1faSRichard Henderson     }
192098cd9ca7SRichard Henderson 
1921d582c1faSRichard Henderson     nullify_over(ctx);
1922d582c1faSRichard Henderson 
1923019f4159SRichard Henderson     install_link(ctx, link, with_sr0);
1924d582c1faSRichard Henderson     if (is_n && use_nullify_skip(ctx)) {
1925bc921866SRichard Henderson         install_iaq_entries(ctx, &ctx->iaq_j, NULL);
1926d582c1faSRichard Henderson         nullify_set(ctx, 0);
1927d582c1faSRichard Henderson     } else {
1928bc921866SRichard Henderson         install_iaq_entries(ctx, &ctx->iaq_b, &ctx->iaq_j);
1929d582c1faSRichard Henderson         nullify_set(ctx, is_n);
1930d582c1faSRichard Henderson     }
1931d582c1faSRichard Henderson 
19327f11636dSEmilio G. Cota     tcg_gen_lookup_and_goto_ptr();
1933d582c1faSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
193401afb7beSRichard Henderson     return nullify_end(ctx);
193598cd9ca7SRichard Henderson }
193698cd9ca7SRichard Henderson 
1937660eefe1SRichard Henderson /* Implement
1938660eefe1SRichard Henderson  *    if (IAOQ_Front{30..31} < GR[b]{30..31})
1939660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← GR[b]{30..31};
1940660eefe1SRichard Henderson  *    else
1941660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← IAOQ_Front{30..31};
1942660eefe1SRichard Henderson  * which keeps the privilege level from being increased.
1943660eefe1SRichard Henderson  */
19446fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset)
1945660eefe1SRichard Henderson {
19461874e6c2SRichard Henderson     TCGv_i64 dest = tcg_temp_new_i64();
1947660eefe1SRichard Henderson     switch (ctx->privilege) {
1948660eefe1SRichard Henderson     case 0:
1949660eefe1SRichard Henderson         /* Privilege 0 is maximum and is allowed to decrease.  */
19501874e6c2SRichard Henderson         tcg_gen_mov_i64(dest, offset);
19511874e6c2SRichard Henderson         break;
1952660eefe1SRichard Henderson     case 3:
1953993119feSRichard Henderson         /* Privilege 3 is minimum and is never allowed to increase.  */
19546fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, offset, 3);
1955660eefe1SRichard Henderson         break;
1956660eefe1SRichard Henderson     default:
19576fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, offset, -4);
19586fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, ctx->privilege);
19590bb02029SRichard Henderson         tcg_gen_umax_i64(dest, dest, offset);
1960660eefe1SRichard Henderson         break;
1961660eefe1SRichard Henderson     }
1962660eefe1SRichard Henderson     return dest;
1963660eefe1SRichard Henderson }
1964660eefe1SRichard Henderson 
1965ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
19667ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
19677ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
19687ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
19697ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
19707ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
19717ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
19727ad439dfSRichard Henderson    aforementioned BE.  */
197331234768SRichard Henderson static void do_page_zero(DisasContext *ctx)
19747ad439dfSRichard Henderson {
19750d89cb7cSRichard Henderson     assert(ctx->iaq_f.disp == 0);
19760d89cb7cSRichard Henderson 
19777ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
19787ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
19798b81968cSMichael Tokarev        next insn within the privileged page.  */
19807ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
19817ad439dfSRichard Henderson     case TCG_COND_NEVER:
19827ad439dfSRichard Henderson         break;
19837ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
19846fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, 0);
19857ad439dfSRichard Henderson         goto do_sigill;
19867ad439dfSRichard Henderson     default:
19877ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
19887ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
19897ad439dfSRichard Henderson         g_assert_not_reached();
19907ad439dfSRichard Henderson     }
19917ad439dfSRichard Henderson 
19927ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
19937ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
19947ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
19957ad439dfSRichard Henderson        under such conditions.  */
19960d89cb7cSRichard Henderson     if (iaqe_variable(&ctx->iaq_b) || ctx->iaq_b.disp != 4) {
19977ad439dfSRichard Henderson         goto do_sigill;
19987ad439dfSRichard Henderson     }
19997ad439dfSRichard Henderson 
20000d89cb7cSRichard Henderson     switch (ctx->base.pc_first) {
20017ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
20022986721dSRichard Henderson         gen_excp_1(EXCP_IMP);
200331234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
200431234768SRichard Henderson         break;
20057ad439dfSRichard Henderson 
20067ad439dfSRichard Henderson     case 0xb0: /* LWS */
20077ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
200831234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
200931234768SRichard Henderson         break;
20107ad439dfSRichard Henderson 
20117ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
2012bc921866SRichard Henderson         {
2013bc921866SRichard Henderson             DisasIAQE next = { .base = tcg_temp_new_i64() };
2014bc921866SRichard Henderson 
2015bc921866SRichard Henderson             tcg_gen_st_i64(cpu_gr[26], tcg_env,
2016bc921866SRichard Henderson                            offsetof(CPUHPPAState, cr[27]));
2017bc921866SRichard Henderson             tcg_gen_ori_i64(next.base, cpu_gr[31], 3);
2018bc921866SRichard Henderson             install_iaq_entries(ctx, &next, NULL);
201931234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
2020bc921866SRichard Henderson         }
202131234768SRichard Henderson         break;
20227ad439dfSRichard Henderson 
20237ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
20247ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
202531234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
202631234768SRichard Henderson         break;
20277ad439dfSRichard Henderson 
20287ad439dfSRichard Henderson     default:
20297ad439dfSRichard Henderson     do_sigill:
20302986721dSRichard Henderson         gen_excp_1(EXCP_ILL);
203131234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
203231234768SRichard Henderson         break;
20337ad439dfSRichard Henderson     }
20347ad439dfSRichard Henderson }
2035ba1d0b44SRichard Henderson #endif
20367ad439dfSRichard Henderson 
2037deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a)
2038b2167459SRichard Henderson {
2039b2167459SRichard Henderson     cond_free(&ctx->null_cond);
204031234768SRichard Henderson     return true;
2041b2167459SRichard Henderson }
2042b2167459SRichard Henderson 
204340f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a)
204498a9cb79SRichard Henderson {
204531234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_BREAK);
204698a9cb79SRichard Henderson }
204798a9cb79SRichard Henderson 
2048e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a)
204998a9cb79SRichard Henderson {
205098a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
205198a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
205298a9cb79SRichard Henderson 
205398a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
205431234768SRichard Henderson     return true;
205598a9cb79SRichard Henderson }
205698a9cb79SRichard Henderson 
2057c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a)
205898a9cb79SRichard Henderson {
2059bc921866SRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
206098a9cb79SRichard Henderson 
2061bc921866SRichard Henderson     copy_iaoq_entry(ctx, dest, &ctx->iaq_f);
2062bc921866SRichard Henderson     tcg_gen_andi_i64(dest, dest, -4);
2063bc921866SRichard Henderson 
2064bc921866SRichard Henderson     save_gpr(ctx, a->t, dest);
206598a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
206631234768SRichard Henderson     return true;
206798a9cb79SRichard Henderson }
206898a9cb79SRichard Henderson 
2069c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a)
207098a9cb79SRichard Henderson {
2071c603e14aSRichard Henderson     unsigned rt = a->t;
2072c603e14aSRichard Henderson     unsigned rs = a->sp;
207333423472SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
207498a9cb79SRichard Henderson 
207533423472SRichard Henderson     load_spr(ctx, t0, rs);
207633423472SRichard Henderson     tcg_gen_shri_i64(t0, t0, 32);
207733423472SRichard Henderson 
2078967662cdSRichard Henderson     save_gpr(ctx, rt, t0);
207998a9cb79SRichard Henderson 
208098a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
208131234768SRichard Henderson     return true;
208298a9cb79SRichard Henderson }
208398a9cb79SRichard Henderson 
2084c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a)
208598a9cb79SRichard Henderson {
2086c603e14aSRichard Henderson     unsigned rt = a->t;
2087c603e14aSRichard Henderson     unsigned ctl = a->r;
20886fd0c7bcSRichard Henderson     TCGv_i64 tmp;
208998a9cb79SRichard Henderson 
209098a9cb79SRichard Henderson     switch (ctl) {
209135136a77SRichard Henderson     case CR_SAR:
2092c603e14aSRichard Henderson         if (a->e == 0) {
209398a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
209498a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
20956fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
209698a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
209735136a77SRichard Henderson             goto done;
209898a9cb79SRichard Henderson         }
209998a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
210035136a77SRichard Henderson         goto done;
210135136a77SRichard Henderson     case CR_IT: /* Interval Timer */
210235136a77SRichard Henderson         /* FIXME: Respect PSW_S bit.  */
210335136a77SRichard Henderson         nullify_over(ctx);
210498a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
2105dfd1b812SRichard Henderson         if (translator_io_start(&ctx->base)) {
210631234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
210749c29d6cSRichard Henderson         }
21080c58c1bcSRichard Henderson         gen_helper_read_interval_timer(tmp);
210998a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
211031234768SRichard Henderson         return nullify_end(ctx);
211198a9cb79SRichard Henderson     case 26:
211298a9cb79SRichard Henderson     case 27:
211398a9cb79SRichard Henderson         break;
211498a9cb79SRichard Henderson     default:
211598a9cb79SRichard Henderson         /* All other control registers are privileged.  */
211635136a77SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
211735136a77SRichard Henderson         break;
211898a9cb79SRichard Henderson     }
211998a9cb79SRichard Henderson 
2120aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
21216fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
212235136a77SRichard Henderson     save_gpr(ctx, rt, tmp);
212335136a77SRichard Henderson 
212435136a77SRichard Henderson  done:
212598a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
212631234768SRichard Henderson     return true;
212798a9cb79SRichard Henderson }
212898a9cb79SRichard Henderson 
2129c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
213033423472SRichard Henderson {
2131c603e14aSRichard Henderson     unsigned rr = a->r;
2132c603e14aSRichard Henderson     unsigned rs = a->sp;
2133967662cdSRichard Henderson     TCGv_i64 tmp;
213433423472SRichard Henderson 
213533423472SRichard Henderson     if (rs >= 5) {
213633423472SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
213733423472SRichard Henderson     }
213833423472SRichard Henderson     nullify_over(ctx);
213933423472SRichard Henderson 
2140967662cdSRichard Henderson     tmp = tcg_temp_new_i64();
2141967662cdSRichard Henderson     tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32);
214233423472SRichard Henderson 
214333423472SRichard Henderson     if (rs >= 4) {
2144967662cdSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs]));
2145494737b7SRichard Henderson         ctx->tb_flags &= ~TB_FLAG_SR_SAME;
214633423472SRichard Henderson     } else {
2147967662cdSRichard Henderson         tcg_gen_mov_i64(cpu_sr[rs], tmp);
214833423472SRichard Henderson     }
214933423472SRichard Henderson 
215031234768SRichard Henderson     return nullify_end(ctx);
215133423472SRichard Henderson }
215233423472SRichard Henderson 
2153c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
215498a9cb79SRichard Henderson {
2155c603e14aSRichard Henderson     unsigned ctl = a->t;
21566fd0c7bcSRichard Henderson     TCGv_i64 reg;
21576fd0c7bcSRichard Henderson     TCGv_i64 tmp;
215898a9cb79SRichard Henderson 
215935136a77SRichard Henderson     if (ctl == CR_SAR) {
21604845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
2161aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
21626fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31);
216398a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
216498a9cb79SRichard Henderson 
216598a9cb79SRichard Henderson         cond_free(&ctx->null_cond);
216631234768SRichard Henderson         return true;
216798a9cb79SRichard Henderson     }
216898a9cb79SRichard Henderson 
216935136a77SRichard Henderson     /* All other control registers are privileged or read-only.  */
217035136a77SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
217135136a77SRichard Henderson 
2172c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
217335136a77SRichard Henderson     nullify_over(ctx);
21744c34bab0SHelge Deller 
21754c34bab0SHelge Deller     if (ctx->is_pa20) {
21764845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
21774c34bab0SHelge Deller     } else {
21784c34bab0SHelge Deller         reg = tcg_temp_new_i64();
21794c34bab0SHelge Deller         tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r));
21804c34bab0SHelge Deller     }
21814845f015SSven Schnelle 
218235136a77SRichard Henderson     switch (ctl) {
218335136a77SRichard Henderson     case CR_IT:
2184104281c1SRichard Henderson         if (translator_io_start(&ctx->base)) {
2185104281c1SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2186104281c1SRichard Henderson         }
2187ad75a51eSRichard Henderson         gen_helper_write_interval_timer(tcg_env, reg);
218835136a77SRichard Henderson         break;
21894f5f2548SRichard Henderson     case CR_EIRR:
21906ebebea7SRichard Henderson         /* Helper modifies interrupt lines and is therefore IO. */
21916ebebea7SRichard Henderson         translator_io_start(&ctx->base);
2192ad75a51eSRichard Henderson         gen_helper_write_eirr(tcg_env, reg);
21936ebebea7SRichard Henderson         /* Exit to re-evaluate interrupts in the main loop. */
219431234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
21954f5f2548SRichard Henderson         break;
21964f5f2548SRichard Henderson 
219735136a77SRichard Henderson     case CR_IIASQ:
219835136a77SRichard Henderson     case CR_IIAOQ:
219935136a77SRichard Henderson         /* FIXME: Respect PSW_Q bit */
220035136a77SRichard Henderson         /* The write advances the queue and stores to the back element.  */
2201aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
22026fd0c7bcSRichard Henderson         tcg_gen_ld_i64(tmp, tcg_env,
220335136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
22046fd0c7bcSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
22056fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env,
220635136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
220735136a77SRichard Henderson         break;
220835136a77SRichard Henderson 
2209d5de20bdSSven Schnelle     case CR_PID1:
2210d5de20bdSSven Schnelle     case CR_PID2:
2211d5de20bdSSven Schnelle     case CR_PID3:
2212d5de20bdSSven Schnelle     case CR_PID4:
22136fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
2214d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY
2215ad75a51eSRichard Henderson         gen_helper_change_prot_id(tcg_env);
2216d5de20bdSSven Schnelle #endif
2217d5de20bdSSven Schnelle         break;
2218d5de20bdSSven Schnelle 
22196ebebea7SRichard Henderson     case CR_EIEM:
22206ebebea7SRichard Henderson         /* Exit to re-evaluate interrupts in the main loop. */
22216ebebea7SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
22226ebebea7SRichard Henderson         /* FALLTHRU */
222335136a77SRichard Henderson     default:
22246fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
222535136a77SRichard Henderson         break;
222635136a77SRichard Henderson     }
222731234768SRichard Henderson     return nullify_end(ctx);
22284f5f2548SRichard Henderson #endif
222935136a77SRichard Henderson }
223035136a77SRichard Henderson 
2231c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
223298a9cb79SRichard Henderson {
2233aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
223498a9cb79SRichard Henderson 
22356fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, load_gpr(ctx, a->r));
22366fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31);
223798a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
223898a9cb79SRichard Henderson 
223998a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
224031234768SRichard Henderson     return true;
224198a9cb79SRichard Henderson }
224298a9cb79SRichard Henderson 
2243e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a)
224498a9cb79SRichard Henderson {
22456fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
224698a9cb79SRichard Henderson 
22472330504cSHelge Deller #ifdef CONFIG_USER_ONLY
22482330504cSHelge Deller     /* We don't implement space registers in user mode. */
22496fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
22502330504cSHelge Deller #else
2251967662cdSRichard Henderson     tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
2252967662cdSRichard Henderson     tcg_gen_shri_i64(dest, dest, 32);
22532330504cSHelge Deller #endif
2254e36f27efSRichard Henderson     save_gpr(ctx, a->t, dest);
225598a9cb79SRichard Henderson 
225698a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
225731234768SRichard Henderson     return true;
225898a9cb79SRichard Henderson }
225998a9cb79SRichard Henderson 
2260e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a)
2261e36f27efSRichard Henderson {
22627b2d70a1SHelge Deller #ifdef CONFIG_USER_ONLY
2263e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
22647b2d70a1SHelge Deller #else
22656fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2266e1b5a5edSRichard Henderson 
22677b2d70a1SHelge Deller     /* HP-UX 11i and HP ODE use rsm for read-access to PSW */
22687b2d70a1SHelge Deller     if (a->i) {
22697b2d70a1SHelge Deller         CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
22707b2d70a1SHelge Deller     }
22717b2d70a1SHelge Deller 
2272e1b5a5edSRichard Henderson     nullify_over(ctx);
2273e1b5a5edSRichard Henderson 
2274aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
22756fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
22766fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ~a->i);
2277ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2278e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2279e1b5a5edSRichard Henderson 
2280e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_M.  */
228131234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
228231234768SRichard Henderson     return nullify_end(ctx);
2283e36f27efSRichard Henderson #endif
2284e1b5a5edSRichard Henderson }
2285e1b5a5edSRichard Henderson 
2286e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
2287e1b5a5edSRichard Henderson {
2288e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2289e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
22906fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2291e1b5a5edSRichard Henderson 
2292e1b5a5edSRichard Henderson     nullify_over(ctx);
2293e1b5a5edSRichard Henderson 
2294aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
22956fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
22966fd0c7bcSRichard Henderson     tcg_gen_ori_i64(tmp, tmp, a->i);
2297ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2298e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2299e1b5a5edSRichard Henderson 
2300e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_I.  */
230131234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
230231234768SRichard Henderson     return nullify_end(ctx);
2303e36f27efSRichard Henderson #endif
2304e1b5a5edSRichard Henderson }
2305e1b5a5edSRichard Henderson 
2306c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
2307e1b5a5edSRichard Henderson {
2308e1b5a5edSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2309c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
23106fd0c7bcSRichard Henderson     TCGv_i64 tmp, reg;
2311e1b5a5edSRichard Henderson     nullify_over(ctx);
2312e1b5a5edSRichard Henderson 
2313c603e14aSRichard Henderson     reg = load_gpr(ctx, a->r);
2314aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2315ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, reg);
2316e1b5a5edSRichard Henderson 
2317e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts.  */
231831234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
231931234768SRichard Henderson     return nullify_end(ctx);
2320c603e14aSRichard Henderson #endif
2321e1b5a5edSRichard Henderson }
2322f49b3537SRichard Henderson 
2323e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r)
2324f49b3537SRichard Henderson {
2325f49b3537SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2326e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
2327f49b3537SRichard Henderson     nullify_over(ctx);
2328f49b3537SRichard Henderson 
2329e36f27efSRichard Henderson     if (rfi_r) {
2330ad75a51eSRichard Henderson         gen_helper_rfi_r(tcg_env);
2331f49b3537SRichard Henderson     } else {
2332ad75a51eSRichard Henderson         gen_helper_rfi(tcg_env);
2333f49b3537SRichard Henderson     }
233431234768SRichard Henderson     /* Exit the TB to recognize new interrupts.  */
233507ea28b4SRichard Henderson     tcg_gen_exit_tb(NULL, 0);
233631234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
2337f49b3537SRichard Henderson 
233831234768SRichard Henderson     return nullify_end(ctx);
2339e36f27efSRichard Henderson #endif
2340f49b3537SRichard Henderson }
23416210db05SHelge Deller 
2342e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a)
2343e36f27efSRichard Henderson {
2344e36f27efSRichard Henderson     return do_rfi(ctx, false);
2345e36f27efSRichard Henderson }
2346e36f27efSRichard Henderson 
2347e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a)
2348e36f27efSRichard Henderson {
2349e36f27efSRichard Henderson     return do_rfi(ctx, true);
2350e36f27efSRichard Henderson }
2351e36f27efSRichard Henderson 
235296927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a)
23536210db05SHelge Deller {
23546210db05SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
235596927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
23566210db05SHelge Deller     nullify_over(ctx);
2357ad75a51eSRichard Henderson     gen_helper_halt(tcg_env);
235831234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
235931234768SRichard Henderson     return nullify_end(ctx);
236096927adbSRichard Henderson #endif
23616210db05SHelge Deller }
236296927adbSRichard Henderson 
236396927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a)
236496927adbSRichard Henderson {
236596927adbSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
236696927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
236796927adbSRichard Henderson     nullify_over(ctx);
2368ad75a51eSRichard Henderson     gen_helper_reset(tcg_env);
236996927adbSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
237096927adbSRichard Henderson     return nullify_end(ctx);
237196927adbSRichard Henderson #endif
237296927adbSRichard Henderson }
2373e1b5a5edSRichard Henderson 
2374558c09beSRichard Henderson static bool do_getshadowregs(DisasContext *ctx)
23754a4554c6SHelge Deller {
23764a4554c6SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
23774a4554c6SHelge Deller     nullify_over(ctx);
2378558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0]));
2379558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1]));
2380558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2]));
2381558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3]));
2382558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4]));
2383558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5]));
2384558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6]));
23854a4554c6SHelge Deller     return nullify_end(ctx);
2386558c09beSRichard Henderson }
2387558c09beSRichard Henderson 
23883bdf2081SHelge Deller static bool do_putshadowregs(DisasContext *ctx)
23893bdf2081SHelge Deller {
23903bdf2081SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
23913bdf2081SHelge Deller     nullify_over(ctx);
23923bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0]));
23933bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1]));
23943bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2]));
23953bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3]));
23963bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4]));
23973bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5]));
23983bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6]));
23993bdf2081SHelge Deller     return nullify_end(ctx);
24003bdf2081SHelge Deller }
24013bdf2081SHelge Deller 
2402558c09beSRichard Henderson static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
2403558c09beSRichard Henderson {
2404558c09beSRichard Henderson     return do_getshadowregs(ctx);
24054a4554c6SHelge Deller }
24064a4554c6SHelge Deller 
2407deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
240898a9cb79SRichard Henderson {
2409deee69a1SRichard Henderson     if (a->m) {
24106fd0c7bcSRichard Henderson         TCGv_i64 dest = dest_gpr(ctx, a->b);
24116fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->b);
24126fd0c7bcSRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->x);
241398a9cb79SRichard Henderson 
241498a9cb79SRichard Henderson         /* The only thing we need to do is the base register modification.  */
24156fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, src1, src2);
2416deee69a1SRichard Henderson         save_gpr(ctx, a->b, dest);
2417deee69a1SRichard Henderson     }
241898a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
241931234768SRichard Henderson     return true;
242098a9cb79SRichard Henderson }
242198a9cb79SRichard Henderson 
2422ad1fdacdSSven Schnelle static bool trans_fic(DisasContext *ctx, arg_ldst *a)
2423ad1fdacdSSven Schnelle {
2424ad1fdacdSSven Schnelle     /* End TB for flush instruction cache, so we pick up new insns. */
2425ad1fdacdSSven Schnelle     ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2426ad1fdacdSSven Schnelle     return trans_nop_addrx(ctx, a);
2427ad1fdacdSSven Schnelle }
2428ad1fdacdSSven Schnelle 
2429deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a)
243098a9cb79SRichard Henderson {
24316fd0c7bcSRichard Henderson     TCGv_i64 dest, ofs;
2432eed14219SRichard Henderson     TCGv_i32 level, want;
24336fd0c7bcSRichard Henderson     TCGv_i64 addr;
243498a9cb79SRichard Henderson 
243598a9cb79SRichard Henderson     nullify_over(ctx);
243698a9cb79SRichard Henderson 
2437deee69a1SRichard Henderson     dest = dest_gpr(ctx, a->t);
2438deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2439eed14219SRichard Henderson 
2440deee69a1SRichard Henderson     if (a->imm) {
2441e5d487c9SRichard Henderson         level = tcg_constant_i32(a->ri & 3);
244298a9cb79SRichard Henderson     } else {
2443eed14219SRichard Henderson         level = tcg_temp_new_i32();
24446fd0c7bcSRichard Henderson         tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri));
2445eed14219SRichard Henderson         tcg_gen_andi_i32(level, level, 3);
244698a9cb79SRichard Henderson     }
244729dd6f64SRichard Henderson     want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ);
2448eed14219SRichard Henderson 
2449ad75a51eSRichard Henderson     gen_helper_probe(dest, tcg_env, addr, level, want);
2450eed14219SRichard Henderson 
2451deee69a1SRichard Henderson     save_gpr(ctx, a->t, dest);
245231234768SRichard Henderson     return nullify_end(ctx);
245398a9cb79SRichard Henderson }
245498a9cb79SRichard Henderson 
2455deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
24568d6ae7fbSRichard Henderson {
24578577f354SRichard Henderson     if (ctx->is_pa20) {
24588577f354SRichard Henderson         return false;
24598577f354SRichard Henderson     }
2460deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2461deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
24626fd0c7bcSRichard Henderson     TCGv_i64 addr;
24636fd0c7bcSRichard Henderson     TCGv_i64 ofs, reg;
24648d6ae7fbSRichard Henderson 
24658d6ae7fbSRichard Henderson     nullify_over(ctx);
24668d6ae7fbSRichard Henderson 
2467deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2468deee69a1SRichard Henderson     reg = load_gpr(ctx, a->r);
2469deee69a1SRichard Henderson     if (a->addr) {
24708577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
24718d6ae7fbSRichard Henderson     } else {
24728577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
24738d6ae7fbSRichard Henderson     }
24748d6ae7fbSRichard Henderson 
247532dc7569SSven Schnelle     /* Exit TB for TLB change if mmu is enabled.  */
247632dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
247731234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
247831234768SRichard Henderson     }
247931234768SRichard Henderson     return nullify_end(ctx);
2480deee69a1SRichard Henderson #endif
24818d6ae7fbSRichard Henderson }
248263300a00SRichard Henderson 
2483eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local)
248463300a00SRichard Henderson {
2485deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2486deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
24876fd0c7bcSRichard Henderson     TCGv_i64 addr;
24886fd0c7bcSRichard Henderson     TCGv_i64 ofs;
248963300a00SRichard Henderson 
249063300a00SRichard Henderson     nullify_over(ctx);
249163300a00SRichard Henderson 
2492deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2493eb25d10fSHelge Deller 
2494eb25d10fSHelge Deller     /*
2495eb25d10fSHelge Deller      * Page align now, rather than later, so that we can add in the
2496eb25d10fSHelge Deller      * page_size field from pa2.0 from the low 4 bits of GR[b].
2497eb25d10fSHelge Deller      */
2498eb25d10fSHelge Deller     tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK);
2499eb25d10fSHelge Deller     if (ctx->is_pa20) {
2500eb25d10fSHelge Deller         tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4);
250163300a00SRichard Henderson     }
2502eb25d10fSHelge Deller 
2503eb25d10fSHelge Deller     if (local) {
2504eb25d10fSHelge Deller         gen_helper_ptlb_l(tcg_env, addr);
250563300a00SRichard Henderson     } else {
2506ad75a51eSRichard Henderson         gen_helper_ptlb(tcg_env, addr);
250763300a00SRichard Henderson     }
250863300a00SRichard Henderson 
2509eb25d10fSHelge Deller     if (a->m) {
2510eb25d10fSHelge Deller         save_gpr(ctx, a->b, ofs);
2511eb25d10fSHelge Deller     }
2512eb25d10fSHelge Deller 
2513eb25d10fSHelge Deller     /* Exit TB for TLB change if mmu is enabled.  */
2514eb25d10fSHelge Deller     if (ctx->tb_flags & PSW_C) {
2515eb25d10fSHelge Deller         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2516eb25d10fSHelge Deller     }
2517eb25d10fSHelge Deller     return nullify_end(ctx);
2518eb25d10fSHelge Deller #endif
2519eb25d10fSHelge Deller }
2520eb25d10fSHelge Deller 
2521eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a)
2522eb25d10fSHelge Deller {
2523eb25d10fSHelge Deller     return do_pxtlb(ctx, a, false);
2524eb25d10fSHelge Deller }
2525eb25d10fSHelge Deller 
2526eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a)
2527eb25d10fSHelge Deller {
2528eb25d10fSHelge Deller     return ctx->is_pa20 && do_pxtlb(ctx, a, true);
2529eb25d10fSHelge Deller }
2530eb25d10fSHelge Deller 
2531eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a)
2532eb25d10fSHelge Deller {
2533eb25d10fSHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2534eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY
2535eb25d10fSHelge Deller     nullify_over(ctx);
2536eb25d10fSHelge Deller 
2537eb25d10fSHelge Deller     trans_nop_addrx(ctx, a);
2538eb25d10fSHelge Deller     gen_helper_ptlbe(tcg_env);
2539eb25d10fSHelge Deller 
254063300a00SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
254132dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
254231234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
254331234768SRichard Henderson     }
254431234768SRichard Henderson     return nullify_end(ctx);
2545deee69a1SRichard Henderson #endif
254663300a00SRichard Henderson }
25472dfcca9fSRichard Henderson 
25486797c315SNick Hudson /*
25496797c315SNick Hudson  * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
25506797c315SNick Hudson  * See
25516797c315SNick Hudson  *     https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
25526797c315SNick Hudson  *     page 13-9 (195/206)
25536797c315SNick Hudson  */
25546797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
25556797c315SNick Hudson {
25568577f354SRichard Henderson     if (ctx->is_pa20) {
25578577f354SRichard Henderson         return false;
25588577f354SRichard Henderson     }
25596797c315SNick Hudson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
25606797c315SNick Hudson #ifndef CONFIG_USER_ONLY
25616fd0c7bcSRichard Henderson     TCGv_i64 addr, atl, stl;
25626fd0c7bcSRichard Henderson     TCGv_i64 reg;
25636797c315SNick Hudson 
25646797c315SNick Hudson     nullify_over(ctx);
25656797c315SNick Hudson 
25666797c315SNick Hudson     /*
25676797c315SNick Hudson      * FIXME:
25686797c315SNick Hudson      *  if (not (pcxl or pcxl2))
25696797c315SNick Hudson      *    return gen_illegal(ctx);
25706797c315SNick Hudson      */
25716797c315SNick Hudson 
25726fd0c7bcSRichard Henderson     atl = tcg_temp_new_i64();
25736fd0c7bcSRichard Henderson     stl = tcg_temp_new_i64();
25746fd0c7bcSRichard Henderson     addr = tcg_temp_new_i64();
25756797c315SNick Hudson 
2576ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(stl, tcg_env,
25776797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
25786797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIASQ]));
2579ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(atl, tcg_env,
25806797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
25816797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIAOQ]));
25826797c315SNick Hudson     tcg_gen_shli_i64(stl, stl, 32);
2583d265360fSRichard Henderson     tcg_gen_or_i64(addr, atl, stl);
25846797c315SNick Hudson 
25856797c315SNick Hudson     reg = load_gpr(ctx, a->r);
25866797c315SNick Hudson     if (a->addr) {
25878577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
25886797c315SNick Hudson     } else {
25898577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
25906797c315SNick Hudson     }
25916797c315SNick Hudson 
25926797c315SNick Hudson     /* Exit TB for TLB change if mmu is enabled.  */
25936797c315SNick Hudson     if (ctx->tb_flags & PSW_C) {
25946797c315SNick Hudson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
25956797c315SNick Hudson     }
25966797c315SNick Hudson     return nullify_end(ctx);
25976797c315SNick Hudson #endif
25986797c315SNick Hudson }
25996797c315SNick Hudson 
26008577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
26018577f354SRichard Henderson {
26028577f354SRichard Henderson     if (!ctx->is_pa20) {
26038577f354SRichard Henderson         return false;
26048577f354SRichard Henderson     }
26058577f354SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
26068577f354SRichard Henderson #ifndef CONFIG_USER_ONLY
26078577f354SRichard Henderson     nullify_over(ctx);
26088577f354SRichard Henderson     {
26098577f354SRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
26108577f354SRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->r2);
26118577f354SRichard Henderson 
26128577f354SRichard Henderson         if (a->data) {
26138577f354SRichard Henderson             gen_helper_idtlbt_pa20(tcg_env, src1, src2);
26148577f354SRichard Henderson         } else {
26158577f354SRichard Henderson             gen_helper_iitlbt_pa20(tcg_env, src1, src2);
26168577f354SRichard Henderson         }
26178577f354SRichard Henderson     }
26188577f354SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
26198577f354SRichard Henderson     if (ctx->tb_flags & PSW_C) {
26208577f354SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
26218577f354SRichard Henderson     }
26228577f354SRichard Henderson     return nullify_end(ctx);
26238577f354SRichard Henderson #endif
26248577f354SRichard Henderson }
26258577f354SRichard Henderson 
2626deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
26272dfcca9fSRichard Henderson {
2628deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2629deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
26306fd0c7bcSRichard Henderson     TCGv_i64 vaddr;
26316fd0c7bcSRichard Henderson     TCGv_i64 ofs, paddr;
26322dfcca9fSRichard Henderson 
26332dfcca9fSRichard Henderson     nullify_over(ctx);
26342dfcca9fSRichard Henderson 
2635deee69a1SRichard Henderson     form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
26362dfcca9fSRichard Henderson 
2637aac0f603SRichard Henderson     paddr = tcg_temp_new_i64();
2638ad75a51eSRichard Henderson     gen_helper_lpa(paddr, tcg_env, vaddr);
26392dfcca9fSRichard Henderson 
26402dfcca9fSRichard Henderson     /* Note that physical address result overrides base modification.  */
2641deee69a1SRichard Henderson     if (a->m) {
2642deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
26432dfcca9fSRichard Henderson     }
2644deee69a1SRichard Henderson     save_gpr(ctx, a->t, paddr);
26452dfcca9fSRichard Henderson 
264631234768SRichard Henderson     return nullify_end(ctx);
2647deee69a1SRichard Henderson #endif
26482dfcca9fSRichard Henderson }
264943a97b81SRichard Henderson 
2650deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a)
265143a97b81SRichard Henderson {
265243a97b81SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
265343a97b81SRichard Henderson 
265443a97b81SRichard Henderson     /* The Coherence Index is an implementation-defined function of the
265543a97b81SRichard Henderson        physical address.  Two addresses with the same CI have a coherent
265643a97b81SRichard Henderson        view of the cache.  Our implementation is to return 0 for all,
265743a97b81SRichard Henderson        since the entire address space is coherent.  */
2658a4db4a78SRichard Henderson     save_gpr(ctx, a->t, ctx->zero);
265943a97b81SRichard Henderson 
266031234768SRichard Henderson     cond_free(&ctx->null_cond);
266131234768SRichard Henderson     return true;
266243a97b81SRichard Henderson }
266398a9cb79SRichard Henderson 
2664faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2665b2167459SRichard Henderson {
26660c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, false);
2667b2167459SRichard Henderson }
2668b2167459SRichard Henderson 
2669faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2670b2167459SRichard Henderson {
26710c982a28SRichard Henderson     return do_add_reg(ctx, a, true, false, false, false);
2672b2167459SRichard Henderson }
2673b2167459SRichard Henderson 
2674faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2675b2167459SRichard Henderson {
26760c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, false);
2677b2167459SRichard Henderson }
2678b2167459SRichard Henderson 
2679faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2680b2167459SRichard Henderson {
26810c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, true);
26820c982a28SRichard Henderson }
2683b2167459SRichard Henderson 
2684faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
26850c982a28SRichard Henderson {
26860c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, true);
26870c982a28SRichard Henderson }
26880c982a28SRichard Henderson 
268963c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
26900c982a28SRichard Henderson {
26910c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, false);
26920c982a28SRichard Henderson }
26930c982a28SRichard Henderson 
269463c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
26950c982a28SRichard Henderson {
26960c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, false);
26970c982a28SRichard Henderson }
26980c982a28SRichard Henderson 
269963c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
27000c982a28SRichard Henderson {
27010c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, true);
27020c982a28SRichard Henderson }
27030c982a28SRichard Henderson 
270463c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
27050c982a28SRichard Henderson {
27060c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, true);
27070c982a28SRichard Henderson }
27080c982a28SRichard Henderson 
270963c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
27100c982a28SRichard Henderson {
27110c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, true, false);
27120c982a28SRichard Henderson }
27130c982a28SRichard Henderson 
271463c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
27150c982a28SRichard Henderson {
27160c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, true, false);
27170c982a28SRichard Henderson }
27180c982a28SRichard Henderson 
2719fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
27200c982a28SRichard Henderson {
27216fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_andc_i64);
27220c982a28SRichard Henderson }
27230c982a28SRichard Henderson 
2724fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
27250c982a28SRichard Henderson {
27266fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_and_i64);
27270c982a28SRichard Henderson }
27280c982a28SRichard Henderson 
2729fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
27300c982a28SRichard Henderson {
27310c982a28SRichard Henderson     if (a->cf == 0) {
27320c982a28SRichard Henderson         unsigned r2 = a->r2;
27330c982a28SRichard Henderson         unsigned r1 = a->r1;
27340c982a28SRichard Henderson         unsigned rt = a->t;
27350c982a28SRichard Henderson 
27367aee8189SRichard Henderson         if (rt == 0) { /* NOP */
27377aee8189SRichard Henderson             cond_free(&ctx->null_cond);
27387aee8189SRichard Henderson             return true;
27397aee8189SRichard Henderson         }
27407aee8189SRichard Henderson         if (r2 == 0) { /* COPY */
2741b2167459SRichard Henderson             if (r1 == 0) {
27426fd0c7bcSRichard Henderson                 TCGv_i64 dest = dest_gpr(ctx, rt);
27436fd0c7bcSRichard Henderson                 tcg_gen_movi_i64(dest, 0);
2744b2167459SRichard Henderson                 save_gpr(ctx, rt, dest);
2745b2167459SRichard Henderson             } else {
2746b2167459SRichard Henderson                 save_gpr(ctx, rt, cpu_gr[r1]);
2747b2167459SRichard Henderson             }
2748b2167459SRichard Henderson             cond_free(&ctx->null_cond);
274931234768SRichard Henderson             return true;
2750b2167459SRichard Henderson         }
27517aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY
27527aee8189SRichard Henderson         /* These are QEMU extensions and are nops in the real architecture:
27537aee8189SRichard Henderson          *
27547aee8189SRichard Henderson          * or %r10,%r10,%r10 -- idle loop; wait for interrupt
27557aee8189SRichard Henderson          * or %r31,%r31,%r31 -- death loop; offline cpu
27567aee8189SRichard Henderson          *                      currently implemented as idle.
27577aee8189SRichard Henderson          */
27587aee8189SRichard Henderson         if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
27597aee8189SRichard Henderson             /* No need to check for supervisor, as userland can only pause
27607aee8189SRichard Henderson                until the next timer interrupt.  */
27617aee8189SRichard Henderson             nullify_over(ctx);
27627aee8189SRichard Henderson 
27637aee8189SRichard Henderson             /* Advance the instruction queue.  */
2764bc921866SRichard Henderson             install_iaq_entries(ctx, &ctx->iaq_b, NULL);
27657aee8189SRichard Henderson             nullify_set(ctx, 0);
27667aee8189SRichard Henderson 
27677aee8189SRichard Henderson             /* Tell the qemu main loop to halt until this cpu has work.  */
2768ad75a51eSRichard Henderson             tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
276929dd6f64SRichard Henderson                            offsetof(CPUState, halted) - offsetof(HPPACPU, env));
27707aee8189SRichard Henderson             gen_excp_1(EXCP_HALTED);
27717aee8189SRichard Henderson             ctx->base.is_jmp = DISAS_NORETURN;
27727aee8189SRichard Henderson 
27737aee8189SRichard Henderson             return nullify_end(ctx);
27747aee8189SRichard Henderson         }
27757aee8189SRichard Henderson #endif
27767aee8189SRichard Henderson     }
27776fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_or_i64);
27787aee8189SRichard Henderson }
2779b2167459SRichard Henderson 
2780fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
2781b2167459SRichard Henderson {
27826fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_xor_i64);
27830c982a28SRichard Henderson }
27840c982a28SRichard Henderson 
2785345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
27860c982a28SRichard Henderson {
27876fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2788b2167459SRichard Henderson 
27890c982a28SRichard Henderson     if (a->cf) {
2790b2167459SRichard Henderson         nullify_over(ctx);
2791b2167459SRichard Henderson     }
27920c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
27930c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2794345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
279531234768SRichard Henderson     return nullify_end(ctx);
2796b2167459SRichard Henderson }
2797b2167459SRichard Henderson 
2798af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
2799b2167459SRichard Henderson {
280046bb3d46SRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, dest;
2801b2167459SRichard Henderson 
28020c982a28SRichard Henderson     if (a->cf) {
2803b2167459SRichard Henderson         nullify_over(ctx);
2804b2167459SRichard Henderson     }
280546bb3d46SRichard Henderson 
28060c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
28070c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
280846bb3d46SRichard Henderson     dest = dest_gpr(ctx, a->t);
280946bb3d46SRichard Henderson 
281046bb3d46SRichard Henderson     tcg_gen_xor_i64(dest, tcg_r1, tcg_r2);
281146bb3d46SRichard Henderson     save_gpr(ctx, a->t, dest);
281246bb3d46SRichard Henderson 
281346bb3d46SRichard Henderson     cond_free(&ctx->null_cond);
281446bb3d46SRichard Henderson     if (a->cf) {
281546bb3d46SRichard Henderson         ctx->null_cond = do_unit_zero_cond(a->cf, a->d, dest);
281646bb3d46SRichard Henderson     }
281746bb3d46SRichard Henderson 
281831234768SRichard Henderson     return nullify_end(ctx);
2819b2167459SRichard Henderson }
2820b2167459SRichard Henderson 
2821af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
2822b2167459SRichard Henderson {
28236fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, tmp;
2824b2167459SRichard Henderson 
2825ababac16SRichard Henderson     if (a->cf == 0) {
2826ababac16SRichard Henderson         tcg_r2 = load_gpr(ctx, a->r2);
2827ababac16SRichard Henderson         tmp = dest_gpr(ctx, a->t);
2828ababac16SRichard Henderson 
2829ababac16SRichard Henderson         if (a->r1 == 0) {
2830ababac16SRichard Henderson             /* UADDCM r0,src,dst is the common idiom for dst = ~src. */
2831ababac16SRichard Henderson             tcg_gen_not_i64(tmp, tcg_r2);
2832ababac16SRichard Henderson         } else {
2833ababac16SRichard Henderson             /*
2834ababac16SRichard Henderson              * Recall that r1 - r2 == r1 + ~r2 + 1.
2835ababac16SRichard Henderson              * Thus r1 + ~r2 == r1 - r2 - 1,
2836ababac16SRichard Henderson              * which does not require an extra temporary.
2837ababac16SRichard Henderson              */
2838ababac16SRichard Henderson             tcg_r1 = load_gpr(ctx, a->r1);
2839ababac16SRichard Henderson             tcg_gen_sub_i64(tmp, tcg_r1, tcg_r2);
2840ababac16SRichard Henderson             tcg_gen_subi_i64(tmp, tmp, 1);
2841b2167459SRichard Henderson         }
2842ababac16SRichard Henderson         save_gpr(ctx, a->t, tmp);
2843ababac16SRichard Henderson         cond_free(&ctx->null_cond);
2844ababac16SRichard Henderson         return true;
2845ababac16SRichard Henderson     }
2846ababac16SRichard Henderson 
2847ababac16SRichard Henderson     nullify_over(ctx);
28480c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
28490c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2850aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
28516fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, tcg_r2);
285246bb3d46SRichard Henderson     do_unit_addsub(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, true);
285331234768SRichard Henderson     return nullify_end(ctx);
2854b2167459SRichard Henderson }
2855b2167459SRichard Henderson 
2856af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
2857b2167459SRichard Henderson {
28580c982a28SRichard Henderson     return do_uaddcm(ctx, a, false);
28590c982a28SRichard Henderson }
28600c982a28SRichard Henderson 
2861af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
28620c982a28SRichard Henderson {
28630c982a28SRichard Henderson     return do_uaddcm(ctx, a, true);
28640c982a28SRichard Henderson }
28650c982a28SRichard Henderson 
2866af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
28670c982a28SRichard Henderson {
28686fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2869b2167459SRichard Henderson 
2870b2167459SRichard Henderson     nullify_over(ctx);
2871b2167459SRichard Henderson 
2872aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2873d0ae87a2SRichard Henderson     tcg_gen_extract2_i64(tmp, cpu_psw_cb, cpu_psw_cb_msb, 4);
2874b2167459SRichard Henderson     if (!is_i) {
28756fd0c7bcSRichard Henderson         tcg_gen_not_i64(tmp, tmp);
2876b2167459SRichard Henderson     }
28776fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
28786fd0c7bcSRichard Henderson     tcg_gen_muli_i64(tmp, tmp, 6);
287946bb3d46SRichard Henderson     do_unit_addsub(ctx, a->t, load_gpr(ctx, a->r), tmp,
288046bb3d46SRichard Henderson                    a->cf, a->d, false, is_i);
288131234768SRichard Henderson     return nullify_end(ctx);
2882b2167459SRichard Henderson }
2883b2167459SRichard Henderson 
2884af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
2885b2167459SRichard Henderson {
28860c982a28SRichard Henderson     return do_dcor(ctx, a, false);
28870c982a28SRichard Henderson }
28880c982a28SRichard Henderson 
2889af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
28900c982a28SRichard Henderson {
28910c982a28SRichard Henderson     return do_dcor(ctx, a, true);
28920c982a28SRichard Henderson }
28930c982a28SRichard Henderson 
28940c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
28950c982a28SRichard Henderson {
2896a4db4a78SRichard Henderson     TCGv_i64 dest, add1, add2, addc, in1, in2;
2897b2167459SRichard Henderson 
2898b2167459SRichard Henderson     nullify_over(ctx);
2899b2167459SRichard Henderson 
29000c982a28SRichard Henderson     in1 = load_gpr(ctx, a->r1);
29010c982a28SRichard Henderson     in2 = load_gpr(ctx, a->r2);
2902b2167459SRichard Henderson 
2903aac0f603SRichard Henderson     add1 = tcg_temp_new_i64();
2904aac0f603SRichard Henderson     add2 = tcg_temp_new_i64();
2905aac0f603SRichard Henderson     addc = tcg_temp_new_i64();
2906aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
2907b2167459SRichard Henderson 
2908b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
29096fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, in1, in1);
29106fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
2911b2167459SRichard Henderson 
291272ca8753SRichard Henderson     /*
291372ca8753SRichard Henderson      * Add or subtract R2, depending on PSW[V].  Proper computation of
291472ca8753SRichard Henderson      * carry requires that we subtract via + ~R2 + 1, as described in
291572ca8753SRichard Henderson      * the manual.  By extracting and masking V, we can produce the
291672ca8753SRichard Henderson      * proper inputs to the addition without movcond.
291772ca8753SRichard Henderson      */
29186fd0c7bcSRichard Henderson     tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
29196fd0c7bcSRichard Henderson     tcg_gen_xor_i64(add2, in2, addc);
29206fd0c7bcSRichard Henderson     tcg_gen_andi_i64(addc, addc, 1);
292172ca8753SRichard Henderson 
2922a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero);
2923a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb,
2924a4db4a78SRichard Henderson                      addc, ctx->zero);
2925b2167459SRichard Henderson 
2926b2167459SRichard Henderson     /* Write back the result register.  */
29270c982a28SRichard Henderson     save_gpr(ctx, a->t, dest);
2928b2167459SRichard Henderson 
2929b2167459SRichard Henderson     /* Write back PSW[CB].  */
29306fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
29316fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
2932b2167459SRichard Henderson 
2933f8f5986eSRichard Henderson     /*
2934f8f5986eSRichard Henderson      * Write back PSW[V] for the division step.
2935f8f5986eSRichard Henderson      * Shift cb{8} from where it lives in bit 32 to bit 31,
2936f8f5986eSRichard Henderson      * so that it overlaps r2{32} in bit 31.
2937f8f5986eSRichard Henderson      */
2938f8f5986eSRichard Henderson     tcg_gen_shri_i64(cpu_psw_v, cpu_psw_cb, 1);
29396fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
2940b2167459SRichard Henderson 
2941b2167459SRichard Henderson     /* Install the new nullification.  */
29420c982a28SRichard Henderson     if (a->cf) {
2943f8f5986eSRichard Henderson         TCGv_i64 sv = NULL, uv = NULL;
2944b47a4a02SSven Schnelle         if (cond_need_sv(a->cf >> 1)) {
2945f8f5986eSRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2, in1, 1, false);
2946f8f5986eSRichard Henderson         } else if (cond_need_cb(a->cf >> 1)) {
2947f8f5986eSRichard Henderson             uv = do_add_uv(ctx, cpu_psw_cb, NULL, in1, 1, false);
2948b2167459SRichard Henderson         }
2949f8f5986eSRichard Henderson         ctx->null_cond = do_cond(ctx, a->cf, false, dest, uv, sv);
2950b2167459SRichard Henderson     }
2951b2167459SRichard Henderson 
295231234768SRichard Henderson     return nullify_end(ctx);
2953b2167459SRichard Henderson }
2954b2167459SRichard Henderson 
29550588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a)
2956b2167459SRichard Henderson {
29570588e061SRichard Henderson     return do_add_imm(ctx, a, false, false);
29580588e061SRichard Henderson }
29590588e061SRichard Henderson 
29600588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a)
29610588e061SRichard Henderson {
29620588e061SRichard Henderson     return do_add_imm(ctx, a, true, false);
29630588e061SRichard Henderson }
29640588e061SRichard Henderson 
29650588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a)
29660588e061SRichard Henderson {
29670588e061SRichard Henderson     return do_add_imm(ctx, a, false, true);
29680588e061SRichard Henderson }
29690588e061SRichard Henderson 
29700588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a)
29710588e061SRichard Henderson {
29720588e061SRichard Henderson     return do_add_imm(ctx, a, true, true);
29730588e061SRichard Henderson }
29740588e061SRichard Henderson 
29750588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a)
29760588e061SRichard Henderson {
29770588e061SRichard Henderson     return do_sub_imm(ctx, a, false);
29780588e061SRichard Henderson }
29790588e061SRichard Henderson 
29800588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
29810588e061SRichard Henderson {
29820588e061SRichard Henderson     return do_sub_imm(ctx, a, true);
29830588e061SRichard Henderson }
29840588e061SRichard Henderson 
2985345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
29860588e061SRichard Henderson {
29876fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
2988b2167459SRichard Henderson 
29890588e061SRichard Henderson     if (a->cf) {
2990b2167459SRichard Henderson         nullify_over(ctx);
2991b2167459SRichard Henderson     }
2992b2167459SRichard Henderson 
29936fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
29940588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
2995345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
2996b2167459SRichard Henderson 
299731234768SRichard Henderson     return nullify_end(ctx);
2998b2167459SRichard Henderson }
2999b2167459SRichard Henderson 
30000843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a,
30010843563fSRichard Henderson                           void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
30020843563fSRichard Henderson {
30030843563fSRichard Henderson     TCGv_i64 r1, r2, dest;
30040843563fSRichard Henderson 
30050843563fSRichard Henderson     if (!ctx->is_pa20) {
30060843563fSRichard Henderson         return false;
30070843563fSRichard Henderson     }
30080843563fSRichard Henderson 
30090843563fSRichard Henderson     nullify_over(ctx);
30100843563fSRichard Henderson 
30110843563fSRichard Henderson     r1 = load_gpr(ctx, a->r1);
30120843563fSRichard Henderson     r2 = load_gpr(ctx, a->r2);
30130843563fSRichard Henderson     dest = dest_gpr(ctx, a->t);
30140843563fSRichard Henderson 
30150843563fSRichard Henderson     fn(dest, r1, r2);
30160843563fSRichard Henderson     save_gpr(ctx, a->t, dest);
30170843563fSRichard Henderson 
30180843563fSRichard Henderson     return nullify_end(ctx);
30190843563fSRichard Henderson }
30200843563fSRichard Henderson 
3021151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a,
3022151f309bSRichard Henderson                              void (*fn)(TCGv_i64, TCGv_i64, int64_t))
3023151f309bSRichard Henderson {
3024151f309bSRichard Henderson     TCGv_i64 r, dest;
3025151f309bSRichard Henderson 
3026151f309bSRichard Henderson     if (!ctx->is_pa20) {
3027151f309bSRichard Henderson         return false;
3028151f309bSRichard Henderson     }
3029151f309bSRichard Henderson 
3030151f309bSRichard Henderson     nullify_over(ctx);
3031151f309bSRichard Henderson 
3032151f309bSRichard Henderson     r = load_gpr(ctx, a->r);
3033151f309bSRichard Henderson     dest = dest_gpr(ctx, a->t);
3034151f309bSRichard Henderson 
3035151f309bSRichard Henderson     fn(dest, r, a->i);
3036151f309bSRichard Henderson     save_gpr(ctx, a->t, dest);
3037151f309bSRichard Henderson 
3038151f309bSRichard Henderson     return nullify_end(ctx);
3039151f309bSRichard Henderson }
3040151f309bSRichard Henderson 
30413bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a,
30423bbb8e48SRichard Henderson                                 void (*fn)(TCGv_i64, TCGv_i64,
30433bbb8e48SRichard Henderson                                            TCGv_i64, TCGv_i32))
30443bbb8e48SRichard Henderson {
30453bbb8e48SRichard Henderson     TCGv_i64 r1, r2, dest;
30463bbb8e48SRichard Henderson 
30473bbb8e48SRichard Henderson     if (!ctx->is_pa20) {
30483bbb8e48SRichard Henderson         return false;
30493bbb8e48SRichard Henderson     }
30503bbb8e48SRichard Henderson 
30513bbb8e48SRichard Henderson     nullify_over(ctx);
30523bbb8e48SRichard Henderson 
30533bbb8e48SRichard Henderson     r1 = load_gpr(ctx, a->r1);
30543bbb8e48SRichard Henderson     r2 = load_gpr(ctx, a->r2);
30553bbb8e48SRichard Henderson     dest = dest_gpr(ctx, a->t);
30563bbb8e48SRichard Henderson 
30573bbb8e48SRichard Henderson     fn(dest, r1, r2, tcg_constant_i32(a->sh));
30583bbb8e48SRichard Henderson     save_gpr(ctx, a->t, dest);
30593bbb8e48SRichard Henderson 
30603bbb8e48SRichard Henderson     return nullify_end(ctx);
30613bbb8e48SRichard Henderson }
30623bbb8e48SRichard Henderson 
30630843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a)
30640843563fSRichard Henderson {
30650843563fSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_add16_i64);
30660843563fSRichard Henderson }
30670843563fSRichard Henderson 
30680843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a)
30690843563fSRichard Henderson {
30700843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_ss);
30710843563fSRichard Henderson }
30720843563fSRichard Henderson 
30730843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a)
30740843563fSRichard Henderson {
30750843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_us);
30760843563fSRichard Henderson }
30770843563fSRichard Henderson 
30781b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a)
30791b3cb7c8SRichard Henderson {
30801b3cb7c8SRichard Henderson     return do_multimedia(ctx, a, gen_helper_havg);
30811b3cb7c8SRichard Henderson }
30821b3cb7c8SRichard Henderson 
3083151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a)
3084151f309bSRichard Henderson {
3085151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64);
3086151f309bSRichard Henderson }
3087151f309bSRichard Henderson 
3088151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a)
3089151f309bSRichard Henderson {
3090151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64);
3091151f309bSRichard Henderson }
3092151f309bSRichard Henderson 
3093151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a)
3094151f309bSRichard Henderson {
3095151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64);
3096151f309bSRichard Henderson }
3097151f309bSRichard Henderson 
30983bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a)
30993bbb8e48SRichard Henderson {
31003bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshladd);
31013bbb8e48SRichard Henderson }
31023bbb8e48SRichard Henderson 
31033bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a)
31043bbb8e48SRichard Henderson {
31053bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshradd);
31063bbb8e48SRichard Henderson }
31073bbb8e48SRichard Henderson 
310810c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a)
310910c9e58dSRichard Henderson {
311010c9e58dSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64);
311110c9e58dSRichard Henderson }
311210c9e58dSRichard Henderson 
311310c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a)
311410c9e58dSRichard Henderson {
311510c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_ss);
311610c9e58dSRichard Henderson }
311710c9e58dSRichard Henderson 
311810c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a)
311910c9e58dSRichard Henderson {
312010c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_us);
312110c9e58dSRichard Henderson }
312210c9e58dSRichard Henderson 
3123c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3124c2a7ee3fSRichard Henderson {
3125c2a7ee3fSRichard Henderson     uint64_t mask = 0xffff0000ffff0000ull;
3126c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3127c2a7ee3fSRichard Henderson 
3128c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r2, mask);
3129c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r1, mask);
3130c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, tmp, 16);
3131c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
3132c2a7ee3fSRichard Henderson }
3133c2a7ee3fSRichard Henderson 
3134c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a)
3135c2a7ee3fSRichard Henderson {
3136c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_l);
3137c2a7ee3fSRichard Henderson }
3138c2a7ee3fSRichard Henderson 
3139c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3140c2a7ee3fSRichard Henderson {
3141c2a7ee3fSRichard Henderson     uint64_t mask = 0x0000ffff0000ffffull;
3142c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3143c2a7ee3fSRichard Henderson 
3144c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r1, mask);
3145c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r2, mask);
3146c2a7ee3fSRichard Henderson     tcg_gen_shli_i64(tmp, tmp, 16);
3147c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
3148c2a7ee3fSRichard Henderson }
3149c2a7ee3fSRichard Henderson 
3150c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a)
3151c2a7ee3fSRichard Henderson {
3152c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_r);
3153c2a7ee3fSRichard Henderson }
3154c2a7ee3fSRichard Henderson 
3155c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3156c2a7ee3fSRichard Henderson {
3157c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3158c2a7ee3fSRichard Henderson 
3159c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, r2, 32);
3160c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r1, tmp, 0, 32);
3161c2a7ee3fSRichard Henderson }
3162c2a7ee3fSRichard Henderson 
3163c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a)
3164c2a7ee3fSRichard Henderson {
3165c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_l);
3166c2a7ee3fSRichard Henderson }
3167c2a7ee3fSRichard Henderson 
3168c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3169c2a7ee3fSRichard Henderson {
3170c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r2, r1, 32, 32);
3171c2a7ee3fSRichard Henderson }
3172c2a7ee3fSRichard Henderson 
3173c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a)
3174c2a7ee3fSRichard Henderson {
3175c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_r);
3176c2a7ee3fSRichard Henderson }
3177c2a7ee3fSRichard Henderson 
31784e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a)
31794e7abdb1SRichard Henderson {
31804e7abdb1SRichard Henderson     TCGv_i64 r, t0, t1, t2, t3;
31814e7abdb1SRichard Henderson 
31824e7abdb1SRichard Henderson     if (!ctx->is_pa20) {
31834e7abdb1SRichard Henderson         return false;
31844e7abdb1SRichard Henderson     }
31854e7abdb1SRichard Henderson 
31864e7abdb1SRichard Henderson     nullify_over(ctx);
31874e7abdb1SRichard Henderson 
31884e7abdb1SRichard Henderson     r = load_gpr(ctx, a->r1);
31894e7abdb1SRichard Henderson     t0 = tcg_temp_new_i64();
31904e7abdb1SRichard Henderson     t1 = tcg_temp_new_i64();
31914e7abdb1SRichard Henderson     t2 = tcg_temp_new_i64();
31924e7abdb1SRichard Henderson     t3 = tcg_temp_new_i64();
31934e7abdb1SRichard Henderson 
31944e7abdb1SRichard Henderson     tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16);
31954e7abdb1SRichard Henderson     tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16);
31964e7abdb1SRichard Henderson     tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16);
31974e7abdb1SRichard Henderson     tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16);
31984e7abdb1SRichard Henderson 
31994e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t1, t0, 16, 48);
32004e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t2, t3, t2, 16, 48);
32014e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t2, t0, 32, 32);
32024e7abdb1SRichard Henderson 
32034e7abdb1SRichard Henderson     save_gpr(ctx, a->t, t0);
32044e7abdb1SRichard Henderson     return nullify_end(ctx);
32054e7abdb1SRichard Henderson }
32064e7abdb1SRichard Henderson 
32071cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a)
320896d6407fSRichard Henderson {
3209b5caa17cSRichard Henderson     if (ctx->is_pa20) {
3210b5caa17cSRichard Henderson        /*
3211b5caa17cSRichard Henderson         * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches.
3212b5caa17cSRichard Henderson         * Any base modification still occurs.
3213b5caa17cSRichard Henderson         */
3214b5caa17cSRichard Henderson         if (a->t == 0) {
3215b5caa17cSRichard Henderson             return trans_nop_addrx(ctx, a);
3216b5caa17cSRichard Henderson         }
3217b5caa17cSRichard Henderson     } else if (a->size > MO_32) {
32180786a3b6SHelge Deller         return gen_illegal(ctx);
3219c53e401eSRichard Henderson     }
32201cd012a5SRichard Henderson     return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
32211cd012a5SRichard Henderson                    a->disp, a->sp, a->m, a->size | MO_TE);
322296d6407fSRichard Henderson }
322396d6407fSRichard Henderson 
32241cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a)
322596d6407fSRichard Henderson {
32261cd012a5SRichard Henderson     assert(a->x == 0 && a->scale == 0);
3227c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
32280786a3b6SHelge Deller         return gen_illegal(ctx);
322996d6407fSRichard Henderson     }
3230c53e401eSRichard Henderson     return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
32310786a3b6SHelge Deller }
323296d6407fSRichard Henderson 
32331cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
323496d6407fSRichard Henderson {
3235b1af755cSRichard Henderson     MemOp mop = MO_TE | MO_ALIGN | a->size;
3236a4db4a78SRichard Henderson     TCGv_i64 dest, ofs;
32376fd0c7bcSRichard Henderson     TCGv_i64 addr;
323896d6407fSRichard Henderson 
3239c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
324051416c4eSRichard Henderson         return gen_illegal(ctx);
324151416c4eSRichard Henderson     }
324251416c4eSRichard Henderson 
324396d6407fSRichard Henderson     nullify_over(ctx);
324496d6407fSRichard Henderson 
32451cd012a5SRichard Henderson     if (a->m) {
324686f8d05fSRichard Henderson         /* Base register modification.  Make sure if RT == RB,
324786f8d05fSRichard Henderson            we see the result of the load.  */
3248aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
324996d6407fSRichard Henderson     } else {
32501cd012a5SRichard Henderson         dest = dest_gpr(ctx, a->t);
325196d6407fSRichard Henderson     }
325296d6407fSRichard Henderson 
3253c3ea1996SSven Schnelle     form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? 3 : 0,
325417fe594cSRichard Henderson              a->disp, a->sp, a->m, MMU_DISABLED(ctx));
3255b1af755cSRichard Henderson 
3256b1af755cSRichard Henderson     /*
3257b1af755cSRichard Henderson      * For hppa1.1, LDCW is undefined unless aligned mod 16.
3258b1af755cSRichard Henderson      * However actual hardware succeeds with aligned mod 4.
3259b1af755cSRichard Henderson      * Detect this case and log a GUEST_ERROR.
3260b1af755cSRichard Henderson      *
3261b1af755cSRichard Henderson      * TODO: HPPA64 relaxes the over-alignment requirement
3262b1af755cSRichard Henderson      * with the ,co completer.
3263b1af755cSRichard Henderson      */
3264b1af755cSRichard Henderson     gen_helper_ldc_check(addr);
3265b1af755cSRichard Henderson 
3266a4db4a78SRichard Henderson     tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop);
3267b1af755cSRichard Henderson 
32681cd012a5SRichard Henderson     if (a->m) {
32691cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
327096d6407fSRichard Henderson     }
32711cd012a5SRichard Henderson     save_gpr(ctx, a->t, dest);
327296d6407fSRichard Henderson 
327331234768SRichard Henderson     return nullify_end(ctx);
327496d6407fSRichard Henderson }
327596d6407fSRichard Henderson 
32761cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a)
327796d6407fSRichard Henderson {
32786fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
32796fd0c7bcSRichard Henderson     TCGv_i64 addr;
328096d6407fSRichard Henderson 
328196d6407fSRichard Henderson     nullify_over(ctx);
328296d6407fSRichard Henderson 
32831cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
328417fe594cSRichard Henderson              MMU_DISABLED(ctx));
32851cd012a5SRichard Henderson     val = load_gpr(ctx, a->r);
32861cd012a5SRichard Henderson     if (a->a) {
3287f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3288ad75a51eSRichard Henderson             gen_helper_stby_e_parallel(tcg_env, addr, val);
3289f9f46db4SEmilio G. Cota         } else {
3290ad75a51eSRichard Henderson             gen_helper_stby_e(tcg_env, addr, val);
3291f9f46db4SEmilio G. Cota         }
3292f9f46db4SEmilio G. Cota     } else {
3293f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3294ad75a51eSRichard Henderson             gen_helper_stby_b_parallel(tcg_env, addr, val);
329596d6407fSRichard Henderson         } else {
3296ad75a51eSRichard Henderson             gen_helper_stby_b(tcg_env, addr, val);
329796d6407fSRichard Henderson         }
3298f9f46db4SEmilio G. Cota     }
32991cd012a5SRichard Henderson     if (a->m) {
33006fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~3);
33011cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
330296d6407fSRichard Henderson     }
330396d6407fSRichard Henderson 
330431234768SRichard Henderson     return nullify_end(ctx);
330596d6407fSRichard Henderson }
330696d6407fSRichard Henderson 
330725460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a)
330825460fc5SRichard Henderson {
33096fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
33106fd0c7bcSRichard Henderson     TCGv_i64 addr;
331125460fc5SRichard Henderson 
331225460fc5SRichard Henderson     if (!ctx->is_pa20) {
331325460fc5SRichard Henderson         return false;
331425460fc5SRichard Henderson     }
331525460fc5SRichard Henderson     nullify_over(ctx);
331625460fc5SRichard Henderson 
331725460fc5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
331817fe594cSRichard Henderson              MMU_DISABLED(ctx));
331925460fc5SRichard Henderson     val = load_gpr(ctx, a->r);
332025460fc5SRichard Henderson     if (a->a) {
332125460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
332225460fc5SRichard Henderson             gen_helper_stdby_e_parallel(tcg_env, addr, val);
332325460fc5SRichard Henderson         } else {
332425460fc5SRichard Henderson             gen_helper_stdby_e(tcg_env, addr, val);
332525460fc5SRichard Henderson         }
332625460fc5SRichard Henderson     } else {
332725460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
332825460fc5SRichard Henderson             gen_helper_stdby_b_parallel(tcg_env, addr, val);
332925460fc5SRichard Henderson         } else {
333025460fc5SRichard Henderson             gen_helper_stdby_b(tcg_env, addr, val);
333125460fc5SRichard Henderson         }
333225460fc5SRichard Henderson     }
333325460fc5SRichard Henderson     if (a->m) {
33346fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~7);
333525460fc5SRichard Henderson         save_gpr(ctx, a->b, ofs);
333625460fc5SRichard Henderson     }
333725460fc5SRichard Henderson 
333825460fc5SRichard Henderson     return nullify_end(ctx);
333925460fc5SRichard Henderson }
334025460fc5SRichard Henderson 
33411cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a)
3342d0a851ccSRichard Henderson {
3343d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3344d0a851ccSRichard Henderson 
3345d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3346451d993dSRichard Henderson     ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX;
33471cd012a5SRichard Henderson     trans_ld(ctx, a);
3348d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
334931234768SRichard Henderson     return true;
3350d0a851ccSRichard Henderson }
3351d0a851ccSRichard Henderson 
33521cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a)
3353d0a851ccSRichard Henderson {
3354d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3355d0a851ccSRichard Henderson 
3356d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3357451d993dSRichard Henderson     ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX;
33581cd012a5SRichard Henderson     trans_st(ctx, a);
3359d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
336031234768SRichard Henderson     return true;
3361d0a851ccSRichard Henderson }
336295412a61SRichard Henderson 
33630588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
3364b2167459SRichard Henderson {
33656fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3366b2167459SRichard Henderson 
33676fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tcg_rt, a->i);
33680588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3369b2167459SRichard Henderson     cond_free(&ctx->null_cond);
337031234768SRichard Henderson     return true;
3371b2167459SRichard Henderson }
3372b2167459SRichard Henderson 
33730588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a)
3374b2167459SRichard Henderson {
33756fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
33766fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
3377b2167459SRichard Henderson 
33786fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
3379b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
3380b2167459SRichard Henderson     cond_free(&ctx->null_cond);
338131234768SRichard Henderson     return true;
3382b2167459SRichard Henderson }
3383b2167459SRichard Henderson 
33840588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
3385b2167459SRichard Henderson {
33866fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3387b2167459SRichard Henderson 
3388b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
3389d265360fSRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_i64.  */
33900588e061SRichard Henderson     if (a->b == 0) {
33916fd0c7bcSRichard Henderson         tcg_gen_movi_i64(tcg_rt, a->i);
3392b2167459SRichard Henderson     } else {
33936fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
3394b2167459SRichard Henderson     }
33950588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3396b2167459SRichard Henderson     cond_free(&ctx->null_cond);
339731234768SRichard Henderson     return true;
3398b2167459SRichard Henderson }
3399b2167459SRichard Henderson 
34006fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
3401e9efd4bcSRichard Henderson                     unsigned c, unsigned f, bool d, unsigned n, int disp)
340298cd9ca7SRichard Henderson {
34036fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv;
340498cd9ca7SRichard Henderson     DisasCond cond;
340598cd9ca7SRichard Henderson 
340698cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3407aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
340898cd9ca7SRichard Henderson 
34096fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
341098cd9ca7SRichard Henderson 
3411f764718dSRichard Henderson     sv = NULL;
3412b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
341398cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
341498cd9ca7SRichard Henderson     }
341598cd9ca7SRichard Henderson 
34164fe9533aSRichard Henderson     cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
341701afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
341898cd9ca7SRichard Henderson }
341998cd9ca7SRichard Henderson 
342001afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
342198cd9ca7SRichard Henderson {
3422e9efd4bcSRichard Henderson     if (!ctx->is_pa20 && a->d) {
3423e9efd4bcSRichard Henderson         return false;
3424e9efd4bcSRichard Henderson     }
342501afb7beSRichard Henderson     nullify_over(ctx);
3426e9efd4bcSRichard Henderson     return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
3427e9efd4bcSRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
342801afb7beSRichard Henderson }
342901afb7beSRichard Henderson 
343001afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
343101afb7beSRichard Henderson {
3432c65c3ee1SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3433c65c3ee1SRichard Henderson         return false;
3434c65c3ee1SRichard Henderson     }
343501afb7beSRichard Henderson     nullify_over(ctx);
34366fd0c7bcSRichard Henderson     return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
3437c65c3ee1SRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
343801afb7beSRichard Henderson }
343901afb7beSRichard Henderson 
34406fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
344101afb7beSRichard Henderson                     unsigned c, unsigned f, unsigned n, int disp)
344201afb7beSRichard Henderson {
34436fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv, cb_cond;
344498cd9ca7SRichard Henderson     DisasCond cond;
3445bdcccc17SRichard Henderson     bool d = false;
344698cd9ca7SRichard Henderson 
3447f25d3160SRichard Henderson     /*
3448f25d3160SRichard Henderson      * For hppa64, the ADDB conditions change with PSW.W,
3449f25d3160SRichard Henderson      * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3450f25d3160SRichard Henderson      */
3451f25d3160SRichard Henderson     if (ctx->tb_flags & PSW_W) {
3452f25d3160SRichard Henderson         d = c >= 5;
3453f25d3160SRichard Henderson         if (d) {
3454f25d3160SRichard Henderson             c &= 3;
3455f25d3160SRichard Henderson         }
3456f25d3160SRichard Henderson     }
3457f25d3160SRichard Henderson 
345898cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3459aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
3460f764718dSRichard Henderson     sv = NULL;
3461bdcccc17SRichard Henderson     cb_cond = NULL;
346298cd9ca7SRichard Henderson 
3463b47a4a02SSven Schnelle     if (cond_need_cb(c)) {
3464aac0f603SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
3465aac0f603SRichard Henderson         TCGv_i64 cb_msb = tcg_temp_new_i64();
3466bdcccc17SRichard Henderson 
34676fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cb_msb, 0);
34686fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
34696fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
34706fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
3471bdcccc17SRichard Henderson         cb_cond = get_carry(ctx, d, cb, cb_msb);
3472b47a4a02SSven Schnelle     } else {
34736fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
3474b47a4a02SSven Schnelle     }
3475b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
3476f8f5986eSRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2, in1, 0, d);
347798cd9ca7SRichard Henderson     }
347898cd9ca7SRichard Henderson 
3479a751eb31SRichard Henderson     cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
348043675d20SSven Schnelle     save_gpr(ctx, r, dest);
348101afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
348298cd9ca7SRichard Henderson }
348398cd9ca7SRichard Henderson 
348401afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a)
348598cd9ca7SRichard Henderson {
348601afb7beSRichard Henderson     nullify_over(ctx);
348701afb7beSRichard Henderson     return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
348801afb7beSRichard Henderson }
348901afb7beSRichard Henderson 
349001afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
349101afb7beSRichard Henderson {
349201afb7beSRichard Henderson     nullify_over(ctx);
34936fd0c7bcSRichard Henderson     return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
349401afb7beSRichard Henderson }
349501afb7beSRichard Henderson 
349601afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
349701afb7beSRichard Henderson {
34986fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
349998cd9ca7SRichard Henderson     DisasCond cond;
350098cd9ca7SRichard Henderson 
350198cd9ca7SRichard Henderson     nullify_over(ctx);
350298cd9ca7SRichard Henderson 
3503aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
350401afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
350582d0c831SRichard Henderson     if (a->d) {
350682d0c831SRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
350782d0c831SRichard Henderson     } else {
35081e9ab9fbSRichard Henderson         /* Force shift into [32,63] */
35096fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_sar, 32);
35106fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, tmp);
35111e9ab9fbSRichard Henderson     }
351298cd9ca7SRichard Henderson 
35134c42fd0dSRichard Henderson     cond = cond_make_ti(a->c ? TCG_COND_GE : TCG_COND_LT, tmp, 0);
351401afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
351598cd9ca7SRichard Henderson }
351698cd9ca7SRichard Henderson 
351701afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
351898cd9ca7SRichard Henderson {
351901afb7beSRichard Henderson     DisasCond cond;
3520*b041ec9dSRichard Henderson     int p = a->p | (a->d ? 0 : 32);
352101afb7beSRichard Henderson 
352201afb7beSRichard Henderson     nullify_over(ctx);
3523*b041ec9dSRichard Henderson     cond = cond_make_vi(a->c ? TCG_COND_TSTEQ : TCG_COND_TSTNE,
3524*b041ec9dSRichard Henderson                         load_gpr(ctx, a->r), 1ull << (63 - p));
352501afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
352601afb7beSRichard Henderson }
352701afb7beSRichard Henderson 
352801afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a)
352901afb7beSRichard Henderson {
35306fd0c7bcSRichard Henderson     TCGv_i64 dest;
353198cd9ca7SRichard Henderson     DisasCond cond;
353298cd9ca7SRichard Henderson 
353398cd9ca7SRichard Henderson     nullify_over(ctx);
353498cd9ca7SRichard Henderson 
353501afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r2);
353601afb7beSRichard Henderson     if (a->r1 == 0) {
35376fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, 0);
353898cd9ca7SRichard Henderson     } else {
35396fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
354098cd9ca7SRichard Henderson     }
354198cd9ca7SRichard Henderson 
35424fa52edfSRichard Henderson     /* All MOVB conditions are 32-bit. */
35434fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
354401afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
354501afb7beSRichard Henderson }
354601afb7beSRichard Henderson 
354701afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
354801afb7beSRichard Henderson {
35496fd0c7bcSRichard Henderson     TCGv_i64 dest;
355001afb7beSRichard Henderson     DisasCond cond;
355101afb7beSRichard Henderson 
355201afb7beSRichard Henderson     nullify_over(ctx);
355301afb7beSRichard Henderson 
355401afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r);
35556fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, a->i);
355601afb7beSRichard Henderson 
35574fa52edfSRichard Henderson     /* All MOVBI conditions are 32-bit. */
35584fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
355901afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
356098cd9ca7SRichard Henderson }
356198cd9ca7SRichard Henderson 
3562f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
35630b1347d2SRichard Henderson {
35646fd0c7bcSRichard Henderson     TCGv_i64 dest, src2;
35650b1347d2SRichard Henderson 
3566f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3567f7b775a9SRichard Henderson         return false;
3568f7b775a9SRichard Henderson     }
356930878590SRichard Henderson     if (a->c) {
35700b1347d2SRichard Henderson         nullify_over(ctx);
35710b1347d2SRichard Henderson     }
35720b1347d2SRichard Henderson 
357330878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
3574f7b775a9SRichard Henderson     src2 = load_gpr(ctx, a->r2);
357530878590SRichard Henderson     if (a->r1 == 0) {
3576f7b775a9SRichard Henderson         if (a->d) {
35776fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src2, cpu_sar);
3578f7b775a9SRichard Henderson         } else {
3579aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
3580f7b775a9SRichard Henderson 
35816fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src2);
35826fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
35836fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, dest, tmp);
3584f7b775a9SRichard Henderson         }
358530878590SRichard Henderson     } else if (a->r1 == a->r2) {
3586f7b775a9SRichard Henderson         if (a->d) {
35876fd0c7bcSRichard Henderson             tcg_gen_rotr_i64(dest, src2, cpu_sar);
3588f7b775a9SRichard Henderson         } else {
35890b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
3590e1d635e8SRichard Henderson             TCGv_i32 s32 = tcg_temp_new_i32();
3591e1d635e8SRichard Henderson 
35926fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, src2);
35936fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(s32, cpu_sar);
3594f7b775a9SRichard Henderson             tcg_gen_andi_i32(s32, s32, 31);
3595e1d635e8SRichard Henderson             tcg_gen_rotr_i32(t32, t32, s32);
35966fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
3597f7b775a9SRichard Henderson         }
3598f7b775a9SRichard Henderson     } else {
35996fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
3600f7b775a9SRichard Henderson 
3601f7b775a9SRichard Henderson         if (a->d) {
3602aac0f603SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
3603aac0f603SRichard Henderson             TCGv_i64 n = tcg_temp_new_i64();
3604f7b775a9SRichard Henderson 
36056fd0c7bcSRichard Henderson             tcg_gen_xori_i64(n, cpu_sar, 63);
3606a01491a2SHelge Deller             tcg_gen_shl_i64(t, src1, n);
36076fd0c7bcSRichard Henderson             tcg_gen_shli_i64(t, t, 1);
3608a01491a2SHelge Deller             tcg_gen_shr_i64(dest, src2, cpu_sar);
36096fd0c7bcSRichard Henderson             tcg_gen_or_i64(dest, dest, t);
36100b1347d2SRichard Henderson         } else {
36110b1347d2SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
36120b1347d2SRichard Henderson             TCGv_i64 s = tcg_temp_new_i64();
36130b1347d2SRichard Henderson 
36146fd0c7bcSRichard Henderson             tcg_gen_concat32_i64(t, src2, src1);
3615967662cdSRichard Henderson             tcg_gen_andi_i64(s, cpu_sar, 31);
3616967662cdSRichard Henderson             tcg_gen_shr_i64(dest, t, s);
36170b1347d2SRichard Henderson         }
3618f7b775a9SRichard Henderson     }
361930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36200b1347d2SRichard Henderson 
36210b1347d2SRichard Henderson     /* Install the new nullification.  */
36220b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
362330878590SRichard Henderson     if (a->c) {
3624d37fad0aSSven Schnelle         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
36250b1347d2SRichard Henderson     }
362631234768SRichard Henderson     return nullify_end(ctx);
36270b1347d2SRichard Henderson }
36280b1347d2SRichard Henderson 
3629f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
36300b1347d2SRichard Henderson {
3631f7b775a9SRichard Henderson     unsigned width, sa;
36326fd0c7bcSRichard Henderson     TCGv_i64 dest, t2;
36330b1347d2SRichard Henderson 
3634f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3635f7b775a9SRichard Henderson         return false;
3636f7b775a9SRichard Henderson     }
363730878590SRichard Henderson     if (a->c) {
36380b1347d2SRichard Henderson         nullify_over(ctx);
36390b1347d2SRichard Henderson     }
36400b1347d2SRichard Henderson 
3641f7b775a9SRichard Henderson     width = a->d ? 64 : 32;
3642f7b775a9SRichard Henderson     sa = width - 1 - a->cpos;
3643f7b775a9SRichard Henderson 
364430878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
364530878590SRichard Henderson     t2 = load_gpr(ctx, a->r2);
364605bfd4dbSRichard Henderson     if (a->r1 == 0) {
36476fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, t2, sa, width - sa);
3648c53e401eSRichard Henderson     } else if (width == TARGET_LONG_BITS) {
36496fd0c7bcSRichard Henderson         tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
3650f7b775a9SRichard Henderson     } else {
3651f7b775a9SRichard Henderson         assert(!a->d);
3652f7b775a9SRichard Henderson         if (a->r1 == a->r2) {
36530b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
36546fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, t2);
36550b1347d2SRichard Henderson             tcg_gen_rotri_i32(t32, t32, sa);
36566fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
36570b1347d2SRichard Henderson         } else {
3658967662cdSRichard Henderson             tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]);
3659967662cdSRichard Henderson             tcg_gen_extract_i64(dest, dest, sa, 32);
36600b1347d2SRichard Henderson         }
3661f7b775a9SRichard Henderson     }
366230878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36630b1347d2SRichard Henderson 
36640b1347d2SRichard Henderson     /* Install the new nullification.  */
36650b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
366630878590SRichard Henderson     if (a->c) {
3667d37fad0aSSven Schnelle         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
36680b1347d2SRichard Henderson     }
366931234768SRichard Henderson     return nullify_end(ctx);
36700b1347d2SRichard Henderson }
36710b1347d2SRichard Henderson 
3672bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
36730b1347d2SRichard Henderson {
3674bd792da3SRichard Henderson     unsigned widthm1 = a->d ? 63 : 31;
36756fd0c7bcSRichard Henderson     TCGv_i64 dest, src, tmp;
36760b1347d2SRichard Henderson 
3677bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3678bd792da3SRichard Henderson         return false;
3679bd792da3SRichard Henderson     }
368030878590SRichard Henderson     if (a->c) {
36810b1347d2SRichard Henderson         nullify_over(ctx);
36820b1347d2SRichard Henderson     }
36830b1347d2SRichard Henderson 
368430878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
368530878590SRichard Henderson     src = load_gpr(ctx, a->r);
3686aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
36870b1347d2SRichard Henderson 
36880b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
36896fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
36906fd0c7bcSRichard Henderson     tcg_gen_xori_i64(tmp, tmp, widthm1);
3691d781cb77SRichard Henderson 
369230878590SRichard Henderson     if (a->se) {
3693bd792da3SRichard Henderson         if (!a->d) {
36946fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(dest, src);
3695bd792da3SRichard Henderson             src = dest;
3696bd792da3SRichard Henderson         }
36976fd0c7bcSRichard Henderson         tcg_gen_sar_i64(dest, src, tmp);
36986fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, dest, 0, a->len);
36990b1347d2SRichard Henderson     } else {
3700bd792da3SRichard Henderson         if (!a->d) {
37016fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src);
3702bd792da3SRichard Henderson             src = dest;
3703bd792da3SRichard Henderson         }
37046fd0c7bcSRichard Henderson         tcg_gen_shr_i64(dest, src, tmp);
37056fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, dest, 0, a->len);
37060b1347d2SRichard Henderson     }
370730878590SRichard Henderson     save_gpr(ctx, a->t, dest);
37080b1347d2SRichard Henderson 
37090b1347d2SRichard Henderson     /* Install the new nullification.  */
37100b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
371130878590SRichard Henderson     if (a->c) {
3712bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
37130b1347d2SRichard Henderson     }
371431234768SRichard Henderson     return nullify_end(ctx);
37150b1347d2SRichard Henderson }
37160b1347d2SRichard Henderson 
3717bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
37180b1347d2SRichard Henderson {
3719bd792da3SRichard Henderson     unsigned len, cpos, width;
37206fd0c7bcSRichard Henderson     TCGv_i64 dest, src;
37210b1347d2SRichard Henderson 
3722bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3723bd792da3SRichard Henderson         return false;
3724bd792da3SRichard Henderson     }
372530878590SRichard Henderson     if (a->c) {
37260b1347d2SRichard Henderson         nullify_over(ctx);
37270b1347d2SRichard Henderson     }
37280b1347d2SRichard Henderson 
3729bd792da3SRichard Henderson     len = a->len;
3730bd792da3SRichard Henderson     width = a->d ? 64 : 32;
3731bd792da3SRichard Henderson     cpos = width - 1 - a->pos;
3732bd792da3SRichard Henderson     if (cpos + len > width) {
3733bd792da3SRichard Henderson         len = width - cpos;
3734bd792da3SRichard Henderson     }
3735bd792da3SRichard Henderson 
373630878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
373730878590SRichard Henderson     src = load_gpr(ctx, a->r);
373830878590SRichard Henderson     if (a->se) {
37396fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, src, cpos, len);
37400b1347d2SRichard Henderson     } else {
37416fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, src, cpos, len);
37420b1347d2SRichard Henderson     }
374330878590SRichard Henderson     save_gpr(ctx, a->t, dest);
37440b1347d2SRichard Henderson 
37450b1347d2SRichard Henderson     /* Install the new nullification.  */
37460b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
374730878590SRichard Henderson     if (a->c) {
3748bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
37490b1347d2SRichard Henderson     }
375031234768SRichard Henderson     return nullify_end(ctx);
37510b1347d2SRichard Henderson }
37520b1347d2SRichard Henderson 
375372ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
37540b1347d2SRichard Henderson {
375572ae4f2bSRichard Henderson     unsigned len, width;
3756c53e401eSRichard Henderson     uint64_t mask0, mask1;
37576fd0c7bcSRichard Henderson     TCGv_i64 dest;
37580b1347d2SRichard Henderson 
375972ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
376072ae4f2bSRichard Henderson         return false;
376172ae4f2bSRichard Henderson     }
376230878590SRichard Henderson     if (a->c) {
37630b1347d2SRichard Henderson         nullify_over(ctx);
37640b1347d2SRichard Henderson     }
376572ae4f2bSRichard Henderson 
376672ae4f2bSRichard Henderson     len = a->len;
376772ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
376872ae4f2bSRichard Henderson     if (a->cpos + len > width) {
376972ae4f2bSRichard Henderson         len = width - a->cpos;
37700b1347d2SRichard Henderson     }
37710b1347d2SRichard Henderson 
377230878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
377330878590SRichard Henderson     mask0 = deposit64(0, a->cpos, len, a->i);
377430878590SRichard Henderson     mask1 = deposit64(-1, a->cpos, len, a->i);
37750b1347d2SRichard Henderson 
377630878590SRichard Henderson     if (a->nz) {
37776fd0c7bcSRichard Henderson         TCGv_i64 src = load_gpr(ctx, a->t);
37786fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, src, mask1);
37796fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, mask0);
37800b1347d2SRichard Henderson     } else {
37816fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, mask0);
37820b1347d2SRichard Henderson     }
378330878590SRichard Henderson     save_gpr(ctx, a->t, dest);
37840b1347d2SRichard Henderson 
37850b1347d2SRichard Henderson     /* Install the new nullification.  */
37860b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
378730878590SRichard Henderson     if (a->c) {
378872ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
37890b1347d2SRichard Henderson     }
379031234768SRichard Henderson     return nullify_end(ctx);
37910b1347d2SRichard Henderson }
37920b1347d2SRichard Henderson 
379372ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
37940b1347d2SRichard Henderson {
379530878590SRichard Henderson     unsigned rs = a->nz ? a->t : 0;
379672ae4f2bSRichard Henderson     unsigned len, width;
37976fd0c7bcSRichard Henderson     TCGv_i64 dest, val;
37980b1347d2SRichard Henderson 
379972ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
380072ae4f2bSRichard Henderson         return false;
380172ae4f2bSRichard Henderson     }
380230878590SRichard Henderson     if (a->c) {
38030b1347d2SRichard Henderson         nullify_over(ctx);
38040b1347d2SRichard Henderson     }
380572ae4f2bSRichard Henderson 
380672ae4f2bSRichard Henderson     len = a->len;
380772ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
380872ae4f2bSRichard Henderson     if (a->cpos + len > width) {
380972ae4f2bSRichard Henderson         len = width - a->cpos;
38100b1347d2SRichard Henderson     }
38110b1347d2SRichard Henderson 
381230878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
381330878590SRichard Henderson     val = load_gpr(ctx, a->r);
38140b1347d2SRichard Henderson     if (rs == 0) {
38156fd0c7bcSRichard Henderson         tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
38160b1347d2SRichard Henderson     } else {
38176fd0c7bcSRichard Henderson         tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
38180b1347d2SRichard Henderson     }
381930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
38200b1347d2SRichard Henderson 
38210b1347d2SRichard Henderson     /* Install the new nullification.  */
38220b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
382330878590SRichard Henderson     if (a->c) {
382472ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
38250b1347d2SRichard Henderson     }
382631234768SRichard Henderson     return nullify_end(ctx);
38270b1347d2SRichard Henderson }
38280b1347d2SRichard Henderson 
382972ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
38306fd0c7bcSRichard Henderson                        bool d, bool nz, unsigned len, TCGv_i64 val)
38310b1347d2SRichard Henderson {
38320b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
383372ae4f2bSRichard Henderson     unsigned widthm1 = d ? 63 : 31;
38346fd0c7bcSRichard Henderson     TCGv_i64 mask, tmp, shift, dest;
3835c53e401eSRichard Henderson     uint64_t msb = 1ULL << (len - 1);
38360b1347d2SRichard Henderson 
38370b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
3838aac0f603SRichard Henderson     shift = tcg_temp_new_i64();
3839aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
38400b1347d2SRichard Henderson 
38410b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
38426fd0c7bcSRichard Henderson     tcg_gen_andi_i64(shift, cpu_sar, widthm1);
38436fd0c7bcSRichard Henderson     tcg_gen_xori_i64(shift, shift, widthm1);
38440b1347d2SRichard Henderson 
3845aac0f603SRichard Henderson     mask = tcg_temp_new_i64();
38466fd0c7bcSRichard Henderson     tcg_gen_movi_i64(mask, msb + (msb - 1));
38476fd0c7bcSRichard Henderson     tcg_gen_and_i64(tmp, val, mask);
38480b1347d2SRichard Henderson     if (rs) {
38496fd0c7bcSRichard Henderson         tcg_gen_shl_i64(mask, mask, shift);
38506fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tmp, shift);
38516fd0c7bcSRichard Henderson         tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
38526fd0c7bcSRichard Henderson         tcg_gen_or_i64(dest, dest, tmp);
38530b1347d2SRichard Henderson     } else {
38546fd0c7bcSRichard Henderson         tcg_gen_shl_i64(dest, tmp, shift);
38550b1347d2SRichard Henderson     }
38560b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
38570b1347d2SRichard Henderson 
38580b1347d2SRichard Henderson     /* Install the new nullification.  */
38590b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
38600b1347d2SRichard Henderson     if (c) {
386172ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, c, d, dest);
38620b1347d2SRichard Henderson     }
386331234768SRichard Henderson     return nullify_end(ctx);
38640b1347d2SRichard Henderson }
38650b1347d2SRichard Henderson 
386672ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
386730878590SRichard Henderson {
386872ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
386972ae4f2bSRichard Henderson         return false;
387072ae4f2bSRichard Henderson     }
3871a6deecceSSven Schnelle     if (a->c) {
3872a6deecceSSven Schnelle         nullify_over(ctx);
3873a6deecceSSven Schnelle     }
387472ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
387572ae4f2bSRichard Henderson                       load_gpr(ctx, a->r));
387630878590SRichard Henderson }
387730878590SRichard Henderson 
387872ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
387930878590SRichard Henderson {
388072ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
388172ae4f2bSRichard Henderson         return false;
388272ae4f2bSRichard Henderson     }
3883a6deecceSSven Schnelle     if (a->c) {
3884a6deecceSSven Schnelle         nullify_over(ctx);
3885a6deecceSSven Schnelle     }
388672ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
38876fd0c7bcSRichard Henderson                       tcg_constant_i64(a->i));
388830878590SRichard Henderson }
38890b1347d2SRichard Henderson 
38908340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a)
389198cd9ca7SRichard Henderson {
3892019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY
3893bc921866SRichard Henderson     ctx->iaq_j.space = tcg_temp_new_i64();
3894bc921866SRichard Henderson     load_spr(ctx, ctx->iaq_j.space, a->sp);
3895c301f34eSRichard Henderson #endif
3896019f4159SRichard Henderson 
3897bc921866SRichard Henderson     ctx->iaq_j.base = tcg_temp_new_i64();
3898bc921866SRichard Henderson     ctx->iaq_j.disp = 0;
3899bc921866SRichard Henderson 
3900bc921866SRichard Henderson     tcg_gen_addi_i64(ctx->iaq_j.base, load_gpr(ctx, a->b), a->disp);
3901bc921866SRichard Henderson     ctx->iaq_j.base = do_ibranch_priv(ctx, ctx->iaq_j.base);
3902bc921866SRichard Henderson 
3903bc921866SRichard Henderson     return do_ibranch(ctx, a->l, true, a->n);
390498cd9ca7SRichard Henderson }
390598cd9ca7SRichard Henderson 
39068340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a)
390798cd9ca7SRichard Henderson {
39082644f80bSRichard Henderson     return do_dbranch(ctx, a->disp, a->l, a->n);
390998cd9ca7SRichard Henderson }
391098cd9ca7SRichard Henderson 
39118340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
391243e05652SRichard Henderson {
3913bc921866SRichard Henderson     int64_t disp = a->disp;
391443e05652SRichard Henderson 
39156e5f5300SSven Schnelle     nullify_over(ctx);
39166e5f5300SSven Schnelle 
391743e05652SRichard Henderson     /* Make sure the caller hasn't done something weird with the queue.
391843e05652SRichard Henderson      * ??? This is not quite the same as the PSW[B] bit, which would be
391943e05652SRichard Henderson      * expensive to track.  Real hardware will trap for
392043e05652SRichard Henderson      *    b  gateway
392143e05652SRichard Henderson      *    b  gateway+4  (in delay slot of first branch)
392243e05652SRichard Henderson      * However, checking for a non-sequential instruction queue *will*
392343e05652SRichard Henderson      * diagnose the security hole
392443e05652SRichard Henderson      *    b  gateway
392543e05652SRichard Henderson      *    b  evil
392643e05652SRichard Henderson      * in which instructions at evil would run with increased privs.
392743e05652SRichard Henderson      */
3928bc921866SRichard Henderson     if (iaqe_variable(&ctx->iaq_b) || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) {
392943e05652SRichard Henderson         return gen_illegal(ctx);
393043e05652SRichard Henderson     }
393143e05652SRichard Henderson 
393243e05652SRichard Henderson #ifndef CONFIG_USER_ONLY
393343e05652SRichard Henderson     if (ctx->tb_flags & PSW_C) {
393494956d7bSPhilippe Mathieu-Daudé         int type = hppa_artype_for_page(cpu_env(ctx->cs), ctx->base.pc_next);
393543e05652SRichard Henderson         /* If we could not find a TLB entry, then we need to generate an
393643e05652SRichard Henderson            ITLB miss exception so the kernel will provide it.
393743e05652SRichard Henderson            The resulting TLB fill operation will invalidate this TB and
393843e05652SRichard Henderson            we will re-translate, at which point we *will* be able to find
393943e05652SRichard Henderson            the TLB entry and determine if this is in fact a gateway page.  */
394043e05652SRichard Henderson         if (type < 0) {
394131234768SRichard Henderson             gen_excp(ctx, EXCP_ITLB_MISS);
394231234768SRichard Henderson             return true;
394343e05652SRichard Henderson         }
394443e05652SRichard Henderson         /* No change for non-gateway pages or for priv decrease.  */
394543e05652SRichard Henderson         if (type >= 4 && type - 4 < ctx->privilege) {
3946bc921866SRichard Henderson             disp -= ctx->privilege;
3947bc921866SRichard Henderson             disp += type - 4;
394843e05652SRichard Henderson         }
394943e05652SRichard Henderson     } else {
3950bc921866SRichard Henderson         disp -= ctx->privilege;  /* priv = 0 */
395143e05652SRichard Henderson     }
395243e05652SRichard Henderson #endif
395343e05652SRichard Henderson 
39546e5f5300SSven Schnelle     if (a->l) {
39556fd0c7bcSRichard Henderson         TCGv_i64 tmp = dest_gpr(ctx, a->l);
39566e5f5300SSven Schnelle         if (ctx->privilege < 3) {
39576fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, tmp, -4);
39586e5f5300SSven Schnelle         }
39596fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
39606e5f5300SSven Schnelle         save_gpr(ctx, a->l, tmp);
39616e5f5300SSven Schnelle     }
39626e5f5300SSven Schnelle 
3963bc921866SRichard Henderson     return do_dbranch(ctx, disp, 0, a->n);
396443e05652SRichard Henderson }
396543e05652SRichard Henderson 
39668340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a)
396798cd9ca7SRichard Henderson {
3968b35aec85SRichard Henderson     if (a->x) {
3969bc921866SRichard Henderson         DisasIAQE next = iaqe_incr(&ctx->iaq_f, 8);
3970bc921866SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
3971bc921866SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
3972bc921866SRichard Henderson 
3973660eefe1SRichard Henderson         /* The computation here never changes privilege level.  */
3974bc921866SRichard Henderson         copy_iaoq_entry(ctx, t0, &next);
3975bc921866SRichard Henderson         tcg_gen_shli_i64(t1, load_gpr(ctx, a->x), 3);
3976bc921866SRichard Henderson         tcg_gen_add_i64(t0, t0, t1);
3977bc921866SRichard Henderson 
3978bc921866SRichard Henderson         ctx->iaq_j = iaqe_next_absv(ctx, t0);
3979bc921866SRichard Henderson         return do_ibranch(ctx, a->l, false, a->n);
3980b35aec85SRichard Henderson     } else {
3981b35aec85SRichard Henderson         /* BLR R0,RX is a good way to load PC+8 into RX.  */
39822644f80bSRichard Henderson         return do_dbranch(ctx, 0, a->l, a->n);
3983b35aec85SRichard Henderson     }
398498cd9ca7SRichard Henderson }
398598cd9ca7SRichard Henderson 
39868340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a)
398798cd9ca7SRichard Henderson {
39886fd0c7bcSRichard Henderson     TCGv_i64 dest;
398998cd9ca7SRichard Henderson 
39908340f534SRichard Henderson     if (a->x == 0) {
39918340f534SRichard Henderson         dest = load_gpr(ctx, a->b);
399298cd9ca7SRichard Henderson     } else {
3993aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
39946fd0c7bcSRichard Henderson         tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
39956fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
399698cd9ca7SRichard Henderson     }
3997660eefe1SRichard Henderson     dest = do_ibranch_priv(ctx, dest);
3998bc921866SRichard Henderson     ctx->iaq_j = iaqe_next_absv(ctx, dest);
3999bc921866SRichard Henderson 
4000bc921866SRichard Henderson     return do_ibranch(ctx, 0, false, a->n);
400198cd9ca7SRichard Henderson }
400298cd9ca7SRichard Henderson 
40038340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a)
400498cd9ca7SRichard Henderson {
4005019f4159SRichard Henderson     TCGv_i64 b = load_gpr(ctx, a->b);
400698cd9ca7SRichard Henderson 
4007019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY
4008bc921866SRichard Henderson     ctx->iaq_j.space = space_select(ctx, 0, b);
4009c301f34eSRichard Henderson #endif
4010bc921866SRichard Henderson     ctx->iaq_j.base = do_ibranch_priv(ctx, b);
4011bc921866SRichard Henderson     ctx->iaq_j.disp = 0;
4012019f4159SRichard Henderson 
4013bc921866SRichard Henderson     return do_ibranch(ctx, a->l, false, a->n);
401498cd9ca7SRichard Henderson }
401598cd9ca7SRichard Henderson 
4016a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
4017a8966ba7SRichard Henderson {
4018a8966ba7SRichard Henderson     /* All branch target stack instructions implement as nop. */
4019a8966ba7SRichard Henderson     return ctx->is_pa20;
4020a8966ba7SRichard Henderson }
4021a8966ba7SRichard Henderson 
40221ca74648SRichard Henderson /*
40231ca74648SRichard Henderson  * Float class 0
40241ca74648SRichard Henderson  */
4025ebe9383cSRichard Henderson 
40261ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4027ebe9383cSRichard Henderson {
4028ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
4029ebe9383cSRichard Henderson }
4030ebe9383cSRichard Henderson 
403159f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
403259f8c04bSHelge Deller {
4033a300dad3SRichard Henderson     uint64_t ret;
4034a300dad3SRichard Henderson 
4035c53e401eSRichard Henderson     if (ctx->is_pa20) {
4036a300dad3SRichard Henderson         ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
4037a300dad3SRichard Henderson     } else {
4038a300dad3SRichard Henderson         ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
4039a300dad3SRichard Henderson     }
4040a300dad3SRichard Henderson 
404159f8c04bSHelge Deller     nullify_over(ctx);
4042a300dad3SRichard Henderson     save_frd(0, tcg_constant_i64(ret));
404359f8c04bSHelge Deller     return nullify_end(ctx);
404459f8c04bSHelge Deller }
404559f8c04bSHelge Deller 
40461ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a)
40471ca74648SRichard Henderson {
40481ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f);
40491ca74648SRichard Henderson }
40501ca74648SRichard Henderson 
4051ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4052ebe9383cSRichard Henderson {
4053ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
4054ebe9383cSRichard Henderson }
4055ebe9383cSRichard Henderson 
40561ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a)
40571ca74648SRichard Henderson {
40581ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d);
40591ca74648SRichard Henderson }
40601ca74648SRichard Henderson 
40611ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4062ebe9383cSRichard Henderson {
4063ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
4064ebe9383cSRichard Henderson }
4065ebe9383cSRichard Henderson 
40661ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a)
40671ca74648SRichard Henderson {
40681ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fabs_f);
40691ca74648SRichard Henderson }
40701ca74648SRichard Henderson 
4071ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4072ebe9383cSRichard Henderson {
4073ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
4074ebe9383cSRichard Henderson }
4075ebe9383cSRichard Henderson 
40761ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a)
40771ca74648SRichard Henderson {
40781ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fabs_d);
40791ca74648SRichard Henderson }
40801ca74648SRichard Henderson 
40811ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a)
40821ca74648SRichard Henderson {
40831ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s);
40841ca74648SRichard Henderson }
40851ca74648SRichard Henderson 
40861ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a)
40871ca74648SRichard Henderson {
40881ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d);
40891ca74648SRichard Henderson }
40901ca74648SRichard Henderson 
40911ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a)
40921ca74648SRichard Henderson {
40931ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s);
40941ca74648SRichard Henderson }
40951ca74648SRichard Henderson 
40961ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a)
40971ca74648SRichard Henderson {
40981ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d);
40991ca74648SRichard Henderson }
41001ca74648SRichard Henderson 
41011ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4102ebe9383cSRichard Henderson {
4103ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
4104ebe9383cSRichard Henderson }
4105ebe9383cSRichard Henderson 
41061ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a)
41071ca74648SRichard Henderson {
41081ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fneg_f);
41091ca74648SRichard Henderson }
41101ca74648SRichard Henderson 
4111ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4112ebe9383cSRichard Henderson {
4113ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
4114ebe9383cSRichard Henderson }
4115ebe9383cSRichard Henderson 
41161ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a)
41171ca74648SRichard Henderson {
41181ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fneg_d);
41191ca74648SRichard Henderson }
41201ca74648SRichard Henderson 
41211ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4122ebe9383cSRichard Henderson {
4123ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
4124ebe9383cSRichard Henderson }
4125ebe9383cSRichard Henderson 
41261ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a)
41271ca74648SRichard Henderson {
41281ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f);
41291ca74648SRichard Henderson }
41301ca74648SRichard Henderson 
4131ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4132ebe9383cSRichard Henderson {
4133ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
4134ebe9383cSRichard Henderson }
4135ebe9383cSRichard Henderson 
41361ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a)
41371ca74648SRichard Henderson {
41381ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d);
41391ca74648SRichard Henderson }
41401ca74648SRichard Henderson 
41411ca74648SRichard Henderson /*
41421ca74648SRichard Henderson  * Float class 1
41431ca74648SRichard Henderson  */
41441ca74648SRichard Henderson 
41451ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a)
41461ca74648SRichard Henderson {
41471ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s);
41481ca74648SRichard Henderson }
41491ca74648SRichard Henderson 
41501ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a)
41511ca74648SRichard Henderson {
41521ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d);
41531ca74648SRichard Henderson }
41541ca74648SRichard Henderson 
41551ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a)
41561ca74648SRichard Henderson {
41571ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s);
41581ca74648SRichard Henderson }
41591ca74648SRichard Henderson 
41601ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a)
41611ca74648SRichard Henderson {
41621ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s);
41631ca74648SRichard Henderson }
41641ca74648SRichard Henderson 
41651ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a)
41661ca74648SRichard Henderson {
41671ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d);
41681ca74648SRichard Henderson }
41691ca74648SRichard Henderson 
41701ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a)
41711ca74648SRichard Henderson {
41721ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d);
41731ca74648SRichard Henderson }
41741ca74648SRichard Henderson 
41751ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a)
41761ca74648SRichard Henderson {
41771ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w);
41781ca74648SRichard Henderson }
41791ca74648SRichard Henderson 
41801ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a)
41811ca74648SRichard Henderson {
41821ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w);
41831ca74648SRichard Henderson }
41841ca74648SRichard Henderson 
41851ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a)
41861ca74648SRichard Henderson {
41871ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw);
41881ca74648SRichard Henderson }
41891ca74648SRichard Henderson 
41901ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a)
41911ca74648SRichard Henderson {
41921ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw);
41931ca74648SRichard Henderson }
41941ca74648SRichard Henderson 
41951ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a)
41961ca74648SRichard Henderson {
41971ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w);
41981ca74648SRichard Henderson }
41991ca74648SRichard Henderson 
42001ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a)
42011ca74648SRichard Henderson {
42021ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w);
42031ca74648SRichard Henderson }
42041ca74648SRichard Henderson 
42051ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a)
42061ca74648SRichard Henderson {
42071ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw);
42081ca74648SRichard Henderson }
42091ca74648SRichard Henderson 
42101ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a)
42111ca74648SRichard Henderson {
42121ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw);
42131ca74648SRichard Henderson }
42141ca74648SRichard Henderson 
42151ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a)
42161ca74648SRichard Henderson {
42171ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s);
42181ca74648SRichard Henderson }
42191ca74648SRichard Henderson 
42201ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a)
42211ca74648SRichard Henderson {
42221ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s);
42231ca74648SRichard Henderson }
42241ca74648SRichard Henderson 
42251ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a)
42261ca74648SRichard Henderson {
42271ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d);
42281ca74648SRichard Henderson }
42291ca74648SRichard Henderson 
42301ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a)
42311ca74648SRichard Henderson {
42321ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d);
42331ca74648SRichard Henderson }
42341ca74648SRichard Henderson 
42351ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a)
42361ca74648SRichard Henderson {
42371ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw);
42381ca74648SRichard Henderson }
42391ca74648SRichard Henderson 
42401ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a)
42411ca74648SRichard Henderson {
42421ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw);
42431ca74648SRichard Henderson }
42441ca74648SRichard Henderson 
42451ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a)
42461ca74648SRichard Henderson {
42471ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw);
42481ca74648SRichard Henderson }
42491ca74648SRichard Henderson 
42501ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a)
42511ca74648SRichard Henderson {
42521ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw);
42531ca74648SRichard Henderson }
42541ca74648SRichard Henderson 
42551ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a)
42561ca74648SRichard Henderson {
42571ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw);
42581ca74648SRichard Henderson }
42591ca74648SRichard Henderson 
42601ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a)
42611ca74648SRichard Henderson {
42621ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw);
42631ca74648SRichard Henderson }
42641ca74648SRichard Henderson 
42651ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a)
42661ca74648SRichard Henderson {
42671ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw);
42681ca74648SRichard Henderson }
42691ca74648SRichard Henderson 
42701ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a)
42711ca74648SRichard Henderson {
42721ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw);
42731ca74648SRichard Henderson }
42741ca74648SRichard Henderson 
42751ca74648SRichard Henderson /*
42761ca74648SRichard Henderson  * Float class 2
42771ca74648SRichard Henderson  */
42781ca74648SRichard Henderson 
42791ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a)
4280ebe9383cSRichard Henderson {
4281ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
4282ebe9383cSRichard Henderson 
4283ebe9383cSRichard Henderson     nullify_over(ctx);
4284ebe9383cSRichard Henderson 
42851ca74648SRichard Henderson     ta = load_frw0_i32(a->r1);
42861ca74648SRichard Henderson     tb = load_frw0_i32(a->r2);
428729dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
428829dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4289ebe9383cSRichard Henderson 
4290ad75a51eSRichard Henderson     gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc);
4291ebe9383cSRichard Henderson 
42921ca74648SRichard Henderson     return nullify_end(ctx);
4293ebe9383cSRichard Henderson }
4294ebe9383cSRichard Henderson 
42951ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
4296ebe9383cSRichard Henderson {
4297ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
4298ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
4299ebe9383cSRichard Henderson 
4300ebe9383cSRichard Henderson     nullify_over(ctx);
4301ebe9383cSRichard Henderson 
43021ca74648SRichard Henderson     ta = load_frd0(a->r1);
43031ca74648SRichard Henderson     tb = load_frd0(a->r2);
430429dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
430529dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4306ebe9383cSRichard Henderson 
4307ad75a51eSRichard Henderson     gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc);
4308ebe9383cSRichard Henderson 
430931234768SRichard Henderson     return nullify_end(ctx);
4310ebe9383cSRichard Henderson }
4311ebe9383cSRichard Henderson 
43121ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
4313ebe9383cSRichard Henderson {
43146fd0c7bcSRichard Henderson     TCGv_i64 t;
4315ebe9383cSRichard Henderson 
4316ebe9383cSRichard Henderson     nullify_over(ctx);
4317ebe9383cSRichard Henderson 
4318aac0f603SRichard Henderson     t = tcg_temp_new_i64();
43196fd0c7bcSRichard Henderson     tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
4320ebe9383cSRichard Henderson 
43211ca74648SRichard Henderson     if (a->y == 1) {
4322ebe9383cSRichard Henderson         int mask;
4323ebe9383cSRichard Henderson         bool inv = false;
4324ebe9383cSRichard Henderson 
43251ca74648SRichard Henderson         switch (a->c) {
4326ebe9383cSRichard Henderson         case 0: /* simple */
43276fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, 0x4000000);
43284c42fd0dSRichard Henderson             ctx->null_cond = cond_make_ti(TCG_COND_NE, t, 0);
4329ebe9383cSRichard Henderson             goto done;
4330ebe9383cSRichard Henderson         case 2: /* rej */
4331ebe9383cSRichard Henderson             inv = true;
4332ebe9383cSRichard Henderson             /* fallthru */
4333ebe9383cSRichard Henderson         case 1: /* acc */
4334ebe9383cSRichard Henderson             mask = 0x43ff800;
4335ebe9383cSRichard Henderson             break;
4336ebe9383cSRichard Henderson         case 6: /* rej8 */
4337ebe9383cSRichard Henderson             inv = true;
4338ebe9383cSRichard Henderson             /* fallthru */
4339ebe9383cSRichard Henderson         case 5: /* acc8 */
4340ebe9383cSRichard Henderson             mask = 0x43f8000;
4341ebe9383cSRichard Henderson             break;
4342ebe9383cSRichard Henderson         case 9: /* acc6 */
4343ebe9383cSRichard Henderson             mask = 0x43e0000;
4344ebe9383cSRichard Henderson             break;
4345ebe9383cSRichard Henderson         case 13: /* acc4 */
4346ebe9383cSRichard Henderson             mask = 0x4380000;
4347ebe9383cSRichard Henderson             break;
4348ebe9383cSRichard Henderson         case 17: /* acc2 */
4349ebe9383cSRichard Henderson             mask = 0x4200000;
4350ebe9383cSRichard Henderson             break;
4351ebe9383cSRichard Henderson         default:
43521ca74648SRichard Henderson             gen_illegal(ctx);
43531ca74648SRichard Henderson             return true;
4354ebe9383cSRichard Henderson         }
4355ebe9383cSRichard Henderson         if (inv) {
43566fd0c7bcSRichard Henderson             TCGv_i64 c = tcg_constant_i64(mask);
43576fd0c7bcSRichard Henderson             tcg_gen_or_i64(t, t, c);
43584c42fd0dSRichard Henderson             ctx->null_cond = cond_make_tt(TCG_COND_EQ, t, c);
4359ebe9383cSRichard Henderson         } else {
43606fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, mask);
43614c42fd0dSRichard Henderson             ctx->null_cond = cond_make_ti(TCG_COND_EQ, t, 0);
4362ebe9383cSRichard Henderson         }
43631ca74648SRichard Henderson     } else {
43641ca74648SRichard Henderson         unsigned cbit = (a->y ^ 1) - 1;
43651ca74648SRichard Henderson 
43666fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, t, 21 - cbit, 1);
43674c42fd0dSRichard Henderson         ctx->null_cond = cond_make_ti(TCG_COND_NE, t, 0);
43681ca74648SRichard Henderson     }
43691ca74648SRichard Henderson 
4370ebe9383cSRichard Henderson  done:
437131234768SRichard Henderson     return nullify_end(ctx);
4372ebe9383cSRichard Henderson }
4373ebe9383cSRichard Henderson 
43741ca74648SRichard Henderson /*
43751ca74648SRichard Henderson  * Float class 2
43761ca74648SRichard Henderson  */
43771ca74648SRichard Henderson 
43781ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a)
4379ebe9383cSRichard Henderson {
43801ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s);
43811ca74648SRichard Henderson }
43821ca74648SRichard Henderson 
43831ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a)
43841ca74648SRichard Henderson {
43851ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d);
43861ca74648SRichard Henderson }
43871ca74648SRichard Henderson 
43881ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a)
43891ca74648SRichard Henderson {
43901ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s);
43911ca74648SRichard Henderson }
43921ca74648SRichard Henderson 
43931ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a)
43941ca74648SRichard Henderson {
43951ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d);
43961ca74648SRichard Henderson }
43971ca74648SRichard Henderson 
43981ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a)
43991ca74648SRichard Henderson {
44001ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s);
44011ca74648SRichard Henderson }
44021ca74648SRichard Henderson 
44031ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a)
44041ca74648SRichard Henderson {
44051ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d);
44061ca74648SRichard Henderson }
44071ca74648SRichard Henderson 
44081ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a)
44091ca74648SRichard Henderson {
44101ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s);
44111ca74648SRichard Henderson }
44121ca74648SRichard Henderson 
44131ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a)
44141ca74648SRichard Henderson {
44151ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d);
44161ca74648SRichard Henderson }
44171ca74648SRichard Henderson 
44181ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a)
44191ca74648SRichard Henderson {
44201ca74648SRichard Henderson     TCGv_i64 x, y;
4421ebe9383cSRichard Henderson 
4422ebe9383cSRichard Henderson     nullify_over(ctx);
4423ebe9383cSRichard Henderson 
44241ca74648SRichard Henderson     x = load_frw0_i64(a->r1);
44251ca74648SRichard Henderson     y = load_frw0_i64(a->r2);
44261ca74648SRichard Henderson     tcg_gen_mul_i64(x, x, y);
44271ca74648SRichard Henderson     save_frd(a->t, x);
4428ebe9383cSRichard Henderson 
442931234768SRichard Henderson     return nullify_end(ctx);
4430ebe9383cSRichard Henderson }
4431ebe9383cSRichard Henderson 
4432ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
4433ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
4434ebe9383cSRichard Henderson {
4435ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
4436ebe9383cSRichard Henderson }
4437ebe9383cSRichard Henderson 
4438b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4439ebe9383cSRichard Henderson {
4440b1e2af57SRichard Henderson     int tm = fmpyadd_s_reg(a->tm);
4441b1e2af57SRichard Henderson     int ra = fmpyadd_s_reg(a->ra);
4442b1e2af57SRichard Henderson     int ta = fmpyadd_s_reg(a->ta);
4443b1e2af57SRichard Henderson     int rm2 = fmpyadd_s_reg(a->rm2);
4444b1e2af57SRichard Henderson     int rm1 = fmpyadd_s_reg(a->rm1);
4445ebe9383cSRichard Henderson 
4446ebe9383cSRichard Henderson     nullify_over(ctx);
4447ebe9383cSRichard Henderson 
4448ebe9383cSRichard Henderson     do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4449ebe9383cSRichard Henderson     do_fop_weww(ctx, ta, ta, ra,
4450ebe9383cSRichard Henderson                 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
4451ebe9383cSRichard Henderson 
445231234768SRichard Henderson     return nullify_end(ctx);
4453ebe9383cSRichard Henderson }
4454ebe9383cSRichard Henderson 
4455b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4456b1e2af57SRichard Henderson {
4457b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, false);
4458b1e2af57SRichard Henderson }
4459b1e2af57SRichard Henderson 
4460b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4461b1e2af57SRichard Henderson {
4462b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, true);
4463b1e2af57SRichard Henderson }
4464b1e2af57SRichard Henderson 
4465b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4466b1e2af57SRichard Henderson {
4467b1e2af57SRichard Henderson     nullify_over(ctx);
4468b1e2af57SRichard Henderson 
4469b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4470b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4471b1e2af57SRichard Henderson                 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4472b1e2af57SRichard Henderson 
4473b1e2af57SRichard Henderson     return nullify_end(ctx);
4474b1e2af57SRichard Henderson }
4475b1e2af57SRichard Henderson 
4476b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4477b1e2af57SRichard Henderson {
4478b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, false);
4479b1e2af57SRichard Henderson }
4480b1e2af57SRichard Henderson 
4481b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4482b1e2af57SRichard Henderson {
4483b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, true);
4484b1e2af57SRichard Henderson }
4485b1e2af57SRichard Henderson 
4486c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a)
4487ebe9383cSRichard Henderson {
4488c3bad4f8SRichard Henderson     TCGv_i32 x, y, z;
4489ebe9383cSRichard Henderson 
4490ebe9383cSRichard Henderson     nullify_over(ctx);
4491c3bad4f8SRichard Henderson     x = load_frw0_i32(a->rm1);
4492c3bad4f8SRichard Henderson     y = load_frw0_i32(a->rm2);
4493c3bad4f8SRichard Henderson     z = load_frw0_i32(a->ra3);
4494ebe9383cSRichard Henderson 
4495c3bad4f8SRichard Henderson     if (a->neg) {
4496ad75a51eSRichard Henderson         gen_helper_fmpynfadd_s(x, tcg_env, x, y, z);
4497ebe9383cSRichard Henderson     } else {
4498ad75a51eSRichard Henderson         gen_helper_fmpyfadd_s(x, tcg_env, x, y, z);
4499ebe9383cSRichard Henderson     }
4500ebe9383cSRichard Henderson 
4501c3bad4f8SRichard Henderson     save_frw_i32(a->t, x);
450231234768SRichard Henderson     return nullify_end(ctx);
4503ebe9383cSRichard Henderson }
4504ebe9383cSRichard Henderson 
4505c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
4506ebe9383cSRichard Henderson {
4507c3bad4f8SRichard Henderson     TCGv_i64 x, y, z;
4508ebe9383cSRichard Henderson 
4509ebe9383cSRichard Henderson     nullify_over(ctx);
4510c3bad4f8SRichard Henderson     x = load_frd0(a->rm1);
4511c3bad4f8SRichard Henderson     y = load_frd0(a->rm2);
4512c3bad4f8SRichard Henderson     z = load_frd0(a->ra3);
4513ebe9383cSRichard Henderson 
4514c3bad4f8SRichard Henderson     if (a->neg) {
4515ad75a51eSRichard Henderson         gen_helper_fmpynfadd_d(x, tcg_env, x, y, z);
4516ebe9383cSRichard Henderson     } else {
4517ad75a51eSRichard Henderson         gen_helper_fmpyfadd_d(x, tcg_env, x, y, z);
4518ebe9383cSRichard Henderson     }
4519ebe9383cSRichard Henderson 
4520c3bad4f8SRichard Henderson     save_frd(a->t, x);
452131234768SRichard Henderson     return nullify_end(ctx);
4522ebe9383cSRichard Henderson }
4523ebe9383cSRichard Henderson 
452438193127SRichard Henderson /* Emulate PDC BTLB, called by SeaBIOS-hppa */
452538193127SRichard Henderson static bool trans_diag_btlb(DisasContext *ctx, arg_diag_btlb *a)
452615da177bSSven Schnelle {
4527cf6b28d4SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4528cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY
4529ad75a51eSRichard Henderson     nullify_over(ctx);
4530ad75a51eSRichard Henderson     gen_helper_diag_btlb(tcg_env);
4531cf6b28d4SHelge Deller     return nullify_end(ctx);
453238193127SRichard Henderson #endif
453315da177bSSven Schnelle }
453438193127SRichard Henderson 
453538193127SRichard Henderson /* Print char in %r26 to first serial console, used by SeaBIOS-hppa */
453638193127SRichard Henderson static bool trans_diag_cout(DisasContext *ctx, arg_diag_cout *a)
453738193127SRichard Henderson {
453838193127SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
453938193127SRichard Henderson #ifndef CONFIG_USER_ONLY
4540dbca0835SHelge Deller     nullify_over(ctx);
4541dbca0835SHelge Deller     gen_helper_diag_console_output(tcg_env);
4542dbca0835SHelge Deller     return nullify_end(ctx);
4543ad75a51eSRichard Henderson #endif
454438193127SRichard Henderson }
454538193127SRichard Henderson 
45463bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa1(DisasContext *ctx, arg_empty *a)
45473bdf2081SHelge Deller {
45483bdf2081SHelge Deller     return !ctx->is_pa20 && do_getshadowregs(ctx);
45493bdf2081SHelge Deller }
45503bdf2081SHelge Deller 
45513bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa2(DisasContext *ctx, arg_empty *a)
45523bdf2081SHelge Deller {
45533bdf2081SHelge Deller     return ctx->is_pa20 && do_getshadowregs(ctx);
45543bdf2081SHelge Deller }
45553bdf2081SHelge Deller 
45563bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa1(DisasContext *ctx, arg_empty *a)
45573bdf2081SHelge Deller {
45583bdf2081SHelge Deller     return !ctx->is_pa20 && do_putshadowregs(ctx);
45593bdf2081SHelge Deller }
45603bdf2081SHelge Deller 
45613bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa2(DisasContext *ctx, arg_empty *a)
45623bdf2081SHelge Deller {
45633bdf2081SHelge Deller     return ctx->is_pa20 && do_putshadowregs(ctx);
45643bdf2081SHelge Deller }
45653bdf2081SHelge Deller 
456638193127SRichard Henderson static bool trans_diag_unimp(DisasContext *ctx, arg_diag_unimp *a)
456738193127SRichard Henderson {
456838193127SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4569ad75a51eSRichard Henderson     qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i);
4570ad75a51eSRichard Henderson     return true;
4571ad75a51eSRichard Henderson }
457215da177bSSven Schnelle 
4573b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
457461766fe9SRichard Henderson {
457551b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4576f764718dSRichard Henderson     int bound;
457761766fe9SRichard Henderson 
457851b061fbSRichard Henderson     ctx->cs = cs;
4579494737b7SRichard Henderson     ctx->tb_flags = ctx->base.tb->flags;
4580bd6243a3SRichard Henderson     ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
45813d68ee7bSRichard Henderson 
45823d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY
4583c01e5dfbSHelge Deller     ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX);
45843d68ee7bSRichard Henderson     ctx->mmu_idx = MMU_USER_IDX;
45850d89cb7cSRichard Henderson     ctx->iaoq_first = ctx->base.pc_first | ctx->privilege;
45860d89cb7cSRichard Henderson     ctx->iaq_b.disp = ctx->base.tb->cs_base - ctx->base.pc_first;
4587217d1a5eSRichard Henderson     ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
4588c301f34eSRichard Henderson #else
4589494737b7SRichard Henderson     ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
4590bb67ec32SRichard Henderson     ctx->mmu_idx = (ctx->tb_flags & PSW_D
4591bb67ec32SRichard Henderson                     ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
4592451d993dSRichard Henderson                     : ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX);
45933d68ee7bSRichard Henderson 
4594c301f34eSRichard Henderson     /* Recover the IAOQ values from the GVA + PRIV.  */
4595c301f34eSRichard Henderson     uint64_t cs_base = ctx->base.tb->cs_base;
4596c301f34eSRichard Henderson     uint64_t iasq_f = cs_base & ~0xffffffffull;
4597c301f34eSRichard Henderson     int32_t diff = cs_base;
4598c301f34eSRichard Henderson 
45990d89cb7cSRichard Henderson     ctx->iaoq_first = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
46000d89cb7cSRichard Henderson 
4601bc921866SRichard Henderson     if (diff) {
46020d89cb7cSRichard Henderson         ctx->iaq_b.disp = diff;
4603bc921866SRichard Henderson     } else {
4604bc921866SRichard Henderson         ctx->iaq_b.base = cpu_iaoq_b;
4605bc921866SRichard Henderson         ctx->iaq_b.space = cpu_iasq_b;
4606bc921866SRichard Henderson     }
4607c301f34eSRichard Henderson #endif
460861766fe9SRichard Henderson 
4609a4db4a78SRichard Henderson     ctx->zero = tcg_constant_i64(0);
4610a4db4a78SRichard Henderson 
46113d68ee7bSRichard Henderson     /* Bound the number of instructions by those left on the page.  */
46123d68ee7bSRichard Henderson     bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
4613b542683dSEmilio G. Cota     ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
461461766fe9SRichard Henderson }
461561766fe9SRichard Henderson 
461651b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
461751b061fbSRichard Henderson {
461851b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
461961766fe9SRichard Henderson 
46203d68ee7bSRichard Henderson     /* Seed the nullification status from PSW[N], as saved in TB->FLAGS.  */
462151b061fbSRichard Henderson     ctx->null_cond = cond_make_f();
462251b061fbSRichard Henderson     ctx->psw_n_nonzero = false;
4623494737b7SRichard Henderson     if (ctx->tb_flags & PSW_N) {
462451b061fbSRichard Henderson         ctx->null_cond.c = TCG_COND_ALWAYS;
462551b061fbSRichard Henderson         ctx->psw_n_nonzero = true;
4626129e9cc3SRichard Henderson     }
462751b061fbSRichard Henderson     ctx->null_lab = NULL;
462861766fe9SRichard Henderson }
462961766fe9SRichard Henderson 
463051b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
463151b061fbSRichard Henderson {
463251b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
463351b061fbSRichard Henderson 
4634bc921866SRichard Henderson     tcg_debug_assert(!iaqe_variable(&ctx->iaq_f));
46350d89cb7cSRichard Henderson     tcg_gen_insn_start(ctx->iaoq_first + ctx->iaq_f.disp,
46360d89cb7cSRichard Henderson                        (iaqe_variable(&ctx->iaq_b) ? -1 :
46370d89cb7cSRichard Henderson                         ctx->iaoq_first + ctx->iaq_b.disp), 0);
463824638bd1SRichard Henderson     ctx->insn_start_updated = false;
463951b061fbSRichard Henderson }
464051b061fbSRichard Henderson 
464151b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
464251b061fbSRichard Henderson {
464351b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4644b77af26eSRichard Henderson     CPUHPPAState *env = cpu_env(cs);
464551b061fbSRichard Henderson     DisasJumpType ret;
464651b061fbSRichard Henderson 
464751b061fbSRichard Henderson     /* Execute one insn.  */
4648ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4649c301f34eSRichard Henderson     if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
465031234768SRichard Henderson         do_page_zero(ctx);
465131234768SRichard Henderson         ret = ctx->base.is_jmp;
4652869051eaSRichard Henderson         assert(ret != DISAS_NEXT);
4653ba1d0b44SRichard Henderson     } else
4654ba1d0b44SRichard Henderson #endif
4655ba1d0b44SRichard Henderson     {
465661766fe9SRichard Henderson         /* Always fetch the insn, even if nullified, so that we check
465761766fe9SRichard Henderson            the page permissions for execute.  */
46584e116893SIlya Leoshkevich         uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next);
465961766fe9SRichard Henderson 
4660bc921866SRichard Henderson         /*
4661bc921866SRichard Henderson          * Set up the IA queue for the next insn.
4662bc921866SRichard Henderson          * This will be overwritten by a branch.
4663bc921866SRichard Henderson          */
4664bc921866SRichard Henderson         ctx->iaq_n = NULL;
4665bc921866SRichard Henderson         memset(&ctx->iaq_j, 0, sizeof(ctx->iaq_j));
466661766fe9SRichard Henderson 
466751b061fbSRichard Henderson         if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
466851b061fbSRichard Henderson             ctx->null_cond.c = TCG_COND_NEVER;
4669869051eaSRichard Henderson             ret = DISAS_NEXT;
4670129e9cc3SRichard Henderson         } else {
46711a19da0dSRichard Henderson             ctx->insn = insn;
467231274b46SRichard Henderson             if (!decode(ctx, insn)) {
467331274b46SRichard Henderson                 gen_illegal(ctx);
467431274b46SRichard Henderson             }
467531234768SRichard Henderson             ret = ctx->base.is_jmp;
467651b061fbSRichard Henderson             assert(ctx->null_lab == NULL);
4677129e9cc3SRichard Henderson         }
467861766fe9SRichard Henderson     }
467961766fe9SRichard Henderson 
4680dbdccbdfSRichard Henderson     /* If the TranslationBlock must end, do so. */
4681dbdccbdfSRichard Henderson     ctx->base.pc_next += 4;
4682dbdccbdfSRichard Henderson     if (ret != DISAS_NEXT) {
4683dbdccbdfSRichard Henderson         return;
468461766fe9SRichard Henderson     }
4685dbdccbdfSRichard Henderson     /* Note this also detects a priority change. */
4686bc921866SRichard Henderson     if (iaqe_variable(&ctx->iaq_b)
4687bc921866SRichard Henderson         || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) {
4688dbdccbdfSRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
4689dbdccbdfSRichard Henderson         return;
4690129e9cc3SRichard Henderson     }
4691dbdccbdfSRichard Henderson 
4692dbdccbdfSRichard Henderson     /*
4693dbdccbdfSRichard Henderson      * Advance the insn queue.
4694dbdccbdfSRichard Henderson      * The only exit now is DISAS_TOO_MANY from the translator loop.
4695dbdccbdfSRichard Henderson      */
4696bc921866SRichard Henderson     ctx->iaq_f.disp = ctx->iaq_b.disp;
4697bc921866SRichard Henderson     if (!ctx->iaq_n) {
4698bc921866SRichard Henderson         ctx->iaq_b.disp += 4;
4699bc921866SRichard Henderson         return;
4700bc921866SRichard Henderson     }
4701bc921866SRichard Henderson     /*
4702bc921866SRichard Henderson      * If IAQ_Next is variable in any way, we need to copy into the
4703bc921866SRichard Henderson      * IAQ_Back globals, in case the next insn raises an exception.
4704bc921866SRichard Henderson      */
4705bc921866SRichard Henderson     if (ctx->iaq_n->base) {
4706bc921866SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaq_n);
4707bc921866SRichard Henderson         ctx->iaq_b.base = cpu_iaoq_b;
4708bc921866SRichard Henderson         ctx->iaq_b.disp = 0;
47090dcd6640SRichard Henderson     } else {
4710bc921866SRichard Henderson         ctx->iaq_b.disp = ctx->iaq_n->disp;
47110dcd6640SRichard Henderson     }
4712bc921866SRichard Henderson     if (ctx->iaq_n->space) {
4713bc921866SRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, ctx->iaq_n->space);
4714bc921866SRichard Henderson         ctx->iaq_b.space = cpu_iasq_b;
4715142faf5fSRichard Henderson     }
471661766fe9SRichard Henderson }
471761766fe9SRichard Henderson 
471851b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
471951b061fbSRichard Henderson {
472051b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4721e1b5a5edSRichard Henderson     DisasJumpType is_jmp = ctx->base.is_jmp;
4722dbdccbdfSRichard Henderson     /* Assume the insn queue has not been advanced. */
4723bc921866SRichard Henderson     DisasIAQE *f = &ctx->iaq_b;
4724bc921866SRichard Henderson     DisasIAQE *b = ctx->iaq_n;
472551b061fbSRichard Henderson 
4726e1b5a5edSRichard Henderson     switch (is_jmp) {
4727869051eaSRichard Henderson     case DISAS_NORETURN:
472861766fe9SRichard Henderson         break;
472951b061fbSRichard Henderson     case DISAS_TOO_MANY:
4730dbdccbdfSRichard Henderson         /* The insn queue has not been advanced. */
4731bc921866SRichard Henderson         f = &ctx->iaq_f;
4732bc921866SRichard Henderson         b = &ctx->iaq_b;
473361766fe9SRichard Henderson         /* FALLTHRU */
4734dbdccbdfSRichard Henderson     case DISAS_IAQ_N_STALE:
4735bc921866SRichard Henderson         if (use_goto_tb(ctx, f, b)
4736dbdccbdfSRichard Henderson             && (ctx->null_cond.c == TCG_COND_NEVER
4737dbdccbdfSRichard Henderson                 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
4738dbdccbdfSRichard Henderson             nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
4739bc921866SRichard Henderson             gen_goto_tb(ctx, 0, f, b);
47408532a14eSRichard Henderson             break;
474161766fe9SRichard Henderson         }
4742c5d0aec2SRichard Henderson         /* FALLTHRU */
4743dbdccbdfSRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
4744bc921866SRichard Henderson         install_iaq_entries(ctx, f, b);
4745dbdccbdfSRichard Henderson         nullify_save(ctx);
4746dbdccbdfSRichard Henderson         if (is_jmp == DISAS_IAQ_N_STALE_EXIT) {
4747dbdccbdfSRichard Henderson             tcg_gen_exit_tb(NULL, 0);
4748dbdccbdfSRichard Henderson             break;
4749dbdccbdfSRichard Henderson         }
4750dbdccbdfSRichard Henderson         /* FALLTHRU */
4751dbdccbdfSRichard Henderson     case DISAS_IAQ_N_UPDATED:
4752dbdccbdfSRichard Henderson         tcg_gen_lookup_and_goto_ptr();
4753dbdccbdfSRichard Henderson         break;
4754c5d0aec2SRichard Henderson     case DISAS_EXIT:
4755c5d0aec2SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
475661766fe9SRichard Henderson         break;
475761766fe9SRichard Henderson     default:
475851b061fbSRichard Henderson         g_assert_not_reached();
475961766fe9SRichard Henderson     }
476051b061fbSRichard Henderson }
476161766fe9SRichard Henderson 
47628eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase,
47638eb806a7SRichard Henderson                               CPUState *cs, FILE *logfile)
476451b061fbSRichard Henderson {
4765c301f34eSRichard Henderson     target_ulong pc = dcbase->pc_first;
476661766fe9SRichard Henderson 
4767ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4768ba1d0b44SRichard Henderson     switch (pc) {
47697ad439dfSRichard Henderson     case 0x00:
47708eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000000:  (null)\n");
4771ba1d0b44SRichard Henderson         return;
47727ad439dfSRichard Henderson     case 0xb0:
47738eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000b0:  light-weight-syscall\n");
4774ba1d0b44SRichard Henderson         return;
47757ad439dfSRichard Henderson     case 0xe0:
47768eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000e0:  set-thread-pointer-syscall\n");
4777ba1d0b44SRichard Henderson         return;
47787ad439dfSRichard Henderson     case 0x100:
47798eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000100:  syscall\n");
4780ba1d0b44SRichard Henderson         return;
47817ad439dfSRichard Henderson     }
4782ba1d0b44SRichard Henderson #endif
4783ba1d0b44SRichard Henderson 
47848eb806a7SRichard Henderson     fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
47858eb806a7SRichard Henderson     target_disas(logfile, cs, pc, dcbase->tb->size);
478661766fe9SRichard Henderson }
478751b061fbSRichard Henderson 
478851b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = {
478951b061fbSRichard Henderson     .init_disas_context = hppa_tr_init_disas_context,
479051b061fbSRichard Henderson     .tb_start           = hppa_tr_tb_start,
479151b061fbSRichard Henderson     .insn_start         = hppa_tr_insn_start,
479251b061fbSRichard Henderson     .translate_insn     = hppa_tr_translate_insn,
479351b061fbSRichard Henderson     .tb_stop            = hppa_tr_tb_stop,
479451b061fbSRichard Henderson     .disas_log          = hppa_tr_disas_log,
479551b061fbSRichard Henderson };
479651b061fbSRichard Henderson 
4797597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
479832f0c394SAnton Johansson                            vaddr pc, void *host_pc)
479951b061fbSRichard Henderson {
4800bc921866SRichard Henderson     DisasContext ctx = { };
4801306c8721SRichard Henderson     translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
480261766fe9SRichard Henderson }
4803