xref: /openbmc/qemu/target/hppa/translate.c (revision aac0f603de963fe6dc8a4b1c83dc43006635f1bc)
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"
25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
2661766fe9SRichard Henderson #include "exec/helper-proto.h"
2761766fe9SRichard Henderson #include "exec/helper-gen.h"
28869051eaSRichard Henderson #include "exec/translator.h"
2961766fe9SRichard Henderson #include "exec/log.h"
3061766fe9SRichard Henderson 
31d53106c9SRichard Henderson #define HELPER_H "helper.h"
32d53106c9SRichard Henderson #include "exec/helper-info.c.inc"
33d53106c9SRichard Henderson #undef  HELPER_H
34d53106c9SRichard Henderson 
35*aac0f603SRichard Henderson /* Choose to use explicit sizes within this file. */
36*aac0f603SRichard Henderson #undef tcg_temp_new
37d53106c9SRichard Henderson 
3861766fe9SRichard Henderson typedef struct DisasCond {
3961766fe9SRichard Henderson     TCGCond c;
406fd0c7bcSRichard Henderson     TCGv_i64 a0, a1;
4161766fe9SRichard Henderson } DisasCond;
4261766fe9SRichard Henderson 
4361766fe9SRichard Henderson typedef struct DisasContext {
44d01a3625SRichard Henderson     DisasContextBase base;
4561766fe9SRichard Henderson     CPUState *cs;
4661766fe9SRichard Henderson 
47c53e401eSRichard Henderson     uint64_t iaoq_f;
48c53e401eSRichard Henderson     uint64_t iaoq_b;
49c53e401eSRichard Henderson     uint64_t iaoq_n;
506fd0c7bcSRichard Henderson     TCGv_i64 iaoq_n_var;
5161766fe9SRichard Henderson 
5261766fe9SRichard Henderson     DisasCond null_cond;
5361766fe9SRichard Henderson     TCGLabel *null_lab;
5461766fe9SRichard Henderson 
551a19da0dSRichard Henderson     uint32_t insn;
56494737b7SRichard Henderson     uint32_t tb_flags;
573d68ee7bSRichard Henderson     int mmu_idx;
583d68ee7bSRichard Henderson     int privilege;
5961766fe9SRichard Henderson     bool psw_n_nonzero;
60bd6243a3SRichard Henderson     bool is_pa20;
61217d1a5eSRichard Henderson 
62217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
63217d1a5eSRichard Henderson     MemOp unalign;
64217d1a5eSRichard Henderson #endif
6561766fe9SRichard Henderson } DisasContext;
6661766fe9SRichard Henderson 
67217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
68217d1a5eSRichard Henderson #define UNALIGN(C)  (C)->unalign
69217d1a5eSRichard Henderson #else
702d4afb03SRichard Henderson #define UNALIGN(C)  MO_ALIGN
71217d1a5eSRichard Henderson #endif
72217d1a5eSRichard Henderson 
73e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently.  */
74451e4ffdSRichard Henderson static int expand_sm_imm(DisasContext *ctx, int val)
75e36f27efSRichard Henderson {
76e36f27efSRichard Henderson     if (val & PSW_SM_E) {
77e36f27efSRichard Henderson         val = (val & ~PSW_SM_E) | PSW_E;
78e36f27efSRichard Henderson     }
79e36f27efSRichard Henderson     if (val & PSW_SM_W) {
80e36f27efSRichard Henderson         val = (val & ~PSW_SM_W) | PSW_W;
81e36f27efSRichard Henderson     }
82e36f27efSRichard Henderson     return val;
83e36f27efSRichard Henderson }
84e36f27efSRichard Henderson 
85deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base.  */
86451e4ffdSRichard Henderson static int expand_sr3x(DisasContext *ctx, int val)
87deee69a1SRichard Henderson {
88deee69a1SRichard Henderson     return ~val;
89deee69a1SRichard Henderson }
90deee69a1SRichard Henderson 
911cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value
921cd012a5SRichard Henderson    we use for the final M.  */
93451e4ffdSRichard Henderson static int ma_to_m(DisasContext *ctx, int val)
941cd012a5SRichard Henderson {
951cd012a5SRichard Henderson     return val & 2 ? (val & 1 ? -1 : 1) : 0;
961cd012a5SRichard Henderson }
971cd012a5SRichard Henderson 
98740038d7SRichard Henderson /* Convert the sign of the displacement to a pre or post-modify.  */
99451e4ffdSRichard Henderson static int pos_to_m(DisasContext *ctx, int val)
100740038d7SRichard Henderson {
101740038d7SRichard Henderson     return val ? 1 : -1;
102740038d7SRichard Henderson }
103740038d7SRichard Henderson 
104451e4ffdSRichard Henderson static int neg_to_m(DisasContext *ctx, int val)
105740038d7SRichard Henderson {
106740038d7SRichard Henderson     return val ? -1 : 1;
107740038d7SRichard Henderson }
108740038d7SRichard Henderson 
109740038d7SRichard Henderson /* Used for branch targets and fp memory ops.  */
110451e4ffdSRichard Henderson static int expand_shl2(DisasContext *ctx, int val)
11101afb7beSRichard Henderson {
11201afb7beSRichard Henderson     return val << 2;
11301afb7beSRichard Henderson }
11401afb7beSRichard Henderson 
115740038d7SRichard Henderson /* Used for fp memory ops.  */
116451e4ffdSRichard Henderson static int expand_shl3(DisasContext *ctx, int val)
117740038d7SRichard Henderson {
118740038d7SRichard Henderson     return val << 3;
119740038d7SRichard Henderson }
120740038d7SRichard Henderson 
1210588e061SRichard Henderson /* Used for assemble_21.  */
122451e4ffdSRichard Henderson static int expand_shl11(DisasContext *ctx, int val)
1230588e061SRichard Henderson {
1240588e061SRichard Henderson     return val << 11;
1250588e061SRichard Henderson }
1260588e061SRichard Henderson 
12772ae4f2bSRichard Henderson static int assemble_6(DisasContext *ctx, int val)
12872ae4f2bSRichard Henderson {
12972ae4f2bSRichard Henderson     /*
13072ae4f2bSRichard Henderson      * Officially, 32 * x + 32 - y.
13172ae4f2bSRichard Henderson      * Here, x is already in bit 5, and y is [4:0].
13272ae4f2bSRichard Henderson      * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1,
13372ae4f2bSRichard Henderson      * with the overflow from bit 4 summing with x.
13472ae4f2bSRichard Henderson      */
13572ae4f2bSRichard Henderson     return (val ^ 31) + 1;
13672ae4f2bSRichard Henderson }
13772ae4f2bSRichard Henderson 
138c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */
139c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val)
140c65c3ee1SRichard Henderson {
141c65c3ee1SRichard Henderson     return val ? val : 4; /* 0 == "*<<" */
142c65c3ee1SRichard Henderson }
143c65c3ee1SRichard Henderson 
14401afb7beSRichard Henderson 
14540f9f908SRichard Henderson /* Include the auto-generated decoder.  */
146abff1abfSPaolo Bonzini #include "decode-insns.c.inc"
14740f9f908SRichard Henderson 
14861766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated
14961766fe9SRichard Henderson    the iaq (for whatever reason), so don't do it again on exit.  */
150869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED  DISAS_TARGET_0
15161766fe9SRichard Henderson 
15261766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor
15361766fe9SRichard Henderson    updated the iaq for the next instruction to be executed.  */
154869051eaSRichard Henderson #define DISAS_IAQ_N_STALE    DISAS_TARGET_1
15561766fe9SRichard Henderson 
156e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately
157e1b5a5edSRichard Henderson    to recognize unmasked interrupts.  */
158e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT      DISAS_TARGET_2
159c5d0aec2SRichard Henderson #define DISAS_EXIT                  DISAS_TARGET_3
160e1b5a5edSRichard Henderson 
16161766fe9SRichard Henderson /* global register indexes */
1626fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32];
16333423472SRichard Henderson static TCGv_i64 cpu_sr[4];
164494737b7SRichard Henderson static TCGv_i64 cpu_srH;
1656fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f;
1666fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b;
167c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f;
168c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b;
1696fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar;
1706fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n;
1716fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v;
1726fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb;
1736fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb;
17461766fe9SRichard Henderson 
17561766fe9SRichard Henderson void hppa_translate_init(void)
17661766fe9SRichard Henderson {
17761766fe9SRichard Henderson #define DEF_VAR(V)  { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
17861766fe9SRichard Henderson 
1796fd0c7bcSRichard Henderson     typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar;
18061766fe9SRichard Henderson     static const GlobalVar vars[] = {
18135136a77SRichard Henderson         { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) },
18261766fe9SRichard Henderson         DEF_VAR(psw_n),
18361766fe9SRichard Henderson         DEF_VAR(psw_v),
18461766fe9SRichard Henderson         DEF_VAR(psw_cb),
18561766fe9SRichard Henderson         DEF_VAR(psw_cb_msb),
18661766fe9SRichard Henderson         DEF_VAR(iaoq_f),
18761766fe9SRichard Henderson         DEF_VAR(iaoq_b),
18861766fe9SRichard Henderson     };
18961766fe9SRichard Henderson 
19061766fe9SRichard Henderson #undef DEF_VAR
19161766fe9SRichard Henderson 
19261766fe9SRichard Henderson     /* Use the symbolic register names that match the disassembler.  */
19361766fe9SRichard Henderson     static const char gr_names[32][4] = {
19461766fe9SRichard Henderson         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
19561766fe9SRichard Henderson         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
19661766fe9SRichard Henderson         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
19761766fe9SRichard Henderson         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
19861766fe9SRichard Henderson     };
19933423472SRichard Henderson     /* SR[4-7] are not global registers so that we can index them.  */
200494737b7SRichard Henderson     static const char sr_names[5][4] = {
201494737b7SRichard Henderson         "sr0", "sr1", "sr2", "sr3", "srH"
20233423472SRichard Henderson     };
20361766fe9SRichard Henderson 
20461766fe9SRichard Henderson     int i;
20561766fe9SRichard Henderson 
206f764718dSRichard Henderson     cpu_gr[0] = NULL;
20761766fe9SRichard Henderson     for (i = 1; i < 32; i++) {
208ad75a51eSRichard Henderson         cpu_gr[i] = tcg_global_mem_new(tcg_env,
20961766fe9SRichard Henderson                                        offsetof(CPUHPPAState, gr[i]),
21061766fe9SRichard Henderson                                        gr_names[i]);
21161766fe9SRichard Henderson     }
21233423472SRichard Henderson     for (i = 0; i < 4; i++) {
213ad75a51eSRichard Henderson         cpu_sr[i] = tcg_global_mem_new_i64(tcg_env,
21433423472SRichard Henderson                                            offsetof(CPUHPPAState, sr[i]),
21533423472SRichard Henderson                                            sr_names[i]);
21633423472SRichard Henderson     }
217ad75a51eSRichard Henderson     cpu_srH = tcg_global_mem_new_i64(tcg_env,
218494737b7SRichard Henderson                                      offsetof(CPUHPPAState, sr[4]),
219494737b7SRichard Henderson                                      sr_names[4]);
22061766fe9SRichard Henderson 
22161766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(vars); ++i) {
22261766fe9SRichard Henderson         const GlobalVar *v = &vars[i];
223ad75a51eSRichard Henderson         *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name);
22461766fe9SRichard Henderson     }
225c301f34eSRichard Henderson 
226ad75a51eSRichard Henderson     cpu_iasq_f = tcg_global_mem_new_i64(tcg_env,
227c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_f),
228c301f34eSRichard Henderson                                         "iasq_f");
229ad75a51eSRichard Henderson     cpu_iasq_b = tcg_global_mem_new_i64(tcg_env,
230c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_b),
231c301f34eSRichard Henderson                                         "iasq_b");
23261766fe9SRichard Henderson }
23361766fe9SRichard Henderson 
234129e9cc3SRichard Henderson static DisasCond cond_make_f(void)
235129e9cc3SRichard Henderson {
236f764718dSRichard Henderson     return (DisasCond){
237f764718dSRichard Henderson         .c = TCG_COND_NEVER,
238f764718dSRichard Henderson         .a0 = NULL,
239f764718dSRichard Henderson         .a1 = NULL,
240f764718dSRichard Henderson     };
241129e9cc3SRichard Henderson }
242129e9cc3SRichard Henderson 
243df0232feSRichard Henderson static DisasCond cond_make_t(void)
244df0232feSRichard Henderson {
245df0232feSRichard Henderson     return (DisasCond){
246df0232feSRichard Henderson         .c = TCG_COND_ALWAYS,
247df0232feSRichard Henderson         .a0 = NULL,
248df0232feSRichard Henderson         .a1 = NULL,
249df0232feSRichard Henderson     };
250df0232feSRichard Henderson }
251df0232feSRichard Henderson 
252129e9cc3SRichard Henderson static DisasCond cond_make_n(void)
253129e9cc3SRichard Henderson {
254f764718dSRichard Henderson     return (DisasCond){
255f764718dSRichard Henderson         .c = TCG_COND_NE,
256f764718dSRichard Henderson         .a0 = cpu_psw_n,
2576fd0c7bcSRichard Henderson         .a1 = tcg_constant_i64(0)
258f764718dSRichard Henderson     };
259129e9cc3SRichard Henderson }
260129e9cc3SRichard Henderson 
2616fd0c7bcSRichard Henderson static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
262b47a4a02SSven Schnelle {
263b47a4a02SSven Schnelle     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
2644fe9533aSRichard Henderson     return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 };
2654fe9533aSRichard Henderson }
2664fe9533aSRichard Henderson 
2676fd0c7bcSRichard Henderson static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0)
2684fe9533aSRichard Henderson {
2696fd0c7bcSRichard Henderson     return cond_make_tmp(c, a0, tcg_constant_i64(0));
270b47a4a02SSven Schnelle }
271b47a4a02SSven Schnelle 
2726fd0c7bcSRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0)
273129e9cc3SRichard Henderson {
274*aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2756fd0c7bcSRichard Henderson     tcg_gen_mov_i64(tmp, a0);
276b47a4a02SSven Schnelle     return cond_make_0_tmp(c, tmp);
277129e9cc3SRichard Henderson }
278129e9cc3SRichard Henderson 
2796fd0c7bcSRichard Henderson static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
280129e9cc3SRichard Henderson {
281*aac0f603SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
282*aac0f603SRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
283129e9cc3SRichard Henderson 
2846fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t0, a0);
2856fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t1, a1);
2864fe9533aSRichard Henderson     return cond_make_tmp(c, t0, t1);
287129e9cc3SRichard Henderson }
288129e9cc3SRichard Henderson 
289129e9cc3SRichard Henderson static void cond_free(DisasCond *cond)
290129e9cc3SRichard Henderson {
291129e9cc3SRichard Henderson     switch (cond->c) {
292129e9cc3SRichard Henderson     default:
293f764718dSRichard Henderson         cond->a0 = NULL;
294f764718dSRichard Henderson         cond->a1 = NULL;
295129e9cc3SRichard Henderson         /* fallthru */
296129e9cc3SRichard Henderson     case TCG_COND_ALWAYS:
297129e9cc3SRichard Henderson         cond->c = TCG_COND_NEVER;
298129e9cc3SRichard Henderson         break;
299129e9cc3SRichard Henderson     case TCG_COND_NEVER:
300129e9cc3SRichard Henderson         break;
301129e9cc3SRichard Henderson     }
302129e9cc3SRichard Henderson }
303129e9cc3SRichard Henderson 
3046fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg)
30561766fe9SRichard Henderson {
30661766fe9SRichard Henderson     if (reg == 0) {
307*aac0f603SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
3086fd0c7bcSRichard Henderson         tcg_gen_movi_i64(t, 0);
30961766fe9SRichard Henderson         return t;
31061766fe9SRichard Henderson     } else {
31161766fe9SRichard Henderson         return cpu_gr[reg];
31261766fe9SRichard Henderson     }
31361766fe9SRichard Henderson }
31461766fe9SRichard Henderson 
3156fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg)
31661766fe9SRichard Henderson {
317129e9cc3SRichard Henderson     if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
318*aac0f603SRichard Henderson         return tcg_temp_new_i64();
31961766fe9SRichard Henderson     } else {
32061766fe9SRichard Henderson         return cpu_gr[reg];
32161766fe9SRichard Henderson     }
32261766fe9SRichard Henderson }
32361766fe9SRichard Henderson 
3246fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t)
325129e9cc3SRichard Henderson {
326129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
3276fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0,
328129e9cc3SRichard Henderson                             ctx->null_cond.a1, dest, t);
329129e9cc3SRichard Henderson     } else {
3306fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, t);
331129e9cc3SRichard Henderson     }
332129e9cc3SRichard Henderson }
333129e9cc3SRichard Henderson 
3346fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t)
335129e9cc3SRichard Henderson {
336129e9cc3SRichard Henderson     if (reg != 0) {
337129e9cc3SRichard Henderson         save_or_nullify(ctx, cpu_gr[reg], t);
338129e9cc3SRichard Henderson     }
339129e9cc3SRichard Henderson }
340129e9cc3SRichard Henderson 
341e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
34296d6407fSRichard Henderson # define HI_OFS  0
34396d6407fSRichard Henderson # define LO_OFS  4
34496d6407fSRichard Henderson #else
34596d6407fSRichard Henderson # define HI_OFS  4
34696d6407fSRichard Henderson # define LO_OFS  0
34796d6407fSRichard Henderson #endif
34896d6407fSRichard Henderson 
34996d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt)
35096d6407fSRichard Henderson {
35196d6407fSRichard Henderson     TCGv_i32 ret = tcg_temp_new_i32();
352ad75a51eSRichard Henderson     tcg_gen_ld_i32(ret, tcg_env,
35396d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
35496d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
35596d6407fSRichard Henderson     return ret;
35696d6407fSRichard Henderson }
35796d6407fSRichard Henderson 
358ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt)
359ebe9383cSRichard Henderson {
360ebe9383cSRichard Henderson     if (rt == 0) {
3610992a930SRichard Henderson         TCGv_i32 ret = tcg_temp_new_i32();
3620992a930SRichard Henderson         tcg_gen_movi_i32(ret, 0);
3630992a930SRichard Henderson         return ret;
364ebe9383cSRichard Henderson     } else {
365ebe9383cSRichard Henderson         return load_frw_i32(rt);
366ebe9383cSRichard Henderson     }
367ebe9383cSRichard Henderson }
368ebe9383cSRichard Henderson 
369ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt)
370ebe9383cSRichard Henderson {
371ebe9383cSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
3720992a930SRichard Henderson     if (rt == 0) {
3730992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
3740992a930SRichard Henderson     } else {
375ad75a51eSRichard Henderson         tcg_gen_ld32u_i64(ret, tcg_env,
376ebe9383cSRichard Henderson                           offsetof(CPUHPPAState, fr[rt & 31])
377ebe9383cSRichard Henderson                           + (rt & 32 ? LO_OFS : HI_OFS));
378ebe9383cSRichard Henderson     }
3790992a930SRichard Henderson     return ret;
380ebe9383cSRichard Henderson }
381ebe9383cSRichard Henderson 
38296d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val)
38396d6407fSRichard Henderson {
384ad75a51eSRichard Henderson     tcg_gen_st_i32(val, tcg_env,
38596d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
38696d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
38796d6407fSRichard Henderson }
38896d6407fSRichard Henderson 
38996d6407fSRichard Henderson #undef HI_OFS
39096d6407fSRichard Henderson #undef LO_OFS
39196d6407fSRichard Henderson 
39296d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt)
39396d6407fSRichard Henderson {
39496d6407fSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
395ad75a51eSRichard Henderson     tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt]));
39696d6407fSRichard Henderson     return ret;
39796d6407fSRichard Henderson }
39896d6407fSRichard Henderson 
399ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt)
400ebe9383cSRichard Henderson {
401ebe9383cSRichard Henderson     if (rt == 0) {
4020992a930SRichard Henderson         TCGv_i64 ret = tcg_temp_new_i64();
4030992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
4040992a930SRichard Henderson         return ret;
405ebe9383cSRichard Henderson     } else {
406ebe9383cSRichard Henderson         return load_frd(rt);
407ebe9383cSRichard Henderson     }
408ebe9383cSRichard Henderson }
409ebe9383cSRichard Henderson 
41096d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val)
41196d6407fSRichard Henderson {
412ad75a51eSRichard Henderson     tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt]));
41396d6407fSRichard Henderson }
41496d6407fSRichard Henderson 
41533423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg)
41633423472SRichard Henderson {
41733423472SRichard Henderson #ifdef CONFIG_USER_ONLY
41833423472SRichard Henderson     tcg_gen_movi_i64(dest, 0);
41933423472SRichard Henderson #else
42033423472SRichard Henderson     if (reg < 4) {
42133423472SRichard Henderson         tcg_gen_mov_i64(dest, cpu_sr[reg]);
422494737b7SRichard Henderson     } else if (ctx->tb_flags & TB_FLAG_SR_SAME) {
423494737b7SRichard Henderson         tcg_gen_mov_i64(dest, cpu_srH);
42433423472SRichard Henderson     } else {
425ad75a51eSRichard Henderson         tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg]));
42633423472SRichard Henderson     }
42733423472SRichard Henderson #endif
42833423472SRichard Henderson }
42933423472SRichard Henderson 
430129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified.
431129e9cc3SRichard Henderson    Use this when the insn is too complex for a conditional move.  */
432129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx)
433129e9cc3SRichard Henderson {
434129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
435129e9cc3SRichard Henderson         /* The always condition should have been handled in the main loop.  */
436129e9cc3SRichard Henderson         assert(ctx->null_cond.c != TCG_COND_ALWAYS);
437129e9cc3SRichard Henderson 
438129e9cc3SRichard Henderson         ctx->null_lab = gen_new_label();
439129e9cc3SRichard Henderson 
440129e9cc3SRichard Henderson         /* If we're using PSW[N], copy it to a temp because... */
4416e94937aSRichard Henderson         if (ctx->null_cond.a0 == cpu_psw_n) {
442*aac0f603SRichard Henderson             ctx->null_cond.a0 = tcg_temp_new_i64();
4436fd0c7bcSRichard Henderson             tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n);
444129e9cc3SRichard Henderson         }
445129e9cc3SRichard Henderson         /* ... we clear it before branching over the implementation,
446129e9cc3SRichard Henderson            so that (1) it's clear after nullifying this insn and
447129e9cc3SRichard Henderson            (2) if this insn nullifies the next, PSW[N] is valid.  */
448129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
449129e9cc3SRichard Henderson             ctx->psw_n_nonzero = false;
4506fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
451129e9cc3SRichard Henderson         }
452129e9cc3SRichard Henderson 
4536fd0c7bcSRichard Henderson         tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0,
454129e9cc3SRichard Henderson                            ctx->null_cond.a1, ctx->null_lab);
455129e9cc3SRichard Henderson         cond_free(&ctx->null_cond);
456129e9cc3SRichard Henderson     }
457129e9cc3SRichard Henderson }
458129e9cc3SRichard Henderson 
459129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N].  */
460129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx)
461129e9cc3SRichard Henderson {
462129e9cc3SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
463129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
4646fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
465129e9cc3SRichard Henderson         }
466129e9cc3SRichard Henderson         return;
467129e9cc3SRichard Henderson     }
4686e94937aSRichard Henderson     if (ctx->null_cond.a0 != cpu_psw_n) {
4696fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n,
470129e9cc3SRichard Henderson                             ctx->null_cond.a0, ctx->null_cond.a1);
471129e9cc3SRichard Henderson         ctx->psw_n_nonzero = true;
472129e9cc3SRichard Henderson     }
473129e9cc3SRichard Henderson     cond_free(&ctx->null_cond);
474129e9cc3SRichard Henderson }
475129e9cc3SRichard Henderson 
476129e9cc3SRichard Henderson /* Set a PSW[N] to X.  The intention is that this is used immediately
477129e9cc3SRichard Henderson    before a goto_tb/exit_tb, so that there is no fallthru path to other
478129e9cc3SRichard Henderson    code within the TB.  Therefore we do not update psw_n_nonzero.  */
479129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x)
480129e9cc3SRichard Henderson {
481129e9cc3SRichard Henderson     if (ctx->psw_n_nonzero || x) {
4826fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, x);
483129e9cc3SRichard Henderson     }
484129e9cc3SRichard Henderson }
485129e9cc3SRichard Henderson 
486129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified.
48740f9f908SRichard Henderson    This is the pair to nullify_over.  Always returns true so that
48840f9f908SRichard Henderson    it may be tail-called from a translate function.  */
48931234768SRichard Henderson static bool nullify_end(DisasContext *ctx)
490129e9cc3SRichard Henderson {
491129e9cc3SRichard Henderson     TCGLabel *null_lab = ctx->null_lab;
49231234768SRichard Henderson     DisasJumpType status = ctx->base.is_jmp;
493129e9cc3SRichard Henderson 
494f49b3537SRichard Henderson     /* For NEXT, NORETURN, STALE, we can easily continue (or exit).
495f49b3537SRichard Henderson        For UPDATED, we cannot update on the nullified path.  */
496f49b3537SRichard Henderson     assert(status != DISAS_IAQ_N_UPDATED);
497f49b3537SRichard Henderson 
498129e9cc3SRichard Henderson     if (likely(null_lab == NULL)) {
499129e9cc3SRichard Henderson         /* The current insn wasn't conditional or handled the condition
500129e9cc3SRichard Henderson            applied to it without a branch, so the (new) setting of
501129e9cc3SRichard Henderson            NULL_COND can be applied directly to the next insn.  */
50231234768SRichard Henderson         return true;
503129e9cc3SRichard Henderson     }
504129e9cc3SRichard Henderson     ctx->null_lab = NULL;
505129e9cc3SRichard Henderson 
506129e9cc3SRichard Henderson     if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
507129e9cc3SRichard Henderson         /* The next instruction will be unconditional,
508129e9cc3SRichard Henderson            and NULL_COND already reflects that.  */
509129e9cc3SRichard Henderson         gen_set_label(null_lab);
510129e9cc3SRichard Henderson     } else {
511129e9cc3SRichard Henderson         /* The insn that we just executed is itself nullifying the next
512129e9cc3SRichard Henderson            instruction.  Store the condition in the PSW[N] global.
513129e9cc3SRichard Henderson            We asserted PSW[N] = 0 in nullify_over, so that after the
514129e9cc3SRichard Henderson            label we have the proper value in place.  */
515129e9cc3SRichard Henderson         nullify_save(ctx);
516129e9cc3SRichard Henderson         gen_set_label(null_lab);
517129e9cc3SRichard Henderson         ctx->null_cond = cond_make_n();
518129e9cc3SRichard Henderson     }
519869051eaSRichard Henderson     if (status == DISAS_NORETURN) {
52031234768SRichard Henderson         ctx->base.is_jmp = DISAS_NEXT;
521129e9cc3SRichard Henderson     }
52231234768SRichard Henderson     return true;
523129e9cc3SRichard Henderson }
524129e9cc3SRichard Henderson 
525c53e401eSRichard Henderson static uint64_t gva_offset_mask(DisasContext *ctx)
526698240d1SRichard Henderson {
527698240d1SRichard Henderson     return (ctx->tb_flags & PSW_W
528698240d1SRichard Henderson             ? MAKE_64BIT_MASK(0, 62)
529698240d1SRichard Henderson             : MAKE_64BIT_MASK(0, 32));
530698240d1SRichard Henderson }
531698240d1SRichard Henderson 
5326fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest,
5336fd0c7bcSRichard Henderson                             uint64_t ival, TCGv_i64 vval)
53461766fe9SRichard Henderson {
535c53e401eSRichard Henderson     uint64_t mask = gva_offset_mask(ctx);
536f13bf343SRichard Henderson 
537f13bf343SRichard Henderson     if (ival != -1) {
5386fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, ival & mask);
539f13bf343SRichard Henderson         return;
540f13bf343SRichard Henderson     }
541f13bf343SRichard Henderson     tcg_debug_assert(vval != NULL);
542f13bf343SRichard Henderson 
543f13bf343SRichard Henderson     /*
544f13bf343SRichard Henderson      * We know that the IAOQ is already properly masked.
545f13bf343SRichard Henderson      * This optimization is primarily for "iaoq_f = iaoq_b".
546f13bf343SRichard Henderson      */
547f13bf343SRichard Henderson     if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) {
5486fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, vval);
54961766fe9SRichard Henderson     } else {
5506fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, vval, mask);
55161766fe9SRichard Henderson     }
55261766fe9SRichard Henderson }
55361766fe9SRichard Henderson 
554c53e401eSRichard Henderson static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp)
55561766fe9SRichard Henderson {
55661766fe9SRichard Henderson     return ctx->iaoq_f + disp + 8;
55761766fe9SRichard Henderson }
55861766fe9SRichard Henderson 
55961766fe9SRichard Henderson static void gen_excp_1(int exception)
56061766fe9SRichard Henderson {
561ad75a51eSRichard Henderson     gen_helper_excp(tcg_env, tcg_constant_i32(exception));
56261766fe9SRichard Henderson }
56361766fe9SRichard Henderson 
56431234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception)
56561766fe9SRichard Henderson {
566741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
567741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
568129e9cc3SRichard Henderson     nullify_save(ctx);
56961766fe9SRichard Henderson     gen_excp_1(exception);
57031234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
57161766fe9SRichard Henderson }
57261766fe9SRichard Henderson 
57331234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc)
5741a19da0dSRichard Henderson {
57531234768SRichard Henderson     nullify_over(ctx);
5766fd0c7bcSRichard Henderson     tcg_gen_st_i64(tcg_constant_i64(ctx->insn),
577ad75a51eSRichard Henderson                    tcg_env, offsetof(CPUHPPAState, cr[CR_IIR]));
57831234768SRichard Henderson     gen_excp(ctx, exc);
57931234768SRichard Henderson     return nullify_end(ctx);
5801a19da0dSRichard Henderson }
5811a19da0dSRichard Henderson 
58231234768SRichard Henderson static bool gen_illegal(DisasContext *ctx)
58361766fe9SRichard Henderson {
58431234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_ILL);
58561766fe9SRichard Henderson }
58661766fe9SRichard Henderson 
58740f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY
58840f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
58940f9f908SRichard Henderson     return gen_excp_iir(ctx, EXCP)
59040f9f908SRichard Henderson #else
591e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
592e1b5a5edSRichard Henderson     do {                                     \
593e1b5a5edSRichard Henderson         if (ctx->privilege != 0) {           \
59431234768SRichard Henderson             return gen_excp_iir(ctx, EXCP);  \
595e1b5a5edSRichard Henderson         }                                    \
596e1b5a5edSRichard Henderson     } while (0)
59740f9f908SRichard Henderson #endif
598e1b5a5edSRichard Henderson 
599c53e401eSRichard Henderson static bool use_goto_tb(DisasContext *ctx, uint64_t dest)
60061766fe9SRichard Henderson {
60157f91498SRichard Henderson     return translator_use_goto_tb(&ctx->base, dest);
60261766fe9SRichard Henderson }
60361766fe9SRichard Henderson 
604129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page,
605129e9cc3SRichard Henderson    and we're not attempting to set a breakpoint on it, then we can
606129e9cc3SRichard Henderson    totally skip the nullified insn.  This avoids creating and
607129e9cc3SRichard Henderson    executing a TB that merely branches to the next TB.  */
608129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx)
609129e9cc3SRichard Henderson {
610129e9cc3SRichard Henderson     return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
611129e9cc3SRichard Henderson             && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
612129e9cc3SRichard Henderson }
613129e9cc3SRichard Henderson 
61461766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which,
615c53e401eSRichard Henderson                         uint64_t f, uint64_t b)
61661766fe9SRichard Henderson {
61761766fe9SRichard Henderson     if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
61861766fe9SRichard Henderson         tcg_gen_goto_tb(which);
619a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, f, NULL);
620a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, b, NULL);
62107ea28b4SRichard Henderson         tcg_gen_exit_tb(ctx->base.tb, which);
62261766fe9SRichard Henderson     } else {
623741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, f, cpu_iaoq_b);
624741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, b, ctx->iaoq_n_var);
6257f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
62661766fe9SRichard Henderson     }
62761766fe9SRichard Henderson }
62861766fe9SRichard Henderson 
629b47a4a02SSven Schnelle static bool cond_need_sv(int c)
630b47a4a02SSven Schnelle {
631b47a4a02SSven Schnelle     return c == 2 || c == 3 || c == 6;
632b47a4a02SSven Schnelle }
633b47a4a02SSven Schnelle 
634b47a4a02SSven Schnelle static bool cond_need_cb(int c)
635b47a4a02SSven Schnelle {
636b47a4a02SSven Schnelle     return c == 4 || c == 5;
637b47a4a02SSven Schnelle }
638b47a4a02SSven Schnelle 
6396fd0c7bcSRichard Henderson /* Need extensions from TCGv_i32 to TCGv_i64. */
64072ca8753SRichard Henderson static bool cond_need_ext(DisasContext *ctx, bool d)
64172ca8753SRichard Henderson {
642c53e401eSRichard Henderson     return !(ctx->is_pa20 && d);
64372ca8753SRichard Henderson }
64472ca8753SRichard Henderson 
645b47a4a02SSven Schnelle /*
646b47a4a02SSven Schnelle  * Compute conditional for arithmetic.  See Page 5-3, Table 5-1, of
647b47a4a02SSven Schnelle  * the Parisc 1.1 Architecture Reference Manual for details.
648b47a4a02SSven Schnelle  */
649b2167459SRichard Henderson 
650a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d,
6516fd0c7bcSRichard Henderson                          TCGv_i64 res, TCGv_i64 cb_msb, TCGv_i64 sv)
652b2167459SRichard Henderson {
653b2167459SRichard Henderson     DisasCond cond;
6546fd0c7bcSRichard Henderson     TCGv_i64 tmp;
655b2167459SRichard Henderson 
656b2167459SRichard Henderson     switch (cf >> 1) {
657b47a4a02SSven Schnelle     case 0: /* Never / TR    (0 / 1) */
658b2167459SRichard Henderson         cond = cond_make_f();
659b2167459SRichard Henderson         break;
660b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
661a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
662*aac0f603SRichard Henderson             tmp = tcg_temp_new_i64();
6636fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
664a751eb31SRichard Henderson             res = tmp;
665a751eb31SRichard Henderson         }
666b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, res);
667b2167459SRichard Henderson         break;
668b47a4a02SSven Schnelle     case 2: /* < / >=        (N ^ V / !(N ^ V) */
669*aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
6706fd0c7bcSRichard Henderson         tcg_gen_xor_i64(tmp, res, sv);
671a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
6726fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, tmp);
673a751eb31SRichard Henderson         }
674b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_LT, tmp);
675b2167459SRichard Henderson         break;
676b47a4a02SSven Schnelle     case 3: /* <= / >        (N ^ V) | Z / !((N ^ V) | Z) */
677b47a4a02SSven Schnelle         /*
678b47a4a02SSven Schnelle          * Simplify:
679b47a4a02SSven Schnelle          *   (N ^ V) | Z
680b47a4a02SSven Schnelle          *   ((res < 0) ^ (sv < 0)) | !res
681b47a4a02SSven Schnelle          *   ((res ^ sv) < 0) | !res
682b47a4a02SSven Schnelle          *   (~(res ^ sv) >= 0) | !res
683b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31) | !res
684b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31 & res)
685b47a4a02SSven Schnelle          */
686*aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
6876fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(tmp, res, sv);
688a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
6896fd0c7bcSRichard Henderson             tcg_gen_sextract_i64(tmp, tmp, 31, 1);
6906fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
6916fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
692a751eb31SRichard Henderson         } else {
6936fd0c7bcSRichard Henderson             tcg_gen_sari_i64(tmp, tmp, 63);
6946fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
695a751eb31SRichard Henderson         }
696b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
697b2167459SRichard Henderson         break;
698b2167459SRichard Henderson     case 4: /* NUV / UV      (!C / C) */
699a751eb31SRichard Henderson         /* Only bit 0 of cb_msb is ever set. */
700b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, cb_msb);
701b2167459SRichard Henderson         break;
702b2167459SRichard Henderson     case 5: /* ZNV / VNZ     (!C | Z / C & !Z) */
703*aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
7046fd0c7bcSRichard Henderson         tcg_gen_neg_i64(tmp, cb_msb);
7056fd0c7bcSRichard Henderson         tcg_gen_and_i64(tmp, tmp, res);
706a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
7076fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
708a751eb31SRichard Henderson         }
709b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
710b2167459SRichard Henderson         break;
711b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
712a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
713*aac0f603SRichard Henderson             tmp = tcg_temp_new_i64();
7146fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, sv);
715a751eb31SRichard Henderson             sv = tmp;
716a751eb31SRichard Henderson         }
717b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, sv);
718b2167459SRichard Henderson         break;
719b2167459SRichard Henderson     case 7: /* OD / EV */
720*aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
7216fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, res, 1);
722b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_NE, tmp);
723b2167459SRichard Henderson         break;
724b2167459SRichard Henderson     default:
725b2167459SRichard Henderson         g_assert_not_reached();
726b2167459SRichard Henderson     }
727b2167459SRichard Henderson     if (cf & 1) {
728b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
729b2167459SRichard Henderson     }
730b2167459SRichard Henderson 
731b2167459SRichard Henderson     return cond;
732b2167459SRichard Henderson }
733b2167459SRichard Henderson 
734b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
735b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
736b2167459SRichard Henderson    deleted as unused.  */
737b2167459SRichard Henderson 
7384fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d,
7396fd0c7bcSRichard Henderson                              TCGv_i64 res, TCGv_i64 in1,
7406fd0c7bcSRichard Henderson                              TCGv_i64 in2, TCGv_i64 sv)
741b2167459SRichard Henderson {
7424fe9533aSRichard Henderson     TCGCond tc;
7434fe9533aSRichard Henderson     bool ext_uns;
744b2167459SRichard Henderson 
745b2167459SRichard Henderson     switch (cf >> 1) {
746b2167459SRichard Henderson     case 1: /* = / <> */
7474fe9533aSRichard Henderson         tc = TCG_COND_EQ;
7484fe9533aSRichard Henderson         ext_uns = true;
749b2167459SRichard Henderson         break;
750b2167459SRichard Henderson     case 2: /* < / >= */
7514fe9533aSRichard Henderson         tc = TCG_COND_LT;
7524fe9533aSRichard Henderson         ext_uns = false;
753b2167459SRichard Henderson         break;
754b2167459SRichard Henderson     case 3: /* <= / > */
7554fe9533aSRichard Henderson         tc = TCG_COND_LE;
7564fe9533aSRichard Henderson         ext_uns = false;
757b2167459SRichard Henderson         break;
758b2167459SRichard Henderson     case 4: /* << / >>= */
7594fe9533aSRichard Henderson         tc = TCG_COND_LTU;
7604fe9533aSRichard Henderson         ext_uns = true;
761b2167459SRichard Henderson         break;
762b2167459SRichard Henderson     case 5: /* <<= / >> */
7634fe9533aSRichard Henderson         tc = TCG_COND_LEU;
7644fe9533aSRichard Henderson         ext_uns = true;
765b2167459SRichard Henderson         break;
766b2167459SRichard Henderson     default:
767a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, sv);
768b2167459SRichard Henderson     }
769b2167459SRichard Henderson 
7704fe9533aSRichard Henderson     if (cf & 1) {
7714fe9533aSRichard Henderson         tc = tcg_invert_cond(tc);
7724fe9533aSRichard Henderson     }
7734fe9533aSRichard Henderson     if (cond_need_ext(ctx, d)) {
774*aac0f603SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
775*aac0f603SRichard Henderson         TCGv_i64 t2 = tcg_temp_new_i64();
7764fe9533aSRichard Henderson 
7774fe9533aSRichard Henderson         if (ext_uns) {
7786fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t1, in1);
7796fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t2, in2);
7804fe9533aSRichard Henderson         } else {
7816fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t1, in1);
7826fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t2, in2);
7834fe9533aSRichard Henderson         }
7844fe9533aSRichard Henderson         return cond_make_tmp(tc, t1, t2);
7854fe9533aSRichard Henderson     }
7864fe9533aSRichard Henderson     return cond_make(tc, in1, in2);
787b2167459SRichard Henderson }
788b2167459SRichard Henderson 
789df0232feSRichard Henderson /*
790df0232feSRichard Henderson  * Similar, but for logicals, where the carry and overflow bits are not
791df0232feSRichard Henderson  * computed, and use of them is undefined.
792df0232feSRichard Henderson  *
793df0232feSRichard Henderson  * Undefined or not, hardware does not trap.  It seems reasonable to
794df0232feSRichard Henderson  * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's
795df0232feSRichard Henderson  * how cases c={2,3} are treated.
796df0232feSRichard Henderson  */
797b2167459SRichard Henderson 
798b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d,
7996fd0c7bcSRichard Henderson                              TCGv_i64 res)
800b2167459SRichard Henderson {
801b5af8423SRichard Henderson     TCGCond tc;
802b5af8423SRichard Henderson     bool ext_uns;
803a751eb31SRichard Henderson 
804df0232feSRichard Henderson     switch (cf) {
805df0232feSRichard Henderson     case 0:  /* never */
806df0232feSRichard Henderson     case 9:  /* undef, C */
807df0232feSRichard Henderson     case 11: /* undef, C & !Z */
808df0232feSRichard Henderson     case 12: /* undef, V */
809df0232feSRichard Henderson         return cond_make_f();
810df0232feSRichard Henderson 
811df0232feSRichard Henderson     case 1:  /* true */
812df0232feSRichard Henderson     case 8:  /* undef, !C */
813df0232feSRichard Henderson     case 10: /* undef, !C | Z */
814df0232feSRichard Henderson     case 13: /* undef, !V */
815df0232feSRichard Henderson         return cond_make_t();
816df0232feSRichard Henderson 
817df0232feSRichard Henderson     case 2:  /* == */
818b5af8423SRichard Henderson         tc = TCG_COND_EQ;
819b5af8423SRichard Henderson         ext_uns = true;
820b5af8423SRichard Henderson         break;
821df0232feSRichard Henderson     case 3:  /* <> */
822b5af8423SRichard Henderson         tc = TCG_COND_NE;
823b5af8423SRichard Henderson         ext_uns = true;
824b5af8423SRichard Henderson         break;
825df0232feSRichard Henderson     case 4:  /* < */
826b5af8423SRichard Henderson         tc = TCG_COND_LT;
827b5af8423SRichard Henderson         ext_uns = false;
828b5af8423SRichard Henderson         break;
829df0232feSRichard Henderson     case 5:  /* >= */
830b5af8423SRichard Henderson         tc = TCG_COND_GE;
831b5af8423SRichard Henderson         ext_uns = false;
832b5af8423SRichard Henderson         break;
833df0232feSRichard Henderson     case 6:  /* <= */
834b5af8423SRichard Henderson         tc = TCG_COND_LE;
835b5af8423SRichard Henderson         ext_uns = false;
836b5af8423SRichard Henderson         break;
837df0232feSRichard Henderson     case 7:  /* > */
838b5af8423SRichard Henderson         tc = TCG_COND_GT;
839b5af8423SRichard Henderson         ext_uns = false;
840b5af8423SRichard Henderson         break;
841df0232feSRichard Henderson 
842df0232feSRichard Henderson     case 14: /* OD */
843df0232feSRichard Henderson     case 15: /* EV */
844a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, NULL);
845df0232feSRichard Henderson 
846df0232feSRichard Henderson     default:
847df0232feSRichard Henderson         g_assert_not_reached();
848b2167459SRichard Henderson     }
849b5af8423SRichard Henderson 
850b5af8423SRichard Henderson     if (cond_need_ext(ctx, d)) {
851*aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
852b5af8423SRichard Henderson 
853b5af8423SRichard Henderson         if (ext_uns) {
8546fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
855b5af8423SRichard Henderson         } else {
8566fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, res);
857b5af8423SRichard Henderson         }
858b5af8423SRichard Henderson         return cond_make_0_tmp(tc, tmp);
859b5af8423SRichard Henderson     }
860b5af8423SRichard Henderson     return cond_make_0(tc, res);
861b2167459SRichard Henderson }
862b2167459SRichard Henderson 
86398cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
86498cd9ca7SRichard Henderson 
8654fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d,
8666fd0c7bcSRichard Henderson                              TCGv_i64 res)
86798cd9ca7SRichard Henderson {
86898cd9ca7SRichard Henderson     unsigned c, f;
86998cd9ca7SRichard Henderson 
87098cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
87198cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
87298cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
87398cd9ca7SRichard Henderson     c = orig & 3;
87498cd9ca7SRichard Henderson     if (c == 3) {
87598cd9ca7SRichard Henderson         c = 7;
87698cd9ca7SRichard Henderson     }
87798cd9ca7SRichard Henderson     f = (orig & 4) / 4;
87898cd9ca7SRichard Henderson 
879b5af8423SRichard Henderson     return do_log_cond(ctx, c * 2 + f, d, res);
88098cd9ca7SRichard Henderson }
88198cd9ca7SRichard Henderson 
882b2167459SRichard Henderson /* Similar, but for unit conditions.  */
883b2167459SRichard Henderson 
8846fd0c7bcSRichard Henderson static DisasCond do_unit_cond(unsigned cf, bool d, TCGv_i64 res,
8856fd0c7bcSRichard Henderson                               TCGv_i64 in1, TCGv_i64 in2)
886b2167459SRichard Henderson {
887b2167459SRichard Henderson     DisasCond cond;
8886fd0c7bcSRichard Henderson     TCGv_i64 tmp, cb = NULL;
889c53e401eSRichard Henderson     uint64_t d_repl = d ? 0x0000000100000001ull : 1;
890b2167459SRichard Henderson 
891b2167459SRichard Henderson     if (cf & 8) {
892b2167459SRichard Henderson         /* Since we want to test lots of carry-out bits all at once, do not
893b2167459SRichard Henderson          * do our normal thing and compute carry-in of bit B+1 since that
894b2167459SRichard Henderson          * leaves us with carry bits spread across two words.
895b2167459SRichard Henderson          */
896*aac0f603SRichard Henderson         cb = tcg_temp_new_i64();
897*aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
8986fd0c7bcSRichard Henderson         tcg_gen_or_i64(cb, in1, in2);
8996fd0c7bcSRichard Henderson         tcg_gen_and_i64(tmp, in1, in2);
9006fd0c7bcSRichard Henderson         tcg_gen_andc_i64(cb, cb, res);
9016fd0c7bcSRichard Henderson         tcg_gen_or_i64(cb, cb, tmp);
902b2167459SRichard Henderson     }
903b2167459SRichard Henderson 
904b2167459SRichard Henderson     switch (cf >> 1) {
905b2167459SRichard Henderson     case 0: /* never / TR */
906b2167459SRichard Henderson     case 1: /* undefined */
907b2167459SRichard Henderson     case 5: /* undefined */
908b2167459SRichard Henderson         cond = cond_make_f();
909b2167459SRichard Henderson         break;
910b2167459SRichard Henderson 
911b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
912b2167459SRichard Henderson         /* See hasless(v,1) from
913b2167459SRichard Henderson          * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
914b2167459SRichard Henderson          */
915*aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
9166fd0c7bcSRichard Henderson         tcg_gen_subi_i64(tmp, res, d_repl * 0x01010101u);
9176fd0c7bcSRichard Henderson         tcg_gen_andc_i64(tmp, tmp, res);
9186fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80808080u);
919b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
920b2167459SRichard Henderson         break;
921b2167459SRichard Henderson 
922b2167459SRichard Henderson     case 3: /* SHZ / NHZ */
923*aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
9246fd0c7bcSRichard Henderson         tcg_gen_subi_i64(tmp, res, d_repl * 0x00010001u);
9256fd0c7bcSRichard Henderson         tcg_gen_andc_i64(tmp, tmp, res);
9266fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80008000u);
927b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
928b2167459SRichard Henderson         break;
929b2167459SRichard Henderson 
930b2167459SRichard Henderson     case 4: /* SDC / NDC */
9316fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x88888888u);
932b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
933b2167459SRichard Henderson         break;
934b2167459SRichard Henderson 
935b2167459SRichard Henderson     case 6: /* SBC / NBC */
9366fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x80808080u);
937b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
938b2167459SRichard Henderson         break;
939b2167459SRichard Henderson 
940b2167459SRichard Henderson     case 7: /* SHC / NHC */
9416fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x80008000u);
942b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
943b2167459SRichard Henderson         break;
944b2167459SRichard Henderson 
945b2167459SRichard Henderson     default:
946b2167459SRichard Henderson         g_assert_not_reached();
947b2167459SRichard Henderson     }
948b2167459SRichard Henderson     if (cf & 1) {
949b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
950b2167459SRichard Henderson     }
951b2167459SRichard Henderson 
952b2167459SRichard Henderson     return cond;
953b2167459SRichard Henderson }
954b2167459SRichard Henderson 
9556fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d,
9566fd0c7bcSRichard Henderson                           TCGv_i64 cb, TCGv_i64 cb_msb)
95772ca8753SRichard Henderson {
95872ca8753SRichard Henderson     if (cond_need_ext(ctx, d)) {
959*aac0f603SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
9606fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, cb, 32, 1);
96172ca8753SRichard Henderson         return t;
96272ca8753SRichard Henderson     }
96372ca8753SRichard Henderson     return cb_msb;
96472ca8753SRichard Henderson }
96572ca8753SRichard Henderson 
9666fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d)
96772ca8753SRichard Henderson {
96872ca8753SRichard Henderson     return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb);
96972ca8753SRichard Henderson }
97072ca8753SRichard Henderson 
971b2167459SRichard Henderson /* Compute signed overflow for addition.  */
9726fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res,
9736fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
974b2167459SRichard Henderson {
975*aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
976*aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
977b2167459SRichard Henderson 
9786fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
9796fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
9806fd0c7bcSRichard Henderson     tcg_gen_andc_i64(sv, sv, tmp);
981b2167459SRichard Henderson 
982b2167459SRichard Henderson     return sv;
983b2167459SRichard Henderson }
984b2167459SRichard Henderson 
985b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
9866fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res,
9876fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
988b2167459SRichard Henderson {
989*aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
990*aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
991b2167459SRichard Henderson 
9926fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
9936fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
9946fd0c7bcSRichard Henderson     tcg_gen_and_i64(sv, sv, tmp);
995b2167459SRichard Henderson 
996b2167459SRichard Henderson     return sv;
997b2167459SRichard Henderson }
998b2167459SRichard Henderson 
9996fd0c7bcSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
10006fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned shift, bool is_l,
1001faf97ba1SRichard Henderson                    bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d)
1002b2167459SRichard Henderson {
10036fd0c7bcSRichard Henderson     TCGv_i64 dest, cb, cb_msb, cb_cond, sv, tmp;
1004b2167459SRichard Henderson     unsigned c = cf >> 1;
1005b2167459SRichard Henderson     DisasCond cond;
1006b2167459SRichard Henderson 
1007*aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1008f764718dSRichard Henderson     cb = NULL;
1009f764718dSRichard Henderson     cb_msb = NULL;
1010bdcccc17SRichard Henderson     cb_cond = NULL;
1011b2167459SRichard Henderson 
1012b2167459SRichard Henderson     if (shift) {
1013*aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
10146fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, in1, shift);
1015b2167459SRichard Henderson         in1 = tmp;
1016b2167459SRichard Henderson     }
1017b2167459SRichard Henderson 
1018b47a4a02SSven Schnelle     if (!is_l || cond_need_cb(c)) {
10196fd0c7bcSRichard Henderson         TCGv_i64 zero = tcg_constant_i64(0);
1020*aac0f603SRichard Henderson         cb_msb = tcg_temp_new_i64();
1021*aac0f603SRichard Henderson         cb = tcg_temp_new_i64();
1022bdcccc17SRichard Henderson 
10236fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, zero, in2, zero);
1024b2167459SRichard Henderson         if (is_c) {
10256fd0c7bcSRichard Henderson             tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb,
1026bdcccc17SRichard Henderson                              get_psw_carry(ctx, d), zero);
1027b2167459SRichard Henderson         }
10286fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
10296fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1030bdcccc17SRichard Henderson         if (cond_need_cb(c)) {
1031bdcccc17SRichard Henderson             cb_cond = get_carry(ctx, d, cb, cb_msb);
1032b2167459SRichard Henderson         }
1033b2167459SRichard Henderson     } else {
10346fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
1035b2167459SRichard Henderson         if (is_c) {
10366fd0c7bcSRichard Henderson             tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d));
1037b2167459SRichard Henderson         }
1038b2167459SRichard Henderson     }
1039b2167459SRichard Henderson 
1040b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1041f764718dSRichard Henderson     sv = NULL;
1042b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1043b2167459SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
1044b2167459SRichard Henderson         if (is_tsv) {
1045b2167459SRichard Henderson             /* ??? Need to include overflow from shift.  */
1046ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1047b2167459SRichard Henderson         }
1048b2167459SRichard Henderson     }
1049b2167459SRichard Henderson 
1050b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1051a751eb31SRichard Henderson     cond = do_cond(ctx, cf, d, dest, cb_cond, sv);
1052b2167459SRichard Henderson     if (is_tc) {
1053*aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
10546fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1055ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1056b2167459SRichard Henderson     }
1057b2167459SRichard Henderson 
1058b2167459SRichard Henderson     /* Write back the result.  */
1059b2167459SRichard Henderson     if (!is_l) {
1060b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
1061b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1062b2167459SRichard Henderson     }
1063b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1064b2167459SRichard Henderson 
1065b2167459SRichard Henderson     /* Install the new nullification.  */
1066b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1067b2167459SRichard Henderson     ctx->null_cond = cond;
1068b2167459SRichard Henderson }
1069b2167459SRichard Henderson 
1070faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a,
10710c982a28SRichard Henderson                        bool is_l, bool is_tsv, bool is_tc, bool is_c)
10720c982a28SRichard Henderson {
10736fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
10740c982a28SRichard Henderson 
10750c982a28SRichard Henderson     if (a->cf) {
10760c982a28SRichard Henderson         nullify_over(ctx);
10770c982a28SRichard Henderson     }
10780c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
10790c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1080faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l,
1081faf97ba1SRichard Henderson            is_tsv, is_tc, is_c, a->cf, a->d);
10820c982a28SRichard Henderson     return nullify_end(ctx);
10830c982a28SRichard Henderson }
10840c982a28SRichard Henderson 
10850588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a,
10860588e061SRichard Henderson                        bool is_tsv, bool is_tc)
10870588e061SRichard Henderson {
10886fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
10890588e061SRichard Henderson 
10900588e061SRichard Henderson     if (a->cf) {
10910588e061SRichard Henderson         nullify_over(ctx);
10920588e061SRichard Henderson     }
10936fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
10940588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
1095faf97ba1SRichard Henderson     /* All ADDI conditions are 32-bit. */
1096faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false);
10970588e061SRichard Henderson     return nullify_end(ctx);
10980588e061SRichard Henderson }
10990588e061SRichard Henderson 
11006fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
11016fd0c7bcSRichard Henderson                    TCGv_i64 in2, bool is_tsv, bool is_b,
110263c427c6SRichard Henderson                    bool is_tc, unsigned cf, bool d)
1103b2167459SRichard Henderson {
11046fd0c7bcSRichard Henderson     TCGv_i64 dest, sv, cb, cb_msb, zero, tmp;
1105b2167459SRichard Henderson     unsigned c = cf >> 1;
1106b2167459SRichard Henderson     DisasCond cond;
1107b2167459SRichard Henderson 
1108*aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1109*aac0f603SRichard Henderson     cb = tcg_temp_new_i64();
1110*aac0f603SRichard Henderson     cb_msb = tcg_temp_new_i64();
1111b2167459SRichard Henderson 
11126fd0c7bcSRichard Henderson     zero = tcg_constant_i64(0);
1113b2167459SRichard Henderson     if (is_b) {
1114b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
11156fd0c7bcSRichard Henderson         tcg_gen_not_i64(cb, in2);
11166fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, zero, get_psw_carry(ctx, d), zero);
11176fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, zero);
11186fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, in1);
11196fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1120b2167459SRichard Henderson     } else {
1121bdcccc17SRichard Henderson         /*
1122bdcccc17SRichard Henderson          * DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
1123bdcccc17SRichard Henderson          * operations by seeding the high word with 1 and subtracting.
1124bdcccc17SRichard Henderson          */
11256fd0c7bcSRichard Henderson         TCGv_i64 one = tcg_constant_i64(1);
11266fd0c7bcSRichard Henderson         tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, zero);
11276fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(cb, in1, in2);
11286fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1129b2167459SRichard Henderson     }
1130b2167459SRichard Henderson 
1131b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1132f764718dSRichard Henderson     sv = NULL;
1133b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1134b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1135b2167459SRichard Henderson         if (is_tsv) {
1136ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1137b2167459SRichard Henderson         }
1138b2167459SRichard Henderson     }
1139b2167459SRichard Henderson 
1140b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
1141b2167459SRichard Henderson     if (!is_b) {
11424fe9533aSRichard Henderson         cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1143b2167459SRichard Henderson     } else {
1144a751eb31SRichard Henderson         cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv);
1145b2167459SRichard Henderson     }
1146b2167459SRichard Henderson 
1147b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1148b2167459SRichard Henderson     if (is_tc) {
1149*aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
11506fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1151ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1152b2167459SRichard Henderson     }
1153b2167459SRichard Henderson 
1154b2167459SRichard Henderson     /* Write back the result.  */
1155b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
1156b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1157b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1158b2167459SRichard Henderson 
1159b2167459SRichard Henderson     /* Install the new nullification.  */
1160b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1161b2167459SRichard Henderson     ctx->null_cond = cond;
1162b2167459SRichard Henderson }
1163b2167459SRichard Henderson 
116463c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a,
11650c982a28SRichard Henderson                        bool is_tsv, bool is_b, bool is_tc)
11660c982a28SRichard Henderson {
11676fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
11680c982a28SRichard Henderson 
11690c982a28SRichard Henderson     if (a->cf) {
11700c982a28SRichard Henderson         nullify_over(ctx);
11710c982a28SRichard Henderson     }
11720c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
11730c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
117463c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d);
11750c982a28SRichard Henderson     return nullify_end(ctx);
11760c982a28SRichard Henderson }
11770c982a28SRichard Henderson 
11780588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv)
11790588e061SRichard Henderson {
11806fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
11810588e061SRichard Henderson 
11820588e061SRichard Henderson     if (a->cf) {
11830588e061SRichard Henderson         nullify_over(ctx);
11840588e061SRichard Henderson     }
11856fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
11860588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
118763c427c6SRichard Henderson     /* All SUBI conditions are 32-bit. */
118863c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false);
11890588e061SRichard Henderson     return nullify_end(ctx);
11900588e061SRichard Henderson }
11910588e061SRichard Henderson 
11926fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
11936fd0c7bcSRichard Henderson                       TCGv_i64 in2, unsigned cf, bool d)
1194b2167459SRichard Henderson {
11956fd0c7bcSRichard Henderson     TCGv_i64 dest, sv;
1196b2167459SRichard Henderson     DisasCond cond;
1197b2167459SRichard Henderson 
1198*aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
11996fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
1200b2167459SRichard Henderson 
1201b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1202f764718dSRichard Henderson     sv = NULL;
1203b47a4a02SSven Schnelle     if (cond_need_sv(cf >> 1)) {
1204b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1205b2167459SRichard Henderson     }
1206b2167459SRichard Henderson 
1207b2167459SRichard Henderson     /* Form the condition for the compare.  */
12084fe9533aSRichard Henderson     cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1209b2167459SRichard Henderson 
1210b2167459SRichard Henderson     /* Clear.  */
12116fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
1212b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1213b2167459SRichard Henderson 
1214b2167459SRichard Henderson     /* Install the new nullification.  */
1215b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1216b2167459SRichard Henderson     ctx->null_cond = cond;
1217b2167459SRichard Henderson }
1218b2167459SRichard Henderson 
12196fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12206fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned cf, bool d,
12216fd0c7bcSRichard Henderson                    void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1222b2167459SRichard Henderson {
12236fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, rt);
1224b2167459SRichard Henderson 
1225b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
1226b2167459SRichard Henderson     fn(dest, in1, in2);
1227b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1228b2167459SRichard Henderson 
1229b2167459SRichard Henderson     /* Install the new nullification.  */
1230b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1231b2167459SRichard Henderson     if (cf) {
1232b5af8423SRichard Henderson         ctx->null_cond = do_log_cond(ctx, cf, d, dest);
1233b2167459SRichard Henderson     }
1234b2167459SRichard Henderson }
1235b2167459SRichard Henderson 
1236fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a,
12376fd0c7bcSRichard Henderson                        void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
12380c982a28SRichard Henderson {
12396fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
12400c982a28SRichard Henderson 
12410c982a28SRichard Henderson     if (a->cf) {
12420c982a28SRichard Henderson         nullify_over(ctx);
12430c982a28SRichard Henderson     }
12440c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
12450c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1246fa8e3bedSRichard Henderson     do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn);
12470c982a28SRichard Henderson     return nullify_end(ctx);
12480c982a28SRichard Henderson }
12490c982a28SRichard Henderson 
12506fd0c7bcSRichard Henderson static void do_unit(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12516fd0c7bcSRichard Henderson                     TCGv_i64 in2, unsigned cf, bool d, bool is_tc,
12526fd0c7bcSRichard Henderson                     void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1253b2167459SRichard Henderson {
12546fd0c7bcSRichard Henderson     TCGv_i64 dest;
1255b2167459SRichard Henderson     DisasCond cond;
1256b2167459SRichard Henderson 
1257b2167459SRichard Henderson     if (cf == 0) {
1258b2167459SRichard Henderson         dest = dest_gpr(ctx, rt);
1259b2167459SRichard Henderson         fn(dest, in1, in2);
1260b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1261b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1262b2167459SRichard Henderson     } else {
1263*aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
1264b2167459SRichard Henderson         fn(dest, in1, in2);
1265b2167459SRichard Henderson 
126659963d8fSRichard Henderson         cond = do_unit_cond(cf, d, dest, in1, in2);
1267b2167459SRichard Henderson 
1268b2167459SRichard Henderson         if (is_tc) {
1269*aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
12706fd0c7bcSRichard Henderson             tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1271ad75a51eSRichard Henderson             gen_helper_tcond(tcg_env, tmp);
1272b2167459SRichard Henderson         }
1273b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1274b2167459SRichard Henderson 
1275b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1276b2167459SRichard Henderson         ctx->null_cond = cond;
1277b2167459SRichard Henderson     }
1278b2167459SRichard Henderson }
1279b2167459SRichard Henderson 
128086f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY
12818d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space
12828d6ae7fbSRichard Henderson    from the top 2 bits of the base register.  There are a few system
12838d6ae7fbSRichard Henderson    instructions that have a 3-bit space specifier, for which SR0 is
12848d6ae7fbSRichard Henderson    not special.  To handle this, pass ~SP.  */
12856fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base)
128686f8d05fSRichard Henderson {
128786f8d05fSRichard Henderson     TCGv_ptr ptr;
12886fd0c7bcSRichard Henderson     TCGv_i64 tmp;
128986f8d05fSRichard Henderson     TCGv_i64 spc;
129086f8d05fSRichard Henderson 
129186f8d05fSRichard Henderson     if (sp != 0) {
12928d6ae7fbSRichard Henderson         if (sp < 0) {
12938d6ae7fbSRichard Henderson             sp = ~sp;
12948d6ae7fbSRichard Henderson         }
12956fd0c7bcSRichard Henderson         spc = tcg_temp_new_i64();
12968d6ae7fbSRichard Henderson         load_spr(ctx, spc, sp);
12978d6ae7fbSRichard Henderson         return spc;
129886f8d05fSRichard Henderson     }
1299494737b7SRichard Henderson     if (ctx->tb_flags & TB_FLAG_SR_SAME) {
1300494737b7SRichard Henderson         return cpu_srH;
1301494737b7SRichard Henderson     }
130286f8d05fSRichard Henderson 
130386f8d05fSRichard Henderson     ptr = tcg_temp_new_ptr();
1304*aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
13056fd0c7bcSRichard Henderson     spc = tcg_temp_new_i64();
130686f8d05fSRichard Henderson 
1307698240d1SRichard Henderson     /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */
13086fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5);
13096fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, 030);
13106fd0c7bcSRichard Henderson     tcg_gen_trunc_i64_ptr(ptr, tmp);
131186f8d05fSRichard Henderson 
1312ad75a51eSRichard Henderson     tcg_gen_add_ptr(ptr, ptr, tcg_env);
131386f8d05fSRichard Henderson     tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4]));
131486f8d05fSRichard Henderson 
131586f8d05fSRichard Henderson     return spc;
131686f8d05fSRichard Henderson }
131786f8d05fSRichard Henderson #endif
131886f8d05fSRichard Henderson 
13196fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
1320c53e401eSRichard Henderson                      unsigned rb, unsigned rx, int scale, int64_t disp,
132186f8d05fSRichard Henderson                      unsigned sp, int modify, bool is_phys)
132286f8d05fSRichard Henderson {
13236fd0c7bcSRichard Henderson     TCGv_i64 base = load_gpr(ctx, rb);
13246fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13256fd0c7bcSRichard Henderson     TCGv_i64 addr;
132686f8d05fSRichard Henderson 
132786f8d05fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
132886f8d05fSRichard Henderson     if (rx) {
1329*aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
13306fd0c7bcSRichard Henderson         tcg_gen_shli_i64(ofs, cpu_gr[rx], scale);
13316fd0c7bcSRichard Henderson         tcg_gen_add_i64(ofs, ofs, base);
133286f8d05fSRichard Henderson     } else if (disp || modify) {
1333*aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
13346fd0c7bcSRichard Henderson         tcg_gen_addi_i64(ofs, base, disp);
133586f8d05fSRichard Henderson     } else {
133686f8d05fSRichard Henderson         ofs = base;
133786f8d05fSRichard Henderson     }
133886f8d05fSRichard Henderson 
133986f8d05fSRichard Henderson     *pofs = ofs;
13406fd0c7bcSRichard Henderson     *pgva = addr = tcg_temp_new_i64();
1341967662cdSRichard Henderson     tcg_gen_andi_tl(addr, modify <= 0 ? ofs : base, gva_offset_mask(ctx));
1342698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY
134386f8d05fSRichard Henderson     if (!is_phys) {
134486f8d05fSRichard Henderson         tcg_gen_or_tl(addr, addr, space_select(ctx, sp, base));
134586f8d05fSRichard Henderson     }
134686f8d05fSRichard Henderson #endif
134786f8d05fSRichard Henderson }
134886f8d05fSRichard Henderson 
134996d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
135096d6407fSRichard Henderson  * < 0 for pre-modify,
135196d6407fSRichard Henderson  * > 0 for post-modify,
135296d6407fSRichard Henderson  * = 0 for no base register update.
135396d6407fSRichard Henderson  */
135496d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1355c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
135614776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
135796d6407fSRichard Henderson {
13586fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13596fd0c7bcSRichard Henderson     TCGv_i64 addr;
136096d6407fSRichard Henderson 
136196d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
136296d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
136396d6407fSRichard Henderson 
136486f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
136586f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1366c1f55d97SRichard Henderson     tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
136786f8d05fSRichard Henderson     if (modify) {
136886f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
136996d6407fSRichard Henderson     }
137096d6407fSRichard Henderson }
137196d6407fSRichard Henderson 
137296d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1373c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
137414776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
137596d6407fSRichard Henderson {
13766fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13776fd0c7bcSRichard Henderson     TCGv_i64 addr;
137896d6407fSRichard Henderson 
137996d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
138096d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
138196d6407fSRichard Henderson 
138286f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
138386f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1384217d1a5eSRichard Henderson     tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
138586f8d05fSRichard Henderson     if (modify) {
138686f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
138796d6407fSRichard Henderson     }
138896d6407fSRichard Henderson }
138996d6407fSRichard Henderson 
139096d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1391c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
139214776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
139396d6407fSRichard Henderson {
13946fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13956fd0c7bcSRichard Henderson     TCGv_i64 addr;
139696d6407fSRichard Henderson 
139796d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
139896d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
139996d6407fSRichard Henderson 
140086f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
140186f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1402217d1a5eSRichard Henderson     tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
140386f8d05fSRichard Henderson     if (modify) {
140486f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
140596d6407fSRichard Henderson     }
140696d6407fSRichard Henderson }
140796d6407fSRichard Henderson 
140896d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1409c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
141014776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
141196d6407fSRichard Henderson {
14126fd0c7bcSRichard Henderson     TCGv_i64 ofs;
14136fd0c7bcSRichard Henderson     TCGv_i64 addr;
141496d6407fSRichard Henderson 
141596d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
141696d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
141796d6407fSRichard Henderson 
141886f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
141986f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1420217d1a5eSRichard Henderson     tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
142186f8d05fSRichard Henderson     if (modify) {
142286f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
142396d6407fSRichard Henderson     }
142496d6407fSRichard Henderson }
142596d6407fSRichard Henderson 
14261cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1427c53e401eSRichard Henderson                     unsigned rx, int scale, int64_t disp,
142814776ab5STony Nguyen                     unsigned sp, int modify, MemOp mop)
142996d6407fSRichard Henderson {
14306fd0c7bcSRichard Henderson     TCGv_i64 dest;
143196d6407fSRichard Henderson 
143296d6407fSRichard Henderson     nullify_over(ctx);
143396d6407fSRichard Henderson 
143496d6407fSRichard Henderson     if (modify == 0) {
143596d6407fSRichard Henderson         /* No base register update.  */
143696d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
143796d6407fSRichard Henderson     } else {
143896d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
1439*aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
144096d6407fSRichard Henderson     }
14416fd0c7bcSRichard Henderson     do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
144296d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
144396d6407fSRichard Henderson 
14441cd012a5SRichard Henderson     return nullify_end(ctx);
144596d6407fSRichard Henderson }
144696d6407fSRichard Henderson 
1447740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
1448c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
144986f8d05fSRichard Henderson                       unsigned sp, int modify)
145096d6407fSRichard Henderson {
145196d6407fSRichard Henderson     TCGv_i32 tmp;
145296d6407fSRichard Henderson 
145396d6407fSRichard Henderson     nullify_over(ctx);
145496d6407fSRichard Henderson 
145596d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
145686f8d05fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
145796d6407fSRichard Henderson     save_frw_i32(rt, tmp);
145896d6407fSRichard Henderson 
145996d6407fSRichard Henderson     if (rt == 0) {
1460ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
146196d6407fSRichard Henderson     }
146296d6407fSRichard Henderson 
1463740038d7SRichard Henderson     return nullify_end(ctx);
146496d6407fSRichard Henderson }
146596d6407fSRichard Henderson 
1466740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a)
1467740038d7SRichard Henderson {
1468740038d7SRichard Henderson     return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1469740038d7SRichard Henderson                      a->disp, a->sp, a->m);
1470740038d7SRichard Henderson }
1471740038d7SRichard Henderson 
1472740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1473c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
147486f8d05fSRichard Henderson                       unsigned sp, int modify)
147596d6407fSRichard Henderson {
147696d6407fSRichard Henderson     TCGv_i64 tmp;
147796d6407fSRichard Henderson 
147896d6407fSRichard Henderson     nullify_over(ctx);
147996d6407fSRichard Henderson 
148096d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
1481fc313c64SFrédéric Pétrot     do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
148296d6407fSRichard Henderson     save_frd(rt, tmp);
148396d6407fSRichard Henderson 
148496d6407fSRichard Henderson     if (rt == 0) {
1485ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
148696d6407fSRichard Henderson     }
148796d6407fSRichard Henderson 
1488740038d7SRichard Henderson     return nullify_end(ctx);
1489740038d7SRichard Henderson }
1490740038d7SRichard Henderson 
1491740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a)
1492740038d7SRichard Henderson {
1493740038d7SRichard Henderson     return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1494740038d7SRichard Henderson                      a->disp, a->sp, a->m);
149596d6407fSRichard Henderson }
149696d6407fSRichard Henderson 
14971cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb,
1498c53e401eSRichard Henderson                      int64_t disp, unsigned sp,
149914776ab5STony Nguyen                      int modify, MemOp mop)
150096d6407fSRichard Henderson {
150196d6407fSRichard Henderson     nullify_over(ctx);
15026fd0c7bcSRichard Henderson     do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
15031cd012a5SRichard Henderson     return nullify_end(ctx);
150496d6407fSRichard Henderson }
150596d6407fSRichard Henderson 
1506740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1507c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
150886f8d05fSRichard Henderson                        unsigned sp, int modify)
150996d6407fSRichard Henderson {
151096d6407fSRichard Henderson     TCGv_i32 tmp;
151196d6407fSRichard Henderson 
151296d6407fSRichard Henderson     nullify_over(ctx);
151396d6407fSRichard Henderson 
151496d6407fSRichard Henderson     tmp = load_frw_i32(rt);
151586f8d05fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
151696d6407fSRichard Henderson 
1517740038d7SRichard Henderson     return nullify_end(ctx);
151896d6407fSRichard Henderson }
151996d6407fSRichard Henderson 
1520740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a)
1521740038d7SRichard Henderson {
1522740038d7SRichard Henderson     return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1523740038d7SRichard Henderson                       a->disp, a->sp, a->m);
1524740038d7SRichard Henderson }
1525740038d7SRichard Henderson 
1526740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1527c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
152886f8d05fSRichard Henderson                        unsigned sp, int modify)
152996d6407fSRichard Henderson {
153096d6407fSRichard Henderson     TCGv_i64 tmp;
153196d6407fSRichard Henderson 
153296d6407fSRichard Henderson     nullify_over(ctx);
153396d6407fSRichard Henderson 
153496d6407fSRichard Henderson     tmp = load_frd(rt);
1535fc313c64SFrédéric Pétrot     do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
153696d6407fSRichard Henderson 
1537740038d7SRichard Henderson     return nullify_end(ctx);
1538740038d7SRichard Henderson }
1539740038d7SRichard Henderson 
1540740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a)
1541740038d7SRichard Henderson {
1542740038d7SRichard Henderson     return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1543740038d7SRichard Henderson                       a->disp, a->sp, a->m);
154496d6407fSRichard Henderson }
154596d6407fSRichard Henderson 
15461ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1547ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1548ebe9383cSRichard Henderson {
1549ebe9383cSRichard Henderson     TCGv_i32 tmp;
1550ebe9383cSRichard Henderson 
1551ebe9383cSRichard Henderson     nullify_over(ctx);
1552ebe9383cSRichard Henderson     tmp = load_frw0_i32(ra);
1553ebe9383cSRichard Henderson 
1554ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1555ebe9383cSRichard Henderson 
1556ebe9383cSRichard Henderson     save_frw_i32(rt, tmp);
15571ca74648SRichard Henderson     return nullify_end(ctx);
1558ebe9383cSRichard Henderson }
1559ebe9383cSRichard Henderson 
15601ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1561ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1562ebe9383cSRichard Henderson {
1563ebe9383cSRichard Henderson     TCGv_i32 dst;
1564ebe9383cSRichard Henderson     TCGv_i64 src;
1565ebe9383cSRichard Henderson 
1566ebe9383cSRichard Henderson     nullify_over(ctx);
1567ebe9383cSRichard Henderson     src = load_frd(ra);
1568ebe9383cSRichard Henderson     dst = tcg_temp_new_i32();
1569ebe9383cSRichard Henderson 
1570ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1571ebe9383cSRichard Henderson 
1572ebe9383cSRichard Henderson     save_frw_i32(rt, dst);
15731ca74648SRichard Henderson     return nullify_end(ctx);
1574ebe9383cSRichard Henderson }
1575ebe9383cSRichard Henderson 
15761ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1577ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1578ebe9383cSRichard Henderson {
1579ebe9383cSRichard Henderson     TCGv_i64 tmp;
1580ebe9383cSRichard Henderson 
1581ebe9383cSRichard Henderson     nullify_over(ctx);
1582ebe9383cSRichard Henderson     tmp = load_frd0(ra);
1583ebe9383cSRichard Henderson 
1584ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1585ebe9383cSRichard Henderson 
1586ebe9383cSRichard Henderson     save_frd(rt, tmp);
15871ca74648SRichard Henderson     return nullify_end(ctx);
1588ebe9383cSRichard Henderson }
1589ebe9383cSRichard Henderson 
15901ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1591ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1592ebe9383cSRichard Henderson {
1593ebe9383cSRichard Henderson     TCGv_i32 src;
1594ebe9383cSRichard Henderson     TCGv_i64 dst;
1595ebe9383cSRichard Henderson 
1596ebe9383cSRichard Henderson     nullify_over(ctx);
1597ebe9383cSRichard Henderson     src = load_frw0_i32(ra);
1598ebe9383cSRichard Henderson     dst = tcg_temp_new_i64();
1599ebe9383cSRichard Henderson 
1600ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1601ebe9383cSRichard Henderson 
1602ebe9383cSRichard Henderson     save_frd(rt, dst);
16031ca74648SRichard Henderson     return nullify_end(ctx);
1604ebe9383cSRichard Henderson }
1605ebe9383cSRichard Henderson 
16061ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt,
1607ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
160831234768SRichard Henderson                         void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
1609ebe9383cSRichard Henderson {
1610ebe9383cSRichard Henderson     TCGv_i32 a, b;
1611ebe9383cSRichard Henderson 
1612ebe9383cSRichard Henderson     nullify_over(ctx);
1613ebe9383cSRichard Henderson     a = load_frw0_i32(ra);
1614ebe9383cSRichard Henderson     b = load_frw0_i32(rb);
1615ebe9383cSRichard Henderson 
1616ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1617ebe9383cSRichard Henderson 
1618ebe9383cSRichard Henderson     save_frw_i32(rt, a);
16191ca74648SRichard Henderson     return nullify_end(ctx);
1620ebe9383cSRichard Henderson }
1621ebe9383cSRichard Henderson 
16221ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt,
1623ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
162431234768SRichard Henderson                         void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
1625ebe9383cSRichard Henderson {
1626ebe9383cSRichard Henderson     TCGv_i64 a, b;
1627ebe9383cSRichard Henderson 
1628ebe9383cSRichard Henderson     nullify_over(ctx);
1629ebe9383cSRichard Henderson     a = load_frd0(ra);
1630ebe9383cSRichard Henderson     b = load_frd0(rb);
1631ebe9383cSRichard Henderson 
1632ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1633ebe9383cSRichard Henderson 
1634ebe9383cSRichard Henderson     save_frd(rt, a);
16351ca74648SRichard Henderson     return nullify_end(ctx);
1636ebe9383cSRichard Henderson }
1637ebe9383cSRichard Henderson 
163898cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
163998cd9ca7SRichard Henderson    have already had nullification handled.  */
1640c53e401eSRichard Henderson static bool do_dbranch(DisasContext *ctx, uint64_t dest,
164198cd9ca7SRichard Henderson                        unsigned link, bool is_n)
164298cd9ca7SRichard Henderson {
164398cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
164498cd9ca7SRichard Henderson         if (link != 0) {
1645741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
164698cd9ca7SRichard Henderson         }
164798cd9ca7SRichard Henderson         ctx->iaoq_n = dest;
164898cd9ca7SRichard Henderson         if (is_n) {
164998cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
165098cd9ca7SRichard Henderson         }
165198cd9ca7SRichard Henderson     } else {
165298cd9ca7SRichard Henderson         nullify_over(ctx);
165398cd9ca7SRichard Henderson 
165498cd9ca7SRichard Henderson         if (link != 0) {
1655741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
165698cd9ca7SRichard Henderson         }
165798cd9ca7SRichard Henderson 
165898cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
165998cd9ca7SRichard Henderson             nullify_set(ctx, 0);
166098cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, dest, dest + 4);
166198cd9ca7SRichard Henderson         } else {
166298cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
166398cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
166498cd9ca7SRichard Henderson         }
166598cd9ca7SRichard Henderson 
166631234768SRichard Henderson         nullify_end(ctx);
166798cd9ca7SRichard Henderson 
166898cd9ca7SRichard Henderson         nullify_set(ctx, 0);
166998cd9ca7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
167031234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
167198cd9ca7SRichard Henderson     }
167201afb7beSRichard Henderson     return true;
167398cd9ca7SRichard Henderson }
167498cd9ca7SRichard Henderson 
167598cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
167698cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
1677c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n,
167898cd9ca7SRichard Henderson                        DisasCond *cond)
167998cd9ca7SRichard Henderson {
1680c53e401eSRichard Henderson     uint64_t dest = iaoq_dest(ctx, disp);
168198cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
168298cd9ca7SRichard Henderson     TCGCond c = cond->c;
168398cd9ca7SRichard Henderson     bool n;
168498cd9ca7SRichard Henderson 
168598cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
168698cd9ca7SRichard Henderson 
168798cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
168898cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
168901afb7beSRichard Henderson         return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
169098cd9ca7SRichard Henderson     }
169198cd9ca7SRichard Henderson     if (c == TCG_COND_NEVER) {
169201afb7beSRichard Henderson         return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
169398cd9ca7SRichard Henderson     }
169498cd9ca7SRichard Henderson 
169598cd9ca7SRichard Henderson     taken = gen_new_label();
16966fd0c7bcSRichard Henderson     tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken);
169798cd9ca7SRichard Henderson     cond_free(cond);
169898cd9ca7SRichard Henderson 
169998cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
170098cd9ca7SRichard Henderson     n = is_n && disp < 0;
170198cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
170298cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1703a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
170498cd9ca7SRichard Henderson     } else {
170598cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
170698cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
170798cd9ca7SRichard Henderson             ctx->null_lab = NULL;
170898cd9ca7SRichard Henderson         }
170998cd9ca7SRichard Henderson         nullify_set(ctx, n);
1710c301f34eSRichard Henderson         if (ctx->iaoq_n == -1) {
1711c301f34eSRichard Henderson             /* The temporary iaoq_n_var died at the branch above.
1712c301f34eSRichard Henderson                Regenerate it here instead of saving it.  */
17136fd0c7bcSRichard Henderson             tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
1714c301f34eSRichard Henderson         }
1715a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
171698cd9ca7SRichard Henderson     }
171798cd9ca7SRichard Henderson 
171898cd9ca7SRichard Henderson     gen_set_label(taken);
171998cd9ca7SRichard Henderson 
172098cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
172198cd9ca7SRichard Henderson     n = is_n && disp >= 0;
172298cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
172398cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1724a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, dest, dest + 4);
172598cd9ca7SRichard Henderson     } else {
172698cd9ca7SRichard Henderson         nullify_set(ctx, n);
1727a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
172898cd9ca7SRichard Henderson     }
172998cd9ca7SRichard Henderson 
173098cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
173198cd9ca7SRichard Henderson     if (ctx->null_lab) {
173298cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
173398cd9ca7SRichard Henderson         ctx->null_lab = NULL;
173431234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
173598cd9ca7SRichard Henderson     } else {
173631234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
173798cd9ca7SRichard Henderson     }
173801afb7beSRichard Henderson     return true;
173998cd9ca7SRichard Henderson }
174098cd9ca7SRichard Henderson 
174198cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target.  This handles
174298cd9ca7SRichard Henderson    nullification of the branch itself.  */
17436fd0c7bcSRichard Henderson static bool do_ibranch(DisasContext *ctx, TCGv_i64 dest,
174498cd9ca7SRichard Henderson                        unsigned link, bool is_n)
174598cd9ca7SRichard Henderson {
17466fd0c7bcSRichard Henderson     TCGv_i64 a0, a1, next, tmp;
174798cd9ca7SRichard Henderson     TCGCond c;
174898cd9ca7SRichard Henderson 
174998cd9ca7SRichard Henderson     assert(ctx->null_lab == NULL);
175098cd9ca7SRichard Henderson 
175198cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
175298cd9ca7SRichard Henderson         if (link != 0) {
1753741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
175498cd9ca7SRichard Henderson         }
1755*aac0f603SRichard Henderson         next = tcg_temp_new_i64();
17566fd0c7bcSRichard Henderson         tcg_gen_mov_i64(next, dest);
175798cd9ca7SRichard Henderson         if (is_n) {
1758c301f34eSRichard Henderson             if (use_nullify_skip(ctx)) {
1759a0180973SRichard Henderson                 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, next);
17606fd0c7bcSRichard Henderson                 tcg_gen_addi_i64(next, next, 4);
1761a0180973SRichard Henderson                 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
1762c301f34eSRichard Henderson                 nullify_set(ctx, 0);
176331234768SRichard Henderson                 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
176401afb7beSRichard Henderson                 return true;
1765c301f34eSRichard Henderson             }
176698cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
176798cd9ca7SRichard Henderson         }
1768c301f34eSRichard Henderson         ctx->iaoq_n = -1;
1769c301f34eSRichard Henderson         ctx->iaoq_n_var = next;
177098cd9ca7SRichard Henderson     } else if (is_n && use_nullify_skip(ctx)) {
177198cd9ca7SRichard Henderson         /* The (conditional) branch, B, nullifies the next insn, N,
177298cd9ca7SRichard Henderson            and we're allowed to skip execution N (no single-step or
17734137cb83SRichard Henderson            tracepoint in effect).  Since the goto_ptr that we must use
177498cd9ca7SRichard Henderson            for the indirect branch consumes no special resources, we
177598cd9ca7SRichard Henderson            can (conditionally) skip B and continue execution.  */
177698cd9ca7SRichard Henderson         /* The use_nullify_skip test implies we have a known control path.  */
177798cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_b != -1);
177898cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_n != -1);
177998cd9ca7SRichard Henderson 
178098cd9ca7SRichard Henderson         /* We do have to handle the non-local temporary, DEST, before
178198cd9ca7SRichard Henderson            branching.  Since IOAQ_F is not really live at this point, we
178298cd9ca7SRichard Henderson            can simply store DEST optimistically.  Similarly with IAOQ_B.  */
1783a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, dest);
1784*aac0f603SRichard Henderson         next = tcg_temp_new_i64();
17856fd0c7bcSRichard Henderson         tcg_gen_addi_i64(next, dest, 4);
1786a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
178798cd9ca7SRichard Henderson 
178898cd9ca7SRichard Henderson         nullify_over(ctx);
178998cd9ca7SRichard Henderson         if (link != 0) {
17909a91dd84SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
179198cd9ca7SRichard Henderson         }
17927f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
179301afb7beSRichard Henderson         return nullify_end(ctx);
179498cd9ca7SRichard Henderson     } else {
179598cd9ca7SRichard Henderson         c = ctx->null_cond.c;
179698cd9ca7SRichard Henderson         a0 = ctx->null_cond.a0;
179798cd9ca7SRichard Henderson         a1 = ctx->null_cond.a1;
179898cd9ca7SRichard Henderson 
1799*aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
1800*aac0f603SRichard Henderson         next = tcg_temp_new_i64();
180198cd9ca7SRichard Henderson 
1802741322f4SRichard Henderson         copy_iaoq_entry(ctx, tmp, ctx->iaoq_n, ctx->iaoq_n_var);
18036fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(c, next, a0, a1, tmp, dest);
180498cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
180598cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
180698cd9ca7SRichard Henderson 
180798cd9ca7SRichard Henderson         if (link != 0) {
18086fd0c7bcSRichard Henderson             tcg_gen_movcond_i64(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
180998cd9ca7SRichard Henderson         }
181098cd9ca7SRichard Henderson 
181198cd9ca7SRichard Henderson         if (is_n) {
181298cd9ca7SRichard Henderson             /* The branch nullifies the next insn, which means the state of N
181398cd9ca7SRichard Henderson                after the branch is the inverse of the state of N that applied
181498cd9ca7SRichard Henderson                to the branch.  */
18156fd0c7bcSRichard Henderson             tcg_gen_setcond_i64(tcg_invert_cond(c), cpu_psw_n, a0, a1);
181698cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
181798cd9ca7SRichard Henderson             ctx->null_cond = cond_make_n();
181898cd9ca7SRichard Henderson             ctx->psw_n_nonzero = true;
181998cd9ca7SRichard Henderson         } else {
182098cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
182198cd9ca7SRichard Henderson         }
182298cd9ca7SRichard Henderson     }
182301afb7beSRichard Henderson     return true;
182498cd9ca7SRichard Henderson }
182598cd9ca7SRichard Henderson 
1826660eefe1SRichard Henderson /* Implement
1827660eefe1SRichard Henderson  *    if (IAOQ_Front{30..31} < GR[b]{30..31})
1828660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← GR[b]{30..31};
1829660eefe1SRichard Henderson  *    else
1830660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← IAOQ_Front{30..31};
1831660eefe1SRichard Henderson  * which keeps the privilege level from being increased.
1832660eefe1SRichard Henderson  */
18336fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset)
1834660eefe1SRichard Henderson {
18356fd0c7bcSRichard Henderson     TCGv_i64 dest;
1836660eefe1SRichard Henderson     switch (ctx->privilege) {
1837660eefe1SRichard Henderson     case 0:
1838660eefe1SRichard Henderson         /* Privilege 0 is maximum and is allowed to decrease.  */
1839660eefe1SRichard Henderson         return offset;
1840660eefe1SRichard Henderson     case 3:
1841993119feSRichard Henderson         /* Privilege 3 is minimum and is never allowed to increase.  */
1842*aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
18436fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, offset, 3);
1844660eefe1SRichard Henderson         break;
1845660eefe1SRichard Henderson     default:
1846*aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
18476fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, offset, -4);
18486fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, ctx->privilege);
18496fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(TCG_COND_GTU, dest, dest, offset, dest, offset);
1850660eefe1SRichard Henderson         break;
1851660eefe1SRichard Henderson     }
1852660eefe1SRichard Henderson     return dest;
1853660eefe1SRichard Henderson }
1854660eefe1SRichard Henderson 
1855ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
18567ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
18577ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
18587ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
18597ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
18607ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
18617ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
18627ad439dfSRichard Henderson    aforementioned BE.  */
186331234768SRichard Henderson static void do_page_zero(DisasContext *ctx)
18647ad439dfSRichard Henderson {
18656fd0c7bcSRichard Henderson     TCGv_i64 tmp;
1866a0180973SRichard Henderson 
18677ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
18687ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
18698b81968cSMichael Tokarev        next insn within the privileged page.  */
18707ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
18717ad439dfSRichard Henderson     case TCG_COND_NEVER:
18727ad439dfSRichard Henderson         break;
18737ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
18746fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, 0);
18757ad439dfSRichard Henderson         goto do_sigill;
18767ad439dfSRichard Henderson     default:
18777ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
18787ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
18797ad439dfSRichard Henderson         g_assert_not_reached();
18807ad439dfSRichard Henderson     }
18817ad439dfSRichard Henderson 
18827ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
18837ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
18847ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
18857ad439dfSRichard Henderson        under such conditions.  */
18867ad439dfSRichard Henderson     if (ctx->iaoq_b != ctx->iaoq_f + 4) {
18877ad439dfSRichard Henderson         goto do_sigill;
18887ad439dfSRichard Henderson     }
18897ad439dfSRichard Henderson 
1890ebd0e151SRichard Henderson     switch (ctx->iaoq_f & -4) {
18917ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
18922986721dSRichard Henderson         gen_excp_1(EXCP_IMP);
189331234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
189431234768SRichard Henderson         break;
18957ad439dfSRichard Henderson 
18967ad439dfSRichard Henderson     case 0xb0: /* LWS */
18977ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
189831234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
189931234768SRichard Henderson         break;
19007ad439dfSRichard Henderson 
19017ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
19026fd0c7bcSRichard Henderson         tcg_gen_st_i64(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27]));
1903*aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
19046fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_gr[31], 3);
1905a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
19066fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, 4);
1907a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
190831234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
190931234768SRichard Henderson         break;
19107ad439dfSRichard Henderson 
19117ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
19127ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
191331234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
191431234768SRichard Henderson         break;
19157ad439dfSRichard Henderson 
19167ad439dfSRichard Henderson     default:
19177ad439dfSRichard Henderson     do_sigill:
19182986721dSRichard Henderson         gen_excp_1(EXCP_ILL);
191931234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
192031234768SRichard Henderson         break;
19217ad439dfSRichard Henderson     }
19227ad439dfSRichard Henderson }
1923ba1d0b44SRichard Henderson #endif
19247ad439dfSRichard Henderson 
1925deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a)
1926b2167459SRichard Henderson {
1927b2167459SRichard Henderson     cond_free(&ctx->null_cond);
192831234768SRichard Henderson     return true;
1929b2167459SRichard Henderson }
1930b2167459SRichard Henderson 
193140f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a)
193298a9cb79SRichard Henderson {
193331234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_BREAK);
193498a9cb79SRichard Henderson }
193598a9cb79SRichard Henderson 
1936e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a)
193798a9cb79SRichard Henderson {
193898a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
193998a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
194098a9cb79SRichard Henderson 
194198a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
194231234768SRichard Henderson     return true;
194398a9cb79SRichard Henderson }
194498a9cb79SRichard Henderson 
1945c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a)
194698a9cb79SRichard Henderson {
1947c603e14aSRichard Henderson     unsigned rt = a->t;
19486fd0c7bcSRichard Henderson     TCGv_i64 tmp = dest_gpr(ctx, rt);
19496fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tmp, ctx->iaoq_f);
195098a9cb79SRichard Henderson     save_gpr(ctx, rt, tmp);
195198a9cb79SRichard Henderson 
195298a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
195331234768SRichard Henderson     return true;
195498a9cb79SRichard Henderson }
195598a9cb79SRichard Henderson 
1956c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a)
195798a9cb79SRichard Henderson {
1958c603e14aSRichard Henderson     unsigned rt = a->t;
1959c603e14aSRichard Henderson     unsigned rs = a->sp;
196033423472SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
196198a9cb79SRichard Henderson 
196233423472SRichard Henderson     load_spr(ctx, t0, rs);
196333423472SRichard Henderson     tcg_gen_shri_i64(t0, t0, 32);
196433423472SRichard Henderson 
1965967662cdSRichard Henderson     save_gpr(ctx, rt, t0);
196698a9cb79SRichard Henderson 
196798a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
196831234768SRichard Henderson     return true;
196998a9cb79SRichard Henderson }
197098a9cb79SRichard Henderson 
1971c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a)
197298a9cb79SRichard Henderson {
1973c603e14aSRichard Henderson     unsigned rt = a->t;
1974c603e14aSRichard Henderson     unsigned ctl = a->r;
19756fd0c7bcSRichard Henderson     TCGv_i64 tmp;
197698a9cb79SRichard Henderson 
197798a9cb79SRichard Henderson     switch (ctl) {
197835136a77SRichard Henderson     case CR_SAR:
1979c603e14aSRichard Henderson         if (a->e == 0) {
198098a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
198198a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
19826fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
198398a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
198435136a77SRichard Henderson             goto done;
198598a9cb79SRichard Henderson         }
198698a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
198735136a77SRichard Henderson         goto done;
198835136a77SRichard Henderson     case CR_IT: /* Interval Timer */
198935136a77SRichard Henderson         /* FIXME: Respect PSW_S bit.  */
199035136a77SRichard Henderson         nullify_over(ctx);
199198a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
1992dfd1b812SRichard Henderson         if (translator_io_start(&ctx->base)) {
199349c29d6cSRichard Henderson             gen_helper_read_interval_timer(tmp);
199431234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
199549c29d6cSRichard Henderson         } else {
199649c29d6cSRichard Henderson             gen_helper_read_interval_timer(tmp);
199749c29d6cSRichard Henderson         }
199898a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
199931234768SRichard Henderson         return nullify_end(ctx);
200098a9cb79SRichard Henderson     case 26:
200198a9cb79SRichard Henderson     case 27:
200298a9cb79SRichard Henderson         break;
200398a9cb79SRichard Henderson     default:
200498a9cb79SRichard Henderson         /* All other control registers are privileged.  */
200535136a77SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
200635136a77SRichard Henderson         break;
200798a9cb79SRichard Henderson     }
200898a9cb79SRichard Henderson 
2009*aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
20106fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
201135136a77SRichard Henderson     save_gpr(ctx, rt, tmp);
201235136a77SRichard Henderson 
201335136a77SRichard Henderson  done:
201498a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
201531234768SRichard Henderson     return true;
201698a9cb79SRichard Henderson }
201798a9cb79SRichard Henderson 
2018c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
201933423472SRichard Henderson {
2020c603e14aSRichard Henderson     unsigned rr = a->r;
2021c603e14aSRichard Henderson     unsigned rs = a->sp;
2022967662cdSRichard Henderson     TCGv_i64 tmp;
202333423472SRichard Henderson 
202433423472SRichard Henderson     if (rs >= 5) {
202533423472SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
202633423472SRichard Henderson     }
202733423472SRichard Henderson     nullify_over(ctx);
202833423472SRichard Henderson 
2029967662cdSRichard Henderson     tmp = tcg_temp_new_i64();
2030967662cdSRichard Henderson     tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32);
203133423472SRichard Henderson 
203233423472SRichard Henderson     if (rs >= 4) {
2033967662cdSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs]));
2034494737b7SRichard Henderson         ctx->tb_flags &= ~TB_FLAG_SR_SAME;
203533423472SRichard Henderson     } else {
2036967662cdSRichard Henderson         tcg_gen_mov_i64(cpu_sr[rs], tmp);
203733423472SRichard Henderson     }
203833423472SRichard Henderson 
203931234768SRichard Henderson     return nullify_end(ctx);
204033423472SRichard Henderson }
204133423472SRichard Henderson 
2042c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
204398a9cb79SRichard Henderson {
2044c603e14aSRichard Henderson     unsigned ctl = a->t;
20456fd0c7bcSRichard Henderson     TCGv_i64 reg;
20466fd0c7bcSRichard Henderson     TCGv_i64 tmp;
204798a9cb79SRichard Henderson 
204835136a77SRichard Henderson     if (ctl == CR_SAR) {
20494845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
2050*aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
20516fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31);
205298a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
205398a9cb79SRichard Henderson 
205498a9cb79SRichard Henderson         cond_free(&ctx->null_cond);
205531234768SRichard Henderson         return true;
205698a9cb79SRichard Henderson     }
205798a9cb79SRichard Henderson 
205835136a77SRichard Henderson     /* All other control registers are privileged or read-only.  */
205935136a77SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
206035136a77SRichard Henderson 
2061c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
206235136a77SRichard Henderson     nullify_over(ctx);
20634845f015SSven Schnelle     reg = load_gpr(ctx, a->r);
20644845f015SSven Schnelle 
206535136a77SRichard Henderson     switch (ctl) {
206635136a77SRichard Henderson     case CR_IT:
2067ad75a51eSRichard Henderson         gen_helper_write_interval_timer(tcg_env, reg);
206835136a77SRichard Henderson         break;
20694f5f2548SRichard Henderson     case CR_EIRR:
2070ad75a51eSRichard Henderson         gen_helper_write_eirr(tcg_env, reg);
20714f5f2548SRichard Henderson         break;
20724f5f2548SRichard Henderson     case CR_EIEM:
2073ad75a51eSRichard Henderson         gen_helper_write_eiem(tcg_env, reg);
207431234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
20754f5f2548SRichard Henderson         break;
20764f5f2548SRichard Henderson 
207735136a77SRichard Henderson     case CR_IIASQ:
207835136a77SRichard Henderson     case CR_IIAOQ:
207935136a77SRichard Henderson         /* FIXME: Respect PSW_Q bit */
208035136a77SRichard Henderson         /* The write advances the queue and stores to the back element.  */
2081*aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
20826fd0c7bcSRichard Henderson         tcg_gen_ld_i64(tmp, tcg_env,
208335136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
20846fd0c7bcSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
20856fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env,
208635136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
208735136a77SRichard Henderson         break;
208835136a77SRichard Henderson 
2089d5de20bdSSven Schnelle     case CR_PID1:
2090d5de20bdSSven Schnelle     case CR_PID2:
2091d5de20bdSSven Schnelle     case CR_PID3:
2092d5de20bdSSven Schnelle     case CR_PID4:
20936fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
2094d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY
2095ad75a51eSRichard Henderson         gen_helper_change_prot_id(tcg_env);
2096d5de20bdSSven Schnelle #endif
2097d5de20bdSSven Schnelle         break;
2098d5de20bdSSven Schnelle 
209935136a77SRichard Henderson     default:
21006fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
210135136a77SRichard Henderson         break;
210235136a77SRichard Henderson     }
210331234768SRichard Henderson     return nullify_end(ctx);
21044f5f2548SRichard Henderson #endif
210535136a77SRichard Henderson }
210635136a77SRichard Henderson 
2107c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
210898a9cb79SRichard Henderson {
2109*aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
211098a9cb79SRichard Henderson 
21116fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, load_gpr(ctx, a->r));
21126fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31);
211398a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
211498a9cb79SRichard Henderson 
211598a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
211631234768SRichard Henderson     return true;
211798a9cb79SRichard Henderson }
211898a9cb79SRichard Henderson 
2119e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a)
212098a9cb79SRichard Henderson {
21216fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
212298a9cb79SRichard Henderson 
21232330504cSHelge Deller #ifdef CONFIG_USER_ONLY
21242330504cSHelge Deller     /* We don't implement space registers in user mode. */
21256fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
21262330504cSHelge Deller #else
2127967662cdSRichard Henderson     tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
2128967662cdSRichard Henderson     tcg_gen_shri_i64(dest, dest, 32);
21292330504cSHelge Deller #endif
2130e36f27efSRichard Henderson     save_gpr(ctx, a->t, dest);
213198a9cb79SRichard Henderson 
213298a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
213331234768SRichard Henderson     return true;
213498a9cb79SRichard Henderson }
213598a9cb79SRichard Henderson 
2136e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a)
2137e36f27efSRichard Henderson {
2138e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2139e1b5a5edSRichard Henderson #ifndef CONFIG_USER_ONLY
21406fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2141e1b5a5edSRichard Henderson 
2142e1b5a5edSRichard Henderson     nullify_over(ctx);
2143e1b5a5edSRichard Henderson 
2144*aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
21456fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
21466fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ~a->i);
2147ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2148e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2149e1b5a5edSRichard Henderson 
2150e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_M.  */
215131234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
215231234768SRichard Henderson     return nullify_end(ctx);
2153e36f27efSRichard Henderson #endif
2154e1b5a5edSRichard Henderson }
2155e1b5a5edSRichard Henderson 
2156e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
2157e1b5a5edSRichard Henderson {
2158e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2159e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
21606fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2161e1b5a5edSRichard Henderson 
2162e1b5a5edSRichard Henderson     nullify_over(ctx);
2163e1b5a5edSRichard Henderson 
2164*aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
21656fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
21666fd0c7bcSRichard Henderson     tcg_gen_ori_i64(tmp, tmp, a->i);
2167ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2168e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2169e1b5a5edSRichard Henderson 
2170e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_I.  */
217131234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
217231234768SRichard Henderson     return nullify_end(ctx);
2173e36f27efSRichard Henderson #endif
2174e1b5a5edSRichard Henderson }
2175e1b5a5edSRichard Henderson 
2176c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
2177e1b5a5edSRichard Henderson {
2178e1b5a5edSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2179c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
21806fd0c7bcSRichard Henderson     TCGv_i64 tmp, reg;
2181e1b5a5edSRichard Henderson     nullify_over(ctx);
2182e1b5a5edSRichard Henderson 
2183c603e14aSRichard Henderson     reg = load_gpr(ctx, a->r);
2184*aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2185ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, reg);
2186e1b5a5edSRichard Henderson 
2187e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts.  */
218831234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
218931234768SRichard Henderson     return nullify_end(ctx);
2190c603e14aSRichard Henderson #endif
2191e1b5a5edSRichard Henderson }
2192f49b3537SRichard Henderson 
2193e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r)
2194f49b3537SRichard Henderson {
2195f49b3537SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2196e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
2197f49b3537SRichard Henderson     nullify_over(ctx);
2198f49b3537SRichard Henderson 
2199e36f27efSRichard Henderson     if (rfi_r) {
2200ad75a51eSRichard Henderson         gen_helper_rfi_r(tcg_env);
2201f49b3537SRichard Henderson     } else {
2202ad75a51eSRichard Henderson         gen_helper_rfi(tcg_env);
2203f49b3537SRichard Henderson     }
220431234768SRichard Henderson     /* Exit the TB to recognize new interrupts.  */
220507ea28b4SRichard Henderson     tcg_gen_exit_tb(NULL, 0);
220631234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
2207f49b3537SRichard Henderson 
220831234768SRichard Henderson     return nullify_end(ctx);
2209e36f27efSRichard Henderson #endif
2210f49b3537SRichard Henderson }
22116210db05SHelge Deller 
2212e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a)
2213e36f27efSRichard Henderson {
2214e36f27efSRichard Henderson     return do_rfi(ctx, false);
2215e36f27efSRichard Henderson }
2216e36f27efSRichard Henderson 
2217e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a)
2218e36f27efSRichard Henderson {
2219e36f27efSRichard Henderson     return do_rfi(ctx, true);
2220e36f27efSRichard Henderson }
2221e36f27efSRichard Henderson 
222296927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a)
22236210db05SHelge Deller {
22246210db05SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
222596927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
22266210db05SHelge Deller     nullify_over(ctx);
2227ad75a51eSRichard Henderson     gen_helper_halt(tcg_env);
222831234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
222931234768SRichard Henderson     return nullify_end(ctx);
223096927adbSRichard Henderson #endif
22316210db05SHelge Deller }
223296927adbSRichard Henderson 
223396927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a)
223496927adbSRichard Henderson {
223596927adbSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
223696927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
223796927adbSRichard Henderson     nullify_over(ctx);
2238ad75a51eSRichard Henderson     gen_helper_reset(tcg_env);
223996927adbSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
224096927adbSRichard Henderson     return nullify_end(ctx);
224196927adbSRichard Henderson #endif
224296927adbSRichard Henderson }
2243e1b5a5edSRichard Henderson 
22444a4554c6SHelge Deller static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
22454a4554c6SHelge Deller {
22464a4554c6SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
22474a4554c6SHelge Deller #ifndef CONFIG_USER_ONLY
22484a4554c6SHelge Deller     nullify_over(ctx);
2249ad75a51eSRichard Henderson     gen_helper_getshadowregs(tcg_env);
22504a4554c6SHelge Deller     return nullify_end(ctx);
22514a4554c6SHelge Deller #endif
22524a4554c6SHelge Deller }
22534a4554c6SHelge Deller 
2254deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
225598a9cb79SRichard Henderson {
2256deee69a1SRichard Henderson     if (a->m) {
22576fd0c7bcSRichard Henderson         TCGv_i64 dest = dest_gpr(ctx, a->b);
22586fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->b);
22596fd0c7bcSRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->x);
226098a9cb79SRichard Henderson 
226198a9cb79SRichard Henderson         /* The only thing we need to do is the base register modification.  */
22626fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, src1, src2);
2263deee69a1SRichard Henderson         save_gpr(ctx, a->b, dest);
2264deee69a1SRichard Henderson     }
226598a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
226631234768SRichard Henderson     return true;
226798a9cb79SRichard Henderson }
226898a9cb79SRichard Henderson 
2269deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a)
227098a9cb79SRichard Henderson {
22716fd0c7bcSRichard Henderson     TCGv_i64 dest, ofs;
2272eed14219SRichard Henderson     TCGv_i32 level, want;
22736fd0c7bcSRichard Henderson     TCGv_i64 addr;
227498a9cb79SRichard Henderson 
227598a9cb79SRichard Henderson     nullify_over(ctx);
227698a9cb79SRichard Henderson 
2277deee69a1SRichard Henderson     dest = dest_gpr(ctx, a->t);
2278deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2279eed14219SRichard Henderson 
2280deee69a1SRichard Henderson     if (a->imm) {
228129dd6f64SRichard Henderson         level = tcg_constant_i32(a->ri);
228298a9cb79SRichard Henderson     } else {
2283eed14219SRichard Henderson         level = tcg_temp_new_i32();
22846fd0c7bcSRichard Henderson         tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri));
2285eed14219SRichard Henderson         tcg_gen_andi_i32(level, level, 3);
228698a9cb79SRichard Henderson     }
228729dd6f64SRichard Henderson     want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ);
2288eed14219SRichard Henderson 
2289ad75a51eSRichard Henderson     gen_helper_probe(dest, tcg_env, addr, level, want);
2290eed14219SRichard Henderson 
2291deee69a1SRichard Henderson     save_gpr(ctx, a->t, dest);
229231234768SRichard Henderson     return nullify_end(ctx);
229398a9cb79SRichard Henderson }
229498a9cb79SRichard Henderson 
2295deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
22968d6ae7fbSRichard Henderson {
22978577f354SRichard Henderson     if (ctx->is_pa20) {
22988577f354SRichard Henderson         return false;
22998577f354SRichard Henderson     }
2300deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2301deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
23026fd0c7bcSRichard Henderson     TCGv_i64 addr;
23036fd0c7bcSRichard Henderson     TCGv_i64 ofs, reg;
23048d6ae7fbSRichard Henderson 
23058d6ae7fbSRichard Henderson     nullify_over(ctx);
23068d6ae7fbSRichard Henderson 
2307deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2308deee69a1SRichard Henderson     reg = load_gpr(ctx, a->r);
2309deee69a1SRichard Henderson     if (a->addr) {
23108577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
23118d6ae7fbSRichard Henderson     } else {
23128577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
23138d6ae7fbSRichard Henderson     }
23148d6ae7fbSRichard Henderson 
231532dc7569SSven Schnelle     /* Exit TB for TLB change if mmu is enabled.  */
231632dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
231731234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
231831234768SRichard Henderson     }
231931234768SRichard Henderson     return nullify_end(ctx);
2320deee69a1SRichard Henderson #endif
23218d6ae7fbSRichard Henderson }
232263300a00SRichard Henderson 
2323deee69a1SRichard Henderson static bool trans_pxtlbx(DisasContext *ctx, arg_pxtlbx *a)
232463300a00SRichard Henderson {
2325deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2326deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
23276fd0c7bcSRichard Henderson     TCGv_i64 addr;
23286fd0c7bcSRichard Henderson     TCGv_i64 ofs;
232963300a00SRichard Henderson 
233063300a00SRichard Henderson     nullify_over(ctx);
233163300a00SRichard Henderson 
2332deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2333deee69a1SRichard Henderson     if (a->m) {
2334deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
233563300a00SRichard Henderson     }
2336deee69a1SRichard Henderson     if (a->local) {
2337ad75a51eSRichard Henderson         gen_helper_ptlbe(tcg_env);
233863300a00SRichard Henderson     } else {
2339ad75a51eSRichard Henderson         gen_helper_ptlb(tcg_env, addr);
234063300a00SRichard Henderson     }
234163300a00SRichard Henderson 
234263300a00SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
234332dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
234431234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
234531234768SRichard Henderson     }
234631234768SRichard Henderson     return nullify_end(ctx);
2347deee69a1SRichard Henderson #endif
234863300a00SRichard Henderson }
23492dfcca9fSRichard Henderson 
23506797c315SNick Hudson /*
23516797c315SNick Hudson  * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
23526797c315SNick Hudson  * See
23536797c315SNick Hudson  *     https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
23546797c315SNick Hudson  *     page 13-9 (195/206)
23556797c315SNick Hudson  */
23566797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
23576797c315SNick Hudson {
23588577f354SRichard Henderson     if (ctx->is_pa20) {
23598577f354SRichard Henderson         return false;
23608577f354SRichard Henderson     }
23616797c315SNick Hudson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
23626797c315SNick Hudson #ifndef CONFIG_USER_ONLY
23636fd0c7bcSRichard Henderson     TCGv_i64 addr, atl, stl;
23646fd0c7bcSRichard Henderson     TCGv_i64 reg;
23656797c315SNick Hudson 
23666797c315SNick Hudson     nullify_over(ctx);
23676797c315SNick Hudson 
23686797c315SNick Hudson     /*
23696797c315SNick Hudson      * FIXME:
23706797c315SNick Hudson      *  if (not (pcxl or pcxl2))
23716797c315SNick Hudson      *    return gen_illegal(ctx);
23726797c315SNick Hudson      */
23736797c315SNick Hudson 
23746fd0c7bcSRichard Henderson     atl = tcg_temp_new_i64();
23756fd0c7bcSRichard Henderson     stl = tcg_temp_new_i64();
23766fd0c7bcSRichard Henderson     addr = tcg_temp_new_i64();
23776797c315SNick Hudson 
2378ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(stl, tcg_env,
23796797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
23806797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIASQ]));
2381ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(atl, tcg_env,
23826797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
23836797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIAOQ]));
23846797c315SNick Hudson     tcg_gen_shli_i64(stl, stl, 32);
23856797c315SNick Hudson     tcg_gen_or_tl(addr, atl, stl);
23866797c315SNick Hudson 
23876797c315SNick Hudson     reg = load_gpr(ctx, a->r);
23886797c315SNick Hudson     if (a->addr) {
23898577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
23906797c315SNick Hudson     } else {
23918577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
23926797c315SNick Hudson     }
23936797c315SNick Hudson 
23946797c315SNick Hudson     /* Exit TB for TLB change if mmu is enabled.  */
23956797c315SNick Hudson     if (ctx->tb_flags & PSW_C) {
23966797c315SNick Hudson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
23976797c315SNick Hudson     }
23986797c315SNick Hudson     return nullify_end(ctx);
23996797c315SNick Hudson #endif
24006797c315SNick Hudson }
24016797c315SNick Hudson 
24028577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
24038577f354SRichard Henderson {
24048577f354SRichard Henderson     if (!ctx->is_pa20) {
24058577f354SRichard Henderson         return false;
24068577f354SRichard Henderson     }
24078577f354SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24088577f354SRichard Henderson #ifndef CONFIG_USER_ONLY
24098577f354SRichard Henderson     nullify_over(ctx);
24108577f354SRichard Henderson     {
24118577f354SRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
24128577f354SRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->r2);
24138577f354SRichard Henderson 
24148577f354SRichard Henderson         if (a->data) {
24158577f354SRichard Henderson             gen_helper_idtlbt_pa20(tcg_env, src1, src2);
24168577f354SRichard Henderson         } else {
24178577f354SRichard Henderson             gen_helper_iitlbt_pa20(tcg_env, src1, src2);
24188577f354SRichard Henderson         }
24198577f354SRichard Henderson     }
24208577f354SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
24218577f354SRichard Henderson     if (ctx->tb_flags & PSW_C) {
24228577f354SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
24238577f354SRichard Henderson     }
24248577f354SRichard Henderson     return nullify_end(ctx);
24258577f354SRichard Henderson #endif
24268577f354SRichard Henderson }
24278577f354SRichard Henderson 
2428deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
24292dfcca9fSRichard Henderson {
2430deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2431deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
24326fd0c7bcSRichard Henderson     TCGv_i64 vaddr;
24336fd0c7bcSRichard Henderson     TCGv_i64 ofs, paddr;
24342dfcca9fSRichard Henderson 
24352dfcca9fSRichard Henderson     nullify_over(ctx);
24362dfcca9fSRichard Henderson 
2437deee69a1SRichard Henderson     form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
24382dfcca9fSRichard Henderson 
2439*aac0f603SRichard Henderson     paddr = tcg_temp_new_i64();
2440ad75a51eSRichard Henderson     gen_helper_lpa(paddr, tcg_env, vaddr);
24412dfcca9fSRichard Henderson 
24422dfcca9fSRichard Henderson     /* Note that physical address result overrides base modification.  */
2443deee69a1SRichard Henderson     if (a->m) {
2444deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
24452dfcca9fSRichard Henderson     }
2446deee69a1SRichard Henderson     save_gpr(ctx, a->t, paddr);
24472dfcca9fSRichard Henderson 
244831234768SRichard Henderson     return nullify_end(ctx);
2449deee69a1SRichard Henderson #endif
24502dfcca9fSRichard Henderson }
245143a97b81SRichard Henderson 
2452deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a)
245343a97b81SRichard Henderson {
245443a97b81SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
245543a97b81SRichard Henderson 
245643a97b81SRichard Henderson     /* The Coherence Index is an implementation-defined function of the
245743a97b81SRichard Henderson        physical address.  Two addresses with the same CI have a coherent
245843a97b81SRichard Henderson        view of the cache.  Our implementation is to return 0 for all,
245943a97b81SRichard Henderson        since the entire address space is coherent.  */
24606fd0c7bcSRichard Henderson     save_gpr(ctx, a->t, tcg_constant_i64(0));
246143a97b81SRichard Henderson 
246231234768SRichard Henderson     cond_free(&ctx->null_cond);
246331234768SRichard Henderson     return true;
246443a97b81SRichard Henderson }
246598a9cb79SRichard Henderson 
2466faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2467b2167459SRichard Henderson {
24680c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, false);
2469b2167459SRichard Henderson }
2470b2167459SRichard Henderson 
2471faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2472b2167459SRichard Henderson {
24730c982a28SRichard Henderson     return do_add_reg(ctx, a, true, false, false, false);
2474b2167459SRichard Henderson }
2475b2167459SRichard Henderson 
2476faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2477b2167459SRichard Henderson {
24780c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, false);
2479b2167459SRichard Henderson }
2480b2167459SRichard Henderson 
2481faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2482b2167459SRichard Henderson {
24830c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, true);
24840c982a28SRichard Henderson }
2485b2167459SRichard Henderson 
2486faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
24870c982a28SRichard Henderson {
24880c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, true);
24890c982a28SRichard Henderson }
24900c982a28SRichard Henderson 
249163c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
24920c982a28SRichard Henderson {
24930c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, false);
24940c982a28SRichard Henderson }
24950c982a28SRichard Henderson 
249663c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
24970c982a28SRichard Henderson {
24980c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, false);
24990c982a28SRichard Henderson }
25000c982a28SRichard Henderson 
250163c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
25020c982a28SRichard Henderson {
25030c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, true);
25040c982a28SRichard Henderson }
25050c982a28SRichard Henderson 
250663c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
25070c982a28SRichard Henderson {
25080c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, true);
25090c982a28SRichard Henderson }
25100c982a28SRichard Henderson 
251163c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
25120c982a28SRichard Henderson {
25130c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, true, false);
25140c982a28SRichard Henderson }
25150c982a28SRichard Henderson 
251663c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
25170c982a28SRichard Henderson {
25180c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, true, false);
25190c982a28SRichard Henderson }
25200c982a28SRichard Henderson 
2521fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
25220c982a28SRichard Henderson {
25236fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_andc_i64);
25240c982a28SRichard Henderson }
25250c982a28SRichard Henderson 
2526fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
25270c982a28SRichard Henderson {
25286fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_and_i64);
25290c982a28SRichard Henderson }
25300c982a28SRichard Henderson 
2531fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
25320c982a28SRichard Henderson {
25330c982a28SRichard Henderson     if (a->cf == 0) {
25340c982a28SRichard Henderson         unsigned r2 = a->r2;
25350c982a28SRichard Henderson         unsigned r1 = a->r1;
25360c982a28SRichard Henderson         unsigned rt = a->t;
25370c982a28SRichard Henderson 
25387aee8189SRichard Henderson         if (rt == 0) { /* NOP */
25397aee8189SRichard Henderson             cond_free(&ctx->null_cond);
25407aee8189SRichard Henderson             return true;
25417aee8189SRichard Henderson         }
25427aee8189SRichard Henderson         if (r2 == 0) { /* COPY */
2543b2167459SRichard Henderson             if (r1 == 0) {
25446fd0c7bcSRichard Henderson                 TCGv_i64 dest = dest_gpr(ctx, rt);
25456fd0c7bcSRichard Henderson                 tcg_gen_movi_i64(dest, 0);
2546b2167459SRichard Henderson                 save_gpr(ctx, rt, dest);
2547b2167459SRichard Henderson             } else {
2548b2167459SRichard Henderson                 save_gpr(ctx, rt, cpu_gr[r1]);
2549b2167459SRichard Henderson             }
2550b2167459SRichard Henderson             cond_free(&ctx->null_cond);
255131234768SRichard Henderson             return true;
2552b2167459SRichard Henderson         }
25537aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY
25547aee8189SRichard Henderson         /* These are QEMU extensions and are nops in the real architecture:
25557aee8189SRichard Henderson          *
25567aee8189SRichard Henderson          * or %r10,%r10,%r10 -- idle loop; wait for interrupt
25577aee8189SRichard Henderson          * or %r31,%r31,%r31 -- death loop; offline cpu
25587aee8189SRichard Henderson          *                      currently implemented as idle.
25597aee8189SRichard Henderson          */
25607aee8189SRichard Henderson         if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
25617aee8189SRichard Henderson             /* No need to check for supervisor, as userland can only pause
25627aee8189SRichard Henderson                until the next timer interrupt.  */
25637aee8189SRichard Henderson             nullify_over(ctx);
25647aee8189SRichard Henderson 
25657aee8189SRichard Henderson             /* Advance the instruction queue.  */
2566741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
2567741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
25687aee8189SRichard Henderson             nullify_set(ctx, 0);
25697aee8189SRichard Henderson 
25707aee8189SRichard Henderson             /* Tell the qemu main loop to halt until this cpu has work.  */
2571ad75a51eSRichard Henderson             tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
257229dd6f64SRichard Henderson                            offsetof(CPUState, halted) - offsetof(HPPACPU, env));
25737aee8189SRichard Henderson             gen_excp_1(EXCP_HALTED);
25747aee8189SRichard Henderson             ctx->base.is_jmp = DISAS_NORETURN;
25757aee8189SRichard Henderson 
25767aee8189SRichard Henderson             return nullify_end(ctx);
25777aee8189SRichard Henderson         }
25787aee8189SRichard Henderson #endif
25797aee8189SRichard Henderson     }
25806fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_or_i64);
25817aee8189SRichard Henderson }
2582b2167459SRichard Henderson 
2583fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
2584b2167459SRichard Henderson {
25856fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_xor_i64);
25860c982a28SRichard Henderson }
25870c982a28SRichard Henderson 
2588345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
25890c982a28SRichard Henderson {
25906fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2591b2167459SRichard Henderson 
25920c982a28SRichard Henderson     if (a->cf) {
2593b2167459SRichard Henderson         nullify_over(ctx);
2594b2167459SRichard Henderson     }
25950c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
25960c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2597345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
259831234768SRichard Henderson     return nullify_end(ctx);
2599b2167459SRichard Henderson }
2600b2167459SRichard Henderson 
2601af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
2602b2167459SRichard Henderson {
26036fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2604b2167459SRichard Henderson 
26050c982a28SRichard Henderson     if (a->cf) {
2606b2167459SRichard Henderson         nullify_over(ctx);
2607b2167459SRichard Henderson     }
26080c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26090c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
26106fd0c7bcSRichard Henderson     do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64);
261131234768SRichard Henderson     return nullify_end(ctx);
2612b2167459SRichard Henderson }
2613b2167459SRichard Henderson 
2614af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
2615b2167459SRichard Henderson {
26166fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, tmp;
2617b2167459SRichard Henderson 
26180c982a28SRichard Henderson     if (a->cf) {
2619b2167459SRichard Henderson         nullify_over(ctx);
2620b2167459SRichard Henderson     }
26210c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26220c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2623*aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
26246fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, tcg_r2);
26256fd0c7bcSRichard Henderson     do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64);
262631234768SRichard Henderson     return nullify_end(ctx);
2627b2167459SRichard Henderson }
2628b2167459SRichard Henderson 
2629af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
2630b2167459SRichard Henderson {
26310c982a28SRichard Henderson     return do_uaddcm(ctx, a, false);
26320c982a28SRichard Henderson }
26330c982a28SRichard Henderson 
2634af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
26350c982a28SRichard Henderson {
26360c982a28SRichard Henderson     return do_uaddcm(ctx, a, true);
26370c982a28SRichard Henderson }
26380c982a28SRichard Henderson 
2639af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
26400c982a28SRichard Henderson {
26416fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2642b2167459SRichard Henderson 
2643b2167459SRichard Henderson     nullify_over(ctx);
2644b2167459SRichard Henderson 
2645*aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
26466fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, cpu_psw_cb, 3);
2647b2167459SRichard Henderson     if (!is_i) {
26486fd0c7bcSRichard Henderson         tcg_gen_not_i64(tmp, tmp);
2649b2167459SRichard Henderson     }
26506fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
26516fd0c7bcSRichard Henderson     tcg_gen_muli_i64(tmp, tmp, 6);
2652af240753SRichard Henderson     do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false,
26536fd0c7bcSRichard Henderson             is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64);
265431234768SRichard Henderson     return nullify_end(ctx);
2655b2167459SRichard Henderson }
2656b2167459SRichard Henderson 
2657af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
2658b2167459SRichard Henderson {
26590c982a28SRichard Henderson     return do_dcor(ctx, a, false);
26600c982a28SRichard Henderson }
26610c982a28SRichard Henderson 
2662af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
26630c982a28SRichard Henderson {
26640c982a28SRichard Henderson     return do_dcor(ctx, a, true);
26650c982a28SRichard Henderson }
26660c982a28SRichard Henderson 
26670c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
26680c982a28SRichard Henderson {
26696fd0c7bcSRichard Henderson     TCGv_i64 dest, add1, add2, addc, zero, in1, in2;
26706fd0c7bcSRichard Henderson     TCGv_i64 cout;
2671b2167459SRichard Henderson 
2672b2167459SRichard Henderson     nullify_over(ctx);
2673b2167459SRichard Henderson 
26740c982a28SRichard Henderson     in1 = load_gpr(ctx, a->r1);
26750c982a28SRichard Henderson     in2 = load_gpr(ctx, a->r2);
2676b2167459SRichard Henderson 
2677*aac0f603SRichard Henderson     add1 = tcg_temp_new_i64();
2678*aac0f603SRichard Henderson     add2 = tcg_temp_new_i64();
2679*aac0f603SRichard Henderson     addc = tcg_temp_new_i64();
2680*aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
26816fd0c7bcSRichard Henderson     zero = tcg_constant_i64(0);
2682b2167459SRichard Henderson 
2683b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
26846fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, in1, in1);
26856fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
2686b2167459SRichard Henderson 
268772ca8753SRichard Henderson     /*
268872ca8753SRichard Henderson      * Add or subtract R2, depending on PSW[V].  Proper computation of
268972ca8753SRichard Henderson      * carry requires that we subtract via + ~R2 + 1, as described in
269072ca8753SRichard Henderson      * the manual.  By extracting and masking V, we can produce the
269172ca8753SRichard Henderson      * proper inputs to the addition without movcond.
269272ca8753SRichard Henderson      */
26936fd0c7bcSRichard Henderson     tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
26946fd0c7bcSRichard Henderson     tcg_gen_xor_i64(add2, in2, addc);
26956fd0c7bcSRichard Henderson     tcg_gen_andi_i64(addc, addc, 1);
269672ca8753SRichard Henderson 
26976fd0c7bcSRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
26986fd0c7bcSRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
2699b2167459SRichard Henderson 
2700b2167459SRichard Henderson     /* Write back the result register.  */
27010c982a28SRichard Henderson     save_gpr(ctx, a->t, dest);
2702b2167459SRichard Henderson 
2703b2167459SRichard Henderson     /* Write back PSW[CB].  */
27046fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
27056fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
2706b2167459SRichard Henderson 
2707b2167459SRichard Henderson     /* Write back PSW[V] for the division step.  */
270872ca8753SRichard Henderson     cout = get_psw_carry(ctx, false);
27096fd0c7bcSRichard Henderson     tcg_gen_neg_i64(cpu_psw_v, cout);
27106fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
2711b2167459SRichard Henderson 
2712b2167459SRichard Henderson     /* Install the new nullification.  */
27130c982a28SRichard Henderson     if (a->cf) {
27146fd0c7bcSRichard Henderson         TCGv_i64 sv = NULL;
2715b47a4a02SSven Schnelle         if (cond_need_sv(a->cf >> 1)) {
2716b2167459SRichard Henderson             /* ??? The lshift is supposed to contribute to overflow.  */
2717b2167459SRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2);
2718b2167459SRichard Henderson         }
2719a751eb31SRichard Henderson         ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv);
2720b2167459SRichard Henderson     }
2721b2167459SRichard Henderson 
272231234768SRichard Henderson     return nullify_end(ctx);
2723b2167459SRichard Henderson }
2724b2167459SRichard Henderson 
27250588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a)
2726b2167459SRichard Henderson {
27270588e061SRichard Henderson     return do_add_imm(ctx, a, false, false);
27280588e061SRichard Henderson }
27290588e061SRichard Henderson 
27300588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a)
27310588e061SRichard Henderson {
27320588e061SRichard Henderson     return do_add_imm(ctx, a, true, false);
27330588e061SRichard Henderson }
27340588e061SRichard Henderson 
27350588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a)
27360588e061SRichard Henderson {
27370588e061SRichard Henderson     return do_add_imm(ctx, a, false, true);
27380588e061SRichard Henderson }
27390588e061SRichard Henderson 
27400588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a)
27410588e061SRichard Henderson {
27420588e061SRichard Henderson     return do_add_imm(ctx, a, true, true);
27430588e061SRichard Henderson }
27440588e061SRichard Henderson 
27450588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a)
27460588e061SRichard Henderson {
27470588e061SRichard Henderson     return do_sub_imm(ctx, a, false);
27480588e061SRichard Henderson }
27490588e061SRichard Henderson 
27500588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
27510588e061SRichard Henderson {
27520588e061SRichard Henderson     return do_sub_imm(ctx, a, true);
27530588e061SRichard Henderson }
27540588e061SRichard Henderson 
2755345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
27560588e061SRichard Henderson {
27576fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
2758b2167459SRichard Henderson 
27590588e061SRichard Henderson     if (a->cf) {
2760b2167459SRichard Henderson         nullify_over(ctx);
2761b2167459SRichard Henderson     }
2762b2167459SRichard Henderson 
27636fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
27640588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
2765345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
2766b2167459SRichard Henderson 
276731234768SRichard Henderson     return nullify_end(ctx);
2768b2167459SRichard Henderson }
2769b2167459SRichard Henderson 
27701cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a)
277196d6407fSRichard Henderson {
2772c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
27730786a3b6SHelge Deller         return gen_illegal(ctx);
2774c53e401eSRichard Henderson     }
27751cd012a5SRichard Henderson     return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
27761cd012a5SRichard Henderson                    a->disp, a->sp, a->m, a->size | MO_TE);
277796d6407fSRichard Henderson }
277896d6407fSRichard Henderson 
27791cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a)
278096d6407fSRichard Henderson {
27811cd012a5SRichard Henderson     assert(a->x == 0 && a->scale == 0);
2782c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
27830786a3b6SHelge Deller         return gen_illegal(ctx);
278496d6407fSRichard Henderson     }
2785c53e401eSRichard Henderson     return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
27860786a3b6SHelge Deller }
278796d6407fSRichard Henderson 
27881cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
278996d6407fSRichard Henderson {
2790b1af755cSRichard Henderson     MemOp mop = MO_TE | MO_ALIGN | a->size;
27916fd0c7bcSRichard Henderson     TCGv_i64 zero, dest, ofs;
27926fd0c7bcSRichard Henderson     TCGv_i64 addr;
279396d6407fSRichard Henderson 
2794c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
279551416c4eSRichard Henderson         return gen_illegal(ctx);
279651416c4eSRichard Henderson     }
279751416c4eSRichard Henderson 
279896d6407fSRichard Henderson     nullify_over(ctx);
279996d6407fSRichard Henderson 
28001cd012a5SRichard Henderson     if (a->m) {
280186f8d05fSRichard Henderson         /* Base register modification.  Make sure if RT == RB,
280286f8d05fSRichard Henderson            we see the result of the load.  */
2803*aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
280496d6407fSRichard Henderson     } else {
28051cd012a5SRichard Henderson         dest = dest_gpr(ctx, a->t);
280696d6407fSRichard Henderson     }
280796d6407fSRichard Henderson 
28081cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0,
28091cd012a5SRichard Henderson              a->disp, a->sp, a->m, ctx->mmu_idx == MMU_PHYS_IDX);
2810b1af755cSRichard Henderson 
2811b1af755cSRichard Henderson     /*
2812b1af755cSRichard Henderson      * For hppa1.1, LDCW is undefined unless aligned mod 16.
2813b1af755cSRichard Henderson      * However actual hardware succeeds with aligned mod 4.
2814b1af755cSRichard Henderson      * Detect this case and log a GUEST_ERROR.
2815b1af755cSRichard Henderson      *
2816b1af755cSRichard Henderson      * TODO: HPPA64 relaxes the over-alignment requirement
2817b1af755cSRichard Henderson      * with the ,co completer.
2818b1af755cSRichard Henderson      */
2819b1af755cSRichard Henderson     gen_helper_ldc_check(addr);
2820b1af755cSRichard Henderson 
28216fd0c7bcSRichard Henderson     zero = tcg_constant_i64(0);
28226fd0c7bcSRichard Henderson     tcg_gen_atomic_xchg_i64(dest, addr, zero, ctx->mmu_idx, mop);
2823b1af755cSRichard Henderson 
28241cd012a5SRichard Henderson     if (a->m) {
28251cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
282696d6407fSRichard Henderson     }
28271cd012a5SRichard Henderson     save_gpr(ctx, a->t, dest);
282896d6407fSRichard Henderson 
282931234768SRichard Henderson     return nullify_end(ctx);
283096d6407fSRichard Henderson }
283196d6407fSRichard Henderson 
28321cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a)
283396d6407fSRichard Henderson {
28346fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
28356fd0c7bcSRichard Henderson     TCGv_i64 addr;
283696d6407fSRichard Henderson 
283796d6407fSRichard Henderson     nullify_over(ctx);
283896d6407fSRichard Henderson 
28391cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
284086f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
28411cd012a5SRichard Henderson     val = load_gpr(ctx, a->r);
28421cd012a5SRichard Henderson     if (a->a) {
2843f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
2844ad75a51eSRichard Henderson             gen_helper_stby_e_parallel(tcg_env, addr, val);
2845f9f46db4SEmilio G. Cota         } else {
2846ad75a51eSRichard Henderson             gen_helper_stby_e(tcg_env, addr, val);
2847f9f46db4SEmilio G. Cota         }
2848f9f46db4SEmilio G. Cota     } else {
2849f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
2850ad75a51eSRichard Henderson             gen_helper_stby_b_parallel(tcg_env, addr, val);
285196d6407fSRichard Henderson         } else {
2852ad75a51eSRichard Henderson             gen_helper_stby_b(tcg_env, addr, val);
285396d6407fSRichard Henderson         }
2854f9f46db4SEmilio G. Cota     }
28551cd012a5SRichard Henderson     if (a->m) {
28566fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~3);
28571cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
285896d6407fSRichard Henderson     }
285996d6407fSRichard Henderson 
286031234768SRichard Henderson     return nullify_end(ctx);
286196d6407fSRichard Henderson }
286296d6407fSRichard Henderson 
286325460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a)
286425460fc5SRichard Henderson {
28656fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
28666fd0c7bcSRichard Henderson     TCGv_i64 addr;
286725460fc5SRichard Henderson 
286825460fc5SRichard Henderson     if (!ctx->is_pa20) {
286925460fc5SRichard Henderson         return false;
287025460fc5SRichard Henderson     }
287125460fc5SRichard Henderson     nullify_over(ctx);
287225460fc5SRichard Henderson 
287325460fc5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
287425460fc5SRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
287525460fc5SRichard Henderson     val = load_gpr(ctx, a->r);
287625460fc5SRichard Henderson     if (a->a) {
287725460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
287825460fc5SRichard Henderson             gen_helper_stdby_e_parallel(tcg_env, addr, val);
287925460fc5SRichard Henderson         } else {
288025460fc5SRichard Henderson             gen_helper_stdby_e(tcg_env, addr, val);
288125460fc5SRichard Henderson         }
288225460fc5SRichard Henderson     } else {
288325460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
288425460fc5SRichard Henderson             gen_helper_stdby_b_parallel(tcg_env, addr, val);
288525460fc5SRichard Henderson         } else {
288625460fc5SRichard Henderson             gen_helper_stdby_b(tcg_env, addr, val);
288725460fc5SRichard Henderson         }
288825460fc5SRichard Henderson     }
288925460fc5SRichard Henderson     if (a->m) {
28906fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~7);
289125460fc5SRichard Henderson         save_gpr(ctx, a->b, ofs);
289225460fc5SRichard Henderson     }
289325460fc5SRichard Henderson 
289425460fc5SRichard Henderson     return nullify_end(ctx);
289525460fc5SRichard Henderson }
289625460fc5SRichard Henderson 
28971cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a)
2898d0a851ccSRichard Henderson {
2899d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
2900d0a851ccSRichard Henderson 
2901d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2902d0a851ccSRichard Henderson     ctx->mmu_idx = MMU_PHYS_IDX;
29031cd012a5SRichard Henderson     trans_ld(ctx, a);
2904d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
290531234768SRichard Henderson     return true;
2906d0a851ccSRichard Henderson }
2907d0a851ccSRichard Henderson 
29081cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a)
2909d0a851ccSRichard Henderson {
2910d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
2911d0a851ccSRichard Henderson 
2912d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2913d0a851ccSRichard Henderson     ctx->mmu_idx = MMU_PHYS_IDX;
29141cd012a5SRichard Henderson     trans_st(ctx, a);
2915d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
291631234768SRichard Henderson     return true;
2917d0a851ccSRichard Henderson }
291895412a61SRichard Henderson 
29190588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
2920b2167459SRichard Henderson {
29216fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
2922b2167459SRichard Henderson 
29236fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tcg_rt, a->i);
29240588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
2925b2167459SRichard Henderson     cond_free(&ctx->null_cond);
292631234768SRichard Henderson     return true;
2927b2167459SRichard Henderson }
2928b2167459SRichard Henderson 
29290588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a)
2930b2167459SRichard Henderson {
29316fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
29326fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
2933b2167459SRichard Henderson 
29346fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
2935b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
2936b2167459SRichard Henderson     cond_free(&ctx->null_cond);
293731234768SRichard Henderson     return true;
2938b2167459SRichard Henderson }
2939b2167459SRichard Henderson 
29400588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
2941b2167459SRichard Henderson {
29426fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
2943b2167459SRichard Henderson 
2944b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
2945b2167459SRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_tl.  */
29460588e061SRichard Henderson     if (a->b == 0) {
29476fd0c7bcSRichard Henderson         tcg_gen_movi_i64(tcg_rt, a->i);
2948b2167459SRichard Henderson     } else {
29496fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
2950b2167459SRichard Henderson     }
29510588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
2952b2167459SRichard Henderson     cond_free(&ctx->null_cond);
295331234768SRichard Henderson     return true;
2954b2167459SRichard Henderson }
2955b2167459SRichard Henderson 
29566fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
2957e9efd4bcSRichard Henderson                     unsigned c, unsigned f, bool d, unsigned n, int disp)
295898cd9ca7SRichard Henderson {
29596fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv;
296098cd9ca7SRichard Henderson     DisasCond cond;
296198cd9ca7SRichard Henderson 
296298cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
2963*aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
296498cd9ca7SRichard Henderson 
29656fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
296698cd9ca7SRichard Henderson 
2967f764718dSRichard Henderson     sv = NULL;
2968b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
296998cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
297098cd9ca7SRichard Henderson     }
297198cd9ca7SRichard Henderson 
29724fe9533aSRichard Henderson     cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
297301afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
297498cd9ca7SRichard Henderson }
297598cd9ca7SRichard Henderson 
297601afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
297798cd9ca7SRichard Henderson {
2978e9efd4bcSRichard Henderson     if (!ctx->is_pa20 && a->d) {
2979e9efd4bcSRichard Henderson         return false;
2980e9efd4bcSRichard Henderson     }
298101afb7beSRichard Henderson     nullify_over(ctx);
2982e9efd4bcSRichard Henderson     return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
2983e9efd4bcSRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
298401afb7beSRichard Henderson }
298501afb7beSRichard Henderson 
298601afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
298701afb7beSRichard Henderson {
2988c65c3ee1SRichard Henderson     if (!ctx->is_pa20 && a->d) {
2989c65c3ee1SRichard Henderson         return false;
2990c65c3ee1SRichard Henderson     }
299101afb7beSRichard Henderson     nullify_over(ctx);
29926fd0c7bcSRichard Henderson     return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
2993c65c3ee1SRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
299401afb7beSRichard Henderson }
299501afb7beSRichard Henderson 
29966fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
299701afb7beSRichard Henderson                     unsigned c, unsigned f, unsigned n, int disp)
299801afb7beSRichard Henderson {
29996fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv, cb_cond;
300098cd9ca7SRichard Henderson     DisasCond cond;
3001bdcccc17SRichard Henderson     bool d = false;
300298cd9ca7SRichard Henderson 
3003f25d3160SRichard Henderson     /*
3004f25d3160SRichard Henderson      * For hppa64, the ADDB conditions change with PSW.W,
3005f25d3160SRichard Henderson      * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3006f25d3160SRichard Henderson      */
3007f25d3160SRichard Henderson     if (ctx->tb_flags & PSW_W) {
3008f25d3160SRichard Henderson         d = c >= 5;
3009f25d3160SRichard Henderson         if (d) {
3010f25d3160SRichard Henderson             c &= 3;
3011f25d3160SRichard Henderson         }
3012f25d3160SRichard Henderson     }
3013f25d3160SRichard Henderson 
301498cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3015*aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
3016f764718dSRichard Henderson     sv = NULL;
3017bdcccc17SRichard Henderson     cb_cond = NULL;
301898cd9ca7SRichard Henderson 
3019b47a4a02SSven Schnelle     if (cond_need_cb(c)) {
3020*aac0f603SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
3021*aac0f603SRichard Henderson         TCGv_i64 cb_msb = tcg_temp_new_i64();
3022bdcccc17SRichard Henderson 
30236fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cb_msb, 0);
30246fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
30256fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
30266fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
3027bdcccc17SRichard Henderson         cb_cond = get_carry(ctx, d, cb, cb_msb);
3028b47a4a02SSven Schnelle     } else {
30296fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
3030b47a4a02SSven Schnelle     }
3031b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
303298cd9ca7SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
303398cd9ca7SRichard Henderson     }
303498cd9ca7SRichard Henderson 
3035a751eb31SRichard Henderson     cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
303643675d20SSven Schnelle     save_gpr(ctx, r, dest);
303701afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
303898cd9ca7SRichard Henderson }
303998cd9ca7SRichard Henderson 
304001afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a)
304198cd9ca7SRichard Henderson {
304201afb7beSRichard Henderson     nullify_over(ctx);
304301afb7beSRichard Henderson     return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
304401afb7beSRichard Henderson }
304501afb7beSRichard Henderson 
304601afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
304701afb7beSRichard Henderson {
304801afb7beSRichard Henderson     nullify_over(ctx);
30496fd0c7bcSRichard Henderson     return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
305001afb7beSRichard Henderson }
305101afb7beSRichard Henderson 
305201afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
305301afb7beSRichard Henderson {
30546fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
305598cd9ca7SRichard Henderson     DisasCond cond;
305698cd9ca7SRichard Henderson 
305798cd9ca7SRichard Henderson     nullify_over(ctx);
305898cd9ca7SRichard Henderson 
3059*aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
306001afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
306184e224d4SRichard Henderson     if (cond_need_ext(ctx, a->d)) {
30621e9ab9fbSRichard Henderson         /* Force shift into [32,63] */
30636fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_sar, 32);
30646fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, tmp);
30651e9ab9fbSRichard Henderson     } else {
30666fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
30671e9ab9fbSRichard Henderson     }
306898cd9ca7SRichard Henderson 
30691e9ab9fbSRichard Henderson     cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
307001afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
307198cd9ca7SRichard Henderson }
307298cd9ca7SRichard Henderson 
307301afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
307498cd9ca7SRichard Henderson {
30756fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
307601afb7beSRichard Henderson     DisasCond cond;
30771e9ab9fbSRichard Henderson     int p;
307801afb7beSRichard Henderson 
307901afb7beSRichard Henderson     nullify_over(ctx);
308001afb7beSRichard Henderson 
3081*aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
308201afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
308384e224d4SRichard Henderson     p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0);
30846fd0c7bcSRichard Henderson     tcg_gen_shli_i64(tmp, tcg_r, p);
308501afb7beSRichard Henderson 
308601afb7beSRichard Henderson     cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
308701afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
308801afb7beSRichard Henderson }
308901afb7beSRichard Henderson 
309001afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a)
309101afb7beSRichard Henderson {
30926fd0c7bcSRichard Henderson     TCGv_i64 dest;
309398cd9ca7SRichard Henderson     DisasCond cond;
309498cd9ca7SRichard Henderson 
309598cd9ca7SRichard Henderson     nullify_over(ctx);
309698cd9ca7SRichard Henderson 
309701afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r2);
309801afb7beSRichard Henderson     if (a->r1 == 0) {
30996fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, 0);
310098cd9ca7SRichard Henderson     } else {
31016fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
310298cd9ca7SRichard Henderson     }
310398cd9ca7SRichard Henderson 
31044fa52edfSRichard Henderson     /* All MOVB conditions are 32-bit. */
31054fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
310601afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
310701afb7beSRichard Henderson }
310801afb7beSRichard Henderson 
310901afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
311001afb7beSRichard Henderson {
31116fd0c7bcSRichard Henderson     TCGv_i64 dest;
311201afb7beSRichard Henderson     DisasCond cond;
311301afb7beSRichard Henderson 
311401afb7beSRichard Henderson     nullify_over(ctx);
311501afb7beSRichard Henderson 
311601afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r);
31176fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, a->i);
311801afb7beSRichard Henderson 
31194fa52edfSRichard Henderson     /* All MOVBI conditions are 32-bit. */
31204fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
312101afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
312298cd9ca7SRichard Henderson }
312398cd9ca7SRichard Henderson 
3124f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
31250b1347d2SRichard Henderson {
31266fd0c7bcSRichard Henderson     TCGv_i64 dest, src2;
31270b1347d2SRichard Henderson 
3128f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3129f7b775a9SRichard Henderson         return false;
3130f7b775a9SRichard Henderson     }
313130878590SRichard Henderson     if (a->c) {
31320b1347d2SRichard Henderson         nullify_over(ctx);
31330b1347d2SRichard Henderson     }
31340b1347d2SRichard Henderson 
313530878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
3136f7b775a9SRichard Henderson     src2 = load_gpr(ctx, a->r2);
313730878590SRichard Henderson     if (a->r1 == 0) {
3138f7b775a9SRichard Henderson         if (a->d) {
31396fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src2, cpu_sar);
3140f7b775a9SRichard Henderson         } else {
3141*aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
3142f7b775a9SRichard Henderson 
31436fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src2);
31446fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
31456fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, dest, tmp);
3146f7b775a9SRichard Henderson         }
314730878590SRichard Henderson     } else if (a->r1 == a->r2) {
3148f7b775a9SRichard Henderson         if (a->d) {
31496fd0c7bcSRichard Henderson             tcg_gen_rotr_i64(dest, src2, cpu_sar);
3150f7b775a9SRichard Henderson         } else {
31510b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
3152e1d635e8SRichard Henderson             TCGv_i32 s32 = tcg_temp_new_i32();
3153e1d635e8SRichard Henderson 
31546fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, src2);
31556fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(s32, cpu_sar);
3156f7b775a9SRichard Henderson             tcg_gen_andi_i32(s32, s32, 31);
3157e1d635e8SRichard Henderson             tcg_gen_rotr_i32(t32, t32, s32);
31586fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
3159f7b775a9SRichard Henderson         }
3160f7b775a9SRichard Henderson     } else {
31616fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
3162f7b775a9SRichard Henderson 
3163f7b775a9SRichard Henderson         if (a->d) {
3164*aac0f603SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
3165*aac0f603SRichard Henderson             TCGv_i64 n = tcg_temp_new_i64();
3166f7b775a9SRichard Henderson 
31676fd0c7bcSRichard Henderson             tcg_gen_xori_i64(n, cpu_sar, 63);
31686fd0c7bcSRichard Henderson             tcg_gen_shl_i64(t, src2, n);
31696fd0c7bcSRichard Henderson             tcg_gen_shli_i64(t, t, 1);
31706fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src1, cpu_sar);
31716fd0c7bcSRichard Henderson             tcg_gen_or_i64(dest, dest, t);
31720b1347d2SRichard Henderson         } else {
31730b1347d2SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
31740b1347d2SRichard Henderson             TCGv_i64 s = tcg_temp_new_i64();
31750b1347d2SRichard Henderson 
31766fd0c7bcSRichard Henderson             tcg_gen_concat32_i64(t, src2, src1);
3177967662cdSRichard Henderson             tcg_gen_andi_i64(s, cpu_sar, 31);
3178967662cdSRichard Henderson             tcg_gen_shr_i64(dest, t, s);
31790b1347d2SRichard Henderson         }
3180f7b775a9SRichard Henderson     }
318130878590SRichard Henderson     save_gpr(ctx, a->t, dest);
31820b1347d2SRichard Henderson 
31830b1347d2SRichard Henderson     /* Install the new nullification.  */
31840b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
318530878590SRichard Henderson     if (a->c) {
31864fa52edfSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
31870b1347d2SRichard Henderson     }
318831234768SRichard Henderson     return nullify_end(ctx);
31890b1347d2SRichard Henderson }
31900b1347d2SRichard Henderson 
3191f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
31920b1347d2SRichard Henderson {
3193f7b775a9SRichard Henderson     unsigned width, sa;
31946fd0c7bcSRichard Henderson     TCGv_i64 dest, t2;
31950b1347d2SRichard Henderson 
3196f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3197f7b775a9SRichard Henderson         return false;
3198f7b775a9SRichard Henderson     }
319930878590SRichard Henderson     if (a->c) {
32000b1347d2SRichard Henderson         nullify_over(ctx);
32010b1347d2SRichard Henderson     }
32020b1347d2SRichard Henderson 
3203f7b775a9SRichard Henderson     width = a->d ? 64 : 32;
3204f7b775a9SRichard Henderson     sa = width - 1 - a->cpos;
3205f7b775a9SRichard Henderson 
320630878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
320730878590SRichard Henderson     t2 = load_gpr(ctx, a->r2);
320805bfd4dbSRichard Henderson     if (a->r1 == 0) {
32096fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, t2, sa, width - sa);
3210c53e401eSRichard Henderson     } else if (width == TARGET_LONG_BITS) {
32116fd0c7bcSRichard Henderson         tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
3212f7b775a9SRichard Henderson     } else {
3213f7b775a9SRichard Henderson         assert(!a->d);
3214f7b775a9SRichard Henderson         if (a->r1 == a->r2) {
32150b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
32166fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, t2);
32170b1347d2SRichard Henderson             tcg_gen_rotri_i32(t32, t32, sa);
32186fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
32190b1347d2SRichard Henderson         } else {
3220967662cdSRichard Henderson             tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]);
3221967662cdSRichard Henderson             tcg_gen_extract_i64(dest, dest, sa, 32);
32220b1347d2SRichard Henderson         }
3223f7b775a9SRichard Henderson     }
322430878590SRichard Henderson     save_gpr(ctx, a->t, dest);
32250b1347d2SRichard Henderson 
32260b1347d2SRichard Henderson     /* Install the new nullification.  */
32270b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
322830878590SRichard Henderson     if (a->c) {
32294fa52edfSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
32300b1347d2SRichard Henderson     }
323131234768SRichard Henderson     return nullify_end(ctx);
32320b1347d2SRichard Henderson }
32330b1347d2SRichard Henderson 
3234bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
32350b1347d2SRichard Henderson {
3236bd792da3SRichard Henderson     unsigned widthm1 = a->d ? 63 : 31;
32376fd0c7bcSRichard Henderson     TCGv_i64 dest, src, tmp;
32380b1347d2SRichard Henderson 
3239bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3240bd792da3SRichard Henderson         return false;
3241bd792da3SRichard Henderson     }
324230878590SRichard Henderson     if (a->c) {
32430b1347d2SRichard Henderson         nullify_over(ctx);
32440b1347d2SRichard Henderson     }
32450b1347d2SRichard Henderson 
324630878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
324730878590SRichard Henderson     src = load_gpr(ctx, a->r);
3248*aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
32490b1347d2SRichard Henderson 
32500b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
32516fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
32526fd0c7bcSRichard Henderson     tcg_gen_xori_i64(tmp, tmp, widthm1);
3253d781cb77SRichard Henderson 
325430878590SRichard Henderson     if (a->se) {
3255bd792da3SRichard Henderson         if (!a->d) {
32566fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(dest, src);
3257bd792da3SRichard Henderson             src = dest;
3258bd792da3SRichard Henderson         }
32596fd0c7bcSRichard Henderson         tcg_gen_sar_i64(dest, src, tmp);
32606fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, dest, 0, a->len);
32610b1347d2SRichard Henderson     } else {
3262bd792da3SRichard Henderson         if (!a->d) {
32636fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src);
3264bd792da3SRichard Henderson             src = dest;
3265bd792da3SRichard Henderson         }
32666fd0c7bcSRichard Henderson         tcg_gen_shr_i64(dest, src, tmp);
32676fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, dest, 0, a->len);
32680b1347d2SRichard Henderson     }
326930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
32700b1347d2SRichard Henderson 
32710b1347d2SRichard Henderson     /* Install the new nullification.  */
32720b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
327330878590SRichard Henderson     if (a->c) {
3274bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
32750b1347d2SRichard Henderson     }
327631234768SRichard Henderson     return nullify_end(ctx);
32770b1347d2SRichard Henderson }
32780b1347d2SRichard Henderson 
3279bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
32800b1347d2SRichard Henderson {
3281bd792da3SRichard Henderson     unsigned len, cpos, width;
32826fd0c7bcSRichard Henderson     TCGv_i64 dest, src;
32830b1347d2SRichard Henderson 
3284bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3285bd792da3SRichard Henderson         return false;
3286bd792da3SRichard Henderson     }
328730878590SRichard Henderson     if (a->c) {
32880b1347d2SRichard Henderson         nullify_over(ctx);
32890b1347d2SRichard Henderson     }
32900b1347d2SRichard Henderson 
3291bd792da3SRichard Henderson     len = a->len;
3292bd792da3SRichard Henderson     width = a->d ? 64 : 32;
3293bd792da3SRichard Henderson     cpos = width - 1 - a->pos;
3294bd792da3SRichard Henderson     if (cpos + len > width) {
3295bd792da3SRichard Henderson         len = width - cpos;
3296bd792da3SRichard Henderson     }
3297bd792da3SRichard Henderson 
329830878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
329930878590SRichard Henderson     src = load_gpr(ctx, a->r);
330030878590SRichard Henderson     if (a->se) {
33016fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, src, cpos, len);
33020b1347d2SRichard Henderson     } else {
33036fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, src, cpos, len);
33040b1347d2SRichard Henderson     }
330530878590SRichard Henderson     save_gpr(ctx, a->t, dest);
33060b1347d2SRichard Henderson 
33070b1347d2SRichard Henderson     /* Install the new nullification.  */
33080b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
330930878590SRichard Henderson     if (a->c) {
3310bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
33110b1347d2SRichard Henderson     }
331231234768SRichard Henderson     return nullify_end(ctx);
33130b1347d2SRichard Henderson }
33140b1347d2SRichard Henderson 
331572ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
33160b1347d2SRichard Henderson {
331772ae4f2bSRichard Henderson     unsigned len, width;
3318c53e401eSRichard Henderson     uint64_t mask0, mask1;
33196fd0c7bcSRichard Henderson     TCGv_i64 dest;
33200b1347d2SRichard Henderson 
332172ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
332272ae4f2bSRichard Henderson         return false;
332372ae4f2bSRichard Henderson     }
332430878590SRichard Henderson     if (a->c) {
33250b1347d2SRichard Henderson         nullify_over(ctx);
33260b1347d2SRichard Henderson     }
332772ae4f2bSRichard Henderson 
332872ae4f2bSRichard Henderson     len = a->len;
332972ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
333072ae4f2bSRichard Henderson     if (a->cpos + len > width) {
333172ae4f2bSRichard Henderson         len = width - a->cpos;
33320b1347d2SRichard Henderson     }
33330b1347d2SRichard Henderson 
333430878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
333530878590SRichard Henderson     mask0 = deposit64(0, a->cpos, len, a->i);
333630878590SRichard Henderson     mask1 = deposit64(-1, a->cpos, len, a->i);
33370b1347d2SRichard Henderson 
333830878590SRichard Henderson     if (a->nz) {
33396fd0c7bcSRichard Henderson         TCGv_i64 src = load_gpr(ctx, a->t);
33406fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, src, mask1);
33416fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, mask0);
33420b1347d2SRichard Henderson     } else {
33436fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, mask0);
33440b1347d2SRichard Henderson     }
334530878590SRichard Henderson     save_gpr(ctx, a->t, dest);
33460b1347d2SRichard Henderson 
33470b1347d2SRichard Henderson     /* Install the new nullification.  */
33480b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
334930878590SRichard Henderson     if (a->c) {
335072ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
33510b1347d2SRichard Henderson     }
335231234768SRichard Henderson     return nullify_end(ctx);
33530b1347d2SRichard Henderson }
33540b1347d2SRichard Henderson 
335572ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
33560b1347d2SRichard Henderson {
335730878590SRichard Henderson     unsigned rs = a->nz ? a->t : 0;
335872ae4f2bSRichard Henderson     unsigned len, width;
33596fd0c7bcSRichard Henderson     TCGv_i64 dest, val;
33600b1347d2SRichard Henderson 
336172ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
336272ae4f2bSRichard Henderson         return false;
336372ae4f2bSRichard Henderson     }
336430878590SRichard Henderson     if (a->c) {
33650b1347d2SRichard Henderson         nullify_over(ctx);
33660b1347d2SRichard Henderson     }
336772ae4f2bSRichard Henderson 
336872ae4f2bSRichard Henderson     len = a->len;
336972ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
337072ae4f2bSRichard Henderson     if (a->cpos + len > width) {
337172ae4f2bSRichard Henderson         len = width - a->cpos;
33720b1347d2SRichard Henderson     }
33730b1347d2SRichard Henderson 
337430878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
337530878590SRichard Henderson     val = load_gpr(ctx, a->r);
33760b1347d2SRichard Henderson     if (rs == 0) {
33776fd0c7bcSRichard Henderson         tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
33780b1347d2SRichard Henderson     } else {
33796fd0c7bcSRichard Henderson         tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
33800b1347d2SRichard Henderson     }
338130878590SRichard Henderson     save_gpr(ctx, a->t, dest);
33820b1347d2SRichard Henderson 
33830b1347d2SRichard Henderson     /* Install the new nullification.  */
33840b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
338530878590SRichard Henderson     if (a->c) {
338672ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
33870b1347d2SRichard Henderson     }
338831234768SRichard Henderson     return nullify_end(ctx);
33890b1347d2SRichard Henderson }
33900b1347d2SRichard Henderson 
339172ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
33926fd0c7bcSRichard Henderson                        bool d, bool nz, unsigned len, TCGv_i64 val)
33930b1347d2SRichard Henderson {
33940b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
339572ae4f2bSRichard Henderson     unsigned widthm1 = d ? 63 : 31;
33966fd0c7bcSRichard Henderson     TCGv_i64 mask, tmp, shift, dest;
3397c53e401eSRichard Henderson     uint64_t msb = 1ULL << (len - 1);
33980b1347d2SRichard Henderson 
33990b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
3400*aac0f603SRichard Henderson     shift = tcg_temp_new_i64();
3401*aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
34020b1347d2SRichard Henderson 
34030b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
34046fd0c7bcSRichard Henderson     tcg_gen_andi_i64(shift, cpu_sar, widthm1);
34056fd0c7bcSRichard Henderson     tcg_gen_xori_i64(shift, shift, widthm1);
34060b1347d2SRichard Henderson 
3407*aac0f603SRichard Henderson     mask = tcg_temp_new_i64();
34086fd0c7bcSRichard Henderson     tcg_gen_movi_i64(mask, msb + (msb - 1));
34096fd0c7bcSRichard Henderson     tcg_gen_and_i64(tmp, val, mask);
34100b1347d2SRichard Henderson     if (rs) {
34116fd0c7bcSRichard Henderson         tcg_gen_shl_i64(mask, mask, shift);
34126fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tmp, shift);
34136fd0c7bcSRichard Henderson         tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
34146fd0c7bcSRichard Henderson         tcg_gen_or_i64(dest, dest, tmp);
34150b1347d2SRichard Henderson     } else {
34166fd0c7bcSRichard Henderson         tcg_gen_shl_i64(dest, tmp, shift);
34170b1347d2SRichard Henderson     }
34180b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
34190b1347d2SRichard Henderson 
34200b1347d2SRichard Henderson     /* Install the new nullification.  */
34210b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
34220b1347d2SRichard Henderson     if (c) {
342372ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, c, d, dest);
34240b1347d2SRichard Henderson     }
342531234768SRichard Henderson     return nullify_end(ctx);
34260b1347d2SRichard Henderson }
34270b1347d2SRichard Henderson 
342872ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
342930878590SRichard Henderson {
343072ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
343172ae4f2bSRichard Henderson         return false;
343272ae4f2bSRichard Henderson     }
3433a6deecceSSven Schnelle     if (a->c) {
3434a6deecceSSven Schnelle         nullify_over(ctx);
3435a6deecceSSven Schnelle     }
343672ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
343772ae4f2bSRichard Henderson                       load_gpr(ctx, a->r));
343830878590SRichard Henderson }
343930878590SRichard Henderson 
344072ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
344130878590SRichard Henderson {
344272ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
344372ae4f2bSRichard Henderson         return false;
344472ae4f2bSRichard Henderson     }
3445a6deecceSSven Schnelle     if (a->c) {
3446a6deecceSSven Schnelle         nullify_over(ctx);
3447a6deecceSSven Schnelle     }
344872ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
34496fd0c7bcSRichard Henderson                       tcg_constant_i64(a->i));
345030878590SRichard Henderson }
34510b1347d2SRichard Henderson 
34528340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a)
345398cd9ca7SRichard Henderson {
34546fd0c7bcSRichard Henderson     TCGv_i64 tmp;
345598cd9ca7SRichard Henderson 
3456c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
345798cd9ca7SRichard Henderson     /* ??? It seems like there should be a good way of using
345898cd9ca7SRichard Henderson        "be disp(sr2, r0)", the canonical gateway entry mechanism
345998cd9ca7SRichard Henderson        to our advantage.  But that appears to be inconvenient to
346098cd9ca7SRichard Henderson        manage along side branch delay slots.  Therefore we handle
346198cd9ca7SRichard Henderson        entry into the gateway page via absolute address.  */
346298cd9ca7SRichard Henderson     /* Since we don't implement spaces, just branch.  Do notice the special
346398cd9ca7SRichard Henderson        case of "be disp(*,r0)" using a direct branch to disp, so that we can
346498cd9ca7SRichard Henderson        goto_tb to the TB containing the syscall.  */
34658340f534SRichard Henderson     if (a->b == 0) {
34668340f534SRichard Henderson         return do_dbranch(ctx, a->disp, a->l, a->n);
346798cd9ca7SRichard Henderson     }
3468c301f34eSRichard Henderson #else
3469c301f34eSRichard Henderson     nullify_over(ctx);
3470660eefe1SRichard Henderson #endif
3471660eefe1SRichard Henderson 
3472*aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
34736fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp);
3474660eefe1SRichard Henderson     tmp = do_ibranch_priv(ctx, tmp);
3475c301f34eSRichard Henderson 
3476c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
34778340f534SRichard Henderson     return do_ibranch(ctx, tmp, a->l, a->n);
3478c301f34eSRichard Henderson #else
3479c301f34eSRichard Henderson     TCGv_i64 new_spc = tcg_temp_new_i64();
3480c301f34eSRichard Henderson 
34818340f534SRichard Henderson     load_spr(ctx, new_spc, a->sp);
34828340f534SRichard Henderson     if (a->l) {
3483741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
3484c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f);
3485c301f34eSRichard Henderson     }
34868340f534SRichard Henderson     if (a->n && use_nullify_skip(ctx)) {
3487a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
34886fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, 4);
3489a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3490c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, new_spc);
3491c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f);
3492c301f34eSRichard Henderson     } else {
3493741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3494c301f34eSRichard Henderson         if (ctx->iaoq_b == -1) {
3495c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3496c301f34eSRichard Henderson         }
3497a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3498c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, new_spc);
34998340f534SRichard Henderson         nullify_set(ctx, a->n);
3500c301f34eSRichard Henderson     }
3501c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
350231234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
350331234768SRichard Henderson     return nullify_end(ctx);
3504c301f34eSRichard Henderson #endif
350598cd9ca7SRichard Henderson }
350698cd9ca7SRichard Henderson 
35078340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a)
350898cd9ca7SRichard Henderson {
35098340f534SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n);
351098cd9ca7SRichard Henderson }
351198cd9ca7SRichard Henderson 
35128340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
351343e05652SRichard Henderson {
3514c53e401eSRichard Henderson     uint64_t dest = iaoq_dest(ctx, a->disp);
351543e05652SRichard Henderson 
35166e5f5300SSven Schnelle     nullify_over(ctx);
35176e5f5300SSven Schnelle 
351843e05652SRichard Henderson     /* Make sure the caller hasn't done something weird with the queue.
351943e05652SRichard Henderson      * ??? This is not quite the same as the PSW[B] bit, which would be
352043e05652SRichard Henderson      * expensive to track.  Real hardware will trap for
352143e05652SRichard Henderson      *    b  gateway
352243e05652SRichard Henderson      *    b  gateway+4  (in delay slot of first branch)
352343e05652SRichard Henderson      * However, checking for a non-sequential instruction queue *will*
352443e05652SRichard Henderson      * diagnose the security hole
352543e05652SRichard Henderson      *    b  gateway
352643e05652SRichard Henderson      *    b  evil
352743e05652SRichard Henderson      * in which instructions at evil would run with increased privs.
352843e05652SRichard Henderson      */
352943e05652SRichard Henderson     if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) {
353043e05652SRichard Henderson         return gen_illegal(ctx);
353143e05652SRichard Henderson     }
353243e05652SRichard Henderson 
353343e05652SRichard Henderson #ifndef CONFIG_USER_ONLY
353443e05652SRichard Henderson     if (ctx->tb_flags & PSW_C) {
3535b77af26eSRichard Henderson         CPUHPPAState *env = cpu_env(ctx->cs);
353643e05652SRichard Henderson         int type = hppa_artype_for_page(env, ctx->base.pc_next);
353743e05652SRichard Henderson         /* If we could not find a TLB entry, then we need to generate an
353843e05652SRichard Henderson            ITLB miss exception so the kernel will provide it.
353943e05652SRichard Henderson            The resulting TLB fill operation will invalidate this TB and
354043e05652SRichard Henderson            we will re-translate, at which point we *will* be able to find
354143e05652SRichard Henderson            the TLB entry and determine if this is in fact a gateway page.  */
354243e05652SRichard Henderson         if (type < 0) {
354331234768SRichard Henderson             gen_excp(ctx, EXCP_ITLB_MISS);
354431234768SRichard Henderson             return true;
354543e05652SRichard Henderson         }
354643e05652SRichard Henderson         /* No change for non-gateway pages or for priv decrease.  */
354743e05652SRichard Henderson         if (type >= 4 && type - 4 < ctx->privilege) {
354843e05652SRichard Henderson             dest = deposit32(dest, 0, 2, type - 4);
354943e05652SRichard Henderson         }
355043e05652SRichard Henderson     } else {
355143e05652SRichard Henderson         dest &= -4;  /* priv = 0 */
355243e05652SRichard Henderson     }
355343e05652SRichard Henderson #endif
355443e05652SRichard Henderson 
35556e5f5300SSven Schnelle     if (a->l) {
35566fd0c7bcSRichard Henderson         TCGv_i64 tmp = dest_gpr(ctx, a->l);
35576e5f5300SSven Schnelle         if (ctx->privilege < 3) {
35586fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, tmp, -4);
35596e5f5300SSven Schnelle         }
35606fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
35616e5f5300SSven Schnelle         save_gpr(ctx, a->l, tmp);
35626e5f5300SSven Schnelle     }
35636e5f5300SSven Schnelle 
35646e5f5300SSven Schnelle     return do_dbranch(ctx, dest, 0, a->n);
356543e05652SRichard Henderson }
356643e05652SRichard Henderson 
35678340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a)
356898cd9ca7SRichard Henderson {
3569b35aec85SRichard Henderson     if (a->x) {
3570*aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
35716fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3);
35726fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8);
3573660eefe1SRichard Henderson         /* The computation here never changes privilege level.  */
35748340f534SRichard Henderson         return do_ibranch(ctx, tmp, a->l, a->n);
3575b35aec85SRichard Henderson     } else {
3576b35aec85SRichard Henderson         /* BLR R0,RX is a good way to load PC+8 into RX.  */
3577b35aec85SRichard Henderson         return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n);
3578b35aec85SRichard Henderson     }
357998cd9ca7SRichard Henderson }
358098cd9ca7SRichard Henderson 
35818340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a)
358298cd9ca7SRichard Henderson {
35836fd0c7bcSRichard Henderson     TCGv_i64 dest;
358498cd9ca7SRichard Henderson 
35858340f534SRichard Henderson     if (a->x == 0) {
35868340f534SRichard Henderson         dest = load_gpr(ctx, a->b);
358798cd9ca7SRichard Henderson     } else {
3588*aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
35896fd0c7bcSRichard Henderson         tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
35906fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
359198cd9ca7SRichard Henderson     }
3592660eefe1SRichard Henderson     dest = do_ibranch_priv(ctx, dest);
35938340f534SRichard Henderson     return do_ibranch(ctx, dest, 0, a->n);
359498cd9ca7SRichard Henderson }
359598cd9ca7SRichard Henderson 
35968340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a)
359798cd9ca7SRichard Henderson {
35986fd0c7bcSRichard Henderson     TCGv_i64 dest;
359998cd9ca7SRichard Henderson 
3600c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
36018340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
36028340f534SRichard Henderson     return do_ibranch(ctx, dest, a->l, a->n);
3603c301f34eSRichard Henderson #else
3604c301f34eSRichard Henderson     nullify_over(ctx);
36058340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
3606c301f34eSRichard Henderson 
3607741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3608c301f34eSRichard Henderson     if (ctx->iaoq_b == -1) {
3609c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3610c301f34eSRichard Henderson     }
3611741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest);
3612c301f34eSRichard Henderson     tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
36138340f534SRichard Henderson     if (a->l) {
3614741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var);
3615c301f34eSRichard Henderson     }
36168340f534SRichard Henderson     nullify_set(ctx, a->n);
3617c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
361831234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
361931234768SRichard Henderson     return nullify_end(ctx);
3620c301f34eSRichard Henderson #endif
362198cd9ca7SRichard Henderson }
362298cd9ca7SRichard Henderson 
3623a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
3624a8966ba7SRichard Henderson {
3625a8966ba7SRichard Henderson     /* All branch target stack instructions implement as nop. */
3626a8966ba7SRichard Henderson     return ctx->is_pa20;
3627a8966ba7SRichard Henderson }
3628a8966ba7SRichard Henderson 
36291ca74648SRichard Henderson /*
36301ca74648SRichard Henderson  * Float class 0
36311ca74648SRichard Henderson  */
3632ebe9383cSRichard Henderson 
36331ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3634ebe9383cSRichard Henderson {
3635ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
3636ebe9383cSRichard Henderson }
3637ebe9383cSRichard Henderson 
363859f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
363959f8c04bSHelge Deller {
3640a300dad3SRichard Henderson     uint64_t ret;
3641a300dad3SRichard Henderson 
3642c53e401eSRichard Henderson     if (ctx->is_pa20) {
3643a300dad3SRichard Henderson         ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
3644a300dad3SRichard Henderson     } else {
3645a300dad3SRichard Henderson         ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
3646a300dad3SRichard Henderson     }
3647a300dad3SRichard Henderson 
364859f8c04bSHelge Deller     nullify_over(ctx);
3649a300dad3SRichard Henderson     save_frd(0, tcg_constant_i64(ret));
365059f8c04bSHelge Deller     return nullify_end(ctx);
365159f8c04bSHelge Deller }
365259f8c04bSHelge Deller 
36531ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a)
36541ca74648SRichard Henderson {
36551ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f);
36561ca74648SRichard Henderson }
36571ca74648SRichard Henderson 
3658ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3659ebe9383cSRichard Henderson {
3660ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
3661ebe9383cSRichard Henderson }
3662ebe9383cSRichard Henderson 
36631ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a)
36641ca74648SRichard Henderson {
36651ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d);
36661ca74648SRichard Henderson }
36671ca74648SRichard Henderson 
36681ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3669ebe9383cSRichard Henderson {
3670ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
3671ebe9383cSRichard Henderson }
3672ebe9383cSRichard Henderson 
36731ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a)
36741ca74648SRichard Henderson {
36751ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fabs_f);
36761ca74648SRichard Henderson }
36771ca74648SRichard Henderson 
3678ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3679ebe9383cSRichard Henderson {
3680ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
3681ebe9383cSRichard Henderson }
3682ebe9383cSRichard Henderson 
36831ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a)
36841ca74648SRichard Henderson {
36851ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fabs_d);
36861ca74648SRichard Henderson }
36871ca74648SRichard Henderson 
36881ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a)
36891ca74648SRichard Henderson {
36901ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s);
36911ca74648SRichard Henderson }
36921ca74648SRichard Henderson 
36931ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a)
36941ca74648SRichard Henderson {
36951ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d);
36961ca74648SRichard Henderson }
36971ca74648SRichard Henderson 
36981ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a)
36991ca74648SRichard Henderson {
37001ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s);
37011ca74648SRichard Henderson }
37021ca74648SRichard Henderson 
37031ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a)
37041ca74648SRichard Henderson {
37051ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d);
37061ca74648SRichard Henderson }
37071ca74648SRichard Henderson 
37081ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3709ebe9383cSRichard Henderson {
3710ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
3711ebe9383cSRichard Henderson }
3712ebe9383cSRichard Henderson 
37131ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a)
37141ca74648SRichard Henderson {
37151ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fneg_f);
37161ca74648SRichard Henderson }
37171ca74648SRichard Henderson 
3718ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3719ebe9383cSRichard Henderson {
3720ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
3721ebe9383cSRichard Henderson }
3722ebe9383cSRichard Henderson 
37231ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a)
37241ca74648SRichard Henderson {
37251ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fneg_d);
37261ca74648SRichard Henderson }
37271ca74648SRichard Henderson 
37281ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3729ebe9383cSRichard Henderson {
3730ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
3731ebe9383cSRichard Henderson }
3732ebe9383cSRichard Henderson 
37331ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a)
37341ca74648SRichard Henderson {
37351ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f);
37361ca74648SRichard Henderson }
37371ca74648SRichard Henderson 
3738ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3739ebe9383cSRichard Henderson {
3740ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
3741ebe9383cSRichard Henderson }
3742ebe9383cSRichard Henderson 
37431ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a)
37441ca74648SRichard Henderson {
37451ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d);
37461ca74648SRichard Henderson }
37471ca74648SRichard Henderson 
37481ca74648SRichard Henderson /*
37491ca74648SRichard Henderson  * Float class 1
37501ca74648SRichard Henderson  */
37511ca74648SRichard Henderson 
37521ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a)
37531ca74648SRichard Henderson {
37541ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s);
37551ca74648SRichard Henderson }
37561ca74648SRichard Henderson 
37571ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a)
37581ca74648SRichard Henderson {
37591ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d);
37601ca74648SRichard Henderson }
37611ca74648SRichard Henderson 
37621ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a)
37631ca74648SRichard Henderson {
37641ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s);
37651ca74648SRichard Henderson }
37661ca74648SRichard Henderson 
37671ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a)
37681ca74648SRichard Henderson {
37691ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s);
37701ca74648SRichard Henderson }
37711ca74648SRichard Henderson 
37721ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a)
37731ca74648SRichard Henderson {
37741ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d);
37751ca74648SRichard Henderson }
37761ca74648SRichard Henderson 
37771ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a)
37781ca74648SRichard Henderson {
37791ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d);
37801ca74648SRichard Henderson }
37811ca74648SRichard Henderson 
37821ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a)
37831ca74648SRichard Henderson {
37841ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w);
37851ca74648SRichard Henderson }
37861ca74648SRichard Henderson 
37871ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a)
37881ca74648SRichard Henderson {
37891ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w);
37901ca74648SRichard Henderson }
37911ca74648SRichard Henderson 
37921ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a)
37931ca74648SRichard Henderson {
37941ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw);
37951ca74648SRichard Henderson }
37961ca74648SRichard Henderson 
37971ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a)
37981ca74648SRichard Henderson {
37991ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw);
38001ca74648SRichard Henderson }
38011ca74648SRichard Henderson 
38021ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a)
38031ca74648SRichard Henderson {
38041ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w);
38051ca74648SRichard Henderson }
38061ca74648SRichard Henderson 
38071ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a)
38081ca74648SRichard Henderson {
38091ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w);
38101ca74648SRichard Henderson }
38111ca74648SRichard Henderson 
38121ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a)
38131ca74648SRichard Henderson {
38141ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw);
38151ca74648SRichard Henderson }
38161ca74648SRichard Henderson 
38171ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a)
38181ca74648SRichard Henderson {
38191ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw);
38201ca74648SRichard Henderson }
38211ca74648SRichard Henderson 
38221ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a)
38231ca74648SRichard Henderson {
38241ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s);
38251ca74648SRichard Henderson }
38261ca74648SRichard Henderson 
38271ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a)
38281ca74648SRichard Henderson {
38291ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s);
38301ca74648SRichard Henderson }
38311ca74648SRichard Henderson 
38321ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a)
38331ca74648SRichard Henderson {
38341ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d);
38351ca74648SRichard Henderson }
38361ca74648SRichard Henderson 
38371ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a)
38381ca74648SRichard Henderson {
38391ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d);
38401ca74648SRichard Henderson }
38411ca74648SRichard Henderson 
38421ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a)
38431ca74648SRichard Henderson {
38441ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw);
38451ca74648SRichard Henderson }
38461ca74648SRichard Henderson 
38471ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a)
38481ca74648SRichard Henderson {
38491ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw);
38501ca74648SRichard Henderson }
38511ca74648SRichard Henderson 
38521ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a)
38531ca74648SRichard Henderson {
38541ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw);
38551ca74648SRichard Henderson }
38561ca74648SRichard Henderson 
38571ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a)
38581ca74648SRichard Henderson {
38591ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw);
38601ca74648SRichard Henderson }
38611ca74648SRichard Henderson 
38621ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a)
38631ca74648SRichard Henderson {
38641ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw);
38651ca74648SRichard Henderson }
38661ca74648SRichard Henderson 
38671ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a)
38681ca74648SRichard Henderson {
38691ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw);
38701ca74648SRichard Henderson }
38711ca74648SRichard Henderson 
38721ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a)
38731ca74648SRichard Henderson {
38741ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw);
38751ca74648SRichard Henderson }
38761ca74648SRichard Henderson 
38771ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a)
38781ca74648SRichard Henderson {
38791ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw);
38801ca74648SRichard Henderson }
38811ca74648SRichard Henderson 
38821ca74648SRichard Henderson /*
38831ca74648SRichard Henderson  * Float class 2
38841ca74648SRichard Henderson  */
38851ca74648SRichard Henderson 
38861ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a)
3887ebe9383cSRichard Henderson {
3888ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
3889ebe9383cSRichard Henderson 
3890ebe9383cSRichard Henderson     nullify_over(ctx);
3891ebe9383cSRichard Henderson 
38921ca74648SRichard Henderson     ta = load_frw0_i32(a->r1);
38931ca74648SRichard Henderson     tb = load_frw0_i32(a->r2);
389429dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
389529dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
3896ebe9383cSRichard Henderson 
3897ad75a51eSRichard Henderson     gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc);
3898ebe9383cSRichard Henderson 
38991ca74648SRichard Henderson     return nullify_end(ctx);
3900ebe9383cSRichard Henderson }
3901ebe9383cSRichard Henderson 
39021ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
3903ebe9383cSRichard Henderson {
3904ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
3905ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
3906ebe9383cSRichard Henderson 
3907ebe9383cSRichard Henderson     nullify_over(ctx);
3908ebe9383cSRichard Henderson 
39091ca74648SRichard Henderson     ta = load_frd0(a->r1);
39101ca74648SRichard Henderson     tb = load_frd0(a->r2);
391129dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
391229dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
3913ebe9383cSRichard Henderson 
3914ad75a51eSRichard Henderson     gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc);
3915ebe9383cSRichard Henderson 
391631234768SRichard Henderson     return nullify_end(ctx);
3917ebe9383cSRichard Henderson }
3918ebe9383cSRichard Henderson 
39191ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
3920ebe9383cSRichard Henderson {
39216fd0c7bcSRichard Henderson     TCGv_i64 t;
3922ebe9383cSRichard Henderson 
3923ebe9383cSRichard Henderson     nullify_over(ctx);
3924ebe9383cSRichard Henderson 
3925*aac0f603SRichard Henderson     t = tcg_temp_new_i64();
39266fd0c7bcSRichard Henderson     tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
3927ebe9383cSRichard Henderson 
39281ca74648SRichard Henderson     if (a->y == 1) {
3929ebe9383cSRichard Henderson         int mask;
3930ebe9383cSRichard Henderson         bool inv = false;
3931ebe9383cSRichard Henderson 
39321ca74648SRichard Henderson         switch (a->c) {
3933ebe9383cSRichard Henderson         case 0: /* simple */
39346fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, 0x4000000);
3935ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3936ebe9383cSRichard Henderson             goto done;
3937ebe9383cSRichard Henderson         case 2: /* rej */
3938ebe9383cSRichard Henderson             inv = true;
3939ebe9383cSRichard Henderson             /* fallthru */
3940ebe9383cSRichard Henderson         case 1: /* acc */
3941ebe9383cSRichard Henderson             mask = 0x43ff800;
3942ebe9383cSRichard Henderson             break;
3943ebe9383cSRichard Henderson         case 6: /* rej8 */
3944ebe9383cSRichard Henderson             inv = true;
3945ebe9383cSRichard Henderson             /* fallthru */
3946ebe9383cSRichard Henderson         case 5: /* acc8 */
3947ebe9383cSRichard Henderson             mask = 0x43f8000;
3948ebe9383cSRichard Henderson             break;
3949ebe9383cSRichard Henderson         case 9: /* acc6 */
3950ebe9383cSRichard Henderson             mask = 0x43e0000;
3951ebe9383cSRichard Henderson             break;
3952ebe9383cSRichard Henderson         case 13: /* acc4 */
3953ebe9383cSRichard Henderson             mask = 0x4380000;
3954ebe9383cSRichard Henderson             break;
3955ebe9383cSRichard Henderson         case 17: /* acc2 */
3956ebe9383cSRichard Henderson             mask = 0x4200000;
3957ebe9383cSRichard Henderson             break;
3958ebe9383cSRichard Henderson         default:
39591ca74648SRichard Henderson             gen_illegal(ctx);
39601ca74648SRichard Henderson             return true;
3961ebe9383cSRichard Henderson         }
3962ebe9383cSRichard Henderson         if (inv) {
39636fd0c7bcSRichard Henderson             TCGv_i64 c = tcg_constant_i64(mask);
39646fd0c7bcSRichard Henderson             tcg_gen_or_i64(t, t, c);
3965ebe9383cSRichard Henderson             ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
3966ebe9383cSRichard Henderson         } else {
39676fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, mask);
3968ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
3969ebe9383cSRichard Henderson         }
39701ca74648SRichard Henderson     } else {
39711ca74648SRichard Henderson         unsigned cbit = (a->y ^ 1) - 1;
39721ca74648SRichard Henderson 
39736fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, t, 21 - cbit, 1);
39741ca74648SRichard Henderson         ctx->null_cond = cond_make_0(TCG_COND_NE, t);
39751ca74648SRichard Henderson     }
39761ca74648SRichard Henderson 
3977ebe9383cSRichard Henderson  done:
397831234768SRichard Henderson     return nullify_end(ctx);
3979ebe9383cSRichard Henderson }
3980ebe9383cSRichard Henderson 
39811ca74648SRichard Henderson /*
39821ca74648SRichard Henderson  * Float class 2
39831ca74648SRichard Henderson  */
39841ca74648SRichard Henderson 
39851ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a)
3986ebe9383cSRichard Henderson {
39871ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s);
39881ca74648SRichard Henderson }
39891ca74648SRichard Henderson 
39901ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a)
39911ca74648SRichard Henderson {
39921ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d);
39931ca74648SRichard Henderson }
39941ca74648SRichard Henderson 
39951ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a)
39961ca74648SRichard Henderson {
39971ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s);
39981ca74648SRichard Henderson }
39991ca74648SRichard Henderson 
40001ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a)
40011ca74648SRichard Henderson {
40021ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d);
40031ca74648SRichard Henderson }
40041ca74648SRichard Henderson 
40051ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a)
40061ca74648SRichard Henderson {
40071ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s);
40081ca74648SRichard Henderson }
40091ca74648SRichard Henderson 
40101ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a)
40111ca74648SRichard Henderson {
40121ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d);
40131ca74648SRichard Henderson }
40141ca74648SRichard Henderson 
40151ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a)
40161ca74648SRichard Henderson {
40171ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s);
40181ca74648SRichard Henderson }
40191ca74648SRichard Henderson 
40201ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a)
40211ca74648SRichard Henderson {
40221ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d);
40231ca74648SRichard Henderson }
40241ca74648SRichard Henderson 
40251ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a)
40261ca74648SRichard Henderson {
40271ca74648SRichard Henderson     TCGv_i64 x, y;
4028ebe9383cSRichard Henderson 
4029ebe9383cSRichard Henderson     nullify_over(ctx);
4030ebe9383cSRichard Henderson 
40311ca74648SRichard Henderson     x = load_frw0_i64(a->r1);
40321ca74648SRichard Henderson     y = load_frw0_i64(a->r2);
40331ca74648SRichard Henderson     tcg_gen_mul_i64(x, x, y);
40341ca74648SRichard Henderson     save_frd(a->t, x);
4035ebe9383cSRichard Henderson 
403631234768SRichard Henderson     return nullify_end(ctx);
4037ebe9383cSRichard Henderson }
4038ebe9383cSRichard Henderson 
4039ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
4040ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
4041ebe9383cSRichard Henderson {
4042ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
4043ebe9383cSRichard Henderson }
4044ebe9383cSRichard Henderson 
4045b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4046ebe9383cSRichard Henderson {
4047b1e2af57SRichard Henderson     int tm = fmpyadd_s_reg(a->tm);
4048b1e2af57SRichard Henderson     int ra = fmpyadd_s_reg(a->ra);
4049b1e2af57SRichard Henderson     int ta = fmpyadd_s_reg(a->ta);
4050b1e2af57SRichard Henderson     int rm2 = fmpyadd_s_reg(a->rm2);
4051b1e2af57SRichard Henderson     int rm1 = fmpyadd_s_reg(a->rm1);
4052ebe9383cSRichard Henderson 
4053ebe9383cSRichard Henderson     nullify_over(ctx);
4054ebe9383cSRichard Henderson 
4055ebe9383cSRichard Henderson     do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4056ebe9383cSRichard Henderson     do_fop_weww(ctx, ta, ta, ra,
4057ebe9383cSRichard Henderson                 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
4058ebe9383cSRichard Henderson 
405931234768SRichard Henderson     return nullify_end(ctx);
4060ebe9383cSRichard Henderson }
4061ebe9383cSRichard Henderson 
4062b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4063b1e2af57SRichard Henderson {
4064b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, false);
4065b1e2af57SRichard Henderson }
4066b1e2af57SRichard Henderson 
4067b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4068b1e2af57SRichard Henderson {
4069b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, true);
4070b1e2af57SRichard Henderson }
4071b1e2af57SRichard Henderson 
4072b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4073b1e2af57SRichard Henderson {
4074b1e2af57SRichard Henderson     nullify_over(ctx);
4075b1e2af57SRichard Henderson 
4076b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4077b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4078b1e2af57SRichard Henderson                 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4079b1e2af57SRichard Henderson 
4080b1e2af57SRichard Henderson     return nullify_end(ctx);
4081b1e2af57SRichard Henderson }
4082b1e2af57SRichard Henderson 
4083b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4084b1e2af57SRichard Henderson {
4085b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, false);
4086b1e2af57SRichard Henderson }
4087b1e2af57SRichard Henderson 
4088b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4089b1e2af57SRichard Henderson {
4090b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, true);
4091b1e2af57SRichard Henderson }
4092b1e2af57SRichard Henderson 
4093c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a)
4094ebe9383cSRichard Henderson {
4095c3bad4f8SRichard Henderson     TCGv_i32 x, y, z;
4096ebe9383cSRichard Henderson 
4097ebe9383cSRichard Henderson     nullify_over(ctx);
4098c3bad4f8SRichard Henderson     x = load_frw0_i32(a->rm1);
4099c3bad4f8SRichard Henderson     y = load_frw0_i32(a->rm2);
4100c3bad4f8SRichard Henderson     z = load_frw0_i32(a->ra3);
4101ebe9383cSRichard Henderson 
4102c3bad4f8SRichard Henderson     if (a->neg) {
4103ad75a51eSRichard Henderson         gen_helper_fmpynfadd_s(x, tcg_env, x, y, z);
4104ebe9383cSRichard Henderson     } else {
4105ad75a51eSRichard Henderson         gen_helper_fmpyfadd_s(x, tcg_env, x, y, z);
4106ebe9383cSRichard Henderson     }
4107ebe9383cSRichard Henderson 
4108c3bad4f8SRichard Henderson     save_frw_i32(a->t, x);
410931234768SRichard Henderson     return nullify_end(ctx);
4110ebe9383cSRichard Henderson }
4111ebe9383cSRichard Henderson 
4112c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
4113ebe9383cSRichard Henderson {
4114c3bad4f8SRichard Henderson     TCGv_i64 x, y, z;
4115ebe9383cSRichard Henderson 
4116ebe9383cSRichard Henderson     nullify_over(ctx);
4117c3bad4f8SRichard Henderson     x = load_frd0(a->rm1);
4118c3bad4f8SRichard Henderson     y = load_frd0(a->rm2);
4119c3bad4f8SRichard Henderson     z = load_frd0(a->ra3);
4120ebe9383cSRichard Henderson 
4121c3bad4f8SRichard Henderson     if (a->neg) {
4122ad75a51eSRichard Henderson         gen_helper_fmpynfadd_d(x, tcg_env, x, y, z);
4123ebe9383cSRichard Henderson     } else {
4124ad75a51eSRichard Henderson         gen_helper_fmpyfadd_d(x, tcg_env, x, y, z);
4125ebe9383cSRichard Henderson     }
4126ebe9383cSRichard Henderson 
4127c3bad4f8SRichard Henderson     save_frd(a->t, x);
412831234768SRichard Henderson     return nullify_end(ctx);
4129ebe9383cSRichard Henderson }
4130ebe9383cSRichard Henderson 
413115da177bSSven Schnelle static bool trans_diag(DisasContext *ctx, arg_diag *a)
413215da177bSSven Schnelle {
4133cf6b28d4SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4134cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY
4135cf6b28d4SHelge Deller     if (a->i == 0x100) {
4136cf6b28d4SHelge Deller         /* emulate PDC BTLB, called by SeaBIOS-hppa */
4137ad75a51eSRichard Henderson         nullify_over(ctx);
4138ad75a51eSRichard Henderson         gen_helper_diag_btlb(tcg_env);
4139cf6b28d4SHelge Deller         return nullify_end(ctx);
414015da177bSSven Schnelle     }
4141ad75a51eSRichard Henderson #endif
4142ad75a51eSRichard Henderson     qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i);
4143ad75a51eSRichard Henderson     return true;
4144ad75a51eSRichard Henderson }
414515da177bSSven Schnelle 
4146b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
414761766fe9SRichard Henderson {
414851b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4149f764718dSRichard Henderson     int bound;
415061766fe9SRichard Henderson 
415151b061fbSRichard Henderson     ctx->cs = cs;
4152494737b7SRichard Henderson     ctx->tb_flags = ctx->base.tb->flags;
4153bd6243a3SRichard Henderson     ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
41543d68ee7bSRichard Henderson 
41553d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY
4156c01e5dfbSHelge Deller     ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX);
41573d68ee7bSRichard Henderson     ctx->mmu_idx = MMU_USER_IDX;
4158c01e5dfbSHelge Deller     ctx->iaoq_f = ctx->base.pc_first | ctx->privilege;
4159c01e5dfbSHelge Deller     ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege;
4160217d1a5eSRichard Henderson     ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
4161c301f34eSRichard Henderson #else
4162494737b7SRichard Henderson     ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
4163bb67ec32SRichard Henderson     ctx->mmu_idx = (ctx->tb_flags & PSW_D
4164bb67ec32SRichard Henderson                     ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
4165bb67ec32SRichard Henderson                     : MMU_PHYS_IDX);
41663d68ee7bSRichard Henderson 
4167c301f34eSRichard Henderson     /* Recover the IAOQ values from the GVA + PRIV.  */
4168c301f34eSRichard Henderson     uint64_t cs_base = ctx->base.tb->cs_base;
4169c301f34eSRichard Henderson     uint64_t iasq_f = cs_base & ~0xffffffffull;
4170c301f34eSRichard Henderson     int32_t diff = cs_base;
4171c301f34eSRichard Henderson 
4172c301f34eSRichard Henderson     ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
4173c301f34eSRichard Henderson     ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1);
4174c301f34eSRichard Henderson #endif
417551b061fbSRichard Henderson     ctx->iaoq_n = -1;
4176f764718dSRichard Henderson     ctx->iaoq_n_var = NULL;
417761766fe9SRichard Henderson 
41783d68ee7bSRichard Henderson     /* Bound the number of instructions by those left on the page.  */
41793d68ee7bSRichard Henderson     bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
4180b542683dSEmilio G. Cota     ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
418161766fe9SRichard Henderson }
418261766fe9SRichard Henderson 
418351b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
418451b061fbSRichard Henderson {
418551b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
418661766fe9SRichard Henderson 
41873d68ee7bSRichard Henderson     /* Seed the nullification status from PSW[N], as saved in TB->FLAGS.  */
418851b061fbSRichard Henderson     ctx->null_cond = cond_make_f();
418951b061fbSRichard Henderson     ctx->psw_n_nonzero = false;
4190494737b7SRichard Henderson     if (ctx->tb_flags & PSW_N) {
419151b061fbSRichard Henderson         ctx->null_cond.c = TCG_COND_ALWAYS;
419251b061fbSRichard Henderson         ctx->psw_n_nonzero = true;
4193129e9cc3SRichard Henderson     }
419451b061fbSRichard Henderson     ctx->null_lab = NULL;
419561766fe9SRichard Henderson }
419661766fe9SRichard Henderson 
419751b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
419851b061fbSRichard Henderson {
419951b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
420051b061fbSRichard Henderson 
420151b061fbSRichard Henderson     tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b);
420251b061fbSRichard Henderson }
420351b061fbSRichard Henderson 
420451b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
420551b061fbSRichard Henderson {
420651b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4207b77af26eSRichard Henderson     CPUHPPAState *env = cpu_env(cs);
420851b061fbSRichard Henderson     DisasJumpType ret;
420951b061fbSRichard Henderson 
421051b061fbSRichard Henderson     /* Execute one insn.  */
4211ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4212c301f34eSRichard Henderson     if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
421331234768SRichard Henderson         do_page_zero(ctx);
421431234768SRichard Henderson         ret = ctx->base.is_jmp;
4215869051eaSRichard Henderson         assert(ret != DISAS_NEXT);
4216ba1d0b44SRichard Henderson     } else
4217ba1d0b44SRichard Henderson #endif
4218ba1d0b44SRichard Henderson     {
421961766fe9SRichard Henderson         /* Always fetch the insn, even if nullified, so that we check
422061766fe9SRichard Henderson            the page permissions for execute.  */
42214e116893SIlya Leoshkevich         uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next);
422261766fe9SRichard Henderson 
422361766fe9SRichard Henderson         /* Set up the IA queue for the next insn.
422461766fe9SRichard Henderson            This will be overwritten by a branch.  */
422551b061fbSRichard Henderson         if (ctx->iaoq_b == -1) {
422651b061fbSRichard Henderson             ctx->iaoq_n = -1;
4227*aac0f603SRichard Henderson             ctx->iaoq_n_var = tcg_temp_new_i64();
42286fd0c7bcSRichard Henderson             tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
422961766fe9SRichard Henderson         } else {
423051b061fbSRichard Henderson             ctx->iaoq_n = ctx->iaoq_b + 4;
4231f764718dSRichard Henderson             ctx->iaoq_n_var = NULL;
423261766fe9SRichard Henderson         }
423361766fe9SRichard Henderson 
423451b061fbSRichard Henderson         if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
423551b061fbSRichard Henderson             ctx->null_cond.c = TCG_COND_NEVER;
4236869051eaSRichard Henderson             ret = DISAS_NEXT;
4237129e9cc3SRichard Henderson         } else {
42381a19da0dSRichard Henderson             ctx->insn = insn;
423931274b46SRichard Henderson             if (!decode(ctx, insn)) {
424031274b46SRichard Henderson                 gen_illegal(ctx);
424131274b46SRichard Henderson             }
424231234768SRichard Henderson             ret = ctx->base.is_jmp;
424351b061fbSRichard Henderson             assert(ctx->null_lab == NULL);
4244129e9cc3SRichard Henderson         }
424561766fe9SRichard Henderson     }
424661766fe9SRichard Henderson 
42473d68ee7bSRichard Henderson     /* Advance the insn queue.  Note that this check also detects
42483d68ee7bSRichard Henderson        a priority change within the instruction queue.  */
424951b061fbSRichard Henderson     if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
4250c301f34eSRichard Henderson         if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1
4251c301f34eSRichard Henderson             && use_goto_tb(ctx, ctx->iaoq_b)
4252c301f34eSRichard Henderson             && (ctx->null_cond.c == TCG_COND_NEVER
4253c301f34eSRichard Henderson                 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
425451b061fbSRichard Henderson             nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
425551b061fbSRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
425631234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_NORETURN;
4257129e9cc3SRichard Henderson         } else {
425831234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE;
425961766fe9SRichard Henderson         }
4260129e9cc3SRichard Henderson     }
426151b061fbSRichard Henderson     ctx->iaoq_f = ctx->iaoq_b;
426251b061fbSRichard Henderson     ctx->iaoq_b = ctx->iaoq_n;
4263c301f34eSRichard Henderson     ctx->base.pc_next += 4;
426461766fe9SRichard Henderson 
4265c5d0aec2SRichard Henderson     switch (ret) {
4266c5d0aec2SRichard Henderson     case DISAS_NORETURN:
4267c5d0aec2SRichard Henderson     case DISAS_IAQ_N_UPDATED:
4268c5d0aec2SRichard Henderson         break;
4269c5d0aec2SRichard Henderson 
4270c5d0aec2SRichard Henderson     case DISAS_NEXT:
4271c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE:
4272c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
427351b061fbSRichard Henderson         if (ctx->iaoq_f == -1) {
4274a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b);
4275741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
4276c301f34eSRichard Henderson #ifndef CONFIG_USER_ONLY
4277c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
4278c301f34eSRichard Henderson #endif
427951b061fbSRichard Henderson             nullify_save(ctx);
4280c5d0aec2SRichard Henderson             ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT
4281c5d0aec2SRichard Henderson                                 ? DISAS_EXIT
4282c5d0aec2SRichard Henderson                                 : DISAS_IAQ_N_UPDATED);
428351b061fbSRichard Henderson         } else if (ctx->iaoq_b == -1) {
4284a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var);
428561766fe9SRichard Henderson         }
4286c5d0aec2SRichard Henderson         break;
4287c5d0aec2SRichard Henderson 
4288c5d0aec2SRichard Henderson     default:
4289c5d0aec2SRichard Henderson         g_assert_not_reached();
4290c5d0aec2SRichard Henderson     }
429161766fe9SRichard Henderson }
429261766fe9SRichard Henderson 
429351b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
429451b061fbSRichard Henderson {
429551b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4296e1b5a5edSRichard Henderson     DisasJumpType is_jmp = ctx->base.is_jmp;
429751b061fbSRichard Henderson 
4298e1b5a5edSRichard Henderson     switch (is_jmp) {
4299869051eaSRichard Henderson     case DISAS_NORETURN:
430061766fe9SRichard Henderson         break;
430151b061fbSRichard Henderson     case DISAS_TOO_MANY:
4302869051eaSRichard Henderson     case DISAS_IAQ_N_STALE:
4303e1b5a5edSRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
4304741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
4305741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
430651b061fbSRichard Henderson         nullify_save(ctx);
430761766fe9SRichard Henderson         /* FALLTHRU */
4308869051eaSRichard Henderson     case DISAS_IAQ_N_UPDATED:
43098532a14eSRichard Henderson         if (is_jmp != DISAS_IAQ_N_STALE_EXIT) {
43107f11636dSEmilio G. Cota             tcg_gen_lookup_and_goto_ptr();
43118532a14eSRichard Henderson             break;
431261766fe9SRichard Henderson         }
4313c5d0aec2SRichard Henderson         /* FALLTHRU */
4314c5d0aec2SRichard Henderson     case DISAS_EXIT:
4315c5d0aec2SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
431661766fe9SRichard Henderson         break;
431761766fe9SRichard Henderson     default:
431851b061fbSRichard Henderson         g_assert_not_reached();
431961766fe9SRichard Henderson     }
432051b061fbSRichard Henderson }
432161766fe9SRichard Henderson 
43228eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase,
43238eb806a7SRichard Henderson                               CPUState *cs, FILE *logfile)
432451b061fbSRichard Henderson {
4325c301f34eSRichard Henderson     target_ulong pc = dcbase->pc_first;
432661766fe9SRichard Henderson 
4327ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4328ba1d0b44SRichard Henderson     switch (pc) {
43297ad439dfSRichard Henderson     case 0x00:
43308eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000000:  (null)\n");
4331ba1d0b44SRichard Henderson         return;
43327ad439dfSRichard Henderson     case 0xb0:
43338eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000b0:  light-weight-syscall\n");
4334ba1d0b44SRichard Henderson         return;
43357ad439dfSRichard Henderson     case 0xe0:
43368eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000e0:  set-thread-pointer-syscall\n");
4337ba1d0b44SRichard Henderson         return;
43387ad439dfSRichard Henderson     case 0x100:
43398eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000100:  syscall\n");
4340ba1d0b44SRichard Henderson         return;
43417ad439dfSRichard Henderson     }
4342ba1d0b44SRichard Henderson #endif
4343ba1d0b44SRichard Henderson 
43448eb806a7SRichard Henderson     fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
43458eb806a7SRichard Henderson     target_disas(logfile, cs, pc, dcbase->tb->size);
434661766fe9SRichard Henderson }
434751b061fbSRichard Henderson 
434851b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = {
434951b061fbSRichard Henderson     .init_disas_context = hppa_tr_init_disas_context,
435051b061fbSRichard Henderson     .tb_start           = hppa_tr_tb_start,
435151b061fbSRichard Henderson     .insn_start         = hppa_tr_insn_start,
435251b061fbSRichard Henderson     .translate_insn     = hppa_tr_translate_insn,
435351b061fbSRichard Henderson     .tb_stop            = hppa_tr_tb_stop,
435451b061fbSRichard Henderson     .disas_log          = hppa_tr_disas_log,
435551b061fbSRichard Henderson };
435651b061fbSRichard Henderson 
4357597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
4358306c8721SRichard Henderson                            target_ulong pc, void *host_pc)
435951b061fbSRichard Henderson {
436051b061fbSRichard Henderson     DisasContext ctx;
4361306c8721SRichard Henderson     translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
436261766fe9SRichard Henderson }
4363