xref: /openbmc/qemu/target/hppa/translate.c (revision d6d46be1bf3876db6168d155ed273866d5f595cd)
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 {
779*d6d46be1SRichard Henderson     TCGCond sign_cond, zero_cond;
780*d6d46be1SRichard Henderson     uint64_t sign_imm, zero_imm;
781b2167459SRichard Henderson     DisasCond cond;
7826fd0c7bcSRichard Henderson     TCGv_i64 tmp;
783b2167459SRichard Henderson 
784*d6d46be1SRichard Henderson     if (d) {
785*d6d46be1SRichard Henderson         /* 64-bit condition. */
786*d6d46be1SRichard Henderson         sign_imm = 0;
787*d6d46be1SRichard Henderson         sign_cond = TCG_COND_LT;
788*d6d46be1SRichard Henderson         zero_imm = 0;
789*d6d46be1SRichard Henderson         zero_cond = TCG_COND_EQ;
790*d6d46be1SRichard Henderson     } else {
791*d6d46be1SRichard Henderson         /* 32-bit condition. */
792*d6d46be1SRichard Henderson         sign_imm = 1ull << 31;
793*d6d46be1SRichard Henderson         sign_cond = TCG_COND_TSTNE;
794*d6d46be1SRichard Henderson         zero_imm = UINT32_MAX;
795*d6d46be1SRichard Henderson         zero_cond = TCG_COND_TSTEQ;
796*d6d46be1SRichard Henderson     }
797*d6d46be1SRichard 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) */
803*d6d46be1SRichard 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);
808*d6d46be1SRichard 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
816*d6d46be1SRichard Henderson          *   ((res ^ sv) < 0 ? 1 : !res)
817*d6d46be1SRichard Henderson          *   !((res ^ sv) < 0 ? 0 : res)
818b47a4a02SSven Schnelle          */
819aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
820*d6d46be1SRichard Henderson         tcg_gen_xor_i64(tmp, res, sv);
821*d6d46be1SRichard Henderson         tcg_gen_movcond_i64(sign_cond, tmp,
822*d6d46be1SRichard Henderson                             tmp, tcg_constant_i64(sign_imm),
823*d6d46be1SRichard Henderson                             ctx->zero, res);
824*d6d46be1SRichard 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);
832*d6d46be1SRichard Henderson         cond = cond_make_ti(zero_cond, tmp, zero_imm);
833b2167459SRichard Henderson         break;
834b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
835*d6d46be1SRichard Henderson         cond = cond_make_vi(sign_cond, sv, sign_imm);
836b2167459SRichard Henderson         break;
837b2167459SRichard Henderson     case 7: /* OD / EV */
838*d6d46be1SRichard 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;
918b5af8423SRichard Henderson     bool ext_uns;
919a751eb31SRichard Henderson 
920df0232feSRichard Henderson     switch (cf) {
921df0232feSRichard Henderson     case 0:  /* never */
922df0232feSRichard Henderson     case 9:  /* undef, C */
923df0232feSRichard Henderson     case 11: /* undef, C & !Z */
924df0232feSRichard Henderson     case 12: /* undef, V */
925df0232feSRichard Henderson         return cond_make_f();
926df0232feSRichard Henderson 
927df0232feSRichard Henderson     case 1:  /* true */
928df0232feSRichard Henderson     case 8:  /* undef, !C */
929df0232feSRichard Henderson     case 10: /* undef, !C | Z */
930df0232feSRichard Henderson     case 13: /* undef, !V */
931df0232feSRichard Henderson         return cond_make_t();
932df0232feSRichard Henderson 
933df0232feSRichard Henderson     case 2:  /* == */
934b5af8423SRichard Henderson         tc = TCG_COND_EQ;
935b5af8423SRichard Henderson         ext_uns = true;
936b5af8423SRichard Henderson         break;
937df0232feSRichard Henderson     case 3:  /* <> */
938b5af8423SRichard Henderson         tc = TCG_COND_NE;
939b5af8423SRichard Henderson         ext_uns = true;
940b5af8423SRichard Henderson         break;
941df0232feSRichard Henderson     case 4:  /* < */
942b5af8423SRichard Henderson         tc = TCG_COND_LT;
943b5af8423SRichard Henderson         ext_uns = false;
944b5af8423SRichard Henderson         break;
945df0232feSRichard Henderson     case 5:  /* >= */
946b5af8423SRichard Henderson         tc = TCG_COND_GE;
947b5af8423SRichard Henderson         ext_uns = false;
948b5af8423SRichard Henderson         break;
949df0232feSRichard Henderson     case 6:  /* <= */
950b5af8423SRichard Henderson         tc = TCG_COND_LE;
951b5af8423SRichard Henderson         ext_uns = false;
952b5af8423SRichard Henderson         break;
953df0232feSRichard Henderson     case 7:  /* > */
954b5af8423SRichard Henderson         tc = TCG_COND_GT;
955b5af8423SRichard Henderson         ext_uns = false;
956b5af8423SRichard Henderson         break;
957df0232feSRichard Henderson 
958df0232feSRichard Henderson     case 14: /* OD */
959df0232feSRichard Henderson     case 15: /* EV */
960a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, NULL);
961df0232feSRichard Henderson 
962df0232feSRichard Henderson     default:
963df0232feSRichard Henderson         g_assert_not_reached();
964b2167459SRichard Henderson     }
965b5af8423SRichard Henderson 
96682d0c831SRichard Henderson     if (!d) {
967aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
968b5af8423SRichard Henderson 
969b5af8423SRichard Henderson         if (ext_uns) {
9706fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
971b5af8423SRichard Henderson         } else {
9726fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, res);
973b5af8423SRichard Henderson         }
9744c42fd0dSRichard Henderson         return cond_make_ti(tc, tmp, 0);
975b5af8423SRichard Henderson     }
9764c42fd0dSRichard Henderson     return cond_make_vi(tc, res, 0);
977b2167459SRichard Henderson }
978b2167459SRichard Henderson 
97998cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
98098cd9ca7SRichard Henderson 
9814fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d,
9826fd0c7bcSRichard Henderson                              TCGv_i64 res)
98398cd9ca7SRichard Henderson {
98498cd9ca7SRichard Henderson     unsigned c, f;
98598cd9ca7SRichard Henderson 
98698cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
98798cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
98898cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
98998cd9ca7SRichard Henderson     c = orig & 3;
99098cd9ca7SRichard Henderson     if (c == 3) {
99198cd9ca7SRichard Henderson         c = 7;
99298cd9ca7SRichard Henderson     }
99398cd9ca7SRichard Henderson     f = (orig & 4) / 4;
99498cd9ca7SRichard Henderson 
995b5af8423SRichard Henderson     return do_log_cond(ctx, c * 2 + f, d, res);
99698cd9ca7SRichard Henderson }
99798cd9ca7SRichard Henderson 
99846bb3d46SRichard Henderson /* Similar, but for unit zero conditions.  */
99946bb3d46SRichard Henderson static DisasCond do_unit_zero_cond(unsigned cf, bool d, TCGv_i64 res)
1000b2167459SRichard Henderson {
100146bb3d46SRichard Henderson     TCGv_i64 tmp;
1002c53e401eSRichard Henderson     uint64_t d_repl = d ? 0x0000000100000001ull : 1;
100346bb3d46SRichard Henderson     uint64_t ones = 0, sgns = 0;
1004b2167459SRichard Henderson 
1005b2167459SRichard Henderson     switch (cf >> 1) {
1006578b8132SSven Schnelle     case 1: /* SBW / NBW */
1007578b8132SSven Schnelle         if (d) {
100846bb3d46SRichard Henderson             ones = d_repl;
100946bb3d46SRichard Henderson             sgns = d_repl << 31;
1010578b8132SSven Schnelle         }
1011578b8132SSven Schnelle         break;
1012b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
101346bb3d46SRichard Henderson         ones = d_repl * 0x01010101u;
101446bb3d46SRichard Henderson         sgns = ones << 7;
101546bb3d46SRichard Henderson         break;
101646bb3d46SRichard Henderson     case 3: /* SHZ / NHZ */
101746bb3d46SRichard Henderson         ones = d_repl * 0x00010001u;
101846bb3d46SRichard Henderson         sgns = ones << 15;
101946bb3d46SRichard Henderson         break;
102046bb3d46SRichard Henderson     }
102146bb3d46SRichard Henderson     if (ones == 0) {
102246bb3d46SRichard Henderson         /* Undefined, or 0/1 (never/always). */
102346bb3d46SRichard Henderson         return cf & 1 ? cond_make_t() : cond_make_f();
102446bb3d46SRichard Henderson     }
102546bb3d46SRichard Henderson 
102646bb3d46SRichard Henderson     /*
102746bb3d46SRichard Henderson      * See hasless(v,1) from
1028b2167459SRichard Henderson      * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
1029b2167459SRichard Henderson      */
1030aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
103146bb3d46SRichard Henderson     tcg_gen_subi_i64(tmp, res, ones);
10326fd0c7bcSRichard Henderson     tcg_gen_andc_i64(tmp, tmp, res);
103346bb3d46SRichard Henderson     tcg_gen_andi_i64(tmp, tmp, sgns);
1034b2167459SRichard Henderson 
10354c42fd0dSRichard Henderson     return cond_make_ti(cf & 1 ? TCG_COND_EQ : TCG_COND_NE, tmp, 0);
1036b2167459SRichard Henderson }
1037b2167459SRichard Henderson 
10386fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d,
10396fd0c7bcSRichard Henderson                           TCGv_i64 cb, TCGv_i64 cb_msb)
104072ca8753SRichard Henderson {
104182d0c831SRichard Henderson     if (!d) {
1042aac0f603SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
10436fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, cb, 32, 1);
104472ca8753SRichard Henderson         return t;
104572ca8753SRichard Henderson     }
104672ca8753SRichard Henderson     return cb_msb;
104772ca8753SRichard Henderson }
104872ca8753SRichard Henderson 
10496fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d)
105072ca8753SRichard Henderson {
105172ca8753SRichard Henderson     return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb);
105272ca8753SRichard Henderson }
105372ca8753SRichard Henderson 
1054b2167459SRichard Henderson /* Compute signed overflow for addition.  */
10556fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res,
1056f8f5986eSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2,
1057f8f5986eSRichard Henderson                           TCGv_i64 orig_in1, int shift, bool d)
1058b2167459SRichard Henderson {
1059aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
1060aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
1061b2167459SRichard Henderson 
10626fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
10636fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
10646fd0c7bcSRichard Henderson     tcg_gen_andc_i64(sv, sv, tmp);
1065b2167459SRichard Henderson 
1066f8f5986eSRichard Henderson     switch (shift) {
1067f8f5986eSRichard Henderson     case 0:
1068f8f5986eSRichard Henderson         break;
1069f8f5986eSRichard Henderson     case 1:
1070f8f5986eSRichard Henderson         /* Shift left by one and compare the sign. */
1071f8f5986eSRichard Henderson         tcg_gen_add_i64(tmp, orig_in1, orig_in1);
1072f8f5986eSRichard Henderson         tcg_gen_xor_i64(tmp, tmp, orig_in1);
1073f8f5986eSRichard Henderson         /* Incorporate into the overflow. */
1074f8f5986eSRichard Henderson         tcg_gen_or_i64(sv, sv, tmp);
1075f8f5986eSRichard Henderson         break;
1076f8f5986eSRichard Henderson     default:
1077f8f5986eSRichard Henderson         {
1078f8f5986eSRichard Henderson             int sign_bit = d ? 63 : 31;
1079f8f5986eSRichard Henderson 
1080f8f5986eSRichard Henderson             /* Compare the sign against all lower bits. */
1081f8f5986eSRichard Henderson             tcg_gen_sextract_i64(tmp, orig_in1, sign_bit, 1);
1082f8f5986eSRichard Henderson             tcg_gen_xor_i64(tmp, tmp, orig_in1);
1083f8f5986eSRichard Henderson             /*
1084f8f5986eSRichard Henderson              * If one of the bits shifting into or through the sign
1085f8f5986eSRichard Henderson              * differs, then we have overflow.
1086f8f5986eSRichard Henderson              */
1087f8f5986eSRichard Henderson             tcg_gen_extract_i64(tmp, tmp, sign_bit - shift, shift);
1088f8f5986eSRichard Henderson             tcg_gen_movcond_i64(TCG_COND_NE, sv, tmp, ctx->zero,
1089f8f5986eSRichard Henderson                                 tcg_constant_i64(-1), sv);
1090f8f5986eSRichard Henderson         }
1091f8f5986eSRichard Henderson     }
1092b2167459SRichard Henderson     return sv;
1093b2167459SRichard Henderson }
1094b2167459SRichard Henderson 
1095f8f5986eSRichard Henderson /* Compute unsigned overflow for addition.  */
1096f8f5986eSRichard Henderson static TCGv_i64 do_add_uv(DisasContext *ctx, TCGv_i64 cb, TCGv_i64 cb_msb,
1097f8f5986eSRichard Henderson                           TCGv_i64 in1, int shift, bool d)
1098f8f5986eSRichard Henderson {
1099f8f5986eSRichard Henderson     if (shift == 0) {
1100f8f5986eSRichard Henderson         return get_carry(ctx, d, cb, cb_msb);
1101f8f5986eSRichard Henderson     } else {
1102f8f5986eSRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
1103f8f5986eSRichard Henderson         tcg_gen_extract_i64(tmp, in1, (d ? 63 : 31) - shift, shift);
1104f8f5986eSRichard Henderson         tcg_gen_or_i64(tmp, tmp, get_carry(ctx, d, cb, cb_msb));
1105f8f5986eSRichard Henderson         return tmp;
1106f8f5986eSRichard Henderson     }
1107f8f5986eSRichard Henderson }
1108f8f5986eSRichard Henderson 
1109b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
11106fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res,
11116fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
1112b2167459SRichard Henderson {
1113aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
1114aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
1115b2167459SRichard Henderson 
11166fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
11176fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
11186fd0c7bcSRichard Henderson     tcg_gen_and_i64(sv, sv, tmp);
1119b2167459SRichard Henderson 
1120b2167459SRichard Henderson     return sv;
1121b2167459SRichard Henderson }
1122b2167459SRichard Henderson 
1123f8f5986eSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 orig_in1,
11246fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned shift, bool is_l,
1125faf97ba1SRichard Henderson                    bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d)
1126b2167459SRichard Henderson {
1127f8f5986eSRichard Henderson     TCGv_i64 dest, cb, cb_msb, in1, uv, sv, tmp;
1128b2167459SRichard Henderson     unsigned c = cf >> 1;
1129b2167459SRichard Henderson     DisasCond cond;
1130b2167459SRichard Henderson 
1131aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1132f764718dSRichard Henderson     cb = NULL;
1133f764718dSRichard Henderson     cb_msb = NULL;
1134b2167459SRichard Henderson 
1135f8f5986eSRichard Henderson     in1 = orig_in1;
1136b2167459SRichard Henderson     if (shift) {
1137aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
11386fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, in1, shift);
1139b2167459SRichard Henderson         in1 = tmp;
1140b2167459SRichard Henderson     }
1141b2167459SRichard Henderson 
1142b47a4a02SSven Schnelle     if (!is_l || cond_need_cb(c)) {
1143aac0f603SRichard Henderson         cb_msb = tcg_temp_new_i64();
1144aac0f603SRichard Henderson         cb = tcg_temp_new_i64();
1145bdcccc17SRichard Henderson 
1146a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero);
1147b2167459SRichard Henderson         if (is_c) {
11486fd0c7bcSRichard Henderson             tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb,
1149a4db4a78SRichard Henderson                              get_psw_carry(ctx, d), ctx->zero);
1150b2167459SRichard Henderson         }
11516fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
11526fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1153b2167459SRichard Henderson     } else {
11546fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
1155b2167459SRichard Henderson         if (is_c) {
11566fd0c7bcSRichard Henderson             tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d));
1157b2167459SRichard Henderson         }
1158b2167459SRichard Henderson     }
1159b2167459SRichard Henderson 
1160b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1161f764718dSRichard Henderson     sv = NULL;
1162b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1163f8f5986eSRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2, orig_in1, shift, d);
1164b2167459SRichard Henderson         if (is_tsv) {
1165bd1ad92cSSven Schnelle             if (!d) {
1166bd1ad92cSSven Schnelle                 tcg_gen_ext32s_i64(sv, sv);
1167bd1ad92cSSven Schnelle             }
1168ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1169b2167459SRichard Henderson         }
1170b2167459SRichard Henderson     }
1171b2167459SRichard Henderson 
1172f8f5986eSRichard Henderson     /* Compute unsigned overflow if required.  */
1173f8f5986eSRichard Henderson     uv = NULL;
1174f8f5986eSRichard Henderson     if (cond_need_cb(c)) {
1175f8f5986eSRichard Henderson         uv = do_add_uv(ctx, cb, cb_msb, orig_in1, shift, d);
1176f8f5986eSRichard Henderson     }
1177f8f5986eSRichard Henderson 
1178b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1179f8f5986eSRichard Henderson     cond = do_cond(ctx, cf, d, dest, uv, sv);
1180b2167459SRichard Henderson     if (is_tc) {
1181aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
11826fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1183ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1184b2167459SRichard Henderson     }
1185b2167459SRichard Henderson 
1186b2167459SRichard Henderson     /* Write back the result.  */
1187b2167459SRichard Henderson     if (!is_l) {
1188b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
1189b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1190b2167459SRichard Henderson     }
1191b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1192b2167459SRichard Henderson 
1193b2167459SRichard Henderson     /* Install the new nullification.  */
1194b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1195b2167459SRichard Henderson     ctx->null_cond = cond;
1196b2167459SRichard Henderson }
1197b2167459SRichard Henderson 
1198faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a,
11990c982a28SRichard Henderson                        bool is_l, bool is_tsv, bool is_tc, bool is_c)
12000c982a28SRichard Henderson {
12016fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
12020c982a28SRichard Henderson 
12030c982a28SRichard Henderson     if (a->cf) {
12040c982a28SRichard Henderson         nullify_over(ctx);
12050c982a28SRichard Henderson     }
12060c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
12070c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1208faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l,
1209faf97ba1SRichard Henderson            is_tsv, is_tc, is_c, a->cf, a->d);
12100c982a28SRichard Henderson     return nullify_end(ctx);
12110c982a28SRichard Henderson }
12120c982a28SRichard Henderson 
12130588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a,
12140588e061SRichard Henderson                        bool is_tsv, bool is_tc)
12150588e061SRichard Henderson {
12166fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
12170588e061SRichard Henderson 
12180588e061SRichard Henderson     if (a->cf) {
12190588e061SRichard Henderson         nullify_over(ctx);
12200588e061SRichard Henderson     }
12216fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
12220588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
1223faf97ba1SRichard Henderson     /* All ADDI conditions are 32-bit. */
1224faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false);
12250588e061SRichard Henderson     return nullify_end(ctx);
12260588e061SRichard Henderson }
12270588e061SRichard Henderson 
12286fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12296fd0c7bcSRichard Henderson                    TCGv_i64 in2, bool is_tsv, bool is_b,
123063c427c6SRichard Henderson                    bool is_tc, unsigned cf, bool d)
1231b2167459SRichard Henderson {
1232a4db4a78SRichard Henderson     TCGv_i64 dest, sv, cb, cb_msb, tmp;
1233b2167459SRichard Henderson     unsigned c = cf >> 1;
1234b2167459SRichard Henderson     DisasCond cond;
1235b2167459SRichard Henderson 
1236aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1237aac0f603SRichard Henderson     cb = tcg_temp_new_i64();
1238aac0f603SRichard Henderson     cb_msb = tcg_temp_new_i64();
1239b2167459SRichard Henderson 
1240b2167459SRichard Henderson     if (is_b) {
1241b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
12426fd0c7bcSRichard Henderson         tcg_gen_not_i64(cb, in2);
1243a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero,
1244a4db4a78SRichard Henderson                          get_psw_carry(ctx, d), ctx->zero);
1245a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero);
12466fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, in1);
12476fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1248b2167459SRichard Henderson     } else {
1249bdcccc17SRichard Henderson         /*
1250bdcccc17SRichard Henderson          * DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
1251bdcccc17SRichard Henderson          * operations by seeding the high word with 1 and subtracting.
1252bdcccc17SRichard Henderson          */
12536fd0c7bcSRichard Henderson         TCGv_i64 one = tcg_constant_i64(1);
1254a4db4a78SRichard Henderson         tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero);
12556fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(cb, in1, in2);
12566fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1257b2167459SRichard Henderson     }
1258b2167459SRichard Henderson 
1259b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1260f764718dSRichard Henderson     sv = NULL;
1261b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1262b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1263b2167459SRichard Henderson         if (is_tsv) {
1264bd1ad92cSSven Schnelle             if (!d) {
1265bd1ad92cSSven Schnelle                 tcg_gen_ext32s_i64(sv, sv);
1266bd1ad92cSSven Schnelle             }
1267ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1268b2167459SRichard Henderson         }
1269b2167459SRichard Henderson     }
1270b2167459SRichard Henderson 
1271b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
1272b2167459SRichard Henderson     if (!is_b) {
12734fe9533aSRichard Henderson         cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1274b2167459SRichard Henderson     } else {
1275a751eb31SRichard Henderson         cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv);
1276b2167459SRichard Henderson     }
1277b2167459SRichard Henderson 
1278b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1279b2167459SRichard Henderson     if (is_tc) {
1280aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
12816fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1282ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1283b2167459SRichard Henderson     }
1284b2167459SRichard Henderson 
1285b2167459SRichard Henderson     /* Write back the result.  */
1286b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
1287b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1288b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1289b2167459SRichard Henderson 
1290b2167459SRichard Henderson     /* Install the new nullification.  */
1291b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1292b2167459SRichard Henderson     ctx->null_cond = cond;
1293b2167459SRichard Henderson }
1294b2167459SRichard Henderson 
129563c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a,
12960c982a28SRichard Henderson                        bool is_tsv, bool is_b, bool is_tc)
12970c982a28SRichard Henderson {
12986fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
12990c982a28SRichard Henderson 
13000c982a28SRichard Henderson     if (a->cf) {
13010c982a28SRichard Henderson         nullify_over(ctx);
13020c982a28SRichard Henderson     }
13030c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
13040c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
130563c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d);
13060c982a28SRichard Henderson     return nullify_end(ctx);
13070c982a28SRichard Henderson }
13080c982a28SRichard Henderson 
13090588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv)
13100588e061SRichard Henderson {
13116fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
13120588e061SRichard Henderson 
13130588e061SRichard Henderson     if (a->cf) {
13140588e061SRichard Henderson         nullify_over(ctx);
13150588e061SRichard Henderson     }
13166fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
13170588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
131863c427c6SRichard Henderson     /* All SUBI conditions are 32-bit. */
131963c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false);
13200588e061SRichard Henderson     return nullify_end(ctx);
13210588e061SRichard Henderson }
13220588e061SRichard Henderson 
13236fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
13246fd0c7bcSRichard Henderson                       TCGv_i64 in2, unsigned cf, bool d)
1325b2167459SRichard Henderson {
13266fd0c7bcSRichard Henderson     TCGv_i64 dest, sv;
1327b2167459SRichard Henderson     DisasCond cond;
1328b2167459SRichard Henderson 
1329aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
13306fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
1331b2167459SRichard Henderson 
1332b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1333f764718dSRichard Henderson     sv = NULL;
1334b47a4a02SSven Schnelle     if (cond_need_sv(cf >> 1)) {
1335b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1336b2167459SRichard Henderson     }
1337b2167459SRichard Henderson 
1338b2167459SRichard Henderson     /* Form the condition for the compare.  */
13394fe9533aSRichard Henderson     cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1340b2167459SRichard Henderson 
1341b2167459SRichard Henderson     /* Clear.  */
13426fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
1343b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1344b2167459SRichard Henderson 
1345b2167459SRichard Henderson     /* Install the new nullification.  */
1346b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1347b2167459SRichard Henderson     ctx->null_cond = cond;
1348b2167459SRichard Henderson }
1349b2167459SRichard Henderson 
13506fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
13516fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned cf, bool d,
13526fd0c7bcSRichard Henderson                    void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1353b2167459SRichard Henderson {
13546fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, rt);
1355b2167459SRichard Henderson 
1356b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
1357b2167459SRichard Henderson     fn(dest, in1, in2);
1358b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1359b2167459SRichard Henderson 
1360b2167459SRichard Henderson     /* Install the new nullification.  */
1361b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1362b2167459SRichard Henderson     if (cf) {
1363b5af8423SRichard Henderson         ctx->null_cond = do_log_cond(ctx, cf, d, dest);
1364b2167459SRichard Henderson     }
1365b2167459SRichard Henderson }
1366b2167459SRichard Henderson 
1367fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a,
13686fd0c7bcSRichard Henderson                        void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
13690c982a28SRichard Henderson {
13706fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
13710c982a28SRichard Henderson 
13720c982a28SRichard Henderson     if (a->cf) {
13730c982a28SRichard Henderson         nullify_over(ctx);
13740c982a28SRichard Henderson     }
13750c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
13760c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1377fa8e3bedSRichard Henderson     do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn);
13780c982a28SRichard Henderson     return nullify_end(ctx);
13790c982a28SRichard Henderson }
13800c982a28SRichard Henderson 
138146bb3d46SRichard Henderson static void do_unit_addsub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
138246bb3d46SRichard Henderson                            TCGv_i64 in2, unsigned cf, bool d,
138346bb3d46SRichard Henderson                            bool is_tc, bool is_add)
1384b2167459SRichard Henderson {
138546bb3d46SRichard Henderson     TCGv_i64 dest = tcg_temp_new_i64();
138646bb3d46SRichard Henderson     uint64_t test_cb = 0;
1387b2167459SRichard Henderson     DisasCond cond;
1388b2167459SRichard Henderson 
138946bb3d46SRichard Henderson     /* Select which carry-out bits to test. */
139046bb3d46SRichard Henderson     switch (cf >> 1) {
139146bb3d46SRichard Henderson     case 4: /* NDC / SDC -- 4-bit carries */
139246bb3d46SRichard Henderson         test_cb = dup_const(MO_8, 0x88);
139346bb3d46SRichard Henderson         break;
139446bb3d46SRichard Henderson     case 5: /* NWC / SWC -- 32-bit carries */
139546bb3d46SRichard Henderson         if (d) {
139646bb3d46SRichard Henderson             test_cb = dup_const(MO_32, INT32_MIN);
1397b2167459SRichard Henderson         } else {
139846bb3d46SRichard Henderson             cf &= 1; /* undefined -- map to never/always */
139946bb3d46SRichard Henderson         }
140046bb3d46SRichard Henderson         break;
140146bb3d46SRichard Henderson     case 6: /* NBC / SBC -- 8-bit carries */
140246bb3d46SRichard Henderson         test_cb = dup_const(MO_8, INT8_MIN);
140346bb3d46SRichard Henderson         break;
140446bb3d46SRichard Henderson     case 7: /* NHC / SHC -- 16-bit carries */
140546bb3d46SRichard Henderson         test_cb = dup_const(MO_16, INT16_MIN);
140646bb3d46SRichard Henderson         break;
140746bb3d46SRichard Henderson     }
140846bb3d46SRichard Henderson     if (!d) {
140946bb3d46SRichard Henderson         test_cb = (uint32_t)test_cb;
141046bb3d46SRichard Henderson     }
1411b2167459SRichard Henderson 
141246bb3d46SRichard Henderson     if (!test_cb) {
141346bb3d46SRichard Henderson         /* No need to compute carries if we don't need to test them. */
141446bb3d46SRichard Henderson         if (is_add) {
141546bb3d46SRichard Henderson             tcg_gen_add_i64(dest, in1, in2);
141646bb3d46SRichard Henderson         } else {
141746bb3d46SRichard Henderson             tcg_gen_sub_i64(dest, in1, in2);
141846bb3d46SRichard Henderson         }
141946bb3d46SRichard Henderson         cond = do_unit_zero_cond(cf, d, dest);
142046bb3d46SRichard Henderson     } else {
142146bb3d46SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
142246bb3d46SRichard Henderson 
142346bb3d46SRichard Henderson         if (d) {
142446bb3d46SRichard Henderson             TCGv_i64 cb_msb = tcg_temp_new_i64();
142546bb3d46SRichard Henderson             if (is_add) {
142646bb3d46SRichard Henderson                 tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero);
142746bb3d46SRichard Henderson                 tcg_gen_xor_i64(cb, in1, in2);
142846bb3d46SRichard Henderson             } else {
142946bb3d46SRichard Henderson                 /* See do_sub, !is_b. */
143046bb3d46SRichard Henderson                 TCGv_i64 one = tcg_constant_i64(1);
143146bb3d46SRichard Henderson                 tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero);
143246bb3d46SRichard Henderson                 tcg_gen_eqv_i64(cb, in1, in2);
143346bb3d46SRichard Henderson             }
143446bb3d46SRichard Henderson             tcg_gen_xor_i64(cb, cb, dest);
143546bb3d46SRichard Henderson             tcg_gen_extract2_i64(cb, cb, cb_msb, 1);
143646bb3d46SRichard Henderson         } else {
143746bb3d46SRichard Henderson             if (is_add) {
143846bb3d46SRichard Henderson                 tcg_gen_add_i64(dest, in1, in2);
143946bb3d46SRichard Henderson                 tcg_gen_xor_i64(cb, in1, in2);
144046bb3d46SRichard Henderson             } else {
144146bb3d46SRichard Henderson                 tcg_gen_sub_i64(dest, in1, in2);
144246bb3d46SRichard Henderson                 tcg_gen_eqv_i64(cb, in1, in2);
144346bb3d46SRichard Henderson             }
144446bb3d46SRichard Henderson             tcg_gen_xor_i64(cb, cb, dest);
144546bb3d46SRichard Henderson             tcg_gen_shri_i64(cb, cb, 1);
144646bb3d46SRichard Henderson         }
144746bb3d46SRichard Henderson 
144846bb3d46SRichard Henderson         tcg_gen_andi_i64(cb, cb, test_cb);
14494c42fd0dSRichard Henderson         cond = cond_make_ti(cf & 1 ? TCG_COND_EQ : TCG_COND_NE, cb, 0);
145046bb3d46SRichard Henderson     }
1451b2167459SRichard Henderson 
1452b2167459SRichard Henderson     if (is_tc) {
1453aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
14546fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1455ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1456b2167459SRichard Henderson     }
1457b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1458b2167459SRichard Henderson 
1459b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1460b2167459SRichard Henderson     ctx->null_cond = cond;
1461b2167459SRichard Henderson }
1462b2167459SRichard Henderson 
146386f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY
14648d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space
14658d6ae7fbSRichard Henderson    from the top 2 bits of the base register.  There are a few system
14668d6ae7fbSRichard Henderson    instructions that have a 3-bit space specifier, for which SR0 is
14678d6ae7fbSRichard Henderson    not special.  To handle this, pass ~SP.  */
14686fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base)
146986f8d05fSRichard Henderson {
147086f8d05fSRichard Henderson     TCGv_ptr ptr;
14716fd0c7bcSRichard Henderson     TCGv_i64 tmp;
147286f8d05fSRichard Henderson     TCGv_i64 spc;
147386f8d05fSRichard Henderson 
147486f8d05fSRichard Henderson     if (sp != 0) {
14758d6ae7fbSRichard Henderson         if (sp < 0) {
14768d6ae7fbSRichard Henderson             sp = ~sp;
14778d6ae7fbSRichard Henderson         }
14786fd0c7bcSRichard Henderson         spc = tcg_temp_new_i64();
14798d6ae7fbSRichard Henderson         load_spr(ctx, spc, sp);
14808d6ae7fbSRichard Henderson         return spc;
148186f8d05fSRichard Henderson     }
1482494737b7SRichard Henderson     if (ctx->tb_flags & TB_FLAG_SR_SAME) {
1483494737b7SRichard Henderson         return cpu_srH;
1484494737b7SRichard Henderson     }
148586f8d05fSRichard Henderson 
148686f8d05fSRichard Henderson     ptr = tcg_temp_new_ptr();
1487aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
14886fd0c7bcSRichard Henderson     spc = tcg_temp_new_i64();
148986f8d05fSRichard Henderson 
1490698240d1SRichard Henderson     /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */
14916fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5);
14926fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, 030);
14936fd0c7bcSRichard Henderson     tcg_gen_trunc_i64_ptr(ptr, tmp);
149486f8d05fSRichard Henderson 
1495ad75a51eSRichard Henderson     tcg_gen_add_ptr(ptr, ptr, tcg_env);
149686f8d05fSRichard Henderson     tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4]));
149786f8d05fSRichard Henderson 
149886f8d05fSRichard Henderson     return spc;
149986f8d05fSRichard Henderson }
150086f8d05fSRichard Henderson #endif
150186f8d05fSRichard Henderson 
15026fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
1503c53e401eSRichard Henderson                      unsigned rb, unsigned rx, int scale, int64_t disp,
150486f8d05fSRichard Henderson                      unsigned sp, int modify, bool is_phys)
150586f8d05fSRichard Henderson {
15066fd0c7bcSRichard Henderson     TCGv_i64 base = load_gpr(ctx, rb);
15076fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15086fd0c7bcSRichard Henderson     TCGv_i64 addr;
150986f8d05fSRichard Henderson 
1510f5b5c857SRichard Henderson     set_insn_breg(ctx, rb);
1511f5b5c857SRichard Henderson 
151286f8d05fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
151386f8d05fSRichard Henderson     if (rx) {
1514aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
15156fd0c7bcSRichard Henderson         tcg_gen_shli_i64(ofs, cpu_gr[rx], scale);
15166fd0c7bcSRichard Henderson         tcg_gen_add_i64(ofs, ofs, base);
151786f8d05fSRichard Henderson     } else if (disp || modify) {
1518aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
15196fd0c7bcSRichard Henderson         tcg_gen_addi_i64(ofs, base, disp);
152086f8d05fSRichard Henderson     } else {
152186f8d05fSRichard Henderson         ofs = base;
152286f8d05fSRichard Henderson     }
152386f8d05fSRichard Henderson 
152486f8d05fSRichard Henderson     *pofs = ofs;
15256fd0c7bcSRichard Henderson     *pgva = addr = tcg_temp_new_i64();
15267d50b696SSven Schnelle     tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base,
15277d50b696SSven Schnelle                      gva_offset_mask(ctx->tb_flags));
1528698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY
152986f8d05fSRichard Henderson     if (!is_phys) {
1530d265360fSRichard Henderson         tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base));
153186f8d05fSRichard Henderson     }
153286f8d05fSRichard Henderson #endif
153386f8d05fSRichard Henderson }
153486f8d05fSRichard Henderson 
153596d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
153696d6407fSRichard Henderson  * < 0 for pre-modify,
153796d6407fSRichard Henderson  * > 0 for post-modify,
153896d6407fSRichard Henderson  * = 0 for no base register update.
153996d6407fSRichard Henderson  */
154096d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1541c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
154214776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
154396d6407fSRichard Henderson {
15446fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15456fd0c7bcSRichard Henderson     TCGv_i64 addr;
154696d6407fSRichard Henderson 
154796d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
154896d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
154996d6407fSRichard Henderson 
155086f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
155117fe594cSRichard Henderson              MMU_DISABLED(ctx));
1552c1f55d97SRichard Henderson     tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
155386f8d05fSRichard Henderson     if (modify) {
155486f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
155596d6407fSRichard Henderson     }
155696d6407fSRichard Henderson }
155796d6407fSRichard Henderson 
155896d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1559c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
156014776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
156196d6407fSRichard Henderson {
15626fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15636fd0c7bcSRichard Henderson     TCGv_i64 addr;
156496d6407fSRichard Henderson 
156596d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
156696d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
156796d6407fSRichard Henderson 
156886f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
156917fe594cSRichard Henderson              MMU_DISABLED(ctx));
1570217d1a5eSRichard Henderson     tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
157186f8d05fSRichard Henderson     if (modify) {
157286f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
157396d6407fSRichard Henderson     }
157496d6407fSRichard Henderson }
157596d6407fSRichard Henderson 
157696d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1577c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
157814776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
157996d6407fSRichard Henderson {
15806fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15816fd0c7bcSRichard Henderson     TCGv_i64 addr;
158296d6407fSRichard Henderson 
158396d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
158496d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
158596d6407fSRichard Henderson 
158686f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
158717fe594cSRichard Henderson              MMU_DISABLED(ctx));
1588217d1a5eSRichard Henderson     tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
158986f8d05fSRichard Henderson     if (modify) {
159086f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
159196d6407fSRichard Henderson     }
159296d6407fSRichard Henderson }
159396d6407fSRichard Henderson 
159496d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1595c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
159614776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
159796d6407fSRichard Henderson {
15986fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15996fd0c7bcSRichard Henderson     TCGv_i64 addr;
160096d6407fSRichard Henderson 
160196d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
160296d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
160396d6407fSRichard Henderson 
160486f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
160517fe594cSRichard Henderson              MMU_DISABLED(ctx));
1606217d1a5eSRichard Henderson     tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
160786f8d05fSRichard Henderson     if (modify) {
160886f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
160996d6407fSRichard Henderson     }
161096d6407fSRichard Henderson }
161196d6407fSRichard Henderson 
16121cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1613c53e401eSRichard Henderson                     unsigned rx, int scale, int64_t disp,
161414776ab5STony Nguyen                     unsigned sp, int modify, MemOp mop)
161596d6407fSRichard Henderson {
16166fd0c7bcSRichard Henderson     TCGv_i64 dest;
161796d6407fSRichard Henderson 
161896d6407fSRichard Henderson     nullify_over(ctx);
161996d6407fSRichard Henderson 
162096d6407fSRichard Henderson     if (modify == 0) {
162196d6407fSRichard Henderson         /* No base register update.  */
162296d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
162396d6407fSRichard Henderson     } else {
162496d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
1625aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
162696d6407fSRichard Henderson     }
16276fd0c7bcSRichard Henderson     do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
162896d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
162996d6407fSRichard Henderson 
16301cd012a5SRichard Henderson     return nullify_end(ctx);
163196d6407fSRichard Henderson }
163296d6407fSRichard Henderson 
1633740038d7SRichard Henderson static bool do_floadw(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_i32 tmp;
163896d6407fSRichard Henderson 
163996d6407fSRichard Henderson     nullify_over(ctx);
164096d6407fSRichard Henderson 
164196d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
164286f8d05fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
164396d6407fSRichard Henderson     save_frw_i32(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);
165096d6407fSRichard Henderson }
165196d6407fSRichard Henderson 
1652740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a)
1653740038d7SRichard Henderson {
1654740038d7SRichard Henderson     return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1655740038d7SRichard Henderson                      a->disp, a->sp, a->m);
1656740038d7SRichard Henderson }
1657740038d7SRichard Henderson 
1658740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1659c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
166086f8d05fSRichard Henderson                       unsigned sp, int modify)
166196d6407fSRichard Henderson {
166296d6407fSRichard Henderson     TCGv_i64 tmp;
166396d6407fSRichard Henderson 
166496d6407fSRichard Henderson     nullify_over(ctx);
166596d6407fSRichard Henderson 
166696d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
1667fc313c64SFrédéric Pétrot     do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
166896d6407fSRichard Henderson     save_frd(rt, tmp);
166996d6407fSRichard Henderson 
167096d6407fSRichard Henderson     if (rt == 0) {
1671ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
167296d6407fSRichard Henderson     }
167396d6407fSRichard Henderson 
1674740038d7SRichard Henderson     return nullify_end(ctx);
1675740038d7SRichard Henderson }
1676740038d7SRichard Henderson 
1677740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a)
1678740038d7SRichard Henderson {
1679740038d7SRichard Henderson     return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1680740038d7SRichard Henderson                      a->disp, a->sp, a->m);
168196d6407fSRichard Henderson }
168296d6407fSRichard Henderson 
16831cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb,
1684c53e401eSRichard Henderson                      int64_t disp, unsigned sp,
168514776ab5STony Nguyen                      int modify, MemOp mop)
168696d6407fSRichard Henderson {
168796d6407fSRichard Henderson     nullify_over(ctx);
16886fd0c7bcSRichard Henderson     do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
16891cd012a5SRichard Henderson     return nullify_end(ctx);
169096d6407fSRichard Henderson }
169196d6407fSRichard Henderson 
1692740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1693c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
169486f8d05fSRichard Henderson                        unsigned sp, int modify)
169596d6407fSRichard Henderson {
169696d6407fSRichard Henderson     TCGv_i32 tmp;
169796d6407fSRichard Henderson 
169896d6407fSRichard Henderson     nullify_over(ctx);
169996d6407fSRichard Henderson 
170096d6407fSRichard Henderson     tmp = load_frw_i32(rt);
170186f8d05fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
170296d6407fSRichard Henderson 
1703740038d7SRichard Henderson     return nullify_end(ctx);
170496d6407fSRichard Henderson }
170596d6407fSRichard Henderson 
1706740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a)
1707740038d7SRichard Henderson {
1708740038d7SRichard Henderson     return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1709740038d7SRichard Henderson                       a->disp, a->sp, a->m);
1710740038d7SRichard Henderson }
1711740038d7SRichard Henderson 
1712740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1713c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
171486f8d05fSRichard Henderson                        unsigned sp, int modify)
171596d6407fSRichard Henderson {
171696d6407fSRichard Henderson     TCGv_i64 tmp;
171796d6407fSRichard Henderson 
171896d6407fSRichard Henderson     nullify_over(ctx);
171996d6407fSRichard Henderson 
172096d6407fSRichard Henderson     tmp = load_frd(rt);
1721fc313c64SFrédéric Pétrot     do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
172296d6407fSRichard Henderson 
1723740038d7SRichard Henderson     return nullify_end(ctx);
1724740038d7SRichard Henderson }
1725740038d7SRichard Henderson 
1726740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a)
1727740038d7SRichard Henderson {
1728740038d7SRichard Henderson     return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1729740038d7SRichard Henderson                       a->disp, a->sp, a->m);
173096d6407fSRichard Henderson }
173196d6407fSRichard Henderson 
17321ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1733ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1734ebe9383cSRichard Henderson {
1735ebe9383cSRichard Henderson     TCGv_i32 tmp;
1736ebe9383cSRichard Henderson 
1737ebe9383cSRichard Henderson     nullify_over(ctx);
1738ebe9383cSRichard Henderson     tmp = load_frw0_i32(ra);
1739ebe9383cSRichard Henderson 
1740ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1741ebe9383cSRichard Henderson 
1742ebe9383cSRichard Henderson     save_frw_i32(rt, tmp);
17431ca74648SRichard Henderson     return nullify_end(ctx);
1744ebe9383cSRichard Henderson }
1745ebe9383cSRichard Henderson 
17461ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1747ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1748ebe9383cSRichard Henderson {
1749ebe9383cSRichard Henderson     TCGv_i32 dst;
1750ebe9383cSRichard Henderson     TCGv_i64 src;
1751ebe9383cSRichard Henderson 
1752ebe9383cSRichard Henderson     nullify_over(ctx);
1753ebe9383cSRichard Henderson     src = load_frd(ra);
1754ebe9383cSRichard Henderson     dst = tcg_temp_new_i32();
1755ebe9383cSRichard Henderson 
1756ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1757ebe9383cSRichard Henderson 
1758ebe9383cSRichard Henderson     save_frw_i32(rt, dst);
17591ca74648SRichard Henderson     return nullify_end(ctx);
1760ebe9383cSRichard Henderson }
1761ebe9383cSRichard Henderson 
17621ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1763ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1764ebe9383cSRichard Henderson {
1765ebe9383cSRichard Henderson     TCGv_i64 tmp;
1766ebe9383cSRichard Henderson 
1767ebe9383cSRichard Henderson     nullify_over(ctx);
1768ebe9383cSRichard Henderson     tmp = load_frd0(ra);
1769ebe9383cSRichard Henderson 
1770ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1771ebe9383cSRichard Henderson 
1772ebe9383cSRichard Henderson     save_frd(rt, tmp);
17731ca74648SRichard Henderson     return nullify_end(ctx);
1774ebe9383cSRichard Henderson }
1775ebe9383cSRichard Henderson 
17761ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1777ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1778ebe9383cSRichard Henderson {
1779ebe9383cSRichard Henderson     TCGv_i32 src;
1780ebe9383cSRichard Henderson     TCGv_i64 dst;
1781ebe9383cSRichard Henderson 
1782ebe9383cSRichard Henderson     nullify_over(ctx);
1783ebe9383cSRichard Henderson     src = load_frw0_i32(ra);
1784ebe9383cSRichard Henderson     dst = tcg_temp_new_i64();
1785ebe9383cSRichard Henderson 
1786ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1787ebe9383cSRichard Henderson 
1788ebe9383cSRichard Henderson     save_frd(rt, dst);
17891ca74648SRichard Henderson     return nullify_end(ctx);
1790ebe9383cSRichard Henderson }
1791ebe9383cSRichard Henderson 
17921ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt,
1793ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
179431234768SRichard Henderson                         void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
1795ebe9383cSRichard Henderson {
1796ebe9383cSRichard Henderson     TCGv_i32 a, b;
1797ebe9383cSRichard Henderson 
1798ebe9383cSRichard Henderson     nullify_over(ctx);
1799ebe9383cSRichard Henderson     a = load_frw0_i32(ra);
1800ebe9383cSRichard Henderson     b = load_frw0_i32(rb);
1801ebe9383cSRichard Henderson 
1802ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1803ebe9383cSRichard Henderson 
1804ebe9383cSRichard Henderson     save_frw_i32(rt, a);
18051ca74648SRichard Henderson     return nullify_end(ctx);
1806ebe9383cSRichard Henderson }
1807ebe9383cSRichard Henderson 
18081ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt,
1809ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
181031234768SRichard Henderson                         void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
1811ebe9383cSRichard Henderson {
1812ebe9383cSRichard Henderson     TCGv_i64 a, b;
1813ebe9383cSRichard Henderson 
1814ebe9383cSRichard Henderson     nullify_over(ctx);
1815ebe9383cSRichard Henderson     a = load_frd0(ra);
1816ebe9383cSRichard Henderson     b = load_frd0(rb);
1817ebe9383cSRichard Henderson 
1818ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1819ebe9383cSRichard Henderson 
1820ebe9383cSRichard Henderson     save_frd(rt, a);
18211ca74648SRichard Henderson     return nullify_end(ctx);
1822ebe9383cSRichard Henderson }
1823ebe9383cSRichard Henderson 
182498cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
182598cd9ca7SRichard Henderson    have already had nullification handled.  */
18262644f80bSRichard Henderson static bool do_dbranch(DisasContext *ctx, int64_t disp,
182798cd9ca7SRichard Henderson                        unsigned link, bool is_n)
182898cd9ca7SRichard Henderson {
1829bc921866SRichard Henderson     ctx->iaq_j = iaqe_branchi(ctx, disp);
18302644f80bSRichard Henderson 
183198cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
183243541db0SRichard Henderson         install_link(ctx, link, false);
183398cd9ca7SRichard Henderson         if (is_n) {
1834d08ad0e0SRichard Henderson             if (use_nullify_skip(ctx)) {
1835d08ad0e0SRichard Henderson                 nullify_set(ctx, 0);
1836bc921866SRichard Henderson                 gen_goto_tb(ctx, 0, &ctx->iaq_j, NULL);
1837d08ad0e0SRichard Henderson                 ctx->base.is_jmp = DISAS_NORETURN;
1838d08ad0e0SRichard Henderson                 return true;
1839d08ad0e0SRichard Henderson             }
184098cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
184198cd9ca7SRichard Henderson         }
1842bc921866SRichard Henderson         ctx->iaq_n = &ctx->iaq_j;
184398cd9ca7SRichard Henderson     } else {
184498cd9ca7SRichard Henderson         nullify_over(ctx);
184598cd9ca7SRichard Henderson 
184643541db0SRichard Henderson         install_link(ctx, link, false);
184798cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
184898cd9ca7SRichard Henderson             nullify_set(ctx, 0);
1849bc921866SRichard Henderson             gen_goto_tb(ctx, 0, &ctx->iaq_j, NULL);
185098cd9ca7SRichard Henderson         } else {
185198cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
1852bc921866SRichard Henderson             gen_goto_tb(ctx, 0, &ctx->iaq_b, &ctx->iaq_j);
185398cd9ca7SRichard Henderson         }
185431234768SRichard Henderson         nullify_end(ctx);
185598cd9ca7SRichard Henderson 
185698cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1857bc921866SRichard Henderson         gen_goto_tb(ctx, 1, &ctx->iaq_b, NULL);
185831234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
185998cd9ca7SRichard Henderson     }
186001afb7beSRichard Henderson     return true;
186198cd9ca7SRichard Henderson }
186298cd9ca7SRichard Henderson 
186398cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
186498cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
1865c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n,
186698cd9ca7SRichard Henderson                        DisasCond *cond)
186798cd9ca7SRichard Henderson {
1868bc921866SRichard Henderson     DisasIAQE next;
186998cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
187098cd9ca7SRichard Henderson     TCGCond c = cond->c;
187198cd9ca7SRichard Henderson     bool n;
187298cd9ca7SRichard Henderson 
187398cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
187498cd9ca7SRichard Henderson 
187598cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
187698cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
18772644f80bSRichard Henderson         return do_dbranch(ctx, disp, 0, is_n && disp >= 0);
187898cd9ca7SRichard Henderson     }
187998cd9ca7SRichard Henderson 
188098cd9ca7SRichard Henderson     taken = gen_new_label();
18816fd0c7bcSRichard Henderson     tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken);
188298cd9ca7SRichard Henderson     cond_free(cond);
188398cd9ca7SRichard Henderson 
188498cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
188598cd9ca7SRichard Henderson     n = is_n && disp < 0;
188698cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
188798cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1888bc921866SRichard Henderson         next = iaqe_incr(&ctx->iaq_b, 4);
1889bc921866SRichard Henderson         gen_goto_tb(ctx, 0, &next, NULL);
189098cd9ca7SRichard Henderson     } else {
189198cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
189298cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
189398cd9ca7SRichard Henderson             ctx->null_lab = NULL;
189498cd9ca7SRichard Henderson         }
189598cd9ca7SRichard Henderson         nullify_set(ctx, n);
1896bc921866SRichard Henderson         gen_goto_tb(ctx, 0, &ctx->iaq_b, NULL);
189798cd9ca7SRichard Henderson     }
189898cd9ca7SRichard Henderson 
189998cd9ca7SRichard Henderson     gen_set_label(taken);
190098cd9ca7SRichard Henderson 
190198cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
190298cd9ca7SRichard Henderson     n = is_n && disp >= 0;
1903bc921866SRichard Henderson 
1904bc921866SRichard Henderson     next = iaqe_branchi(ctx, disp);
190598cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
190698cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1907bc921866SRichard Henderson         gen_goto_tb(ctx, 1, &next, NULL);
190898cd9ca7SRichard Henderson     } else {
190998cd9ca7SRichard Henderson         nullify_set(ctx, n);
1910bc921866SRichard Henderson         gen_goto_tb(ctx, 1, &ctx->iaq_b, &next);
191198cd9ca7SRichard Henderson     }
191298cd9ca7SRichard Henderson 
191398cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
191498cd9ca7SRichard Henderson     if (ctx->null_lab) {
191598cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
191698cd9ca7SRichard Henderson         ctx->null_lab = NULL;
191731234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
191898cd9ca7SRichard Henderson     } else {
191931234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
192098cd9ca7SRichard Henderson     }
192101afb7beSRichard Henderson     return true;
192298cd9ca7SRichard Henderson }
192398cd9ca7SRichard Henderson 
1924bc921866SRichard Henderson /*
1925bc921866SRichard Henderson  * Emit an unconditional branch to an indirect target, in ctx->iaq_j.
1926bc921866SRichard Henderson  * This handles nullification of the branch itself.
1927bc921866SRichard Henderson  */
1928bc921866SRichard Henderson static bool do_ibranch(DisasContext *ctx, unsigned link,
1929bc921866SRichard Henderson                        bool with_sr0, bool is_n)
193098cd9ca7SRichard Henderson {
1931d582c1faSRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
1932019f4159SRichard Henderson         install_link(ctx, link, with_sr0);
193398cd9ca7SRichard Henderson         if (is_n) {
1934c301f34eSRichard Henderson             if (use_nullify_skip(ctx)) {
1935bc921866SRichard Henderson                 install_iaq_entries(ctx, &ctx->iaq_j, NULL);
1936c301f34eSRichard Henderson                 nullify_set(ctx, 0);
193731234768SRichard Henderson                 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
193801afb7beSRichard Henderson                 return true;
1939c301f34eSRichard Henderson             }
194098cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
194198cd9ca7SRichard Henderson         }
1942bc921866SRichard Henderson         ctx->iaq_n = &ctx->iaq_j;
1943d582c1faSRichard Henderson         return true;
1944d582c1faSRichard Henderson     }
194598cd9ca7SRichard Henderson 
1946d582c1faSRichard Henderson     nullify_over(ctx);
1947d582c1faSRichard Henderson 
1948019f4159SRichard Henderson     install_link(ctx, link, with_sr0);
1949d582c1faSRichard Henderson     if (is_n && use_nullify_skip(ctx)) {
1950bc921866SRichard Henderson         install_iaq_entries(ctx, &ctx->iaq_j, NULL);
1951d582c1faSRichard Henderson         nullify_set(ctx, 0);
1952d582c1faSRichard Henderson     } else {
1953bc921866SRichard Henderson         install_iaq_entries(ctx, &ctx->iaq_b, &ctx->iaq_j);
1954d582c1faSRichard Henderson         nullify_set(ctx, is_n);
1955d582c1faSRichard Henderson     }
1956d582c1faSRichard Henderson 
19577f11636dSEmilio G. Cota     tcg_gen_lookup_and_goto_ptr();
1958d582c1faSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
195901afb7beSRichard Henderson     return nullify_end(ctx);
196098cd9ca7SRichard Henderson }
196198cd9ca7SRichard Henderson 
1962660eefe1SRichard Henderson /* Implement
1963660eefe1SRichard Henderson  *    if (IAOQ_Front{30..31} < GR[b]{30..31})
1964660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← GR[b]{30..31};
1965660eefe1SRichard Henderson  *    else
1966660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← IAOQ_Front{30..31};
1967660eefe1SRichard Henderson  * which keeps the privilege level from being increased.
1968660eefe1SRichard Henderson  */
19696fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset)
1970660eefe1SRichard Henderson {
19711874e6c2SRichard Henderson     TCGv_i64 dest = tcg_temp_new_i64();
1972660eefe1SRichard Henderson     switch (ctx->privilege) {
1973660eefe1SRichard Henderson     case 0:
1974660eefe1SRichard Henderson         /* Privilege 0 is maximum and is allowed to decrease.  */
19751874e6c2SRichard Henderson         tcg_gen_mov_i64(dest, offset);
19761874e6c2SRichard Henderson         break;
1977660eefe1SRichard Henderson     case 3:
1978993119feSRichard Henderson         /* Privilege 3 is minimum and is never allowed to increase.  */
19796fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, offset, 3);
1980660eefe1SRichard Henderson         break;
1981660eefe1SRichard Henderson     default:
19826fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, offset, -4);
19836fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, ctx->privilege);
19840bb02029SRichard Henderson         tcg_gen_umax_i64(dest, dest, offset);
1985660eefe1SRichard Henderson         break;
1986660eefe1SRichard Henderson     }
1987660eefe1SRichard Henderson     return dest;
1988660eefe1SRichard Henderson }
1989660eefe1SRichard Henderson 
1990ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
19917ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
19927ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
19937ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
19947ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
19957ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
19967ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
19977ad439dfSRichard Henderson    aforementioned BE.  */
199831234768SRichard Henderson static void do_page_zero(DisasContext *ctx)
19997ad439dfSRichard Henderson {
20000d89cb7cSRichard Henderson     assert(ctx->iaq_f.disp == 0);
20010d89cb7cSRichard Henderson 
20027ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
20037ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
20048b81968cSMichael Tokarev        next insn within the privileged page.  */
20057ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
20067ad439dfSRichard Henderson     case TCG_COND_NEVER:
20077ad439dfSRichard Henderson         break;
20087ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
20096fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, 0);
20107ad439dfSRichard Henderson         goto do_sigill;
20117ad439dfSRichard Henderson     default:
20127ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
20137ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
20147ad439dfSRichard Henderson         g_assert_not_reached();
20157ad439dfSRichard Henderson     }
20167ad439dfSRichard Henderson 
20177ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
20187ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
20197ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
20207ad439dfSRichard Henderson        under such conditions.  */
20210d89cb7cSRichard Henderson     if (iaqe_variable(&ctx->iaq_b) || ctx->iaq_b.disp != 4) {
20227ad439dfSRichard Henderson         goto do_sigill;
20237ad439dfSRichard Henderson     }
20247ad439dfSRichard Henderson 
20250d89cb7cSRichard Henderson     switch (ctx->base.pc_first) {
20267ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
20272986721dSRichard Henderson         gen_excp_1(EXCP_IMP);
202831234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
202931234768SRichard Henderson         break;
20307ad439dfSRichard Henderson 
20317ad439dfSRichard Henderson     case 0xb0: /* LWS */
20327ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
203331234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
203431234768SRichard Henderson         break;
20357ad439dfSRichard Henderson 
20367ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
2037bc921866SRichard Henderson         {
2038bc921866SRichard Henderson             DisasIAQE next = { .base = tcg_temp_new_i64() };
2039bc921866SRichard Henderson 
2040bc921866SRichard Henderson             tcg_gen_st_i64(cpu_gr[26], tcg_env,
2041bc921866SRichard Henderson                            offsetof(CPUHPPAState, cr[27]));
2042bc921866SRichard Henderson             tcg_gen_ori_i64(next.base, cpu_gr[31], 3);
2043bc921866SRichard Henderson             install_iaq_entries(ctx, &next, NULL);
204431234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
2045bc921866SRichard Henderson         }
204631234768SRichard Henderson         break;
20477ad439dfSRichard Henderson 
20487ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
20497ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
205031234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
205131234768SRichard Henderson         break;
20527ad439dfSRichard Henderson 
20537ad439dfSRichard Henderson     default:
20547ad439dfSRichard Henderson     do_sigill:
20552986721dSRichard Henderson         gen_excp_1(EXCP_ILL);
205631234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
205731234768SRichard Henderson         break;
20587ad439dfSRichard Henderson     }
20597ad439dfSRichard Henderson }
2060ba1d0b44SRichard Henderson #endif
20617ad439dfSRichard Henderson 
2062deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a)
2063b2167459SRichard Henderson {
2064b2167459SRichard Henderson     cond_free(&ctx->null_cond);
206531234768SRichard Henderson     return true;
2066b2167459SRichard Henderson }
2067b2167459SRichard Henderson 
206840f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a)
206998a9cb79SRichard Henderson {
207031234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_BREAK);
207198a9cb79SRichard Henderson }
207298a9cb79SRichard Henderson 
2073e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a)
207498a9cb79SRichard Henderson {
207598a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
207698a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
207798a9cb79SRichard Henderson 
207898a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
207931234768SRichard Henderson     return true;
208098a9cb79SRichard Henderson }
208198a9cb79SRichard Henderson 
2082c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a)
208398a9cb79SRichard Henderson {
2084bc921866SRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
208598a9cb79SRichard Henderson 
2086bc921866SRichard Henderson     copy_iaoq_entry(ctx, dest, &ctx->iaq_f);
2087bc921866SRichard Henderson     tcg_gen_andi_i64(dest, dest, -4);
2088bc921866SRichard Henderson 
2089bc921866SRichard Henderson     save_gpr(ctx, a->t, dest);
209098a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
209131234768SRichard Henderson     return true;
209298a9cb79SRichard Henderson }
209398a9cb79SRichard Henderson 
2094c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a)
209598a9cb79SRichard Henderson {
2096c603e14aSRichard Henderson     unsigned rt = a->t;
2097c603e14aSRichard Henderson     unsigned rs = a->sp;
209833423472SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
209998a9cb79SRichard Henderson 
210033423472SRichard Henderson     load_spr(ctx, t0, rs);
210133423472SRichard Henderson     tcg_gen_shri_i64(t0, t0, 32);
210233423472SRichard Henderson 
2103967662cdSRichard Henderson     save_gpr(ctx, rt, t0);
210498a9cb79SRichard Henderson 
210598a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
210631234768SRichard Henderson     return true;
210798a9cb79SRichard Henderson }
210898a9cb79SRichard Henderson 
2109c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a)
211098a9cb79SRichard Henderson {
2111c603e14aSRichard Henderson     unsigned rt = a->t;
2112c603e14aSRichard Henderson     unsigned ctl = a->r;
21136fd0c7bcSRichard Henderson     TCGv_i64 tmp;
211498a9cb79SRichard Henderson 
211598a9cb79SRichard Henderson     switch (ctl) {
211635136a77SRichard Henderson     case CR_SAR:
2117c603e14aSRichard Henderson         if (a->e == 0) {
211898a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
211998a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
21206fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
212198a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
212235136a77SRichard Henderson             goto done;
212398a9cb79SRichard Henderson         }
212498a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
212535136a77SRichard Henderson         goto done;
212635136a77SRichard Henderson     case CR_IT: /* Interval Timer */
212735136a77SRichard Henderson         /* FIXME: Respect PSW_S bit.  */
212835136a77SRichard Henderson         nullify_over(ctx);
212998a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
2130dfd1b812SRichard Henderson         if (translator_io_start(&ctx->base)) {
213131234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
213249c29d6cSRichard Henderson         }
21330c58c1bcSRichard Henderson         gen_helper_read_interval_timer(tmp);
213498a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
213531234768SRichard Henderson         return nullify_end(ctx);
213698a9cb79SRichard Henderson     case 26:
213798a9cb79SRichard Henderson     case 27:
213898a9cb79SRichard Henderson         break;
213998a9cb79SRichard Henderson     default:
214098a9cb79SRichard Henderson         /* All other control registers are privileged.  */
214135136a77SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
214235136a77SRichard Henderson         break;
214398a9cb79SRichard Henderson     }
214498a9cb79SRichard Henderson 
2145aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
21466fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
214735136a77SRichard Henderson     save_gpr(ctx, rt, tmp);
214835136a77SRichard Henderson 
214935136a77SRichard Henderson  done:
215098a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
215131234768SRichard Henderson     return true;
215298a9cb79SRichard Henderson }
215398a9cb79SRichard Henderson 
2154c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
215533423472SRichard Henderson {
2156c603e14aSRichard Henderson     unsigned rr = a->r;
2157c603e14aSRichard Henderson     unsigned rs = a->sp;
2158967662cdSRichard Henderson     TCGv_i64 tmp;
215933423472SRichard Henderson 
216033423472SRichard Henderson     if (rs >= 5) {
216133423472SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
216233423472SRichard Henderson     }
216333423472SRichard Henderson     nullify_over(ctx);
216433423472SRichard Henderson 
2165967662cdSRichard Henderson     tmp = tcg_temp_new_i64();
2166967662cdSRichard Henderson     tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32);
216733423472SRichard Henderson 
216833423472SRichard Henderson     if (rs >= 4) {
2169967662cdSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs]));
2170494737b7SRichard Henderson         ctx->tb_flags &= ~TB_FLAG_SR_SAME;
217133423472SRichard Henderson     } else {
2172967662cdSRichard Henderson         tcg_gen_mov_i64(cpu_sr[rs], tmp);
217333423472SRichard Henderson     }
217433423472SRichard Henderson 
217531234768SRichard Henderson     return nullify_end(ctx);
217633423472SRichard Henderson }
217733423472SRichard Henderson 
2178c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
217998a9cb79SRichard Henderson {
2180c603e14aSRichard Henderson     unsigned ctl = a->t;
21816fd0c7bcSRichard Henderson     TCGv_i64 reg;
21826fd0c7bcSRichard Henderson     TCGv_i64 tmp;
218398a9cb79SRichard Henderson 
218435136a77SRichard Henderson     if (ctl == CR_SAR) {
21854845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
2186aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
21876fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31);
218898a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
218998a9cb79SRichard Henderson 
219098a9cb79SRichard Henderson         cond_free(&ctx->null_cond);
219131234768SRichard Henderson         return true;
219298a9cb79SRichard Henderson     }
219398a9cb79SRichard Henderson 
219435136a77SRichard Henderson     /* All other control registers are privileged or read-only.  */
219535136a77SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
219635136a77SRichard Henderson 
2197c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
219835136a77SRichard Henderson     nullify_over(ctx);
21994c34bab0SHelge Deller 
22004c34bab0SHelge Deller     if (ctx->is_pa20) {
22014845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
22024c34bab0SHelge Deller     } else {
22034c34bab0SHelge Deller         reg = tcg_temp_new_i64();
22044c34bab0SHelge Deller         tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r));
22054c34bab0SHelge Deller     }
22064845f015SSven Schnelle 
220735136a77SRichard Henderson     switch (ctl) {
220835136a77SRichard Henderson     case CR_IT:
2209104281c1SRichard Henderson         if (translator_io_start(&ctx->base)) {
2210104281c1SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2211104281c1SRichard Henderson         }
2212ad75a51eSRichard Henderson         gen_helper_write_interval_timer(tcg_env, reg);
221335136a77SRichard Henderson         break;
22144f5f2548SRichard Henderson     case CR_EIRR:
22156ebebea7SRichard Henderson         /* Helper modifies interrupt lines and is therefore IO. */
22166ebebea7SRichard Henderson         translator_io_start(&ctx->base);
2217ad75a51eSRichard Henderson         gen_helper_write_eirr(tcg_env, reg);
22186ebebea7SRichard Henderson         /* Exit to re-evaluate interrupts in the main loop. */
221931234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
22204f5f2548SRichard Henderson         break;
22214f5f2548SRichard Henderson 
222235136a77SRichard Henderson     case CR_IIASQ:
222335136a77SRichard Henderson     case CR_IIAOQ:
222435136a77SRichard Henderson         /* FIXME: Respect PSW_Q bit */
222535136a77SRichard Henderson         /* The write advances the queue and stores to the back element.  */
2226aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
22276fd0c7bcSRichard Henderson         tcg_gen_ld_i64(tmp, tcg_env,
222835136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
22296fd0c7bcSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
22306fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env,
223135136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
223235136a77SRichard Henderson         break;
223335136a77SRichard Henderson 
2234d5de20bdSSven Schnelle     case CR_PID1:
2235d5de20bdSSven Schnelle     case CR_PID2:
2236d5de20bdSSven Schnelle     case CR_PID3:
2237d5de20bdSSven Schnelle     case CR_PID4:
22386fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
2239d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY
2240ad75a51eSRichard Henderson         gen_helper_change_prot_id(tcg_env);
2241d5de20bdSSven Schnelle #endif
2242d5de20bdSSven Schnelle         break;
2243d5de20bdSSven Schnelle 
22446ebebea7SRichard Henderson     case CR_EIEM:
22456ebebea7SRichard Henderson         /* Exit to re-evaluate interrupts in the main loop. */
22466ebebea7SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
22476ebebea7SRichard Henderson         /* FALLTHRU */
224835136a77SRichard Henderson     default:
22496fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
225035136a77SRichard Henderson         break;
225135136a77SRichard Henderson     }
225231234768SRichard Henderson     return nullify_end(ctx);
22534f5f2548SRichard Henderson #endif
225435136a77SRichard Henderson }
225535136a77SRichard Henderson 
2256c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
225798a9cb79SRichard Henderson {
2258aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
225998a9cb79SRichard Henderson 
22606fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, load_gpr(ctx, a->r));
22616fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31);
226298a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
226398a9cb79SRichard Henderson 
226498a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
226531234768SRichard Henderson     return true;
226698a9cb79SRichard Henderson }
226798a9cb79SRichard Henderson 
2268e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a)
226998a9cb79SRichard Henderson {
22706fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
227198a9cb79SRichard Henderson 
22722330504cSHelge Deller #ifdef CONFIG_USER_ONLY
22732330504cSHelge Deller     /* We don't implement space registers in user mode. */
22746fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
22752330504cSHelge Deller #else
2276967662cdSRichard Henderson     tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
2277967662cdSRichard Henderson     tcg_gen_shri_i64(dest, dest, 32);
22782330504cSHelge Deller #endif
2279e36f27efSRichard Henderson     save_gpr(ctx, a->t, dest);
228098a9cb79SRichard Henderson 
228198a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
228231234768SRichard Henderson     return true;
228398a9cb79SRichard Henderson }
228498a9cb79SRichard Henderson 
2285e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a)
2286e36f27efSRichard Henderson {
22877b2d70a1SHelge Deller #ifdef CONFIG_USER_ONLY
2288e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
22897b2d70a1SHelge Deller #else
22906fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2291e1b5a5edSRichard Henderson 
22927b2d70a1SHelge Deller     /* HP-UX 11i and HP ODE use rsm for read-access to PSW */
22937b2d70a1SHelge Deller     if (a->i) {
22947b2d70a1SHelge Deller         CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
22957b2d70a1SHelge Deller     }
22967b2d70a1SHelge Deller 
2297e1b5a5edSRichard Henderson     nullify_over(ctx);
2298e1b5a5edSRichard Henderson 
2299aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
23006fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
23016fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ~a->i);
2302ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2303e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2304e1b5a5edSRichard Henderson 
2305e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_M.  */
230631234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
230731234768SRichard Henderson     return nullify_end(ctx);
2308e36f27efSRichard Henderson #endif
2309e1b5a5edSRichard Henderson }
2310e1b5a5edSRichard Henderson 
2311e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
2312e1b5a5edSRichard Henderson {
2313e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2314e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
23156fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2316e1b5a5edSRichard Henderson 
2317e1b5a5edSRichard Henderson     nullify_over(ctx);
2318e1b5a5edSRichard Henderson 
2319aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
23206fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
23216fd0c7bcSRichard Henderson     tcg_gen_ori_i64(tmp, tmp, a->i);
2322ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2323e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2324e1b5a5edSRichard Henderson 
2325e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_I.  */
232631234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
232731234768SRichard Henderson     return nullify_end(ctx);
2328e36f27efSRichard Henderson #endif
2329e1b5a5edSRichard Henderson }
2330e1b5a5edSRichard Henderson 
2331c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
2332e1b5a5edSRichard Henderson {
2333e1b5a5edSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2334c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
23356fd0c7bcSRichard Henderson     TCGv_i64 tmp, reg;
2336e1b5a5edSRichard Henderson     nullify_over(ctx);
2337e1b5a5edSRichard Henderson 
2338c603e14aSRichard Henderson     reg = load_gpr(ctx, a->r);
2339aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2340ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, reg);
2341e1b5a5edSRichard Henderson 
2342e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts.  */
234331234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
234431234768SRichard Henderson     return nullify_end(ctx);
2345c603e14aSRichard Henderson #endif
2346e1b5a5edSRichard Henderson }
2347f49b3537SRichard Henderson 
2348e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r)
2349f49b3537SRichard Henderson {
2350f49b3537SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2351e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
2352f49b3537SRichard Henderson     nullify_over(ctx);
2353f49b3537SRichard Henderson 
2354e36f27efSRichard Henderson     if (rfi_r) {
2355ad75a51eSRichard Henderson         gen_helper_rfi_r(tcg_env);
2356f49b3537SRichard Henderson     } else {
2357ad75a51eSRichard Henderson         gen_helper_rfi(tcg_env);
2358f49b3537SRichard Henderson     }
235931234768SRichard Henderson     /* Exit the TB to recognize new interrupts.  */
236007ea28b4SRichard Henderson     tcg_gen_exit_tb(NULL, 0);
236131234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
2362f49b3537SRichard Henderson 
236331234768SRichard Henderson     return nullify_end(ctx);
2364e36f27efSRichard Henderson #endif
2365f49b3537SRichard Henderson }
23666210db05SHelge Deller 
2367e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a)
2368e36f27efSRichard Henderson {
2369e36f27efSRichard Henderson     return do_rfi(ctx, false);
2370e36f27efSRichard Henderson }
2371e36f27efSRichard Henderson 
2372e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a)
2373e36f27efSRichard Henderson {
2374e36f27efSRichard Henderson     return do_rfi(ctx, true);
2375e36f27efSRichard Henderson }
2376e36f27efSRichard Henderson 
237796927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a)
23786210db05SHelge Deller {
23796210db05SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
238096927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
23816210db05SHelge Deller     nullify_over(ctx);
2382ad75a51eSRichard Henderson     gen_helper_halt(tcg_env);
238331234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
238431234768SRichard Henderson     return nullify_end(ctx);
238596927adbSRichard Henderson #endif
23866210db05SHelge Deller }
238796927adbSRichard Henderson 
238896927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a)
238996927adbSRichard Henderson {
239096927adbSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
239196927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
239296927adbSRichard Henderson     nullify_over(ctx);
2393ad75a51eSRichard Henderson     gen_helper_reset(tcg_env);
239496927adbSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
239596927adbSRichard Henderson     return nullify_end(ctx);
239696927adbSRichard Henderson #endif
239796927adbSRichard Henderson }
2398e1b5a5edSRichard Henderson 
2399558c09beSRichard Henderson static bool do_getshadowregs(DisasContext *ctx)
24004a4554c6SHelge Deller {
24014a4554c6SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24024a4554c6SHelge Deller     nullify_over(ctx);
2403558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0]));
2404558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1]));
2405558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2]));
2406558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3]));
2407558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4]));
2408558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5]));
2409558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6]));
24104a4554c6SHelge Deller     return nullify_end(ctx);
2411558c09beSRichard Henderson }
2412558c09beSRichard Henderson 
24133bdf2081SHelge Deller static bool do_putshadowregs(DisasContext *ctx)
24143bdf2081SHelge Deller {
24153bdf2081SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24163bdf2081SHelge Deller     nullify_over(ctx);
24173bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0]));
24183bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1]));
24193bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2]));
24203bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3]));
24213bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4]));
24223bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5]));
24233bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6]));
24243bdf2081SHelge Deller     return nullify_end(ctx);
24253bdf2081SHelge Deller }
24263bdf2081SHelge Deller 
2427558c09beSRichard Henderson static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
2428558c09beSRichard Henderson {
2429558c09beSRichard Henderson     return do_getshadowregs(ctx);
24304a4554c6SHelge Deller }
24314a4554c6SHelge Deller 
2432deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
243398a9cb79SRichard Henderson {
2434deee69a1SRichard Henderson     if (a->m) {
24356fd0c7bcSRichard Henderson         TCGv_i64 dest = dest_gpr(ctx, a->b);
24366fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->b);
24376fd0c7bcSRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->x);
243898a9cb79SRichard Henderson 
243998a9cb79SRichard Henderson         /* The only thing we need to do is the base register modification.  */
24406fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, src1, src2);
2441deee69a1SRichard Henderson         save_gpr(ctx, a->b, dest);
2442deee69a1SRichard Henderson     }
244398a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
244431234768SRichard Henderson     return true;
244598a9cb79SRichard Henderson }
244698a9cb79SRichard Henderson 
2447ad1fdacdSSven Schnelle static bool trans_fic(DisasContext *ctx, arg_ldst *a)
2448ad1fdacdSSven Schnelle {
2449ad1fdacdSSven Schnelle     /* End TB for flush instruction cache, so we pick up new insns. */
2450ad1fdacdSSven Schnelle     ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2451ad1fdacdSSven Schnelle     return trans_nop_addrx(ctx, a);
2452ad1fdacdSSven Schnelle }
2453ad1fdacdSSven Schnelle 
2454deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a)
245598a9cb79SRichard Henderson {
24566fd0c7bcSRichard Henderson     TCGv_i64 dest, ofs;
2457eed14219SRichard Henderson     TCGv_i32 level, want;
24586fd0c7bcSRichard Henderson     TCGv_i64 addr;
245998a9cb79SRichard Henderson 
246098a9cb79SRichard Henderson     nullify_over(ctx);
246198a9cb79SRichard Henderson 
2462deee69a1SRichard Henderson     dest = dest_gpr(ctx, a->t);
2463deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2464eed14219SRichard Henderson 
2465deee69a1SRichard Henderson     if (a->imm) {
2466e5d487c9SRichard Henderson         level = tcg_constant_i32(a->ri & 3);
246798a9cb79SRichard Henderson     } else {
2468eed14219SRichard Henderson         level = tcg_temp_new_i32();
24696fd0c7bcSRichard Henderson         tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri));
2470eed14219SRichard Henderson         tcg_gen_andi_i32(level, level, 3);
247198a9cb79SRichard Henderson     }
247229dd6f64SRichard Henderson     want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ);
2473eed14219SRichard Henderson 
2474ad75a51eSRichard Henderson     gen_helper_probe(dest, tcg_env, addr, level, want);
2475eed14219SRichard Henderson 
2476deee69a1SRichard Henderson     save_gpr(ctx, a->t, dest);
247731234768SRichard Henderson     return nullify_end(ctx);
247898a9cb79SRichard Henderson }
247998a9cb79SRichard Henderson 
2480deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
24818d6ae7fbSRichard Henderson {
24828577f354SRichard Henderson     if (ctx->is_pa20) {
24838577f354SRichard Henderson         return false;
24848577f354SRichard 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, reg;
24898d6ae7fbSRichard Henderson 
24908d6ae7fbSRichard Henderson     nullify_over(ctx);
24918d6ae7fbSRichard Henderson 
2492deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2493deee69a1SRichard Henderson     reg = load_gpr(ctx, a->r);
2494deee69a1SRichard Henderson     if (a->addr) {
24958577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
24968d6ae7fbSRichard Henderson     } else {
24978577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
24988d6ae7fbSRichard Henderson     }
24998d6ae7fbSRichard Henderson 
250032dc7569SSven Schnelle     /* Exit TB for TLB change if mmu is enabled.  */
250132dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
250231234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
250331234768SRichard Henderson     }
250431234768SRichard Henderson     return nullify_end(ctx);
2505deee69a1SRichard Henderson #endif
25068d6ae7fbSRichard Henderson }
250763300a00SRichard Henderson 
2508eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local)
250963300a00SRichard Henderson {
2510deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2511deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
25126fd0c7bcSRichard Henderson     TCGv_i64 addr;
25136fd0c7bcSRichard Henderson     TCGv_i64 ofs;
251463300a00SRichard Henderson 
251563300a00SRichard Henderson     nullify_over(ctx);
251663300a00SRichard Henderson 
2517deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2518eb25d10fSHelge Deller 
2519eb25d10fSHelge Deller     /*
2520eb25d10fSHelge Deller      * Page align now, rather than later, so that we can add in the
2521eb25d10fSHelge Deller      * page_size field from pa2.0 from the low 4 bits of GR[b].
2522eb25d10fSHelge Deller      */
2523eb25d10fSHelge Deller     tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK);
2524eb25d10fSHelge Deller     if (ctx->is_pa20) {
2525eb25d10fSHelge Deller         tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4);
252663300a00SRichard Henderson     }
2527eb25d10fSHelge Deller 
2528eb25d10fSHelge Deller     if (local) {
2529eb25d10fSHelge Deller         gen_helper_ptlb_l(tcg_env, addr);
253063300a00SRichard Henderson     } else {
2531ad75a51eSRichard Henderson         gen_helper_ptlb(tcg_env, addr);
253263300a00SRichard Henderson     }
253363300a00SRichard Henderson 
2534eb25d10fSHelge Deller     if (a->m) {
2535eb25d10fSHelge Deller         save_gpr(ctx, a->b, ofs);
2536eb25d10fSHelge Deller     }
2537eb25d10fSHelge Deller 
2538eb25d10fSHelge Deller     /* Exit TB for TLB change if mmu is enabled.  */
2539eb25d10fSHelge Deller     if (ctx->tb_flags & PSW_C) {
2540eb25d10fSHelge Deller         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2541eb25d10fSHelge Deller     }
2542eb25d10fSHelge Deller     return nullify_end(ctx);
2543eb25d10fSHelge Deller #endif
2544eb25d10fSHelge Deller }
2545eb25d10fSHelge Deller 
2546eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a)
2547eb25d10fSHelge Deller {
2548eb25d10fSHelge Deller     return do_pxtlb(ctx, a, false);
2549eb25d10fSHelge Deller }
2550eb25d10fSHelge Deller 
2551eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a)
2552eb25d10fSHelge Deller {
2553eb25d10fSHelge Deller     return ctx->is_pa20 && do_pxtlb(ctx, a, true);
2554eb25d10fSHelge Deller }
2555eb25d10fSHelge Deller 
2556eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a)
2557eb25d10fSHelge Deller {
2558eb25d10fSHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2559eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY
2560eb25d10fSHelge Deller     nullify_over(ctx);
2561eb25d10fSHelge Deller 
2562eb25d10fSHelge Deller     trans_nop_addrx(ctx, a);
2563eb25d10fSHelge Deller     gen_helper_ptlbe(tcg_env);
2564eb25d10fSHelge Deller 
256563300a00SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
256632dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
256731234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
256831234768SRichard Henderson     }
256931234768SRichard Henderson     return nullify_end(ctx);
2570deee69a1SRichard Henderson #endif
257163300a00SRichard Henderson }
25722dfcca9fSRichard Henderson 
25736797c315SNick Hudson /*
25746797c315SNick Hudson  * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
25756797c315SNick Hudson  * See
25766797c315SNick Hudson  *     https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
25776797c315SNick Hudson  *     page 13-9 (195/206)
25786797c315SNick Hudson  */
25796797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
25806797c315SNick Hudson {
25818577f354SRichard Henderson     if (ctx->is_pa20) {
25828577f354SRichard Henderson         return false;
25838577f354SRichard Henderson     }
25846797c315SNick Hudson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
25856797c315SNick Hudson #ifndef CONFIG_USER_ONLY
25866fd0c7bcSRichard Henderson     TCGv_i64 addr, atl, stl;
25876fd0c7bcSRichard Henderson     TCGv_i64 reg;
25886797c315SNick Hudson 
25896797c315SNick Hudson     nullify_over(ctx);
25906797c315SNick Hudson 
25916797c315SNick Hudson     /*
25926797c315SNick Hudson      * FIXME:
25936797c315SNick Hudson      *  if (not (pcxl or pcxl2))
25946797c315SNick Hudson      *    return gen_illegal(ctx);
25956797c315SNick Hudson      */
25966797c315SNick Hudson 
25976fd0c7bcSRichard Henderson     atl = tcg_temp_new_i64();
25986fd0c7bcSRichard Henderson     stl = tcg_temp_new_i64();
25996fd0c7bcSRichard Henderson     addr = tcg_temp_new_i64();
26006797c315SNick Hudson 
2601ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(stl, tcg_env,
26026797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
26036797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIASQ]));
2604ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(atl, tcg_env,
26056797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
26066797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIAOQ]));
26076797c315SNick Hudson     tcg_gen_shli_i64(stl, stl, 32);
2608d265360fSRichard Henderson     tcg_gen_or_i64(addr, atl, stl);
26096797c315SNick Hudson 
26106797c315SNick Hudson     reg = load_gpr(ctx, a->r);
26116797c315SNick Hudson     if (a->addr) {
26128577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
26136797c315SNick Hudson     } else {
26148577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
26156797c315SNick Hudson     }
26166797c315SNick Hudson 
26176797c315SNick Hudson     /* Exit TB for TLB change if mmu is enabled.  */
26186797c315SNick Hudson     if (ctx->tb_flags & PSW_C) {
26196797c315SNick Hudson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
26206797c315SNick Hudson     }
26216797c315SNick Hudson     return nullify_end(ctx);
26226797c315SNick Hudson #endif
26236797c315SNick Hudson }
26246797c315SNick Hudson 
26258577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
26268577f354SRichard Henderson {
26278577f354SRichard Henderson     if (!ctx->is_pa20) {
26288577f354SRichard Henderson         return false;
26298577f354SRichard Henderson     }
26308577f354SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
26318577f354SRichard Henderson #ifndef CONFIG_USER_ONLY
26328577f354SRichard Henderson     nullify_over(ctx);
26338577f354SRichard Henderson     {
26348577f354SRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
26358577f354SRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->r2);
26368577f354SRichard Henderson 
26378577f354SRichard Henderson         if (a->data) {
26388577f354SRichard Henderson             gen_helper_idtlbt_pa20(tcg_env, src1, src2);
26398577f354SRichard Henderson         } else {
26408577f354SRichard Henderson             gen_helper_iitlbt_pa20(tcg_env, src1, src2);
26418577f354SRichard Henderson         }
26428577f354SRichard Henderson     }
26438577f354SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
26448577f354SRichard Henderson     if (ctx->tb_flags & PSW_C) {
26458577f354SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
26468577f354SRichard Henderson     }
26478577f354SRichard Henderson     return nullify_end(ctx);
26488577f354SRichard Henderson #endif
26498577f354SRichard Henderson }
26508577f354SRichard Henderson 
2651deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
26522dfcca9fSRichard Henderson {
2653deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2654deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
26556fd0c7bcSRichard Henderson     TCGv_i64 vaddr;
26566fd0c7bcSRichard Henderson     TCGv_i64 ofs, paddr;
26572dfcca9fSRichard Henderson 
26582dfcca9fSRichard Henderson     nullify_over(ctx);
26592dfcca9fSRichard Henderson 
2660deee69a1SRichard Henderson     form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
26612dfcca9fSRichard Henderson 
2662aac0f603SRichard Henderson     paddr = tcg_temp_new_i64();
2663ad75a51eSRichard Henderson     gen_helper_lpa(paddr, tcg_env, vaddr);
26642dfcca9fSRichard Henderson 
26652dfcca9fSRichard Henderson     /* Note that physical address result overrides base modification.  */
2666deee69a1SRichard Henderson     if (a->m) {
2667deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
26682dfcca9fSRichard Henderson     }
2669deee69a1SRichard Henderson     save_gpr(ctx, a->t, paddr);
26702dfcca9fSRichard Henderson 
267131234768SRichard Henderson     return nullify_end(ctx);
2672deee69a1SRichard Henderson #endif
26732dfcca9fSRichard Henderson }
267443a97b81SRichard Henderson 
2675deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a)
267643a97b81SRichard Henderson {
267743a97b81SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
267843a97b81SRichard Henderson 
267943a97b81SRichard Henderson     /* The Coherence Index is an implementation-defined function of the
268043a97b81SRichard Henderson        physical address.  Two addresses with the same CI have a coherent
268143a97b81SRichard Henderson        view of the cache.  Our implementation is to return 0 for all,
268243a97b81SRichard Henderson        since the entire address space is coherent.  */
2683a4db4a78SRichard Henderson     save_gpr(ctx, a->t, ctx->zero);
268443a97b81SRichard Henderson 
268531234768SRichard Henderson     cond_free(&ctx->null_cond);
268631234768SRichard Henderson     return true;
268743a97b81SRichard Henderson }
268898a9cb79SRichard Henderson 
2689faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2690b2167459SRichard Henderson {
26910c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, false);
2692b2167459SRichard Henderson }
2693b2167459SRichard Henderson 
2694faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2695b2167459SRichard Henderson {
26960c982a28SRichard Henderson     return do_add_reg(ctx, a, true, false, false, false);
2697b2167459SRichard Henderson }
2698b2167459SRichard Henderson 
2699faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2700b2167459SRichard Henderson {
27010c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, false);
2702b2167459SRichard Henderson }
2703b2167459SRichard Henderson 
2704faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2705b2167459SRichard Henderson {
27060c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, true);
27070c982a28SRichard Henderson }
2708b2167459SRichard Henderson 
2709faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
27100c982a28SRichard Henderson {
27110c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, true);
27120c982a28SRichard Henderson }
27130c982a28SRichard Henderson 
271463c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
27150c982a28SRichard Henderson {
27160c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, false);
27170c982a28SRichard Henderson }
27180c982a28SRichard Henderson 
271963c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
27200c982a28SRichard Henderson {
27210c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, false);
27220c982a28SRichard Henderson }
27230c982a28SRichard Henderson 
272463c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
27250c982a28SRichard Henderson {
27260c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, true);
27270c982a28SRichard Henderson }
27280c982a28SRichard Henderson 
272963c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
27300c982a28SRichard Henderson {
27310c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, true);
27320c982a28SRichard Henderson }
27330c982a28SRichard Henderson 
273463c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
27350c982a28SRichard Henderson {
27360c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, true, false);
27370c982a28SRichard Henderson }
27380c982a28SRichard Henderson 
273963c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
27400c982a28SRichard Henderson {
27410c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, true, false);
27420c982a28SRichard Henderson }
27430c982a28SRichard Henderson 
2744fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
27450c982a28SRichard Henderson {
27466fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_andc_i64);
27470c982a28SRichard Henderson }
27480c982a28SRichard Henderson 
2749fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
27500c982a28SRichard Henderson {
27516fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_and_i64);
27520c982a28SRichard Henderson }
27530c982a28SRichard Henderson 
2754fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
27550c982a28SRichard Henderson {
27560c982a28SRichard Henderson     if (a->cf == 0) {
27570c982a28SRichard Henderson         unsigned r2 = a->r2;
27580c982a28SRichard Henderson         unsigned r1 = a->r1;
27590c982a28SRichard Henderson         unsigned rt = a->t;
27600c982a28SRichard Henderson 
27617aee8189SRichard Henderson         if (rt == 0) { /* NOP */
27627aee8189SRichard Henderson             cond_free(&ctx->null_cond);
27637aee8189SRichard Henderson             return true;
27647aee8189SRichard Henderson         }
27657aee8189SRichard Henderson         if (r2 == 0) { /* COPY */
2766b2167459SRichard Henderson             if (r1 == 0) {
27676fd0c7bcSRichard Henderson                 TCGv_i64 dest = dest_gpr(ctx, rt);
27686fd0c7bcSRichard Henderson                 tcg_gen_movi_i64(dest, 0);
2769b2167459SRichard Henderson                 save_gpr(ctx, rt, dest);
2770b2167459SRichard Henderson             } else {
2771b2167459SRichard Henderson                 save_gpr(ctx, rt, cpu_gr[r1]);
2772b2167459SRichard Henderson             }
2773b2167459SRichard Henderson             cond_free(&ctx->null_cond);
277431234768SRichard Henderson             return true;
2775b2167459SRichard Henderson         }
27767aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY
27777aee8189SRichard Henderson         /* These are QEMU extensions and are nops in the real architecture:
27787aee8189SRichard Henderson          *
27797aee8189SRichard Henderson          * or %r10,%r10,%r10 -- idle loop; wait for interrupt
27807aee8189SRichard Henderson          * or %r31,%r31,%r31 -- death loop; offline cpu
27817aee8189SRichard Henderson          *                      currently implemented as idle.
27827aee8189SRichard Henderson          */
27837aee8189SRichard Henderson         if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
27847aee8189SRichard Henderson             /* No need to check for supervisor, as userland can only pause
27857aee8189SRichard Henderson                until the next timer interrupt.  */
27867aee8189SRichard Henderson             nullify_over(ctx);
27877aee8189SRichard Henderson 
27887aee8189SRichard Henderson             /* Advance the instruction queue.  */
2789bc921866SRichard Henderson             install_iaq_entries(ctx, &ctx->iaq_b, NULL);
27907aee8189SRichard Henderson             nullify_set(ctx, 0);
27917aee8189SRichard Henderson 
27927aee8189SRichard Henderson             /* Tell the qemu main loop to halt until this cpu has work.  */
2793ad75a51eSRichard Henderson             tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
279429dd6f64SRichard Henderson                            offsetof(CPUState, halted) - offsetof(HPPACPU, env));
27957aee8189SRichard Henderson             gen_excp_1(EXCP_HALTED);
27967aee8189SRichard Henderson             ctx->base.is_jmp = DISAS_NORETURN;
27977aee8189SRichard Henderson 
27987aee8189SRichard Henderson             return nullify_end(ctx);
27997aee8189SRichard Henderson         }
28007aee8189SRichard Henderson #endif
28017aee8189SRichard Henderson     }
28026fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_or_i64);
28037aee8189SRichard Henderson }
2804b2167459SRichard Henderson 
2805fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
2806b2167459SRichard Henderson {
28076fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_xor_i64);
28080c982a28SRichard Henderson }
28090c982a28SRichard Henderson 
2810345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
28110c982a28SRichard Henderson {
28126fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2813b2167459SRichard Henderson 
28140c982a28SRichard Henderson     if (a->cf) {
2815b2167459SRichard Henderson         nullify_over(ctx);
2816b2167459SRichard Henderson     }
28170c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
28180c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2819345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
282031234768SRichard Henderson     return nullify_end(ctx);
2821b2167459SRichard Henderson }
2822b2167459SRichard Henderson 
2823af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
2824b2167459SRichard Henderson {
282546bb3d46SRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, dest;
2826b2167459SRichard Henderson 
28270c982a28SRichard Henderson     if (a->cf) {
2828b2167459SRichard Henderson         nullify_over(ctx);
2829b2167459SRichard Henderson     }
283046bb3d46SRichard Henderson 
28310c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
28320c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
283346bb3d46SRichard Henderson     dest = dest_gpr(ctx, a->t);
283446bb3d46SRichard Henderson 
283546bb3d46SRichard Henderson     tcg_gen_xor_i64(dest, tcg_r1, tcg_r2);
283646bb3d46SRichard Henderson     save_gpr(ctx, a->t, dest);
283746bb3d46SRichard Henderson 
283846bb3d46SRichard Henderson     cond_free(&ctx->null_cond);
283946bb3d46SRichard Henderson     if (a->cf) {
284046bb3d46SRichard Henderson         ctx->null_cond = do_unit_zero_cond(a->cf, a->d, dest);
284146bb3d46SRichard Henderson     }
284246bb3d46SRichard Henderson 
284331234768SRichard Henderson     return nullify_end(ctx);
2844b2167459SRichard Henderson }
2845b2167459SRichard Henderson 
2846af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
2847b2167459SRichard Henderson {
28486fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, tmp;
2849b2167459SRichard Henderson 
2850ababac16SRichard Henderson     if (a->cf == 0) {
2851ababac16SRichard Henderson         tcg_r2 = load_gpr(ctx, a->r2);
2852ababac16SRichard Henderson         tmp = dest_gpr(ctx, a->t);
2853ababac16SRichard Henderson 
2854ababac16SRichard Henderson         if (a->r1 == 0) {
2855ababac16SRichard Henderson             /* UADDCM r0,src,dst is the common idiom for dst = ~src. */
2856ababac16SRichard Henderson             tcg_gen_not_i64(tmp, tcg_r2);
2857ababac16SRichard Henderson         } else {
2858ababac16SRichard Henderson             /*
2859ababac16SRichard Henderson              * Recall that r1 - r2 == r1 + ~r2 + 1.
2860ababac16SRichard Henderson              * Thus r1 + ~r2 == r1 - r2 - 1,
2861ababac16SRichard Henderson              * which does not require an extra temporary.
2862ababac16SRichard Henderson              */
2863ababac16SRichard Henderson             tcg_r1 = load_gpr(ctx, a->r1);
2864ababac16SRichard Henderson             tcg_gen_sub_i64(tmp, tcg_r1, tcg_r2);
2865ababac16SRichard Henderson             tcg_gen_subi_i64(tmp, tmp, 1);
2866b2167459SRichard Henderson         }
2867ababac16SRichard Henderson         save_gpr(ctx, a->t, tmp);
2868ababac16SRichard Henderson         cond_free(&ctx->null_cond);
2869ababac16SRichard Henderson         return true;
2870ababac16SRichard Henderson     }
2871ababac16SRichard Henderson 
2872ababac16SRichard Henderson     nullify_over(ctx);
28730c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
28740c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2875aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
28766fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, tcg_r2);
287746bb3d46SRichard Henderson     do_unit_addsub(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, true);
287831234768SRichard Henderson     return nullify_end(ctx);
2879b2167459SRichard Henderson }
2880b2167459SRichard Henderson 
2881af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
2882b2167459SRichard Henderson {
28830c982a28SRichard Henderson     return do_uaddcm(ctx, a, false);
28840c982a28SRichard Henderson }
28850c982a28SRichard Henderson 
2886af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
28870c982a28SRichard Henderson {
28880c982a28SRichard Henderson     return do_uaddcm(ctx, a, true);
28890c982a28SRichard Henderson }
28900c982a28SRichard Henderson 
2891af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
28920c982a28SRichard Henderson {
28936fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2894b2167459SRichard Henderson 
2895b2167459SRichard Henderson     nullify_over(ctx);
2896b2167459SRichard Henderson 
2897aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2898d0ae87a2SRichard Henderson     tcg_gen_extract2_i64(tmp, cpu_psw_cb, cpu_psw_cb_msb, 4);
2899b2167459SRichard Henderson     if (!is_i) {
29006fd0c7bcSRichard Henderson         tcg_gen_not_i64(tmp, tmp);
2901b2167459SRichard Henderson     }
29026fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
29036fd0c7bcSRichard Henderson     tcg_gen_muli_i64(tmp, tmp, 6);
290446bb3d46SRichard Henderson     do_unit_addsub(ctx, a->t, load_gpr(ctx, a->r), tmp,
290546bb3d46SRichard Henderson                    a->cf, a->d, false, is_i);
290631234768SRichard Henderson     return nullify_end(ctx);
2907b2167459SRichard Henderson }
2908b2167459SRichard Henderson 
2909af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
2910b2167459SRichard Henderson {
29110c982a28SRichard Henderson     return do_dcor(ctx, a, false);
29120c982a28SRichard Henderson }
29130c982a28SRichard Henderson 
2914af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
29150c982a28SRichard Henderson {
29160c982a28SRichard Henderson     return do_dcor(ctx, a, true);
29170c982a28SRichard Henderson }
29180c982a28SRichard Henderson 
29190c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
29200c982a28SRichard Henderson {
2921a4db4a78SRichard Henderson     TCGv_i64 dest, add1, add2, addc, in1, in2;
2922b2167459SRichard Henderson 
2923b2167459SRichard Henderson     nullify_over(ctx);
2924b2167459SRichard Henderson 
29250c982a28SRichard Henderson     in1 = load_gpr(ctx, a->r1);
29260c982a28SRichard Henderson     in2 = load_gpr(ctx, a->r2);
2927b2167459SRichard Henderson 
2928aac0f603SRichard Henderson     add1 = tcg_temp_new_i64();
2929aac0f603SRichard Henderson     add2 = tcg_temp_new_i64();
2930aac0f603SRichard Henderson     addc = tcg_temp_new_i64();
2931aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
2932b2167459SRichard Henderson 
2933b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
29346fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, in1, in1);
29356fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
2936b2167459SRichard Henderson 
293772ca8753SRichard Henderson     /*
293872ca8753SRichard Henderson      * Add or subtract R2, depending on PSW[V].  Proper computation of
293972ca8753SRichard Henderson      * carry requires that we subtract via + ~R2 + 1, as described in
294072ca8753SRichard Henderson      * the manual.  By extracting and masking V, we can produce the
294172ca8753SRichard Henderson      * proper inputs to the addition without movcond.
294272ca8753SRichard Henderson      */
29436fd0c7bcSRichard Henderson     tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
29446fd0c7bcSRichard Henderson     tcg_gen_xor_i64(add2, in2, addc);
29456fd0c7bcSRichard Henderson     tcg_gen_andi_i64(addc, addc, 1);
294672ca8753SRichard Henderson 
2947a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero);
2948a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb,
2949a4db4a78SRichard Henderson                      addc, ctx->zero);
2950b2167459SRichard Henderson 
2951b2167459SRichard Henderson     /* Write back the result register.  */
29520c982a28SRichard Henderson     save_gpr(ctx, a->t, dest);
2953b2167459SRichard Henderson 
2954b2167459SRichard Henderson     /* Write back PSW[CB].  */
29556fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
29566fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
2957b2167459SRichard Henderson 
2958f8f5986eSRichard Henderson     /*
2959f8f5986eSRichard Henderson      * Write back PSW[V] for the division step.
2960f8f5986eSRichard Henderson      * Shift cb{8} from where it lives in bit 32 to bit 31,
2961f8f5986eSRichard Henderson      * so that it overlaps r2{32} in bit 31.
2962f8f5986eSRichard Henderson      */
2963f8f5986eSRichard Henderson     tcg_gen_shri_i64(cpu_psw_v, cpu_psw_cb, 1);
29646fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
2965b2167459SRichard Henderson 
2966b2167459SRichard Henderson     /* Install the new nullification.  */
29670c982a28SRichard Henderson     if (a->cf) {
2968f8f5986eSRichard Henderson         TCGv_i64 sv = NULL, uv = NULL;
2969b47a4a02SSven Schnelle         if (cond_need_sv(a->cf >> 1)) {
2970f8f5986eSRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2, in1, 1, false);
2971f8f5986eSRichard Henderson         } else if (cond_need_cb(a->cf >> 1)) {
2972f8f5986eSRichard Henderson             uv = do_add_uv(ctx, cpu_psw_cb, NULL, in1, 1, false);
2973b2167459SRichard Henderson         }
2974f8f5986eSRichard Henderson         ctx->null_cond = do_cond(ctx, a->cf, false, dest, uv, sv);
2975b2167459SRichard Henderson     }
2976b2167459SRichard Henderson 
297731234768SRichard Henderson     return nullify_end(ctx);
2978b2167459SRichard Henderson }
2979b2167459SRichard Henderson 
29800588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a)
2981b2167459SRichard Henderson {
29820588e061SRichard Henderson     return do_add_imm(ctx, a, false, false);
29830588e061SRichard Henderson }
29840588e061SRichard Henderson 
29850588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a)
29860588e061SRichard Henderson {
29870588e061SRichard Henderson     return do_add_imm(ctx, a, true, false);
29880588e061SRichard Henderson }
29890588e061SRichard Henderson 
29900588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a)
29910588e061SRichard Henderson {
29920588e061SRichard Henderson     return do_add_imm(ctx, a, false, true);
29930588e061SRichard Henderson }
29940588e061SRichard Henderson 
29950588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a)
29960588e061SRichard Henderson {
29970588e061SRichard Henderson     return do_add_imm(ctx, a, true, true);
29980588e061SRichard Henderson }
29990588e061SRichard Henderson 
30000588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a)
30010588e061SRichard Henderson {
30020588e061SRichard Henderson     return do_sub_imm(ctx, a, false);
30030588e061SRichard Henderson }
30040588e061SRichard Henderson 
30050588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
30060588e061SRichard Henderson {
30070588e061SRichard Henderson     return do_sub_imm(ctx, a, true);
30080588e061SRichard Henderson }
30090588e061SRichard Henderson 
3010345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
30110588e061SRichard Henderson {
30126fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
3013b2167459SRichard Henderson 
30140588e061SRichard Henderson     if (a->cf) {
3015b2167459SRichard Henderson         nullify_over(ctx);
3016b2167459SRichard Henderson     }
3017b2167459SRichard Henderson 
30186fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
30190588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
3020345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
3021b2167459SRichard Henderson 
302231234768SRichard Henderson     return nullify_end(ctx);
3023b2167459SRichard Henderson }
3024b2167459SRichard Henderson 
30250843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a,
30260843563fSRichard Henderson                           void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
30270843563fSRichard Henderson {
30280843563fSRichard Henderson     TCGv_i64 r1, r2, dest;
30290843563fSRichard Henderson 
30300843563fSRichard Henderson     if (!ctx->is_pa20) {
30310843563fSRichard Henderson         return false;
30320843563fSRichard Henderson     }
30330843563fSRichard Henderson 
30340843563fSRichard Henderson     nullify_over(ctx);
30350843563fSRichard Henderson 
30360843563fSRichard Henderson     r1 = load_gpr(ctx, a->r1);
30370843563fSRichard Henderson     r2 = load_gpr(ctx, a->r2);
30380843563fSRichard Henderson     dest = dest_gpr(ctx, a->t);
30390843563fSRichard Henderson 
30400843563fSRichard Henderson     fn(dest, r1, r2);
30410843563fSRichard Henderson     save_gpr(ctx, a->t, dest);
30420843563fSRichard Henderson 
30430843563fSRichard Henderson     return nullify_end(ctx);
30440843563fSRichard Henderson }
30450843563fSRichard Henderson 
3046151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a,
3047151f309bSRichard Henderson                              void (*fn)(TCGv_i64, TCGv_i64, int64_t))
3048151f309bSRichard Henderson {
3049151f309bSRichard Henderson     TCGv_i64 r, dest;
3050151f309bSRichard Henderson 
3051151f309bSRichard Henderson     if (!ctx->is_pa20) {
3052151f309bSRichard Henderson         return false;
3053151f309bSRichard Henderson     }
3054151f309bSRichard Henderson 
3055151f309bSRichard Henderson     nullify_over(ctx);
3056151f309bSRichard Henderson 
3057151f309bSRichard Henderson     r = load_gpr(ctx, a->r);
3058151f309bSRichard Henderson     dest = dest_gpr(ctx, a->t);
3059151f309bSRichard Henderson 
3060151f309bSRichard Henderson     fn(dest, r, a->i);
3061151f309bSRichard Henderson     save_gpr(ctx, a->t, dest);
3062151f309bSRichard Henderson 
3063151f309bSRichard Henderson     return nullify_end(ctx);
3064151f309bSRichard Henderson }
3065151f309bSRichard Henderson 
30663bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a,
30673bbb8e48SRichard Henderson                                 void (*fn)(TCGv_i64, TCGv_i64,
30683bbb8e48SRichard Henderson                                            TCGv_i64, TCGv_i32))
30693bbb8e48SRichard Henderson {
30703bbb8e48SRichard Henderson     TCGv_i64 r1, r2, dest;
30713bbb8e48SRichard Henderson 
30723bbb8e48SRichard Henderson     if (!ctx->is_pa20) {
30733bbb8e48SRichard Henderson         return false;
30743bbb8e48SRichard Henderson     }
30753bbb8e48SRichard Henderson 
30763bbb8e48SRichard Henderson     nullify_over(ctx);
30773bbb8e48SRichard Henderson 
30783bbb8e48SRichard Henderson     r1 = load_gpr(ctx, a->r1);
30793bbb8e48SRichard Henderson     r2 = load_gpr(ctx, a->r2);
30803bbb8e48SRichard Henderson     dest = dest_gpr(ctx, a->t);
30813bbb8e48SRichard Henderson 
30823bbb8e48SRichard Henderson     fn(dest, r1, r2, tcg_constant_i32(a->sh));
30833bbb8e48SRichard Henderson     save_gpr(ctx, a->t, dest);
30843bbb8e48SRichard Henderson 
30853bbb8e48SRichard Henderson     return nullify_end(ctx);
30863bbb8e48SRichard Henderson }
30873bbb8e48SRichard Henderson 
30880843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a)
30890843563fSRichard Henderson {
30900843563fSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_add16_i64);
30910843563fSRichard Henderson }
30920843563fSRichard Henderson 
30930843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a)
30940843563fSRichard Henderson {
30950843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_ss);
30960843563fSRichard Henderson }
30970843563fSRichard Henderson 
30980843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a)
30990843563fSRichard Henderson {
31000843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_us);
31010843563fSRichard Henderson }
31020843563fSRichard Henderson 
31031b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a)
31041b3cb7c8SRichard Henderson {
31051b3cb7c8SRichard Henderson     return do_multimedia(ctx, a, gen_helper_havg);
31061b3cb7c8SRichard Henderson }
31071b3cb7c8SRichard Henderson 
3108151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a)
3109151f309bSRichard Henderson {
3110151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64);
3111151f309bSRichard Henderson }
3112151f309bSRichard Henderson 
3113151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a)
3114151f309bSRichard Henderson {
3115151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64);
3116151f309bSRichard Henderson }
3117151f309bSRichard Henderson 
3118151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a)
3119151f309bSRichard Henderson {
3120151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64);
3121151f309bSRichard Henderson }
3122151f309bSRichard Henderson 
31233bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a)
31243bbb8e48SRichard Henderson {
31253bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshladd);
31263bbb8e48SRichard Henderson }
31273bbb8e48SRichard Henderson 
31283bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a)
31293bbb8e48SRichard Henderson {
31303bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshradd);
31313bbb8e48SRichard Henderson }
31323bbb8e48SRichard Henderson 
313310c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a)
313410c9e58dSRichard Henderson {
313510c9e58dSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64);
313610c9e58dSRichard Henderson }
313710c9e58dSRichard Henderson 
313810c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a)
313910c9e58dSRichard Henderson {
314010c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_ss);
314110c9e58dSRichard Henderson }
314210c9e58dSRichard Henderson 
314310c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a)
314410c9e58dSRichard Henderson {
314510c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_us);
314610c9e58dSRichard Henderson }
314710c9e58dSRichard Henderson 
3148c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3149c2a7ee3fSRichard Henderson {
3150c2a7ee3fSRichard Henderson     uint64_t mask = 0xffff0000ffff0000ull;
3151c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3152c2a7ee3fSRichard Henderson 
3153c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r2, mask);
3154c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r1, mask);
3155c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, tmp, 16);
3156c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
3157c2a7ee3fSRichard Henderson }
3158c2a7ee3fSRichard Henderson 
3159c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a)
3160c2a7ee3fSRichard Henderson {
3161c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_l);
3162c2a7ee3fSRichard Henderson }
3163c2a7ee3fSRichard Henderson 
3164c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3165c2a7ee3fSRichard Henderson {
3166c2a7ee3fSRichard Henderson     uint64_t mask = 0x0000ffff0000ffffull;
3167c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3168c2a7ee3fSRichard Henderson 
3169c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r1, mask);
3170c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r2, mask);
3171c2a7ee3fSRichard Henderson     tcg_gen_shli_i64(tmp, tmp, 16);
3172c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
3173c2a7ee3fSRichard Henderson }
3174c2a7ee3fSRichard Henderson 
3175c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a)
3176c2a7ee3fSRichard Henderson {
3177c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_r);
3178c2a7ee3fSRichard Henderson }
3179c2a7ee3fSRichard Henderson 
3180c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3181c2a7ee3fSRichard Henderson {
3182c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3183c2a7ee3fSRichard Henderson 
3184c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, r2, 32);
3185c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r1, tmp, 0, 32);
3186c2a7ee3fSRichard Henderson }
3187c2a7ee3fSRichard Henderson 
3188c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a)
3189c2a7ee3fSRichard Henderson {
3190c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_l);
3191c2a7ee3fSRichard Henderson }
3192c2a7ee3fSRichard Henderson 
3193c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3194c2a7ee3fSRichard Henderson {
3195c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r2, r1, 32, 32);
3196c2a7ee3fSRichard Henderson }
3197c2a7ee3fSRichard Henderson 
3198c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a)
3199c2a7ee3fSRichard Henderson {
3200c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_r);
3201c2a7ee3fSRichard Henderson }
3202c2a7ee3fSRichard Henderson 
32034e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a)
32044e7abdb1SRichard Henderson {
32054e7abdb1SRichard Henderson     TCGv_i64 r, t0, t1, t2, t3;
32064e7abdb1SRichard Henderson 
32074e7abdb1SRichard Henderson     if (!ctx->is_pa20) {
32084e7abdb1SRichard Henderson         return false;
32094e7abdb1SRichard Henderson     }
32104e7abdb1SRichard Henderson 
32114e7abdb1SRichard Henderson     nullify_over(ctx);
32124e7abdb1SRichard Henderson 
32134e7abdb1SRichard Henderson     r = load_gpr(ctx, a->r1);
32144e7abdb1SRichard Henderson     t0 = tcg_temp_new_i64();
32154e7abdb1SRichard Henderson     t1 = tcg_temp_new_i64();
32164e7abdb1SRichard Henderson     t2 = tcg_temp_new_i64();
32174e7abdb1SRichard Henderson     t3 = tcg_temp_new_i64();
32184e7abdb1SRichard Henderson 
32194e7abdb1SRichard Henderson     tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16);
32204e7abdb1SRichard Henderson     tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16);
32214e7abdb1SRichard Henderson     tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16);
32224e7abdb1SRichard Henderson     tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16);
32234e7abdb1SRichard Henderson 
32244e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t1, t0, 16, 48);
32254e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t2, t3, t2, 16, 48);
32264e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t2, t0, 32, 32);
32274e7abdb1SRichard Henderson 
32284e7abdb1SRichard Henderson     save_gpr(ctx, a->t, t0);
32294e7abdb1SRichard Henderson     return nullify_end(ctx);
32304e7abdb1SRichard Henderson }
32314e7abdb1SRichard Henderson 
32321cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a)
323396d6407fSRichard Henderson {
3234b5caa17cSRichard Henderson     if (ctx->is_pa20) {
3235b5caa17cSRichard Henderson        /*
3236b5caa17cSRichard Henderson         * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches.
3237b5caa17cSRichard Henderson         * Any base modification still occurs.
3238b5caa17cSRichard Henderson         */
3239b5caa17cSRichard Henderson         if (a->t == 0) {
3240b5caa17cSRichard Henderson             return trans_nop_addrx(ctx, a);
3241b5caa17cSRichard Henderson         }
3242b5caa17cSRichard Henderson     } else if (a->size > MO_32) {
32430786a3b6SHelge Deller         return gen_illegal(ctx);
3244c53e401eSRichard Henderson     }
32451cd012a5SRichard Henderson     return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
32461cd012a5SRichard Henderson                    a->disp, a->sp, a->m, a->size | MO_TE);
324796d6407fSRichard Henderson }
324896d6407fSRichard Henderson 
32491cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a)
325096d6407fSRichard Henderson {
32511cd012a5SRichard Henderson     assert(a->x == 0 && a->scale == 0);
3252c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
32530786a3b6SHelge Deller         return gen_illegal(ctx);
325496d6407fSRichard Henderson     }
3255c53e401eSRichard Henderson     return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
32560786a3b6SHelge Deller }
325796d6407fSRichard Henderson 
32581cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
325996d6407fSRichard Henderson {
3260b1af755cSRichard Henderson     MemOp mop = MO_TE | MO_ALIGN | a->size;
3261a4db4a78SRichard Henderson     TCGv_i64 dest, ofs;
32626fd0c7bcSRichard Henderson     TCGv_i64 addr;
326396d6407fSRichard Henderson 
3264c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
326551416c4eSRichard Henderson         return gen_illegal(ctx);
326651416c4eSRichard Henderson     }
326751416c4eSRichard Henderson 
326896d6407fSRichard Henderson     nullify_over(ctx);
326996d6407fSRichard Henderson 
32701cd012a5SRichard Henderson     if (a->m) {
327186f8d05fSRichard Henderson         /* Base register modification.  Make sure if RT == RB,
327286f8d05fSRichard Henderson            we see the result of the load.  */
3273aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
327496d6407fSRichard Henderson     } else {
32751cd012a5SRichard Henderson         dest = dest_gpr(ctx, a->t);
327696d6407fSRichard Henderson     }
327796d6407fSRichard Henderson 
3278c3ea1996SSven Schnelle     form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? 3 : 0,
327917fe594cSRichard Henderson              a->disp, a->sp, a->m, MMU_DISABLED(ctx));
3280b1af755cSRichard Henderson 
3281b1af755cSRichard Henderson     /*
3282b1af755cSRichard Henderson      * For hppa1.1, LDCW is undefined unless aligned mod 16.
3283b1af755cSRichard Henderson      * However actual hardware succeeds with aligned mod 4.
3284b1af755cSRichard Henderson      * Detect this case and log a GUEST_ERROR.
3285b1af755cSRichard Henderson      *
3286b1af755cSRichard Henderson      * TODO: HPPA64 relaxes the over-alignment requirement
3287b1af755cSRichard Henderson      * with the ,co completer.
3288b1af755cSRichard Henderson      */
3289b1af755cSRichard Henderson     gen_helper_ldc_check(addr);
3290b1af755cSRichard Henderson 
3291a4db4a78SRichard Henderson     tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop);
3292b1af755cSRichard Henderson 
32931cd012a5SRichard Henderson     if (a->m) {
32941cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
329596d6407fSRichard Henderson     }
32961cd012a5SRichard Henderson     save_gpr(ctx, a->t, dest);
329796d6407fSRichard Henderson 
329831234768SRichard Henderson     return nullify_end(ctx);
329996d6407fSRichard Henderson }
330096d6407fSRichard Henderson 
33011cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a)
330296d6407fSRichard Henderson {
33036fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
33046fd0c7bcSRichard Henderson     TCGv_i64 addr;
330596d6407fSRichard Henderson 
330696d6407fSRichard Henderson     nullify_over(ctx);
330796d6407fSRichard Henderson 
33081cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
330917fe594cSRichard Henderson              MMU_DISABLED(ctx));
33101cd012a5SRichard Henderson     val = load_gpr(ctx, a->r);
33111cd012a5SRichard Henderson     if (a->a) {
3312f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3313ad75a51eSRichard Henderson             gen_helper_stby_e_parallel(tcg_env, addr, val);
3314f9f46db4SEmilio G. Cota         } else {
3315ad75a51eSRichard Henderson             gen_helper_stby_e(tcg_env, addr, val);
3316f9f46db4SEmilio G. Cota         }
3317f9f46db4SEmilio G. Cota     } else {
3318f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3319ad75a51eSRichard Henderson             gen_helper_stby_b_parallel(tcg_env, addr, val);
332096d6407fSRichard Henderson         } else {
3321ad75a51eSRichard Henderson             gen_helper_stby_b(tcg_env, addr, val);
332296d6407fSRichard Henderson         }
3323f9f46db4SEmilio G. Cota     }
33241cd012a5SRichard Henderson     if (a->m) {
33256fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~3);
33261cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
332796d6407fSRichard Henderson     }
332896d6407fSRichard Henderson 
332931234768SRichard Henderson     return nullify_end(ctx);
333096d6407fSRichard Henderson }
333196d6407fSRichard Henderson 
333225460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a)
333325460fc5SRichard Henderson {
33346fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
33356fd0c7bcSRichard Henderson     TCGv_i64 addr;
333625460fc5SRichard Henderson 
333725460fc5SRichard Henderson     if (!ctx->is_pa20) {
333825460fc5SRichard Henderson         return false;
333925460fc5SRichard Henderson     }
334025460fc5SRichard Henderson     nullify_over(ctx);
334125460fc5SRichard Henderson 
334225460fc5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
334317fe594cSRichard Henderson              MMU_DISABLED(ctx));
334425460fc5SRichard Henderson     val = load_gpr(ctx, a->r);
334525460fc5SRichard Henderson     if (a->a) {
334625460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
334725460fc5SRichard Henderson             gen_helper_stdby_e_parallel(tcg_env, addr, val);
334825460fc5SRichard Henderson         } else {
334925460fc5SRichard Henderson             gen_helper_stdby_e(tcg_env, addr, val);
335025460fc5SRichard Henderson         }
335125460fc5SRichard Henderson     } else {
335225460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
335325460fc5SRichard Henderson             gen_helper_stdby_b_parallel(tcg_env, addr, val);
335425460fc5SRichard Henderson         } else {
335525460fc5SRichard Henderson             gen_helper_stdby_b(tcg_env, addr, val);
335625460fc5SRichard Henderson         }
335725460fc5SRichard Henderson     }
335825460fc5SRichard Henderson     if (a->m) {
33596fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~7);
336025460fc5SRichard Henderson         save_gpr(ctx, a->b, ofs);
336125460fc5SRichard Henderson     }
336225460fc5SRichard Henderson 
336325460fc5SRichard Henderson     return nullify_end(ctx);
336425460fc5SRichard Henderson }
336525460fc5SRichard Henderson 
33661cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a)
3367d0a851ccSRichard Henderson {
3368d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3369d0a851ccSRichard Henderson 
3370d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3371451d993dSRichard Henderson     ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX;
33721cd012a5SRichard Henderson     trans_ld(ctx, a);
3373d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
337431234768SRichard Henderson     return true;
3375d0a851ccSRichard Henderson }
3376d0a851ccSRichard Henderson 
33771cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a)
3378d0a851ccSRichard Henderson {
3379d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3380d0a851ccSRichard Henderson 
3381d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3382451d993dSRichard Henderson     ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX;
33831cd012a5SRichard Henderson     trans_st(ctx, a);
3384d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
338531234768SRichard Henderson     return true;
3386d0a851ccSRichard Henderson }
338795412a61SRichard Henderson 
33880588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
3389b2167459SRichard Henderson {
33906fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3391b2167459SRichard Henderson 
33926fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tcg_rt, a->i);
33930588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3394b2167459SRichard Henderson     cond_free(&ctx->null_cond);
339531234768SRichard Henderson     return true;
3396b2167459SRichard Henderson }
3397b2167459SRichard Henderson 
33980588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a)
3399b2167459SRichard Henderson {
34006fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
34016fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
3402b2167459SRichard Henderson 
34036fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
3404b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
3405b2167459SRichard Henderson     cond_free(&ctx->null_cond);
340631234768SRichard Henderson     return true;
3407b2167459SRichard Henderson }
3408b2167459SRichard Henderson 
34090588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
3410b2167459SRichard Henderson {
34116fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3412b2167459SRichard Henderson 
3413b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
3414d265360fSRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_i64.  */
34150588e061SRichard Henderson     if (a->b == 0) {
34166fd0c7bcSRichard Henderson         tcg_gen_movi_i64(tcg_rt, a->i);
3417b2167459SRichard Henderson     } else {
34186fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
3419b2167459SRichard Henderson     }
34200588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3421b2167459SRichard Henderson     cond_free(&ctx->null_cond);
342231234768SRichard Henderson     return true;
3423b2167459SRichard Henderson }
3424b2167459SRichard Henderson 
34256fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
3426e9efd4bcSRichard Henderson                     unsigned c, unsigned f, bool d, unsigned n, int disp)
342798cd9ca7SRichard Henderson {
34286fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv;
342998cd9ca7SRichard Henderson     DisasCond cond;
343098cd9ca7SRichard Henderson 
343198cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3432aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
343398cd9ca7SRichard Henderson 
34346fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
343598cd9ca7SRichard Henderson 
3436f764718dSRichard Henderson     sv = NULL;
3437b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
343898cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
343998cd9ca7SRichard Henderson     }
344098cd9ca7SRichard Henderson 
34414fe9533aSRichard Henderson     cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
344201afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
344398cd9ca7SRichard Henderson }
344498cd9ca7SRichard Henderson 
344501afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
344698cd9ca7SRichard Henderson {
3447e9efd4bcSRichard Henderson     if (!ctx->is_pa20 && a->d) {
3448e9efd4bcSRichard Henderson         return false;
3449e9efd4bcSRichard Henderson     }
345001afb7beSRichard Henderson     nullify_over(ctx);
3451e9efd4bcSRichard Henderson     return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
3452e9efd4bcSRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
345301afb7beSRichard Henderson }
345401afb7beSRichard Henderson 
345501afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
345601afb7beSRichard Henderson {
3457c65c3ee1SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3458c65c3ee1SRichard Henderson         return false;
3459c65c3ee1SRichard Henderson     }
346001afb7beSRichard Henderson     nullify_over(ctx);
34616fd0c7bcSRichard Henderson     return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
3462c65c3ee1SRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
346301afb7beSRichard Henderson }
346401afb7beSRichard Henderson 
34656fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
346601afb7beSRichard Henderson                     unsigned c, unsigned f, unsigned n, int disp)
346701afb7beSRichard Henderson {
34686fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv, cb_cond;
346998cd9ca7SRichard Henderson     DisasCond cond;
3470bdcccc17SRichard Henderson     bool d = false;
347198cd9ca7SRichard Henderson 
3472f25d3160SRichard Henderson     /*
3473f25d3160SRichard Henderson      * For hppa64, the ADDB conditions change with PSW.W,
3474f25d3160SRichard Henderson      * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3475f25d3160SRichard Henderson      */
3476f25d3160SRichard Henderson     if (ctx->tb_flags & PSW_W) {
3477f25d3160SRichard Henderson         d = c >= 5;
3478f25d3160SRichard Henderson         if (d) {
3479f25d3160SRichard Henderson             c &= 3;
3480f25d3160SRichard Henderson         }
3481f25d3160SRichard Henderson     }
3482f25d3160SRichard Henderson 
348398cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3484aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
3485f764718dSRichard Henderson     sv = NULL;
3486bdcccc17SRichard Henderson     cb_cond = NULL;
348798cd9ca7SRichard Henderson 
3488b47a4a02SSven Schnelle     if (cond_need_cb(c)) {
3489aac0f603SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
3490aac0f603SRichard Henderson         TCGv_i64 cb_msb = tcg_temp_new_i64();
3491bdcccc17SRichard Henderson 
34926fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cb_msb, 0);
34936fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
34946fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
34956fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
3496bdcccc17SRichard Henderson         cb_cond = get_carry(ctx, d, cb, cb_msb);
3497b47a4a02SSven Schnelle     } else {
34986fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
3499b47a4a02SSven Schnelle     }
3500b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
3501f8f5986eSRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2, in1, 0, d);
350298cd9ca7SRichard Henderson     }
350398cd9ca7SRichard Henderson 
3504a751eb31SRichard Henderson     cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
350543675d20SSven Schnelle     save_gpr(ctx, r, dest);
350601afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
350798cd9ca7SRichard Henderson }
350898cd9ca7SRichard Henderson 
350901afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a)
351098cd9ca7SRichard Henderson {
351101afb7beSRichard Henderson     nullify_over(ctx);
351201afb7beSRichard Henderson     return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
351301afb7beSRichard Henderson }
351401afb7beSRichard Henderson 
351501afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
351601afb7beSRichard Henderson {
351701afb7beSRichard Henderson     nullify_over(ctx);
35186fd0c7bcSRichard Henderson     return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
351901afb7beSRichard Henderson }
352001afb7beSRichard Henderson 
352101afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
352201afb7beSRichard Henderson {
35236fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
352498cd9ca7SRichard Henderson     DisasCond cond;
352598cd9ca7SRichard Henderson 
352698cd9ca7SRichard Henderson     nullify_over(ctx);
352798cd9ca7SRichard Henderson 
3528aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
352901afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
353082d0c831SRichard Henderson     if (a->d) {
353182d0c831SRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
353282d0c831SRichard Henderson     } else {
35331e9ab9fbSRichard Henderson         /* Force shift into [32,63] */
35346fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_sar, 32);
35356fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, tmp);
35361e9ab9fbSRichard Henderson     }
353798cd9ca7SRichard Henderson 
35384c42fd0dSRichard Henderson     cond = cond_make_ti(a->c ? TCG_COND_GE : TCG_COND_LT, tmp, 0);
353901afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
354098cd9ca7SRichard Henderson }
354198cd9ca7SRichard Henderson 
354201afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
354398cd9ca7SRichard Henderson {
35446fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
354501afb7beSRichard Henderson     DisasCond cond;
35461e9ab9fbSRichard Henderson     int p;
354701afb7beSRichard Henderson 
354801afb7beSRichard Henderson     nullify_over(ctx);
354901afb7beSRichard Henderson 
3550aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
355101afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
355282d0c831SRichard Henderson     p = a->p | (a->d ? 0 : 32);
35536fd0c7bcSRichard Henderson     tcg_gen_shli_i64(tmp, tcg_r, p);
355401afb7beSRichard Henderson 
35554c42fd0dSRichard Henderson     cond = cond_make_ti(a->c ? TCG_COND_GE : TCG_COND_LT, tmp, 0);
355601afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
355701afb7beSRichard Henderson }
355801afb7beSRichard Henderson 
355901afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a)
356001afb7beSRichard Henderson {
35616fd0c7bcSRichard Henderson     TCGv_i64 dest;
356298cd9ca7SRichard Henderson     DisasCond cond;
356398cd9ca7SRichard Henderson 
356498cd9ca7SRichard Henderson     nullify_over(ctx);
356598cd9ca7SRichard Henderson 
356601afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r2);
356701afb7beSRichard Henderson     if (a->r1 == 0) {
35686fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, 0);
356998cd9ca7SRichard Henderson     } else {
35706fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
357198cd9ca7SRichard Henderson     }
357298cd9ca7SRichard Henderson 
35734fa52edfSRichard Henderson     /* All MOVB conditions are 32-bit. */
35744fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
357501afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
357601afb7beSRichard Henderson }
357701afb7beSRichard Henderson 
357801afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
357901afb7beSRichard Henderson {
35806fd0c7bcSRichard Henderson     TCGv_i64 dest;
358101afb7beSRichard Henderson     DisasCond cond;
358201afb7beSRichard Henderson 
358301afb7beSRichard Henderson     nullify_over(ctx);
358401afb7beSRichard Henderson 
358501afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r);
35866fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, a->i);
358701afb7beSRichard Henderson 
35884fa52edfSRichard Henderson     /* All MOVBI conditions are 32-bit. */
35894fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
359001afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
359198cd9ca7SRichard Henderson }
359298cd9ca7SRichard Henderson 
3593f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
35940b1347d2SRichard Henderson {
35956fd0c7bcSRichard Henderson     TCGv_i64 dest, src2;
35960b1347d2SRichard Henderson 
3597f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3598f7b775a9SRichard Henderson         return false;
3599f7b775a9SRichard Henderson     }
360030878590SRichard Henderson     if (a->c) {
36010b1347d2SRichard Henderson         nullify_over(ctx);
36020b1347d2SRichard Henderson     }
36030b1347d2SRichard Henderson 
360430878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
3605f7b775a9SRichard Henderson     src2 = load_gpr(ctx, a->r2);
360630878590SRichard Henderson     if (a->r1 == 0) {
3607f7b775a9SRichard Henderson         if (a->d) {
36086fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src2, cpu_sar);
3609f7b775a9SRichard Henderson         } else {
3610aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
3611f7b775a9SRichard Henderson 
36126fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src2);
36136fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
36146fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, dest, tmp);
3615f7b775a9SRichard Henderson         }
361630878590SRichard Henderson     } else if (a->r1 == a->r2) {
3617f7b775a9SRichard Henderson         if (a->d) {
36186fd0c7bcSRichard Henderson             tcg_gen_rotr_i64(dest, src2, cpu_sar);
3619f7b775a9SRichard Henderson         } else {
36200b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
3621e1d635e8SRichard Henderson             TCGv_i32 s32 = tcg_temp_new_i32();
3622e1d635e8SRichard Henderson 
36236fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, src2);
36246fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(s32, cpu_sar);
3625f7b775a9SRichard Henderson             tcg_gen_andi_i32(s32, s32, 31);
3626e1d635e8SRichard Henderson             tcg_gen_rotr_i32(t32, t32, s32);
36276fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
3628f7b775a9SRichard Henderson         }
3629f7b775a9SRichard Henderson     } else {
36306fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
3631f7b775a9SRichard Henderson 
3632f7b775a9SRichard Henderson         if (a->d) {
3633aac0f603SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
3634aac0f603SRichard Henderson             TCGv_i64 n = tcg_temp_new_i64();
3635f7b775a9SRichard Henderson 
36366fd0c7bcSRichard Henderson             tcg_gen_xori_i64(n, cpu_sar, 63);
3637a01491a2SHelge Deller             tcg_gen_shl_i64(t, src1, n);
36386fd0c7bcSRichard Henderson             tcg_gen_shli_i64(t, t, 1);
3639a01491a2SHelge Deller             tcg_gen_shr_i64(dest, src2, cpu_sar);
36406fd0c7bcSRichard Henderson             tcg_gen_or_i64(dest, dest, t);
36410b1347d2SRichard Henderson         } else {
36420b1347d2SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
36430b1347d2SRichard Henderson             TCGv_i64 s = tcg_temp_new_i64();
36440b1347d2SRichard Henderson 
36456fd0c7bcSRichard Henderson             tcg_gen_concat32_i64(t, src2, src1);
3646967662cdSRichard Henderson             tcg_gen_andi_i64(s, cpu_sar, 31);
3647967662cdSRichard Henderson             tcg_gen_shr_i64(dest, t, s);
36480b1347d2SRichard Henderson         }
3649f7b775a9SRichard Henderson     }
365030878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36510b1347d2SRichard Henderson 
36520b1347d2SRichard Henderson     /* Install the new nullification.  */
36530b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
365430878590SRichard Henderson     if (a->c) {
3655d37fad0aSSven Schnelle         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
36560b1347d2SRichard Henderson     }
365731234768SRichard Henderson     return nullify_end(ctx);
36580b1347d2SRichard Henderson }
36590b1347d2SRichard Henderson 
3660f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
36610b1347d2SRichard Henderson {
3662f7b775a9SRichard Henderson     unsigned width, sa;
36636fd0c7bcSRichard Henderson     TCGv_i64 dest, t2;
36640b1347d2SRichard Henderson 
3665f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3666f7b775a9SRichard Henderson         return false;
3667f7b775a9SRichard Henderson     }
366830878590SRichard Henderson     if (a->c) {
36690b1347d2SRichard Henderson         nullify_over(ctx);
36700b1347d2SRichard Henderson     }
36710b1347d2SRichard Henderson 
3672f7b775a9SRichard Henderson     width = a->d ? 64 : 32;
3673f7b775a9SRichard Henderson     sa = width - 1 - a->cpos;
3674f7b775a9SRichard Henderson 
367530878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
367630878590SRichard Henderson     t2 = load_gpr(ctx, a->r2);
367705bfd4dbSRichard Henderson     if (a->r1 == 0) {
36786fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, t2, sa, width - sa);
3679c53e401eSRichard Henderson     } else if (width == TARGET_LONG_BITS) {
36806fd0c7bcSRichard Henderson         tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
3681f7b775a9SRichard Henderson     } else {
3682f7b775a9SRichard Henderson         assert(!a->d);
3683f7b775a9SRichard Henderson         if (a->r1 == a->r2) {
36840b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
36856fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, t2);
36860b1347d2SRichard Henderson             tcg_gen_rotri_i32(t32, t32, sa);
36876fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
36880b1347d2SRichard Henderson         } else {
3689967662cdSRichard Henderson             tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]);
3690967662cdSRichard Henderson             tcg_gen_extract_i64(dest, dest, sa, 32);
36910b1347d2SRichard Henderson         }
3692f7b775a9SRichard Henderson     }
369330878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36940b1347d2SRichard Henderson 
36950b1347d2SRichard Henderson     /* Install the new nullification.  */
36960b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
369730878590SRichard Henderson     if (a->c) {
3698d37fad0aSSven Schnelle         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
36990b1347d2SRichard Henderson     }
370031234768SRichard Henderson     return nullify_end(ctx);
37010b1347d2SRichard Henderson }
37020b1347d2SRichard Henderson 
3703bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
37040b1347d2SRichard Henderson {
3705bd792da3SRichard Henderson     unsigned widthm1 = a->d ? 63 : 31;
37066fd0c7bcSRichard Henderson     TCGv_i64 dest, src, tmp;
37070b1347d2SRichard Henderson 
3708bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3709bd792da3SRichard Henderson         return false;
3710bd792da3SRichard Henderson     }
371130878590SRichard Henderson     if (a->c) {
37120b1347d2SRichard Henderson         nullify_over(ctx);
37130b1347d2SRichard Henderson     }
37140b1347d2SRichard Henderson 
371530878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
371630878590SRichard Henderson     src = load_gpr(ctx, a->r);
3717aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
37180b1347d2SRichard Henderson 
37190b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
37206fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
37216fd0c7bcSRichard Henderson     tcg_gen_xori_i64(tmp, tmp, widthm1);
3722d781cb77SRichard Henderson 
372330878590SRichard Henderson     if (a->se) {
3724bd792da3SRichard Henderson         if (!a->d) {
37256fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(dest, src);
3726bd792da3SRichard Henderson             src = dest;
3727bd792da3SRichard Henderson         }
37286fd0c7bcSRichard Henderson         tcg_gen_sar_i64(dest, src, tmp);
37296fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, dest, 0, a->len);
37300b1347d2SRichard Henderson     } else {
3731bd792da3SRichard Henderson         if (!a->d) {
37326fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src);
3733bd792da3SRichard Henderson             src = dest;
3734bd792da3SRichard Henderson         }
37356fd0c7bcSRichard Henderson         tcg_gen_shr_i64(dest, src, tmp);
37366fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, dest, 0, a->len);
37370b1347d2SRichard Henderson     }
373830878590SRichard Henderson     save_gpr(ctx, a->t, dest);
37390b1347d2SRichard Henderson 
37400b1347d2SRichard Henderson     /* Install the new nullification.  */
37410b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
374230878590SRichard Henderson     if (a->c) {
3743bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
37440b1347d2SRichard Henderson     }
374531234768SRichard Henderson     return nullify_end(ctx);
37460b1347d2SRichard Henderson }
37470b1347d2SRichard Henderson 
3748bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
37490b1347d2SRichard Henderson {
3750bd792da3SRichard Henderson     unsigned len, cpos, width;
37516fd0c7bcSRichard Henderson     TCGv_i64 dest, src;
37520b1347d2SRichard Henderson 
3753bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3754bd792da3SRichard Henderson         return false;
3755bd792da3SRichard Henderson     }
375630878590SRichard Henderson     if (a->c) {
37570b1347d2SRichard Henderson         nullify_over(ctx);
37580b1347d2SRichard Henderson     }
37590b1347d2SRichard Henderson 
3760bd792da3SRichard Henderson     len = a->len;
3761bd792da3SRichard Henderson     width = a->d ? 64 : 32;
3762bd792da3SRichard Henderson     cpos = width - 1 - a->pos;
3763bd792da3SRichard Henderson     if (cpos + len > width) {
3764bd792da3SRichard Henderson         len = width - cpos;
3765bd792da3SRichard Henderson     }
3766bd792da3SRichard Henderson 
376730878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
376830878590SRichard Henderson     src = load_gpr(ctx, a->r);
376930878590SRichard Henderson     if (a->se) {
37706fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, src, cpos, len);
37710b1347d2SRichard Henderson     } else {
37726fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, src, cpos, len);
37730b1347d2SRichard Henderson     }
377430878590SRichard Henderson     save_gpr(ctx, a->t, dest);
37750b1347d2SRichard Henderson 
37760b1347d2SRichard Henderson     /* Install the new nullification.  */
37770b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
377830878590SRichard Henderson     if (a->c) {
3779bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
37800b1347d2SRichard Henderson     }
378131234768SRichard Henderson     return nullify_end(ctx);
37820b1347d2SRichard Henderson }
37830b1347d2SRichard Henderson 
378472ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
37850b1347d2SRichard Henderson {
378672ae4f2bSRichard Henderson     unsigned len, width;
3787c53e401eSRichard Henderson     uint64_t mask0, mask1;
37886fd0c7bcSRichard Henderson     TCGv_i64 dest;
37890b1347d2SRichard Henderson 
379072ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
379172ae4f2bSRichard Henderson         return false;
379272ae4f2bSRichard Henderson     }
379330878590SRichard Henderson     if (a->c) {
37940b1347d2SRichard Henderson         nullify_over(ctx);
37950b1347d2SRichard Henderson     }
379672ae4f2bSRichard Henderson 
379772ae4f2bSRichard Henderson     len = a->len;
379872ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
379972ae4f2bSRichard Henderson     if (a->cpos + len > width) {
380072ae4f2bSRichard Henderson         len = width - a->cpos;
38010b1347d2SRichard Henderson     }
38020b1347d2SRichard Henderson 
380330878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
380430878590SRichard Henderson     mask0 = deposit64(0, a->cpos, len, a->i);
380530878590SRichard Henderson     mask1 = deposit64(-1, a->cpos, len, a->i);
38060b1347d2SRichard Henderson 
380730878590SRichard Henderson     if (a->nz) {
38086fd0c7bcSRichard Henderson         TCGv_i64 src = load_gpr(ctx, a->t);
38096fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, src, mask1);
38106fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, mask0);
38110b1347d2SRichard Henderson     } else {
38126fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, mask0);
38130b1347d2SRichard Henderson     }
381430878590SRichard Henderson     save_gpr(ctx, a->t, dest);
38150b1347d2SRichard Henderson 
38160b1347d2SRichard Henderson     /* Install the new nullification.  */
38170b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
381830878590SRichard Henderson     if (a->c) {
381972ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
38200b1347d2SRichard Henderson     }
382131234768SRichard Henderson     return nullify_end(ctx);
38220b1347d2SRichard Henderson }
38230b1347d2SRichard Henderson 
382472ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
38250b1347d2SRichard Henderson {
382630878590SRichard Henderson     unsigned rs = a->nz ? a->t : 0;
382772ae4f2bSRichard Henderson     unsigned len, width;
38286fd0c7bcSRichard Henderson     TCGv_i64 dest, val;
38290b1347d2SRichard Henderson 
383072ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
383172ae4f2bSRichard Henderson         return false;
383272ae4f2bSRichard Henderson     }
383330878590SRichard Henderson     if (a->c) {
38340b1347d2SRichard Henderson         nullify_over(ctx);
38350b1347d2SRichard Henderson     }
383672ae4f2bSRichard Henderson 
383772ae4f2bSRichard Henderson     len = a->len;
383872ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
383972ae4f2bSRichard Henderson     if (a->cpos + len > width) {
384072ae4f2bSRichard Henderson         len = width - a->cpos;
38410b1347d2SRichard Henderson     }
38420b1347d2SRichard Henderson 
384330878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
384430878590SRichard Henderson     val = load_gpr(ctx, a->r);
38450b1347d2SRichard Henderson     if (rs == 0) {
38466fd0c7bcSRichard Henderson         tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
38470b1347d2SRichard Henderson     } else {
38486fd0c7bcSRichard Henderson         tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
38490b1347d2SRichard Henderson     }
385030878590SRichard Henderson     save_gpr(ctx, a->t, dest);
38510b1347d2SRichard Henderson 
38520b1347d2SRichard Henderson     /* Install the new nullification.  */
38530b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
385430878590SRichard Henderson     if (a->c) {
385572ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
38560b1347d2SRichard Henderson     }
385731234768SRichard Henderson     return nullify_end(ctx);
38580b1347d2SRichard Henderson }
38590b1347d2SRichard Henderson 
386072ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
38616fd0c7bcSRichard Henderson                        bool d, bool nz, unsigned len, TCGv_i64 val)
38620b1347d2SRichard Henderson {
38630b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
386472ae4f2bSRichard Henderson     unsigned widthm1 = d ? 63 : 31;
38656fd0c7bcSRichard Henderson     TCGv_i64 mask, tmp, shift, dest;
3866c53e401eSRichard Henderson     uint64_t msb = 1ULL << (len - 1);
38670b1347d2SRichard Henderson 
38680b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
3869aac0f603SRichard Henderson     shift = tcg_temp_new_i64();
3870aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
38710b1347d2SRichard Henderson 
38720b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
38736fd0c7bcSRichard Henderson     tcg_gen_andi_i64(shift, cpu_sar, widthm1);
38746fd0c7bcSRichard Henderson     tcg_gen_xori_i64(shift, shift, widthm1);
38750b1347d2SRichard Henderson 
3876aac0f603SRichard Henderson     mask = tcg_temp_new_i64();
38776fd0c7bcSRichard Henderson     tcg_gen_movi_i64(mask, msb + (msb - 1));
38786fd0c7bcSRichard Henderson     tcg_gen_and_i64(tmp, val, mask);
38790b1347d2SRichard Henderson     if (rs) {
38806fd0c7bcSRichard Henderson         tcg_gen_shl_i64(mask, mask, shift);
38816fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tmp, shift);
38826fd0c7bcSRichard Henderson         tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
38836fd0c7bcSRichard Henderson         tcg_gen_or_i64(dest, dest, tmp);
38840b1347d2SRichard Henderson     } else {
38856fd0c7bcSRichard Henderson         tcg_gen_shl_i64(dest, tmp, shift);
38860b1347d2SRichard Henderson     }
38870b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
38880b1347d2SRichard Henderson 
38890b1347d2SRichard Henderson     /* Install the new nullification.  */
38900b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
38910b1347d2SRichard Henderson     if (c) {
389272ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, c, d, dest);
38930b1347d2SRichard Henderson     }
389431234768SRichard Henderson     return nullify_end(ctx);
38950b1347d2SRichard Henderson }
38960b1347d2SRichard Henderson 
389772ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
389830878590SRichard Henderson {
389972ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
390072ae4f2bSRichard Henderson         return false;
390172ae4f2bSRichard Henderson     }
3902a6deecceSSven Schnelle     if (a->c) {
3903a6deecceSSven Schnelle         nullify_over(ctx);
3904a6deecceSSven Schnelle     }
390572ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
390672ae4f2bSRichard Henderson                       load_gpr(ctx, a->r));
390730878590SRichard Henderson }
390830878590SRichard Henderson 
390972ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
391030878590SRichard Henderson {
391172ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
391272ae4f2bSRichard Henderson         return false;
391372ae4f2bSRichard Henderson     }
3914a6deecceSSven Schnelle     if (a->c) {
3915a6deecceSSven Schnelle         nullify_over(ctx);
3916a6deecceSSven Schnelle     }
391772ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
39186fd0c7bcSRichard Henderson                       tcg_constant_i64(a->i));
391930878590SRichard Henderson }
39200b1347d2SRichard Henderson 
39218340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a)
392298cd9ca7SRichard Henderson {
3923019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY
3924bc921866SRichard Henderson     ctx->iaq_j.space = tcg_temp_new_i64();
3925bc921866SRichard Henderson     load_spr(ctx, ctx->iaq_j.space, a->sp);
3926c301f34eSRichard Henderson #endif
3927019f4159SRichard Henderson 
3928bc921866SRichard Henderson     ctx->iaq_j.base = tcg_temp_new_i64();
3929bc921866SRichard Henderson     ctx->iaq_j.disp = 0;
3930bc921866SRichard Henderson 
3931bc921866SRichard Henderson     tcg_gen_addi_i64(ctx->iaq_j.base, load_gpr(ctx, a->b), a->disp);
3932bc921866SRichard Henderson     ctx->iaq_j.base = do_ibranch_priv(ctx, ctx->iaq_j.base);
3933bc921866SRichard Henderson 
3934bc921866SRichard Henderson     return do_ibranch(ctx, a->l, true, a->n);
393598cd9ca7SRichard Henderson }
393698cd9ca7SRichard Henderson 
39378340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a)
393898cd9ca7SRichard Henderson {
39392644f80bSRichard Henderson     return do_dbranch(ctx, a->disp, a->l, a->n);
394098cd9ca7SRichard Henderson }
394198cd9ca7SRichard Henderson 
39428340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
394343e05652SRichard Henderson {
3944bc921866SRichard Henderson     int64_t disp = a->disp;
394543e05652SRichard Henderson 
39466e5f5300SSven Schnelle     nullify_over(ctx);
39476e5f5300SSven Schnelle 
394843e05652SRichard Henderson     /* Make sure the caller hasn't done something weird with the queue.
394943e05652SRichard Henderson      * ??? This is not quite the same as the PSW[B] bit, which would be
395043e05652SRichard Henderson      * expensive to track.  Real hardware will trap for
395143e05652SRichard Henderson      *    b  gateway
395243e05652SRichard Henderson      *    b  gateway+4  (in delay slot of first branch)
395343e05652SRichard Henderson      * However, checking for a non-sequential instruction queue *will*
395443e05652SRichard Henderson      * diagnose the security hole
395543e05652SRichard Henderson      *    b  gateway
395643e05652SRichard Henderson      *    b  evil
395743e05652SRichard Henderson      * in which instructions at evil would run with increased privs.
395843e05652SRichard Henderson      */
3959bc921866SRichard Henderson     if (iaqe_variable(&ctx->iaq_b) || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) {
396043e05652SRichard Henderson         return gen_illegal(ctx);
396143e05652SRichard Henderson     }
396243e05652SRichard Henderson 
396343e05652SRichard Henderson #ifndef CONFIG_USER_ONLY
396443e05652SRichard Henderson     if (ctx->tb_flags & PSW_C) {
396594956d7bSPhilippe Mathieu-Daudé         int type = hppa_artype_for_page(cpu_env(ctx->cs), ctx->base.pc_next);
396643e05652SRichard Henderson         /* If we could not find a TLB entry, then we need to generate an
396743e05652SRichard Henderson            ITLB miss exception so the kernel will provide it.
396843e05652SRichard Henderson            The resulting TLB fill operation will invalidate this TB and
396943e05652SRichard Henderson            we will re-translate, at which point we *will* be able to find
397043e05652SRichard Henderson            the TLB entry and determine if this is in fact a gateway page.  */
397143e05652SRichard Henderson         if (type < 0) {
397231234768SRichard Henderson             gen_excp(ctx, EXCP_ITLB_MISS);
397331234768SRichard Henderson             return true;
397443e05652SRichard Henderson         }
397543e05652SRichard Henderson         /* No change for non-gateway pages or for priv decrease.  */
397643e05652SRichard Henderson         if (type >= 4 && type - 4 < ctx->privilege) {
3977bc921866SRichard Henderson             disp -= ctx->privilege;
3978bc921866SRichard Henderson             disp += type - 4;
397943e05652SRichard Henderson         }
398043e05652SRichard Henderson     } else {
3981bc921866SRichard Henderson         disp -= ctx->privilege;  /* priv = 0 */
398243e05652SRichard Henderson     }
398343e05652SRichard Henderson #endif
398443e05652SRichard Henderson 
39856e5f5300SSven Schnelle     if (a->l) {
39866fd0c7bcSRichard Henderson         TCGv_i64 tmp = dest_gpr(ctx, a->l);
39876e5f5300SSven Schnelle         if (ctx->privilege < 3) {
39886fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, tmp, -4);
39896e5f5300SSven Schnelle         }
39906fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
39916e5f5300SSven Schnelle         save_gpr(ctx, a->l, tmp);
39926e5f5300SSven Schnelle     }
39936e5f5300SSven Schnelle 
3994bc921866SRichard Henderson     return do_dbranch(ctx, disp, 0, a->n);
399543e05652SRichard Henderson }
399643e05652SRichard Henderson 
39978340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a)
399898cd9ca7SRichard Henderson {
3999b35aec85SRichard Henderson     if (a->x) {
4000bc921866SRichard Henderson         DisasIAQE next = iaqe_incr(&ctx->iaq_f, 8);
4001bc921866SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
4002bc921866SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
4003bc921866SRichard Henderson 
4004660eefe1SRichard Henderson         /* The computation here never changes privilege level.  */
4005bc921866SRichard Henderson         copy_iaoq_entry(ctx, t0, &next);
4006bc921866SRichard Henderson         tcg_gen_shli_i64(t1, load_gpr(ctx, a->x), 3);
4007bc921866SRichard Henderson         tcg_gen_add_i64(t0, t0, t1);
4008bc921866SRichard Henderson 
4009bc921866SRichard Henderson         ctx->iaq_j = iaqe_next_absv(ctx, t0);
4010bc921866SRichard Henderson         return do_ibranch(ctx, a->l, false, a->n);
4011b35aec85SRichard Henderson     } else {
4012b35aec85SRichard Henderson         /* BLR R0,RX is a good way to load PC+8 into RX.  */
40132644f80bSRichard Henderson         return do_dbranch(ctx, 0, a->l, a->n);
4014b35aec85SRichard Henderson     }
401598cd9ca7SRichard Henderson }
401698cd9ca7SRichard Henderson 
40178340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a)
401898cd9ca7SRichard Henderson {
40196fd0c7bcSRichard Henderson     TCGv_i64 dest;
402098cd9ca7SRichard Henderson 
40218340f534SRichard Henderson     if (a->x == 0) {
40228340f534SRichard Henderson         dest = load_gpr(ctx, a->b);
402398cd9ca7SRichard Henderson     } else {
4024aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
40256fd0c7bcSRichard Henderson         tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
40266fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
402798cd9ca7SRichard Henderson     }
4028660eefe1SRichard Henderson     dest = do_ibranch_priv(ctx, dest);
4029bc921866SRichard Henderson     ctx->iaq_j = iaqe_next_absv(ctx, dest);
4030bc921866SRichard Henderson 
4031bc921866SRichard Henderson     return do_ibranch(ctx, 0, false, a->n);
403298cd9ca7SRichard Henderson }
403398cd9ca7SRichard Henderson 
40348340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a)
403598cd9ca7SRichard Henderson {
4036019f4159SRichard Henderson     TCGv_i64 b = load_gpr(ctx, a->b);
403798cd9ca7SRichard Henderson 
4038019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY
4039bc921866SRichard Henderson     ctx->iaq_j.space = space_select(ctx, 0, b);
4040c301f34eSRichard Henderson #endif
4041bc921866SRichard Henderson     ctx->iaq_j.base = do_ibranch_priv(ctx, b);
4042bc921866SRichard Henderson     ctx->iaq_j.disp = 0;
4043019f4159SRichard Henderson 
4044bc921866SRichard Henderson     return do_ibranch(ctx, a->l, false, a->n);
404598cd9ca7SRichard Henderson }
404698cd9ca7SRichard Henderson 
4047a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
4048a8966ba7SRichard Henderson {
4049a8966ba7SRichard Henderson     /* All branch target stack instructions implement as nop. */
4050a8966ba7SRichard Henderson     return ctx->is_pa20;
4051a8966ba7SRichard Henderson }
4052a8966ba7SRichard Henderson 
40531ca74648SRichard Henderson /*
40541ca74648SRichard Henderson  * Float class 0
40551ca74648SRichard Henderson  */
4056ebe9383cSRichard Henderson 
40571ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4058ebe9383cSRichard Henderson {
4059ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
4060ebe9383cSRichard Henderson }
4061ebe9383cSRichard Henderson 
406259f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
406359f8c04bSHelge Deller {
4064a300dad3SRichard Henderson     uint64_t ret;
4065a300dad3SRichard Henderson 
4066c53e401eSRichard Henderson     if (ctx->is_pa20) {
4067a300dad3SRichard Henderson         ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
4068a300dad3SRichard Henderson     } else {
4069a300dad3SRichard Henderson         ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
4070a300dad3SRichard Henderson     }
4071a300dad3SRichard Henderson 
407259f8c04bSHelge Deller     nullify_over(ctx);
4073a300dad3SRichard Henderson     save_frd(0, tcg_constant_i64(ret));
407459f8c04bSHelge Deller     return nullify_end(ctx);
407559f8c04bSHelge Deller }
407659f8c04bSHelge Deller 
40771ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a)
40781ca74648SRichard Henderson {
40791ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f);
40801ca74648SRichard Henderson }
40811ca74648SRichard Henderson 
4082ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4083ebe9383cSRichard Henderson {
4084ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
4085ebe9383cSRichard Henderson }
4086ebe9383cSRichard Henderson 
40871ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a)
40881ca74648SRichard Henderson {
40891ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d);
40901ca74648SRichard Henderson }
40911ca74648SRichard Henderson 
40921ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4093ebe9383cSRichard Henderson {
4094ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
4095ebe9383cSRichard Henderson }
4096ebe9383cSRichard Henderson 
40971ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a)
40981ca74648SRichard Henderson {
40991ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fabs_f);
41001ca74648SRichard Henderson }
41011ca74648SRichard Henderson 
4102ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4103ebe9383cSRichard Henderson {
4104ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
4105ebe9383cSRichard Henderson }
4106ebe9383cSRichard Henderson 
41071ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a)
41081ca74648SRichard Henderson {
41091ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fabs_d);
41101ca74648SRichard Henderson }
41111ca74648SRichard Henderson 
41121ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a)
41131ca74648SRichard Henderson {
41141ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s);
41151ca74648SRichard Henderson }
41161ca74648SRichard Henderson 
41171ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a)
41181ca74648SRichard Henderson {
41191ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d);
41201ca74648SRichard Henderson }
41211ca74648SRichard Henderson 
41221ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a)
41231ca74648SRichard Henderson {
41241ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s);
41251ca74648SRichard Henderson }
41261ca74648SRichard Henderson 
41271ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a)
41281ca74648SRichard Henderson {
41291ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d);
41301ca74648SRichard Henderson }
41311ca74648SRichard Henderson 
41321ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4133ebe9383cSRichard Henderson {
4134ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
4135ebe9383cSRichard Henderson }
4136ebe9383cSRichard Henderson 
41371ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a)
41381ca74648SRichard Henderson {
41391ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fneg_f);
41401ca74648SRichard Henderson }
41411ca74648SRichard Henderson 
4142ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4143ebe9383cSRichard Henderson {
4144ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
4145ebe9383cSRichard Henderson }
4146ebe9383cSRichard Henderson 
41471ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a)
41481ca74648SRichard Henderson {
41491ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fneg_d);
41501ca74648SRichard Henderson }
41511ca74648SRichard Henderson 
41521ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4153ebe9383cSRichard Henderson {
4154ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
4155ebe9383cSRichard Henderson }
4156ebe9383cSRichard Henderson 
41571ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a)
41581ca74648SRichard Henderson {
41591ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f);
41601ca74648SRichard Henderson }
41611ca74648SRichard Henderson 
4162ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4163ebe9383cSRichard Henderson {
4164ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
4165ebe9383cSRichard Henderson }
4166ebe9383cSRichard Henderson 
41671ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a)
41681ca74648SRichard Henderson {
41691ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d);
41701ca74648SRichard Henderson }
41711ca74648SRichard Henderson 
41721ca74648SRichard Henderson /*
41731ca74648SRichard Henderson  * Float class 1
41741ca74648SRichard Henderson  */
41751ca74648SRichard Henderson 
41761ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a)
41771ca74648SRichard Henderson {
41781ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s);
41791ca74648SRichard Henderson }
41801ca74648SRichard Henderson 
41811ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a)
41821ca74648SRichard Henderson {
41831ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d);
41841ca74648SRichard Henderson }
41851ca74648SRichard Henderson 
41861ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a)
41871ca74648SRichard Henderson {
41881ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s);
41891ca74648SRichard Henderson }
41901ca74648SRichard Henderson 
41911ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a)
41921ca74648SRichard Henderson {
41931ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s);
41941ca74648SRichard Henderson }
41951ca74648SRichard Henderson 
41961ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a)
41971ca74648SRichard Henderson {
41981ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d);
41991ca74648SRichard Henderson }
42001ca74648SRichard Henderson 
42011ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a)
42021ca74648SRichard Henderson {
42031ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d);
42041ca74648SRichard Henderson }
42051ca74648SRichard Henderson 
42061ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a)
42071ca74648SRichard Henderson {
42081ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w);
42091ca74648SRichard Henderson }
42101ca74648SRichard Henderson 
42111ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a)
42121ca74648SRichard Henderson {
42131ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w);
42141ca74648SRichard Henderson }
42151ca74648SRichard Henderson 
42161ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a)
42171ca74648SRichard Henderson {
42181ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw);
42191ca74648SRichard Henderson }
42201ca74648SRichard Henderson 
42211ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a)
42221ca74648SRichard Henderson {
42231ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw);
42241ca74648SRichard Henderson }
42251ca74648SRichard Henderson 
42261ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a)
42271ca74648SRichard Henderson {
42281ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w);
42291ca74648SRichard Henderson }
42301ca74648SRichard Henderson 
42311ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a)
42321ca74648SRichard Henderson {
42331ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w);
42341ca74648SRichard Henderson }
42351ca74648SRichard Henderson 
42361ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a)
42371ca74648SRichard Henderson {
42381ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw);
42391ca74648SRichard Henderson }
42401ca74648SRichard Henderson 
42411ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a)
42421ca74648SRichard Henderson {
42431ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw);
42441ca74648SRichard Henderson }
42451ca74648SRichard Henderson 
42461ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a)
42471ca74648SRichard Henderson {
42481ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s);
42491ca74648SRichard Henderson }
42501ca74648SRichard Henderson 
42511ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a)
42521ca74648SRichard Henderson {
42531ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s);
42541ca74648SRichard Henderson }
42551ca74648SRichard Henderson 
42561ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a)
42571ca74648SRichard Henderson {
42581ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d);
42591ca74648SRichard Henderson }
42601ca74648SRichard Henderson 
42611ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a)
42621ca74648SRichard Henderson {
42631ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d);
42641ca74648SRichard Henderson }
42651ca74648SRichard Henderson 
42661ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a)
42671ca74648SRichard Henderson {
42681ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw);
42691ca74648SRichard Henderson }
42701ca74648SRichard Henderson 
42711ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a)
42721ca74648SRichard Henderson {
42731ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw);
42741ca74648SRichard Henderson }
42751ca74648SRichard Henderson 
42761ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a)
42771ca74648SRichard Henderson {
42781ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw);
42791ca74648SRichard Henderson }
42801ca74648SRichard Henderson 
42811ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a)
42821ca74648SRichard Henderson {
42831ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw);
42841ca74648SRichard Henderson }
42851ca74648SRichard Henderson 
42861ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a)
42871ca74648SRichard Henderson {
42881ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw);
42891ca74648SRichard Henderson }
42901ca74648SRichard Henderson 
42911ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a)
42921ca74648SRichard Henderson {
42931ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw);
42941ca74648SRichard Henderson }
42951ca74648SRichard Henderson 
42961ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a)
42971ca74648SRichard Henderson {
42981ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw);
42991ca74648SRichard Henderson }
43001ca74648SRichard Henderson 
43011ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a)
43021ca74648SRichard Henderson {
43031ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw);
43041ca74648SRichard Henderson }
43051ca74648SRichard Henderson 
43061ca74648SRichard Henderson /*
43071ca74648SRichard Henderson  * Float class 2
43081ca74648SRichard Henderson  */
43091ca74648SRichard Henderson 
43101ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a)
4311ebe9383cSRichard Henderson {
4312ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
4313ebe9383cSRichard Henderson 
4314ebe9383cSRichard Henderson     nullify_over(ctx);
4315ebe9383cSRichard Henderson 
43161ca74648SRichard Henderson     ta = load_frw0_i32(a->r1);
43171ca74648SRichard Henderson     tb = load_frw0_i32(a->r2);
431829dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
431929dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4320ebe9383cSRichard Henderson 
4321ad75a51eSRichard Henderson     gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc);
4322ebe9383cSRichard Henderson 
43231ca74648SRichard Henderson     return nullify_end(ctx);
4324ebe9383cSRichard Henderson }
4325ebe9383cSRichard Henderson 
43261ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
4327ebe9383cSRichard Henderson {
4328ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
4329ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
4330ebe9383cSRichard Henderson 
4331ebe9383cSRichard Henderson     nullify_over(ctx);
4332ebe9383cSRichard Henderson 
43331ca74648SRichard Henderson     ta = load_frd0(a->r1);
43341ca74648SRichard Henderson     tb = load_frd0(a->r2);
433529dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
433629dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4337ebe9383cSRichard Henderson 
4338ad75a51eSRichard Henderson     gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc);
4339ebe9383cSRichard Henderson 
434031234768SRichard Henderson     return nullify_end(ctx);
4341ebe9383cSRichard Henderson }
4342ebe9383cSRichard Henderson 
43431ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
4344ebe9383cSRichard Henderson {
43456fd0c7bcSRichard Henderson     TCGv_i64 t;
4346ebe9383cSRichard Henderson 
4347ebe9383cSRichard Henderson     nullify_over(ctx);
4348ebe9383cSRichard Henderson 
4349aac0f603SRichard Henderson     t = tcg_temp_new_i64();
43506fd0c7bcSRichard Henderson     tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
4351ebe9383cSRichard Henderson 
43521ca74648SRichard Henderson     if (a->y == 1) {
4353ebe9383cSRichard Henderson         int mask;
4354ebe9383cSRichard Henderson         bool inv = false;
4355ebe9383cSRichard Henderson 
43561ca74648SRichard Henderson         switch (a->c) {
4357ebe9383cSRichard Henderson         case 0: /* simple */
43586fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, 0x4000000);
43594c42fd0dSRichard Henderson             ctx->null_cond = cond_make_ti(TCG_COND_NE, t, 0);
4360ebe9383cSRichard Henderson             goto done;
4361ebe9383cSRichard Henderson         case 2: /* rej */
4362ebe9383cSRichard Henderson             inv = true;
4363ebe9383cSRichard Henderson             /* fallthru */
4364ebe9383cSRichard Henderson         case 1: /* acc */
4365ebe9383cSRichard Henderson             mask = 0x43ff800;
4366ebe9383cSRichard Henderson             break;
4367ebe9383cSRichard Henderson         case 6: /* rej8 */
4368ebe9383cSRichard Henderson             inv = true;
4369ebe9383cSRichard Henderson             /* fallthru */
4370ebe9383cSRichard Henderson         case 5: /* acc8 */
4371ebe9383cSRichard Henderson             mask = 0x43f8000;
4372ebe9383cSRichard Henderson             break;
4373ebe9383cSRichard Henderson         case 9: /* acc6 */
4374ebe9383cSRichard Henderson             mask = 0x43e0000;
4375ebe9383cSRichard Henderson             break;
4376ebe9383cSRichard Henderson         case 13: /* acc4 */
4377ebe9383cSRichard Henderson             mask = 0x4380000;
4378ebe9383cSRichard Henderson             break;
4379ebe9383cSRichard Henderson         case 17: /* acc2 */
4380ebe9383cSRichard Henderson             mask = 0x4200000;
4381ebe9383cSRichard Henderson             break;
4382ebe9383cSRichard Henderson         default:
43831ca74648SRichard Henderson             gen_illegal(ctx);
43841ca74648SRichard Henderson             return true;
4385ebe9383cSRichard Henderson         }
4386ebe9383cSRichard Henderson         if (inv) {
43876fd0c7bcSRichard Henderson             TCGv_i64 c = tcg_constant_i64(mask);
43886fd0c7bcSRichard Henderson             tcg_gen_or_i64(t, t, c);
43894c42fd0dSRichard Henderson             ctx->null_cond = cond_make_tt(TCG_COND_EQ, t, c);
4390ebe9383cSRichard Henderson         } else {
43916fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, mask);
43924c42fd0dSRichard Henderson             ctx->null_cond = cond_make_ti(TCG_COND_EQ, t, 0);
4393ebe9383cSRichard Henderson         }
43941ca74648SRichard Henderson     } else {
43951ca74648SRichard Henderson         unsigned cbit = (a->y ^ 1) - 1;
43961ca74648SRichard Henderson 
43976fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, t, 21 - cbit, 1);
43984c42fd0dSRichard Henderson         ctx->null_cond = cond_make_ti(TCG_COND_NE, t, 0);
43991ca74648SRichard Henderson     }
44001ca74648SRichard Henderson 
4401ebe9383cSRichard Henderson  done:
440231234768SRichard Henderson     return nullify_end(ctx);
4403ebe9383cSRichard Henderson }
4404ebe9383cSRichard Henderson 
44051ca74648SRichard Henderson /*
44061ca74648SRichard Henderson  * Float class 2
44071ca74648SRichard Henderson  */
44081ca74648SRichard Henderson 
44091ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a)
4410ebe9383cSRichard Henderson {
44111ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s);
44121ca74648SRichard Henderson }
44131ca74648SRichard Henderson 
44141ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a)
44151ca74648SRichard Henderson {
44161ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d);
44171ca74648SRichard Henderson }
44181ca74648SRichard Henderson 
44191ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a)
44201ca74648SRichard Henderson {
44211ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s);
44221ca74648SRichard Henderson }
44231ca74648SRichard Henderson 
44241ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a)
44251ca74648SRichard Henderson {
44261ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d);
44271ca74648SRichard Henderson }
44281ca74648SRichard Henderson 
44291ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a)
44301ca74648SRichard Henderson {
44311ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s);
44321ca74648SRichard Henderson }
44331ca74648SRichard Henderson 
44341ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a)
44351ca74648SRichard Henderson {
44361ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d);
44371ca74648SRichard Henderson }
44381ca74648SRichard Henderson 
44391ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a)
44401ca74648SRichard Henderson {
44411ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s);
44421ca74648SRichard Henderson }
44431ca74648SRichard Henderson 
44441ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a)
44451ca74648SRichard Henderson {
44461ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d);
44471ca74648SRichard Henderson }
44481ca74648SRichard Henderson 
44491ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a)
44501ca74648SRichard Henderson {
44511ca74648SRichard Henderson     TCGv_i64 x, y;
4452ebe9383cSRichard Henderson 
4453ebe9383cSRichard Henderson     nullify_over(ctx);
4454ebe9383cSRichard Henderson 
44551ca74648SRichard Henderson     x = load_frw0_i64(a->r1);
44561ca74648SRichard Henderson     y = load_frw0_i64(a->r2);
44571ca74648SRichard Henderson     tcg_gen_mul_i64(x, x, y);
44581ca74648SRichard Henderson     save_frd(a->t, x);
4459ebe9383cSRichard Henderson 
446031234768SRichard Henderson     return nullify_end(ctx);
4461ebe9383cSRichard Henderson }
4462ebe9383cSRichard Henderson 
4463ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
4464ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
4465ebe9383cSRichard Henderson {
4466ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
4467ebe9383cSRichard Henderson }
4468ebe9383cSRichard Henderson 
4469b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4470ebe9383cSRichard Henderson {
4471b1e2af57SRichard Henderson     int tm = fmpyadd_s_reg(a->tm);
4472b1e2af57SRichard Henderson     int ra = fmpyadd_s_reg(a->ra);
4473b1e2af57SRichard Henderson     int ta = fmpyadd_s_reg(a->ta);
4474b1e2af57SRichard Henderson     int rm2 = fmpyadd_s_reg(a->rm2);
4475b1e2af57SRichard Henderson     int rm1 = fmpyadd_s_reg(a->rm1);
4476ebe9383cSRichard Henderson 
4477ebe9383cSRichard Henderson     nullify_over(ctx);
4478ebe9383cSRichard Henderson 
4479ebe9383cSRichard Henderson     do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4480ebe9383cSRichard Henderson     do_fop_weww(ctx, ta, ta, ra,
4481ebe9383cSRichard Henderson                 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
4482ebe9383cSRichard Henderson 
448331234768SRichard Henderson     return nullify_end(ctx);
4484ebe9383cSRichard Henderson }
4485ebe9383cSRichard Henderson 
4486b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4487b1e2af57SRichard Henderson {
4488b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, false);
4489b1e2af57SRichard Henderson }
4490b1e2af57SRichard Henderson 
4491b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4492b1e2af57SRichard Henderson {
4493b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, true);
4494b1e2af57SRichard Henderson }
4495b1e2af57SRichard Henderson 
4496b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4497b1e2af57SRichard Henderson {
4498b1e2af57SRichard Henderson     nullify_over(ctx);
4499b1e2af57SRichard Henderson 
4500b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4501b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4502b1e2af57SRichard Henderson                 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4503b1e2af57SRichard Henderson 
4504b1e2af57SRichard Henderson     return nullify_end(ctx);
4505b1e2af57SRichard Henderson }
4506b1e2af57SRichard Henderson 
4507b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4508b1e2af57SRichard Henderson {
4509b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, false);
4510b1e2af57SRichard Henderson }
4511b1e2af57SRichard Henderson 
4512b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4513b1e2af57SRichard Henderson {
4514b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, true);
4515b1e2af57SRichard Henderson }
4516b1e2af57SRichard Henderson 
4517c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a)
4518ebe9383cSRichard Henderson {
4519c3bad4f8SRichard Henderson     TCGv_i32 x, y, z;
4520ebe9383cSRichard Henderson 
4521ebe9383cSRichard Henderson     nullify_over(ctx);
4522c3bad4f8SRichard Henderson     x = load_frw0_i32(a->rm1);
4523c3bad4f8SRichard Henderson     y = load_frw0_i32(a->rm2);
4524c3bad4f8SRichard Henderson     z = load_frw0_i32(a->ra3);
4525ebe9383cSRichard Henderson 
4526c3bad4f8SRichard Henderson     if (a->neg) {
4527ad75a51eSRichard Henderson         gen_helper_fmpynfadd_s(x, tcg_env, x, y, z);
4528ebe9383cSRichard Henderson     } else {
4529ad75a51eSRichard Henderson         gen_helper_fmpyfadd_s(x, tcg_env, x, y, z);
4530ebe9383cSRichard Henderson     }
4531ebe9383cSRichard Henderson 
4532c3bad4f8SRichard Henderson     save_frw_i32(a->t, x);
453331234768SRichard Henderson     return nullify_end(ctx);
4534ebe9383cSRichard Henderson }
4535ebe9383cSRichard Henderson 
4536c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
4537ebe9383cSRichard Henderson {
4538c3bad4f8SRichard Henderson     TCGv_i64 x, y, z;
4539ebe9383cSRichard Henderson 
4540ebe9383cSRichard Henderson     nullify_over(ctx);
4541c3bad4f8SRichard Henderson     x = load_frd0(a->rm1);
4542c3bad4f8SRichard Henderson     y = load_frd0(a->rm2);
4543c3bad4f8SRichard Henderson     z = load_frd0(a->ra3);
4544ebe9383cSRichard Henderson 
4545c3bad4f8SRichard Henderson     if (a->neg) {
4546ad75a51eSRichard Henderson         gen_helper_fmpynfadd_d(x, tcg_env, x, y, z);
4547ebe9383cSRichard Henderson     } else {
4548ad75a51eSRichard Henderson         gen_helper_fmpyfadd_d(x, tcg_env, x, y, z);
4549ebe9383cSRichard Henderson     }
4550ebe9383cSRichard Henderson 
4551c3bad4f8SRichard Henderson     save_frd(a->t, x);
455231234768SRichard Henderson     return nullify_end(ctx);
4553ebe9383cSRichard Henderson }
4554ebe9383cSRichard Henderson 
455538193127SRichard Henderson /* Emulate PDC BTLB, called by SeaBIOS-hppa */
455638193127SRichard Henderson static bool trans_diag_btlb(DisasContext *ctx, arg_diag_btlb *a)
455715da177bSSven Schnelle {
4558cf6b28d4SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4559cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY
4560ad75a51eSRichard Henderson     nullify_over(ctx);
4561ad75a51eSRichard Henderson     gen_helper_diag_btlb(tcg_env);
4562cf6b28d4SHelge Deller     return nullify_end(ctx);
456338193127SRichard Henderson #endif
456415da177bSSven Schnelle }
456538193127SRichard Henderson 
456638193127SRichard Henderson /* Print char in %r26 to first serial console, used by SeaBIOS-hppa */
456738193127SRichard Henderson static bool trans_diag_cout(DisasContext *ctx, arg_diag_cout *a)
456838193127SRichard Henderson {
456938193127SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
457038193127SRichard Henderson #ifndef CONFIG_USER_ONLY
4571dbca0835SHelge Deller     nullify_over(ctx);
4572dbca0835SHelge Deller     gen_helper_diag_console_output(tcg_env);
4573dbca0835SHelge Deller     return nullify_end(ctx);
4574ad75a51eSRichard Henderson #endif
457538193127SRichard Henderson }
457638193127SRichard Henderson 
45773bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa1(DisasContext *ctx, arg_empty *a)
45783bdf2081SHelge Deller {
45793bdf2081SHelge Deller     return !ctx->is_pa20 && do_getshadowregs(ctx);
45803bdf2081SHelge Deller }
45813bdf2081SHelge Deller 
45823bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa2(DisasContext *ctx, arg_empty *a)
45833bdf2081SHelge Deller {
45843bdf2081SHelge Deller     return ctx->is_pa20 && do_getshadowregs(ctx);
45853bdf2081SHelge Deller }
45863bdf2081SHelge Deller 
45873bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa1(DisasContext *ctx, arg_empty *a)
45883bdf2081SHelge Deller {
45893bdf2081SHelge Deller     return !ctx->is_pa20 && do_putshadowregs(ctx);
45903bdf2081SHelge Deller }
45913bdf2081SHelge Deller 
45923bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa2(DisasContext *ctx, arg_empty *a)
45933bdf2081SHelge Deller {
45943bdf2081SHelge Deller     return ctx->is_pa20 && do_putshadowregs(ctx);
45953bdf2081SHelge Deller }
45963bdf2081SHelge Deller 
459738193127SRichard Henderson static bool trans_diag_unimp(DisasContext *ctx, arg_diag_unimp *a)
459838193127SRichard Henderson {
459938193127SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4600ad75a51eSRichard Henderson     qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i);
4601ad75a51eSRichard Henderson     return true;
4602ad75a51eSRichard Henderson }
460315da177bSSven Schnelle 
4604b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
460561766fe9SRichard Henderson {
460651b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4607f764718dSRichard Henderson     int bound;
460861766fe9SRichard Henderson 
460951b061fbSRichard Henderson     ctx->cs = cs;
4610494737b7SRichard Henderson     ctx->tb_flags = ctx->base.tb->flags;
4611bd6243a3SRichard Henderson     ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
46123d68ee7bSRichard Henderson 
46133d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY
4614c01e5dfbSHelge Deller     ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX);
46153d68ee7bSRichard Henderson     ctx->mmu_idx = MMU_USER_IDX;
46160d89cb7cSRichard Henderson     ctx->iaoq_first = ctx->base.pc_first | ctx->privilege;
46170d89cb7cSRichard Henderson     ctx->iaq_b.disp = ctx->base.tb->cs_base - ctx->base.pc_first;
4618217d1a5eSRichard Henderson     ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
4619c301f34eSRichard Henderson #else
4620494737b7SRichard Henderson     ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
4621bb67ec32SRichard Henderson     ctx->mmu_idx = (ctx->tb_flags & PSW_D
4622bb67ec32SRichard Henderson                     ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
4623451d993dSRichard Henderson                     : ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX);
46243d68ee7bSRichard Henderson 
4625c301f34eSRichard Henderson     /* Recover the IAOQ values from the GVA + PRIV.  */
4626c301f34eSRichard Henderson     uint64_t cs_base = ctx->base.tb->cs_base;
4627c301f34eSRichard Henderson     uint64_t iasq_f = cs_base & ~0xffffffffull;
4628c301f34eSRichard Henderson     int32_t diff = cs_base;
4629c301f34eSRichard Henderson 
46300d89cb7cSRichard Henderson     ctx->iaoq_first = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
46310d89cb7cSRichard Henderson 
4632bc921866SRichard Henderson     if (diff) {
46330d89cb7cSRichard Henderson         ctx->iaq_b.disp = diff;
4634bc921866SRichard Henderson     } else {
4635bc921866SRichard Henderson         ctx->iaq_b.base = cpu_iaoq_b;
4636bc921866SRichard Henderson         ctx->iaq_b.space = cpu_iasq_b;
4637bc921866SRichard Henderson     }
4638c301f34eSRichard Henderson #endif
463961766fe9SRichard Henderson 
4640a4db4a78SRichard Henderson     ctx->zero = tcg_constant_i64(0);
4641a4db4a78SRichard Henderson 
46423d68ee7bSRichard Henderson     /* Bound the number of instructions by those left on the page.  */
46433d68ee7bSRichard Henderson     bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
4644b542683dSEmilio G. Cota     ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
464561766fe9SRichard Henderson }
464661766fe9SRichard Henderson 
464751b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
464851b061fbSRichard Henderson {
464951b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
465061766fe9SRichard Henderson 
46513d68ee7bSRichard Henderson     /* Seed the nullification status from PSW[N], as saved in TB->FLAGS.  */
465251b061fbSRichard Henderson     ctx->null_cond = cond_make_f();
465351b061fbSRichard Henderson     ctx->psw_n_nonzero = false;
4654494737b7SRichard Henderson     if (ctx->tb_flags & PSW_N) {
465551b061fbSRichard Henderson         ctx->null_cond.c = TCG_COND_ALWAYS;
465651b061fbSRichard Henderson         ctx->psw_n_nonzero = true;
4657129e9cc3SRichard Henderson     }
465851b061fbSRichard Henderson     ctx->null_lab = NULL;
465961766fe9SRichard Henderson }
466061766fe9SRichard Henderson 
466151b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
466251b061fbSRichard Henderson {
466351b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
466451b061fbSRichard Henderson 
4665bc921866SRichard Henderson     tcg_debug_assert(!iaqe_variable(&ctx->iaq_f));
46660d89cb7cSRichard Henderson     tcg_gen_insn_start(ctx->iaoq_first + ctx->iaq_f.disp,
46670d89cb7cSRichard Henderson                        (iaqe_variable(&ctx->iaq_b) ? -1 :
46680d89cb7cSRichard Henderson                         ctx->iaoq_first + ctx->iaq_b.disp), 0);
466924638bd1SRichard Henderson     ctx->insn_start_updated = false;
467051b061fbSRichard Henderson }
467151b061fbSRichard Henderson 
467251b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
467351b061fbSRichard Henderson {
467451b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4675b77af26eSRichard Henderson     CPUHPPAState *env = cpu_env(cs);
467651b061fbSRichard Henderson     DisasJumpType ret;
467751b061fbSRichard Henderson 
467851b061fbSRichard Henderson     /* Execute one insn.  */
4679ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4680c301f34eSRichard Henderson     if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
468131234768SRichard Henderson         do_page_zero(ctx);
468231234768SRichard Henderson         ret = ctx->base.is_jmp;
4683869051eaSRichard Henderson         assert(ret != DISAS_NEXT);
4684ba1d0b44SRichard Henderson     } else
4685ba1d0b44SRichard Henderson #endif
4686ba1d0b44SRichard Henderson     {
468761766fe9SRichard Henderson         /* Always fetch the insn, even if nullified, so that we check
468861766fe9SRichard Henderson            the page permissions for execute.  */
46894e116893SIlya Leoshkevich         uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next);
469061766fe9SRichard Henderson 
4691bc921866SRichard Henderson         /*
4692bc921866SRichard Henderson          * Set up the IA queue for the next insn.
4693bc921866SRichard Henderson          * This will be overwritten by a branch.
4694bc921866SRichard Henderson          */
4695bc921866SRichard Henderson         ctx->iaq_n = NULL;
4696bc921866SRichard Henderson         memset(&ctx->iaq_j, 0, sizeof(ctx->iaq_j));
469761766fe9SRichard Henderson 
469851b061fbSRichard Henderson         if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
469951b061fbSRichard Henderson             ctx->null_cond.c = TCG_COND_NEVER;
4700869051eaSRichard Henderson             ret = DISAS_NEXT;
4701129e9cc3SRichard Henderson         } else {
47021a19da0dSRichard Henderson             ctx->insn = insn;
470331274b46SRichard Henderson             if (!decode(ctx, insn)) {
470431274b46SRichard Henderson                 gen_illegal(ctx);
470531274b46SRichard Henderson             }
470631234768SRichard Henderson             ret = ctx->base.is_jmp;
470751b061fbSRichard Henderson             assert(ctx->null_lab == NULL);
4708129e9cc3SRichard Henderson         }
470961766fe9SRichard Henderson     }
471061766fe9SRichard Henderson 
4711dbdccbdfSRichard Henderson     /* If the TranslationBlock must end, do so. */
4712dbdccbdfSRichard Henderson     ctx->base.pc_next += 4;
4713dbdccbdfSRichard Henderson     if (ret != DISAS_NEXT) {
4714dbdccbdfSRichard Henderson         return;
471561766fe9SRichard Henderson     }
4716dbdccbdfSRichard Henderson     /* Note this also detects a priority change. */
4717bc921866SRichard Henderson     if (iaqe_variable(&ctx->iaq_b)
4718bc921866SRichard Henderson         || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) {
4719dbdccbdfSRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
4720dbdccbdfSRichard Henderson         return;
4721129e9cc3SRichard Henderson     }
4722dbdccbdfSRichard Henderson 
4723dbdccbdfSRichard Henderson     /*
4724dbdccbdfSRichard Henderson      * Advance the insn queue.
4725dbdccbdfSRichard Henderson      * The only exit now is DISAS_TOO_MANY from the translator loop.
4726dbdccbdfSRichard Henderson      */
4727bc921866SRichard Henderson     ctx->iaq_f.disp = ctx->iaq_b.disp;
4728bc921866SRichard Henderson     if (!ctx->iaq_n) {
4729bc921866SRichard Henderson         ctx->iaq_b.disp += 4;
4730bc921866SRichard Henderson         return;
4731bc921866SRichard Henderson     }
4732bc921866SRichard Henderson     /*
4733bc921866SRichard Henderson      * If IAQ_Next is variable in any way, we need to copy into the
4734bc921866SRichard Henderson      * IAQ_Back globals, in case the next insn raises an exception.
4735bc921866SRichard Henderson      */
4736bc921866SRichard Henderson     if (ctx->iaq_n->base) {
4737bc921866SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaq_n);
4738bc921866SRichard Henderson         ctx->iaq_b.base = cpu_iaoq_b;
4739bc921866SRichard Henderson         ctx->iaq_b.disp = 0;
47400dcd6640SRichard Henderson     } else {
4741bc921866SRichard Henderson         ctx->iaq_b.disp = ctx->iaq_n->disp;
47420dcd6640SRichard Henderson     }
4743bc921866SRichard Henderson     if (ctx->iaq_n->space) {
4744bc921866SRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, ctx->iaq_n->space);
4745bc921866SRichard Henderson         ctx->iaq_b.space = cpu_iasq_b;
4746142faf5fSRichard Henderson     }
474761766fe9SRichard Henderson }
474861766fe9SRichard Henderson 
474951b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
475051b061fbSRichard Henderson {
475151b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4752e1b5a5edSRichard Henderson     DisasJumpType is_jmp = ctx->base.is_jmp;
4753dbdccbdfSRichard Henderson     /* Assume the insn queue has not been advanced. */
4754bc921866SRichard Henderson     DisasIAQE *f = &ctx->iaq_b;
4755bc921866SRichard Henderson     DisasIAQE *b = ctx->iaq_n;
475651b061fbSRichard Henderson 
4757e1b5a5edSRichard Henderson     switch (is_jmp) {
4758869051eaSRichard Henderson     case DISAS_NORETURN:
475961766fe9SRichard Henderson         break;
476051b061fbSRichard Henderson     case DISAS_TOO_MANY:
4761dbdccbdfSRichard Henderson         /* The insn queue has not been advanced. */
4762bc921866SRichard Henderson         f = &ctx->iaq_f;
4763bc921866SRichard Henderson         b = &ctx->iaq_b;
476461766fe9SRichard Henderson         /* FALLTHRU */
4765dbdccbdfSRichard Henderson     case DISAS_IAQ_N_STALE:
4766bc921866SRichard Henderson         if (use_goto_tb(ctx, f, b)
4767dbdccbdfSRichard Henderson             && (ctx->null_cond.c == TCG_COND_NEVER
4768dbdccbdfSRichard Henderson                 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
4769dbdccbdfSRichard Henderson             nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
4770bc921866SRichard Henderson             gen_goto_tb(ctx, 0, f, b);
47718532a14eSRichard Henderson             break;
477261766fe9SRichard Henderson         }
4773c5d0aec2SRichard Henderson         /* FALLTHRU */
4774dbdccbdfSRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
4775bc921866SRichard Henderson         install_iaq_entries(ctx, f, b);
4776dbdccbdfSRichard Henderson         nullify_save(ctx);
4777dbdccbdfSRichard Henderson         if (is_jmp == DISAS_IAQ_N_STALE_EXIT) {
4778dbdccbdfSRichard Henderson             tcg_gen_exit_tb(NULL, 0);
4779dbdccbdfSRichard Henderson             break;
4780dbdccbdfSRichard Henderson         }
4781dbdccbdfSRichard Henderson         /* FALLTHRU */
4782dbdccbdfSRichard Henderson     case DISAS_IAQ_N_UPDATED:
4783dbdccbdfSRichard Henderson         tcg_gen_lookup_and_goto_ptr();
4784dbdccbdfSRichard Henderson         break;
4785c5d0aec2SRichard Henderson     case DISAS_EXIT:
4786c5d0aec2SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
478761766fe9SRichard Henderson         break;
478861766fe9SRichard Henderson     default:
478951b061fbSRichard Henderson         g_assert_not_reached();
479061766fe9SRichard Henderson     }
479151b061fbSRichard Henderson }
479261766fe9SRichard Henderson 
47938eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase,
47948eb806a7SRichard Henderson                               CPUState *cs, FILE *logfile)
479551b061fbSRichard Henderson {
4796c301f34eSRichard Henderson     target_ulong pc = dcbase->pc_first;
479761766fe9SRichard Henderson 
4798ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4799ba1d0b44SRichard Henderson     switch (pc) {
48007ad439dfSRichard Henderson     case 0x00:
48018eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000000:  (null)\n");
4802ba1d0b44SRichard Henderson         return;
48037ad439dfSRichard Henderson     case 0xb0:
48048eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000b0:  light-weight-syscall\n");
4805ba1d0b44SRichard Henderson         return;
48067ad439dfSRichard Henderson     case 0xe0:
48078eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000e0:  set-thread-pointer-syscall\n");
4808ba1d0b44SRichard Henderson         return;
48097ad439dfSRichard Henderson     case 0x100:
48108eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000100:  syscall\n");
4811ba1d0b44SRichard Henderson         return;
48127ad439dfSRichard Henderson     }
4813ba1d0b44SRichard Henderson #endif
4814ba1d0b44SRichard Henderson 
48158eb806a7SRichard Henderson     fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
48168eb806a7SRichard Henderson     target_disas(logfile, cs, pc, dcbase->tb->size);
481761766fe9SRichard Henderson }
481851b061fbSRichard Henderson 
481951b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = {
482051b061fbSRichard Henderson     .init_disas_context = hppa_tr_init_disas_context,
482151b061fbSRichard Henderson     .tb_start           = hppa_tr_tb_start,
482251b061fbSRichard Henderson     .insn_start         = hppa_tr_insn_start,
482351b061fbSRichard Henderson     .translate_insn     = hppa_tr_translate_insn,
482451b061fbSRichard Henderson     .tb_stop            = hppa_tr_tb_stop,
482551b061fbSRichard Henderson     .disas_log          = hppa_tr_disas_log,
482651b061fbSRichard Henderson };
482751b061fbSRichard Henderson 
4828597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
482932f0c394SAnton Johansson                            vaddr pc, void *host_pc)
483051b061fbSRichard Henderson {
4831bc921866SRichard Henderson     DisasContext ctx = { };
4832306c8721SRichard Henderson     translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
483361766fe9SRichard Henderson }
4834