xref: /openbmc/qemu/target/hppa/translate.c (revision 967662cd5a0c05544c5d4dc1ba20b24fa42af6c4)
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 
35d53106c9SRichard Henderson 
3661766fe9SRichard Henderson typedef struct DisasCond {
3761766fe9SRichard Henderson     TCGCond c;
386fd0c7bcSRichard Henderson     TCGv_i64 a0, a1;
3961766fe9SRichard Henderson } DisasCond;
4061766fe9SRichard Henderson 
4161766fe9SRichard Henderson typedef struct DisasContext {
42d01a3625SRichard Henderson     DisasContextBase base;
4361766fe9SRichard Henderson     CPUState *cs;
4461766fe9SRichard Henderson 
45c53e401eSRichard Henderson     uint64_t iaoq_f;
46c53e401eSRichard Henderson     uint64_t iaoq_b;
47c53e401eSRichard Henderson     uint64_t iaoq_n;
486fd0c7bcSRichard Henderson     TCGv_i64 iaoq_n_var;
4961766fe9SRichard Henderson 
5061766fe9SRichard Henderson     DisasCond null_cond;
5161766fe9SRichard Henderson     TCGLabel *null_lab;
5261766fe9SRichard Henderson 
531a19da0dSRichard Henderson     uint32_t insn;
54494737b7SRichard Henderson     uint32_t tb_flags;
553d68ee7bSRichard Henderson     int mmu_idx;
563d68ee7bSRichard Henderson     int privilege;
5761766fe9SRichard Henderson     bool psw_n_nonzero;
58bd6243a3SRichard Henderson     bool is_pa20;
59217d1a5eSRichard Henderson 
60217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
61217d1a5eSRichard Henderson     MemOp unalign;
62217d1a5eSRichard Henderson #endif
6361766fe9SRichard Henderson } DisasContext;
6461766fe9SRichard Henderson 
65217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
66217d1a5eSRichard Henderson #define UNALIGN(C)  (C)->unalign
67217d1a5eSRichard Henderson #else
682d4afb03SRichard Henderson #define UNALIGN(C)  MO_ALIGN
69217d1a5eSRichard Henderson #endif
70217d1a5eSRichard Henderson 
71e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently.  */
72451e4ffdSRichard Henderson static int expand_sm_imm(DisasContext *ctx, int val)
73e36f27efSRichard Henderson {
74e36f27efSRichard Henderson     if (val & PSW_SM_E) {
75e36f27efSRichard Henderson         val = (val & ~PSW_SM_E) | PSW_E;
76e36f27efSRichard Henderson     }
77e36f27efSRichard Henderson     if (val & PSW_SM_W) {
78e36f27efSRichard Henderson         val = (val & ~PSW_SM_W) | PSW_W;
79e36f27efSRichard Henderson     }
80e36f27efSRichard Henderson     return val;
81e36f27efSRichard Henderson }
82e36f27efSRichard Henderson 
83deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base.  */
84451e4ffdSRichard Henderson static int expand_sr3x(DisasContext *ctx, int val)
85deee69a1SRichard Henderson {
86deee69a1SRichard Henderson     return ~val;
87deee69a1SRichard Henderson }
88deee69a1SRichard Henderson 
891cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value
901cd012a5SRichard Henderson    we use for the final M.  */
91451e4ffdSRichard Henderson static int ma_to_m(DisasContext *ctx, int val)
921cd012a5SRichard Henderson {
931cd012a5SRichard Henderson     return val & 2 ? (val & 1 ? -1 : 1) : 0;
941cd012a5SRichard Henderson }
951cd012a5SRichard Henderson 
96740038d7SRichard Henderson /* Convert the sign of the displacement to a pre or post-modify.  */
97451e4ffdSRichard Henderson static int pos_to_m(DisasContext *ctx, int val)
98740038d7SRichard Henderson {
99740038d7SRichard Henderson     return val ? 1 : -1;
100740038d7SRichard Henderson }
101740038d7SRichard Henderson 
102451e4ffdSRichard Henderson static int neg_to_m(DisasContext *ctx, int val)
103740038d7SRichard Henderson {
104740038d7SRichard Henderson     return val ? -1 : 1;
105740038d7SRichard Henderson }
106740038d7SRichard Henderson 
107740038d7SRichard Henderson /* Used for branch targets and fp memory ops.  */
108451e4ffdSRichard Henderson static int expand_shl2(DisasContext *ctx, int val)
10901afb7beSRichard Henderson {
11001afb7beSRichard Henderson     return val << 2;
11101afb7beSRichard Henderson }
11201afb7beSRichard Henderson 
113740038d7SRichard Henderson /* Used for fp memory ops.  */
114451e4ffdSRichard Henderson static int expand_shl3(DisasContext *ctx, int val)
115740038d7SRichard Henderson {
116740038d7SRichard Henderson     return val << 3;
117740038d7SRichard Henderson }
118740038d7SRichard Henderson 
1190588e061SRichard Henderson /* Used for assemble_21.  */
120451e4ffdSRichard Henderson static int expand_shl11(DisasContext *ctx, int val)
1210588e061SRichard Henderson {
1220588e061SRichard Henderson     return val << 11;
1230588e061SRichard Henderson }
1240588e061SRichard Henderson 
12572ae4f2bSRichard Henderson static int assemble_6(DisasContext *ctx, int val)
12672ae4f2bSRichard Henderson {
12772ae4f2bSRichard Henderson     /*
12872ae4f2bSRichard Henderson      * Officially, 32 * x + 32 - y.
12972ae4f2bSRichard Henderson      * Here, x is already in bit 5, and y is [4:0].
13072ae4f2bSRichard Henderson      * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1,
13172ae4f2bSRichard Henderson      * with the overflow from bit 4 summing with x.
13272ae4f2bSRichard Henderson      */
13372ae4f2bSRichard Henderson     return (val ^ 31) + 1;
13472ae4f2bSRichard Henderson }
13572ae4f2bSRichard Henderson 
136c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */
137c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val)
138c65c3ee1SRichard Henderson {
139c65c3ee1SRichard Henderson     return val ? val : 4; /* 0 == "*<<" */
140c65c3ee1SRichard Henderson }
141c65c3ee1SRichard Henderson 
14201afb7beSRichard Henderson 
14340f9f908SRichard Henderson /* Include the auto-generated decoder.  */
144abff1abfSPaolo Bonzini #include "decode-insns.c.inc"
14540f9f908SRichard Henderson 
14661766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated
14761766fe9SRichard Henderson    the iaq (for whatever reason), so don't do it again on exit.  */
148869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED  DISAS_TARGET_0
14961766fe9SRichard Henderson 
15061766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor
15161766fe9SRichard Henderson    updated the iaq for the next instruction to be executed.  */
152869051eaSRichard Henderson #define DISAS_IAQ_N_STALE    DISAS_TARGET_1
15361766fe9SRichard Henderson 
154e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately
155e1b5a5edSRichard Henderson    to recognize unmasked interrupts.  */
156e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT      DISAS_TARGET_2
157c5d0aec2SRichard Henderson #define DISAS_EXIT                  DISAS_TARGET_3
158e1b5a5edSRichard Henderson 
15961766fe9SRichard Henderson /* global register indexes */
1606fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32];
16133423472SRichard Henderson static TCGv_i64 cpu_sr[4];
162494737b7SRichard Henderson static TCGv_i64 cpu_srH;
1636fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f;
1646fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b;
165c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f;
166c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b;
1676fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar;
1686fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n;
1696fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v;
1706fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb;
1716fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb;
17261766fe9SRichard Henderson 
17361766fe9SRichard Henderson void hppa_translate_init(void)
17461766fe9SRichard Henderson {
17561766fe9SRichard Henderson #define DEF_VAR(V)  { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
17661766fe9SRichard Henderson 
1776fd0c7bcSRichard Henderson     typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar;
17861766fe9SRichard Henderson     static const GlobalVar vars[] = {
17935136a77SRichard Henderson         { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) },
18061766fe9SRichard Henderson         DEF_VAR(psw_n),
18161766fe9SRichard Henderson         DEF_VAR(psw_v),
18261766fe9SRichard Henderson         DEF_VAR(psw_cb),
18361766fe9SRichard Henderson         DEF_VAR(psw_cb_msb),
18461766fe9SRichard Henderson         DEF_VAR(iaoq_f),
18561766fe9SRichard Henderson         DEF_VAR(iaoq_b),
18661766fe9SRichard Henderson     };
18761766fe9SRichard Henderson 
18861766fe9SRichard Henderson #undef DEF_VAR
18961766fe9SRichard Henderson 
19061766fe9SRichard Henderson     /* Use the symbolic register names that match the disassembler.  */
19161766fe9SRichard Henderson     static const char gr_names[32][4] = {
19261766fe9SRichard Henderson         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
19361766fe9SRichard Henderson         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
19461766fe9SRichard Henderson         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
19561766fe9SRichard Henderson         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
19661766fe9SRichard Henderson     };
19733423472SRichard Henderson     /* SR[4-7] are not global registers so that we can index them.  */
198494737b7SRichard Henderson     static const char sr_names[5][4] = {
199494737b7SRichard Henderson         "sr0", "sr1", "sr2", "sr3", "srH"
20033423472SRichard Henderson     };
20161766fe9SRichard Henderson 
20261766fe9SRichard Henderson     int i;
20361766fe9SRichard Henderson 
204f764718dSRichard Henderson     cpu_gr[0] = NULL;
20561766fe9SRichard Henderson     for (i = 1; i < 32; i++) {
206ad75a51eSRichard Henderson         cpu_gr[i] = tcg_global_mem_new(tcg_env,
20761766fe9SRichard Henderson                                        offsetof(CPUHPPAState, gr[i]),
20861766fe9SRichard Henderson                                        gr_names[i]);
20961766fe9SRichard Henderson     }
21033423472SRichard Henderson     for (i = 0; i < 4; i++) {
211ad75a51eSRichard Henderson         cpu_sr[i] = tcg_global_mem_new_i64(tcg_env,
21233423472SRichard Henderson                                            offsetof(CPUHPPAState, sr[i]),
21333423472SRichard Henderson                                            sr_names[i]);
21433423472SRichard Henderson     }
215ad75a51eSRichard Henderson     cpu_srH = tcg_global_mem_new_i64(tcg_env,
216494737b7SRichard Henderson                                      offsetof(CPUHPPAState, sr[4]),
217494737b7SRichard Henderson                                      sr_names[4]);
21861766fe9SRichard Henderson 
21961766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(vars); ++i) {
22061766fe9SRichard Henderson         const GlobalVar *v = &vars[i];
221ad75a51eSRichard Henderson         *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name);
22261766fe9SRichard Henderson     }
223c301f34eSRichard Henderson 
224ad75a51eSRichard Henderson     cpu_iasq_f = tcg_global_mem_new_i64(tcg_env,
225c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_f),
226c301f34eSRichard Henderson                                         "iasq_f");
227ad75a51eSRichard Henderson     cpu_iasq_b = tcg_global_mem_new_i64(tcg_env,
228c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_b),
229c301f34eSRichard Henderson                                         "iasq_b");
23061766fe9SRichard Henderson }
23161766fe9SRichard Henderson 
232129e9cc3SRichard Henderson static DisasCond cond_make_f(void)
233129e9cc3SRichard Henderson {
234f764718dSRichard Henderson     return (DisasCond){
235f764718dSRichard Henderson         .c = TCG_COND_NEVER,
236f764718dSRichard Henderson         .a0 = NULL,
237f764718dSRichard Henderson         .a1 = NULL,
238f764718dSRichard Henderson     };
239129e9cc3SRichard Henderson }
240129e9cc3SRichard Henderson 
241df0232feSRichard Henderson static DisasCond cond_make_t(void)
242df0232feSRichard Henderson {
243df0232feSRichard Henderson     return (DisasCond){
244df0232feSRichard Henderson         .c = TCG_COND_ALWAYS,
245df0232feSRichard Henderson         .a0 = NULL,
246df0232feSRichard Henderson         .a1 = NULL,
247df0232feSRichard Henderson     };
248df0232feSRichard Henderson }
249df0232feSRichard Henderson 
250129e9cc3SRichard Henderson static DisasCond cond_make_n(void)
251129e9cc3SRichard Henderson {
252f764718dSRichard Henderson     return (DisasCond){
253f764718dSRichard Henderson         .c = TCG_COND_NE,
254f764718dSRichard Henderson         .a0 = cpu_psw_n,
2556fd0c7bcSRichard Henderson         .a1 = tcg_constant_i64(0)
256f764718dSRichard Henderson     };
257129e9cc3SRichard Henderson }
258129e9cc3SRichard Henderson 
2596fd0c7bcSRichard Henderson static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
260b47a4a02SSven Schnelle {
261b47a4a02SSven Schnelle     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
2624fe9533aSRichard Henderson     return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 };
2634fe9533aSRichard Henderson }
2644fe9533aSRichard Henderson 
2656fd0c7bcSRichard Henderson static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0)
2664fe9533aSRichard Henderson {
2676fd0c7bcSRichard Henderson     return cond_make_tmp(c, a0, tcg_constant_i64(0));
268b47a4a02SSven Schnelle }
269b47a4a02SSven Schnelle 
2706fd0c7bcSRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0)
271129e9cc3SRichard Henderson {
2726fd0c7bcSRichard Henderson     TCGv_i64 tmp = tcg_temp_new();
2736fd0c7bcSRichard Henderson     tcg_gen_mov_i64(tmp, a0);
274b47a4a02SSven Schnelle     return cond_make_0_tmp(c, tmp);
275129e9cc3SRichard Henderson }
276129e9cc3SRichard Henderson 
2776fd0c7bcSRichard Henderson static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
278129e9cc3SRichard Henderson {
2796fd0c7bcSRichard Henderson     TCGv_i64 t0 = tcg_temp_new();
2806fd0c7bcSRichard Henderson     TCGv_i64 t1 = tcg_temp_new();
281129e9cc3SRichard Henderson 
2826fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t0, a0);
2836fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t1, a1);
2844fe9533aSRichard Henderson     return cond_make_tmp(c, t0, t1);
285129e9cc3SRichard Henderson }
286129e9cc3SRichard Henderson 
287129e9cc3SRichard Henderson static void cond_free(DisasCond *cond)
288129e9cc3SRichard Henderson {
289129e9cc3SRichard Henderson     switch (cond->c) {
290129e9cc3SRichard Henderson     default:
291f764718dSRichard Henderson         cond->a0 = NULL;
292f764718dSRichard Henderson         cond->a1 = NULL;
293129e9cc3SRichard Henderson         /* fallthru */
294129e9cc3SRichard Henderson     case TCG_COND_ALWAYS:
295129e9cc3SRichard Henderson         cond->c = TCG_COND_NEVER;
296129e9cc3SRichard Henderson         break;
297129e9cc3SRichard Henderson     case TCG_COND_NEVER:
298129e9cc3SRichard Henderson         break;
299129e9cc3SRichard Henderson     }
300129e9cc3SRichard Henderson }
301129e9cc3SRichard Henderson 
3026fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg)
30361766fe9SRichard Henderson {
30461766fe9SRichard Henderson     if (reg == 0) {
3056fd0c7bcSRichard Henderson         TCGv_i64 t = tcg_temp_new();
3066fd0c7bcSRichard Henderson         tcg_gen_movi_i64(t, 0);
30761766fe9SRichard Henderson         return t;
30861766fe9SRichard Henderson     } else {
30961766fe9SRichard Henderson         return cpu_gr[reg];
31061766fe9SRichard Henderson     }
31161766fe9SRichard Henderson }
31261766fe9SRichard Henderson 
3136fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg)
31461766fe9SRichard Henderson {
315129e9cc3SRichard Henderson     if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
316e12c6309SRichard Henderson         return tcg_temp_new();
31761766fe9SRichard Henderson     } else {
31861766fe9SRichard Henderson         return cpu_gr[reg];
31961766fe9SRichard Henderson     }
32061766fe9SRichard Henderson }
32161766fe9SRichard Henderson 
3226fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t)
323129e9cc3SRichard Henderson {
324129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
3256fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0,
326129e9cc3SRichard Henderson                             ctx->null_cond.a1, dest, t);
327129e9cc3SRichard Henderson     } else {
3286fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, t);
329129e9cc3SRichard Henderson     }
330129e9cc3SRichard Henderson }
331129e9cc3SRichard Henderson 
3326fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t)
333129e9cc3SRichard Henderson {
334129e9cc3SRichard Henderson     if (reg != 0) {
335129e9cc3SRichard Henderson         save_or_nullify(ctx, cpu_gr[reg], t);
336129e9cc3SRichard Henderson     }
337129e9cc3SRichard Henderson }
338129e9cc3SRichard Henderson 
339e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
34096d6407fSRichard Henderson # define HI_OFS  0
34196d6407fSRichard Henderson # define LO_OFS  4
34296d6407fSRichard Henderson #else
34396d6407fSRichard Henderson # define HI_OFS  4
34496d6407fSRichard Henderson # define LO_OFS  0
34596d6407fSRichard Henderson #endif
34696d6407fSRichard Henderson 
34796d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt)
34896d6407fSRichard Henderson {
34996d6407fSRichard Henderson     TCGv_i32 ret = tcg_temp_new_i32();
350ad75a51eSRichard Henderson     tcg_gen_ld_i32(ret, tcg_env,
35196d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
35296d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
35396d6407fSRichard Henderson     return ret;
35496d6407fSRichard Henderson }
35596d6407fSRichard Henderson 
356ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt)
357ebe9383cSRichard Henderson {
358ebe9383cSRichard Henderson     if (rt == 0) {
3590992a930SRichard Henderson         TCGv_i32 ret = tcg_temp_new_i32();
3600992a930SRichard Henderson         tcg_gen_movi_i32(ret, 0);
3610992a930SRichard Henderson         return ret;
362ebe9383cSRichard Henderson     } else {
363ebe9383cSRichard Henderson         return load_frw_i32(rt);
364ebe9383cSRichard Henderson     }
365ebe9383cSRichard Henderson }
366ebe9383cSRichard Henderson 
367ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt)
368ebe9383cSRichard Henderson {
369ebe9383cSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
3700992a930SRichard Henderson     if (rt == 0) {
3710992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
3720992a930SRichard Henderson     } else {
373ad75a51eSRichard Henderson         tcg_gen_ld32u_i64(ret, tcg_env,
374ebe9383cSRichard Henderson                           offsetof(CPUHPPAState, fr[rt & 31])
375ebe9383cSRichard Henderson                           + (rt & 32 ? LO_OFS : HI_OFS));
376ebe9383cSRichard Henderson     }
3770992a930SRichard Henderson     return ret;
378ebe9383cSRichard Henderson }
379ebe9383cSRichard Henderson 
38096d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val)
38196d6407fSRichard Henderson {
382ad75a51eSRichard Henderson     tcg_gen_st_i32(val, tcg_env,
38396d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
38496d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
38596d6407fSRichard Henderson }
38696d6407fSRichard Henderson 
38796d6407fSRichard Henderson #undef HI_OFS
38896d6407fSRichard Henderson #undef LO_OFS
38996d6407fSRichard Henderson 
39096d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt)
39196d6407fSRichard Henderson {
39296d6407fSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
393ad75a51eSRichard Henderson     tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt]));
39496d6407fSRichard Henderson     return ret;
39596d6407fSRichard Henderson }
39696d6407fSRichard Henderson 
397ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt)
398ebe9383cSRichard Henderson {
399ebe9383cSRichard Henderson     if (rt == 0) {
4000992a930SRichard Henderson         TCGv_i64 ret = tcg_temp_new_i64();
4010992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
4020992a930SRichard Henderson         return ret;
403ebe9383cSRichard Henderson     } else {
404ebe9383cSRichard Henderson         return load_frd(rt);
405ebe9383cSRichard Henderson     }
406ebe9383cSRichard Henderson }
407ebe9383cSRichard Henderson 
40896d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val)
40996d6407fSRichard Henderson {
410ad75a51eSRichard Henderson     tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt]));
41196d6407fSRichard Henderson }
41296d6407fSRichard Henderson 
41333423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg)
41433423472SRichard Henderson {
41533423472SRichard Henderson #ifdef CONFIG_USER_ONLY
41633423472SRichard Henderson     tcg_gen_movi_i64(dest, 0);
41733423472SRichard Henderson #else
41833423472SRichard Henderson     if (reg < 4) {
41933423472SRichard Henderson         tcg_gen_mov_i64(dest, cpu_sr[reg]);
420494737b7SRichard Henderson     } else if (ctx->tb_flags & TB_FLAG_SR_SAME) {
421494737b7SRichard Henderson         tcg_gen_mov_i64(dest, cpu_srH);
42233423472SRichard Henderson     } else {
423ad75a51eSRichard Henderson         tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg]));
42433423472SRichard Henderson     }
42533423472SRichard Henderson #endif
42633423472SRichard Henderson }
42733423472SRichard Henderson 
428129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified.
429129e9cc3SRichard Henderson    Use this when the insn is too complex for a conditional move.  */
430129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx)
431129e9cc3SRichard Henderson {
432129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
433129e9cc3SRichard Henderson         /* The always condition should have been handled in the main loop.  */
434129e9cc3SRichard Henderson         assert(ctx->null_cond.c != TCG_COND_ALWAYS);
435129e9cc3SRichard Henderson 
436129e9cc3SRichard Henderson         ctx->null_lab = gen_new_label();
437129e9cc3SRichard Henderson 
438129e9cc3SRichard Henderson         /* If we're using PSW[N], copy it to a temp because... */
4396e94937aSRichard Henderson         if (ctx->null_cond.a0 == cpu_psw_n) {
440129e9cc3SRichard Henderson             ctx->null_cond.a0 = tcg_temp_new();
4416fd0c7bcSRichard Henderson             tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n);
442129e9cc3SRichard Henderson         }
443129e9cc3SRichard Henderson         /* ... we clear it before branching over the implementation,
444129e9cc3SRichard Henderson            so that (1) it's clear after nullifying this insn and
445129e9cc3SRichard Henderson            (2) if this insn nullifies the next, PSW[N] is valid.  */
446129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
447129e9cc3SRichard Henderson             ctx->psw_n_nonzero = false;
4486fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
449129e9cc3SRichard Henderson         }
450129e9cc3SRichard Henderson 
4516fd0c7bcSRichard Henderson         tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0,
452129e9cc3SRichard Henderson                            ctx->null_cond.a1, ctx->null_lab);
453129e9cc3SRichard Henderson         cond_free(&ctx->null_cond);
454129e9cc3SRichard Henderson     }
455129e9cc3SRichard Henderson }
456129e9cc3SRichard Henderson 
457129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N].  */
458129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx)
459129e9cc3SRichard Henderson {
460129e9cc3SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
461129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
4626fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
463129e9cc3SRichard Henderson         }
464129e9cc3SRichard Henderson         return;
465129e9cc3SRichard Henderson     }
4666e94937aSRichard Henderson     if (ctx->null_cond.a0 != cpu_psw_n) {
4676fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n,
468129e9cc3SRichard Henderson                             ctx->null_cond.a0, ctx->null_cond.a1);
469129e9cc3SRichard Henderson         ctx->psw_n_nonzero = true;
470129e9cc3SRichard Henderson     }
471129e9cc3SRichard Henderson     cond_free(&ctx->null_cond);
472129e9cc3SRichard Henderson }
473129e9cc3SRichard Henderson 
474129e9cc3SRichard Henderson /* Set a PSW[N] to X.  The intention is that this is used immediately
475129e9cc3SRichard Henderson    before a goto_tb/exit_tb, so that there is no fallthru path to other
476129e9cc3SRichard Henderson    code within the TB.  Therefore we do not update psw_n_nonzero.  */
477129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x)
478129e9cc3SRichard Henderson {
479129e9cc3SRichard Henderson     if (ctx->psw_n_nonzero || x) {
4806fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, x);
481129e9cc3SRichard Henderson     }
482129e9cc3SRichard Henderson }
483129e9cc3SRichard Henderson 
484129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified.
48540f9f908SRichard Henderson    This is the pair to nullify_over.  Always returns true so that
48640f9f908SRichard Henderson    it may be tail-called from a translate function.  */
48731234768SRichard Henderson static bool nullify_end(DisasContext *ctx)
488129e9cc3SRichard Henderson {
489129e9cc3SRichard Henderson     TCGLabel *null_lab = ctx->null_lab;
49031234768SRichard Henderson     DisasJumpType status = ctx->base.is_jmp;
491129e9cc3SRichard Henderson 
492f49b3537SRichard Henderson     /* For NEXT, NORETURN, STALE, we can easily continue (or exit).
493f49b3537SRichard Henderson        For UPDATED, we cannot update on the nullified path.  */
494f49b3537SRichard Henderson     assert(status != DISAS_IAQ_N_UPDATED);
495f49b3537SRichard Henderson 
496129e9cc3SRichard Henderson     if (likely(null_lab == NULL)) {
497129e9cc3SRichard Henderson         /* The current insn wasn't conditional or handled the condition
498129e9cc3SRichard Henderson            applied to it without a branch, so the (new) setting of
499129e9cc3SRichard Henderson            NULL_COND can be applied directly to the next insn.  */
50031234768SRichard Henderson         return true;
501129e9cc3SRichard Henderson     }
502129e9cc3SRichard Henderson     ctx->null_lab = NULL;
503129e9cc3SRichard Henderson 
504129e9cc3SRichard Henderson     if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
505129e9cc3SRichard Henderson         /* The next instruction will be unconditional,
506129e9cc3SRichard Henderson            and NULL_COND already reflects that.  */
507129e9cc3SRichard Henderson         gen_set_label(null_lab);
508129e9cc3SRichard Henderson     } else {
509129e9cc3SRichard Henderson         /* The insn that we just executed is itself nullifying the next
510129e9cc3SRichard Henderson            instruction.  Store the condition in the PSW[N] global.
511129e9cc3SRichard Henderson            We asserted PSW[N] = 0 in nullify_over, so that after the
512129e9cc3SRichard Henderson            label we have the proper value in place.  */
513129e9cc3SRichard Henderson         nullify_save(ctx);
514129e9cc3SRichard Henderson         gen_set_label(null_lab);
515129e9cc3SRichard Henderson         ctx->null_cond = cond_make_n();
516129e9cc3SRichard Henderson     }
517869051eaSRichard Henderson     if (status == DISAS_NORETURN) {
51831234768SRichard Henderson         ctx->base.is_jmp = DISAS_NEXT;
519129e9cc3SRichard Henderson     }
52031234768SRichard Henderson     return true;
521129e9cc3SRichard Henderson }
522129e9cc3SRichard Henderson 
523c53e401eSRichard Henderson static uint64_t gva_offset_mask(DisasContext *ctx)
524698240d1SRichard Henderson {
525698240d1SRichard Henderson     return (ctx->tb_flags & PSW_W
526698240d1SRichard Henderson             ? MAKE_64BIT_MASK(0, 62)
527698240d1SRichard Henderson             : MAKE_64BIT_MASK(0, 32));
528698240d1SRichard Henderson }
529698240d1SRichard Henderson 
5306fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest,
5316fd0c7bcSRichard Henderson                             uint64_t ival, TCGv_i64 vval)
53261766fe9SRichard Henderson {
533c53e401eSRichard Henderson     uint64_t mask = gva_offset_mask(ctx);
534f13bf343SRichard Henderson 
535f13bf343SRichard Henderson     if (ival != -1) {
5366fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, ival & mask);
537f13bf343SRichard Henderson         return;
538f13bf343SRichard Henderson     }
539f13bf343SRichard Henderson     tcg_debug_assert(vval != NULL);
540f13bf343SRichard Henderson 
541f13bf343SRichard Henderson     /*
542f13bf343SRichard Henderson      * We know that the IAOQ is already properly masked.
543f13bf343SRichard Henderson      * This optimization is primarily for "iaoq_f = iaoq_b".
544f13bf343SRichard Henderson      */
545f13bf343SRichard Henderson     if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) {
5466fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, vval);
54761766fe9SRichard Henderson     } else {
5486fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, vval, mask);
54961766fe9SRichard Henderson     }
55061766fe9SRichard Henderson }
55161766fe9SRichard Henderson 
552c53e401eSRichard Henderson static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp)
55361766fe9SRichard Henderson {
55461766fe9SRichard Henderson     return ctx->iaoq_f + disp + 8;
55561766fe9SRichard Henderson }
55661766fe9SRichard Henderson 
55761766fe9SRichard Henderson static void gen_excp_1(int exception)
55861766fe9SRichard Henderson {
559ad75a51eSRichard Henderson     gen_helper_excp(tcg_env, tcg_constant_i32(exception));
56061766fe9SRichard Henderson }
56161766fe9SRichard Henderson 
56231234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception)
56361766fe9SRichard Henderson {
564741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
565741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
566129e9cc3SRichard Henderson     nullify_save(ctx);
56761766fe9SRichard Henderson     gen_excp_1(exception);
56831234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
56961766fe9SRichard Henderson }
57061766fe9SRichard Henderson 
57131234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc)
5721a19da0dSRichard Henderson {
57331234768SRichard Henderson     nullify_over(ctx);
5746fd0c7bcSRichard Henderson     tcg_gen_st_i64(tcg_constant_i64(ctx->insn),
575ad75a51eSRichard Henderson                    tcg_env, offsetof(CPUHPPAState, cr[CR_IIR]));
57631234768SRichard Henderson     gen_excp(ctx, exc);
57731234768SRichard Henderson     return nullify_end(ctx);
5781a19da0dSRichard Henderson }
5791a19da0dSRichard Henderson 
58031234768SRichard Henderson static bool gen_illegal(DisasContext *ctx)
58161766fe9SRichard Henderson {
58231234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_ILL);
58361766fe9SRichard Henderson }
58461766fe9SRichard Henderson 
58540f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY
58640f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
58740f9f908SRichard Henderson     return gen_excp_iir(ctx, EXCP)
58840f9f908SRichard Henderson #else
589e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
590e1b5a5edSRichard Henderson     do {                                     \
591e1b5a5edSRichard Henderson         if (ctx->privilege != 0) {           \
59231234768SRichard Henderson             return gen_excp_iir(ctx, EXCP);  \
593e1b5a5edSRichard Henderson         }                                    \
594e1b5a5edSRichard Henderson     } while (0)
59540f9f908SRichard Henderson #endif
596e1b5a5edSRichard Henderson 
597c53e401eSRichard Henderson static bool use_goto_tb(DisasContext *ctx, uint64_t dest)
59861766fe9SRichard Henderson {
59957f91498SRichard Henderson     return translator_use_goto_tb(&ctx->base, dest);
60061766fe9SRichard Henderson }
60161766fe9SRichard Henderson 
602129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page,
603129e9cc3SRichard Henderson    and we're not attempting to set a breakpoint on it, then we can
604129e9cc3SRichard Henderson    totally skip the nullified insn.  This avoids creating and
605129e9cc3SRichard Henderson    executing a TB that merely branches to the next TB.  */
606129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx)
607129e9cc3SRichard Henderson {
608129e9cc3SRichard Henderson     return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
609129e9cc3SRichard Henderson             && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
610129e9cc3SRichard Henderson }
611129e9cc3SRichard Henderson 
61261766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which,
613c53e401eSRichard Henderson                         uint64_t f, uint64_t b)
61461766fe9SRichard Henderson {
61561766fe9SRichard Henderson     if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
61661766fe9SRichard Henderson         tcg_gen_goto_tb(which);
617a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, f, NULL);
618a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, b, NULL);
61907ea28b4SRichard Henderson         tcg_gen_exit_tb(ctx->base.tb, which);
62061766fe9SRichard Henderson     } else {
621741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, f, cpu_iaoq_b);
622741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, b, ctx->iaoq_n_var);
6237f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
62461766fe9SRichard Henderson     }
62561766fe9SRichard Henderson }
62661766fe9SRichard Henderson 
627b47a4a02SSven Schnelle static bool cond_need_sv(int c)
628b47a4a02SSven Schnelle {
629b47a4a02SSven Schnelle     return c == 2 || c == 3 || c == 6;
630b47a4a02SSven Schnelle }
631b47a4a02SSven Schnelle 
632b47a4a02SSven Schnelle static bool cond_need_cb(int c)
633b47a4a02SSven Schnelle {
634b47a4a02SSven Schnelle     return c == 4 || c == 5;
635b47a4a02SSven Schnelle }
636b47a4a02SSven Schnelle 
6376fd0c7bcSRichard Henderson /* Need extensions from TCGv_i32 to TCGv_i64. */
63872ca8753SRichard Henderson static bool cond_need_ext(DisasContext *ctx, bool d)
63972ca8753SRichard Henderson {
640c53e401eSRichard Henderson     return !(ctx->is_pa20 && d);
64172ca8753SRichard Henderson }
64272ca8753SRichard Henderson 
643b47a4a02SSven Schnelle /*
644b47a4a02SSven Schnelle  * Compute conditional for arithmetic.  See Page 5-3, Table 5-1, of
645b47a4a02SSven Schnelle  * the Parisc 1.1 Architecture Reference Manual for details.
646b47a4a02SSven Schnelle  */
647b2167459SRichard Henderson 
648a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d,
6496fd0c7bcSRichard Henderson                          TCGv_i64 res, TCGv_i64 cb_msb, TCGv_i64 sv)
650b2167459SRichard Henderson {
651b2167459SRichard Henderson     DisasCond cond;
6526fd0c7bcSRichard Henderson     TCGv_i64 tmp;
653b2167459SRichard Henderson 
654b2167459SRichard Henderson     switch (cf >> 1) {
655b47a4a02SSven Schnelle     case 0: /* Never / TR    (0 / 1) */
656b2167459SRichard Henderson         cond = cond_make_f();
657b2167459SRichard Henderson         break;
658b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
659a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
660a751eb31SRichard Henderson             tmp = tcg_temp_new();
6616fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
662a751eb31SRichard Henderson             res = tmp;
663a751eb31SRichard Henderson         }
664b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, res);
665b2167459SRichard Henderson         break;
666b47a4a02SSven Schnelle     case 2: /* < / >=        (N ^ V / !(N ^ V) */
667b47a4a02SSven Schnelle         tmp = tcg_temp_new();
6686fd0c7bcSRichard Henderson         tcg_gen_xor_i64(tmp, res, sv);
669a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
6706fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, tmp);
671a751eb31SRichard Henderson         }
672b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_LT, tmp);
673b2167459SRichard Henderson         break;
674b47a4a02SSven Schnelle     case 3: /* <= / >        (N ^ V) | Z / !((N ^ V) | Z) */
675b47a4a02SSven Schnelle         /*
676b47a4a02SSven Schnelle          * Simplify:
677b47a4a02SSven Schnelle          *   (N ^ V) | Z
678b47a4a02SSven Schnelle          *   ((res < 0) ^ (sv < 0)) | !res
679b47a4a02SSven Schnelle          *   ((res ^ sv) < 0) | !res
680b47a4a02SSven Schnelle          *   (~(res ^ sv) >= 0) | !res
681b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31) | !res
682b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31 & res)
683b47a4a02SSven Schnelle          */
684b47a4a02SSven Schnelle         tmp = tcg_temp_new();
6856fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(tmp, res, sv);
686a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
6876fd0c7bcSRichard Henderson             tcg_gen_sextract_i64(tmp, tmp, 31, 1);
6886fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
6896fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
690a751eb31SRichard Henderson         } else {
6916fd0c7bcSRichard Henderson             tcg_gen_sari_i64(tmp, tmp, 63);
6926fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
693a751eb31SRichard Henderson         }
694b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
695b2167459SRichard Henderson         break;
696b2167459SRichard Henderson     case 4: /* NUV / UV      (!C / C) */
697a751eb31SRichard Henderson         /* Only bit 0 of cb_msb is ever set. */
698b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, cb_msb);
699b2167459SRichard Henderson         break;
700b2167459SRichard Henderson     case 5: /* ZNV / VNZ     (!C | Z / C & !Z) */
701b2167459SRichard Henderson         tmp = tcg_temp_new();
7026fd0c7bcSRichard Henderson         tcg_gen_neg_i64(tmp, cb_msb);
7036fd0c7bcSRichard Henderson         tcg_gen_and_i64(tmp, tmp, res);
704a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
7056fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
706a751eb31SRichard Henderson         }
707b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
708b2167459SRichard Henderson         break;
709b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
710a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
711a751eb31SRichard Henderson             tmp = tcg_temp_new();
7126fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, sv);
713a751eb31SRichard Henderson             sv = tmp;
714a751eb31SRichard Henderson         }
715b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, sv);
716b2167459SRichard Henderson         break;
717b2167459SRichard Henderson     case 7: /* OD / EV */
718b2167459SRichard Henderson         tmp = tcg_temp_new();
7196fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, res, 1);
720b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_NE, tmp);
721b2167459SRichard Henderson         break;
722b2167459SRichard Henderson     default:
723b2167459SRichard Henderson         g_assert_not_reached();
724b2167459SRichard Henderson     }
725b2167459SRichard Henderson     if (cf & 1) {
726b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
727b2167459SRichard Henderson     }
728b2167459SRichard Henderson 
729b2167459SRichard Henderson     return cond;
730b2167459SRichard Henderson }
731b2167459SRichard Henderson 
732b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
733b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
734b2167459SRichard Henderson    deleted as unused.  */
735b2167459SRichard Henderson 
7364fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d,
7376fd0c7bcSRichard Henderson                              TCGv_i64 res, TCGv_i64 in1,
7386fd0c7bcSRichard Henderson                              TCGv_i64 in2, TCGv_i64 sv)
739b2167459SRichard Henderson {
7404fe9533aSRichard Henderson     TCGCond tc;
7414fe9533aSRichard Henderson     bool ext_uns;
742b2167459SRichard Henderson 
743b2167459SRichard Henderson     switch (cf >> 1) {
744b2167459SRichard Henderson     case 1: /* = / <> */
7454fe9533aSRichard Henderson         tc = TCG_COND_EQ;
7464fe9533aSRichard Henderson         ext_uns = true;
747b2167459SRichard Henderson         break;
748b2167459SRichard Henderson     case 2: /* < / >= */
7494fe9533aSRichard Henderson         tc = TCG_COND_LT;
7504fe9533aSRichard Henderson         ext_uns = false;
751b2167459SRichard Henderson         break;
752b2167459SRichard Henderson     case 3: /* <= / > */
7534fe9533aSRichard Henderson         tc = TCG_COND_LE;
7544fe9533aSRichard Henderson         ext_uns = false;
755b2167459SRichard Henderson         break;
756b2167459SRichard Henderson     case 4: /* << / >>= */
7574fe9533aSRichard Henderson         tc = TCG_COND_LTU;
7584fe9533aSRichard Henderson         ext_uns = true;
759b2167459SRichard Henderson         break;
760b2167459SRichard Henderson     case 5: /* <<= / >> */
7614fe9533aSRichard Henderson         tc = TCG_COND_LEU;
7624fe9533aSRichard Henderson         ext_uns = true;
763b2167459SRichard Henderson         break;
764b2167459SRichard Henderson     default:
765a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, sv);
766b2167459SRichard Henderson     }
767b2167459SRichard Henderson 
7684fe9533aSRichard Henderson     if (cf & 1) {
7694fe9533aSRichard Henderson         tc = tcg_invert_cond(tc);
7704fe9533aSRichard Henderson     }
7714fe9533aSRichard Henderson     if (cond_need_ext(ctx, d)) {
7726fd0c7bcSRichard Henderson         TCGv_i64 t1 = tcg_temp_new();
7736fd0c7bcSRichard Henderson         TCGv_i64 t2 = tcg_temp_new();
7744fe9533aSRichard Henderson 
7754fe9533aSRichard Henderson         if (ext_uns) {
7766fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t1, in1);
7776fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t2, in2);
7784fe9533aSRichard Henderson         } else {
7796fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t1, in1);
7806fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t2, in2);
7814fe9533aSRichard Henderson         }
7824fe9533aSRichard Henderson         return cond_make_tmp(tc, t1, t2);
7834fe9533aSRichard Henderson     }
7844fe9533aSRichard Henderson     return cond_make(tc, in1, in2);
785b2167459SRichard Henderson }
786b2167459SRichard Henderson 
787df0232feSRichard Henderson /*
788df0232feSRichard Henderson  * Similar, but for logicals, where the carry and overflow bits are not
789df0232feSRichard Henderson  * computed, and use of them is undefined.
790df0232feSRichard Henderson  *
791df0232feSRichard Henderson  * Undefined or not, hardware does not trap.  It seems reasonable to
792df0232feSRichard Henderson  * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's
793df0232feSRichard Henderson  * how cases c={2,3} are treated.
794df0232feSRichard Henderson  */
795b2167459SRichard Henderson 
796b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d,
7976fd0c7bcSRichard Henderson                              TCGv_i64 res)
798b2167459SRichard Henderson {
799b5af8423SRichard Henderson     TCGCond tc;
800b5af8423SRichard Henderson     bool ext_uns;
801a751eb31SRichard Henderson 
802df0232feSRichard Henderson     switch (cf) {
803df0232feSRichard Henderson     case 0:  /* never */
804df0232feSRichard Henderson     case 9:  /* undef, C */
805df0232feSRichard Henderson     case 11: /* undef, C & !Z */
806df0232feSRichard Henderson     case 12: /* undef, V */
807df0232feSRichard Henderson         return cond_make_f();
808df0232feSRichard Henderson 
809df0232feSRichard Henderson     case 1:  /* true */
810df0232feSRichard Henderson     case 8:  /* undef, !C */
811df0232feSRichard Henderson     case 10: /* undef, !C | Z */
812df0232feSRichard Henderson     case 13: /* undef, !V */
813df0232feSRichard Henderson         return cond_make_t();
814df0232feSRichard Henderson 
815df0232feSRichard Henderson     case 2:  /* == */
816b5af8423SRichard Henderson         tc = TCG_COND_EQ;
817b5af8423SRichard Henderson         ext_uns = true;
818b5af8423SRichard Henderson         break;
819df0232feSRichard Henderson     case 3:  /* <> */
820b5af8423SRichard Henderson         tc = TCG_COND_NE;
821b5af8423SRichard Henderson         ext_uns = true;
822b5af8423SRichard Henderson         break;
823df0232feSRichard Henderson     case 4:  /* < */
824b5af8423SRichard Henderson         tc = TCG_COND_LT;
825b5af8423SRichard Henderson         ext_uns = false;
826b5af8423SRichard Henderson         break;
827df0232feSRichard Henderson     case 5:  /* >= */
828b5af8423SRichard Henderson         tc = TCG_COND_GE;
829b5af8423SRichard Henderson         ext_uns = false;
830b5af8423SRichard Henderson         break;
831df0232feSRichard Henderson     case 6:  /* <= */
832b5af8423SRichard Henderson         tc = TCG_COND_LE;
833b5af8423SRichard Henderson         ext_uns = false;
834b5af8423SRichard Henderson         break;
835df0232feSRichard Henderson     case 7:  /* > */
836b5af8423SRichard Henderson         tc = TCG_COND_GT;
837b5af8423SRichard Henderson         ext_uns = false;
838b5af8423SRichard Henderson         break;
839df0232feSRichard Henderson 
840df0232feSRichard Henderson     case 14: /* OD */
841df0232feSRichard Henderson     case 15: /* EV */
842a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, NULL);
843df0232feSRichard Henderson 
844df0232feSRichard Henderson     default:
845df0232feSRichard Henderson         g_assert_not_reached();
846b2167459SRichard Henderson     }
847b5af8423SRichard Henderson 
848b5af8423SRichard Henderson     if (cond_need_ext(ctx, d)) {
8496fd0c7bcSRichard Henderson         TCGv_i64 tmp = tcg_temp_new();
850b5af8423SRichard Henderson 
851b5af8423SRichard Henderson         if (ext_uns) {
8526fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
853b5af8423SRichard Henderson         } else {
8546fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, res);
855b5af8423SRichard Henderson         }
856b5af8423SRichard Henderson         return cond_make_0_tmp(tc, tmp);
857b5af8423SRichard Henderson     }
858b5af8423SRichard Henderson     return cond_make_0(tc, res);
859b2167459SRichard Henderson }
860b2167459SRichard Henderson 
86198cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
86298cd9ca7SRichard Henderson 
8634fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d,
8646fd0c7bcSRichard Henderson                              TCGv_i64 res)
86598cd9ca7SRichard Henderson {
86698cd9ca7SRichard Henderson     unsigned c, f;
86798cd9ca7SRichard Henderson 
86898cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
86998cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
87098cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
87198cd9ca7SRichard Henderson     c = orig & 3;
87298cd9ca7SRichard Henderson     if (c == 3) {
87398cd9ca7SRichard Henderson         c = 7;
87498cd9ca7SRichard Henderson     }
87598cd9ca7SRichard Henderson     f = (orig & 4) / 4;
87698cd9ca7SRichard Henderson 
877b5af8423SRichard Henderson     return do_log_cond(ctx, c * 2 + f, d, res);
87898cd9ca7SRichard Henderson }
87998cd9ca7SRichard Henderson 
880b2167459SRichard Henderson /* Similar, but for unit conditions.  */
881b2167459SRichard Henderson 
8826fd0c7bcSRichard Henderson static DisasCond do_unit_cond(unsigned cf, bool d, TCGv_i64 res,
8836fd0c7bcSRichard Henderson                               TCGv_i64 in1, TCGv_i64 in2)
884b2167459SRichard Henderson {
885b2167459SRichard Henderson     DisasCond cond;
8866fd0c7bcSRichard Henderson     TCGv_i64 tmp, cb = NULL;
887c53e401eSRichard Henderson     uint64_t d_repl = d ? 0x0000000100000001ull : 1;
888b2167459SRichard Henderson 
889b2167459SRichard Henderson     if (cf & 8) {
890b2167459SRichard Henderson         /* Since we want to test lots of carry-out bits all at once, do not
891b2167459SRichard Henderson          * do our normal thing and compute carry-in of bit B+1 since that
892b2167459SRichard Henderson          * leaves us with carry bits spread across two words.
893b2167459SRichard Henderson          */
894b2167459SRichard Henderson         cb = tcg_temp_new();
895b2167459SRichard Henderson         tmp = tcg_temp_new();
8966fd0c7bcSRichard Henderson         tcg_gen_or_i64(cb, in1, in2);
8976fd0c7bcSRichard Henderson         tcg_gen_and_i64(tmp, in1, in2);
8986fd0c7bcSRichard Henderson         tcg_gen_andc_i64(cb, cb, res);
8996fd0c7bcSRichard Henderson         tcg_gen_or_i64(cb, cb, tmp);
900b2167459SRichard Henderson     }
901b2167459SRichard Henderson 
902b2167459SRichard Henderson     switch (cf >> 1) {
903b2167459SRichard Henderson     case 0: /* never / TR */
904b2167459SRichard Henderson     case 1: /* undefined */
905b2167459SRichard Henderson     case 5: /* undefined */
906b2167459SRichard Henderson         cond = cond_make_f();
907b2167459SRichard Henderson         break;
908b2167459SRichard Henderson 
909b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
910b2167459SRichard Henderson         /* See hasless(v,1) from
911b2167459SRichard Henderson          * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
912b2167459SRichard Henderson          */
913b2167459SRichard Henderson         tmp = tcg_temp_new();
9146fd0c7bcSRichard Henderson         tcg_gen_subi_i64(tmp, res, d_repl * 0x01010101u);
9156fd0c7bcSRichard Henderson         tcg_gen_andc_i64(tmp, tmp, res);
9166fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80808080u);
917b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
918b2167459SRichard Henderson         break;
919b2167459SRichard Henderson 
920b2167459SRichard Henderson     case 3: /* SHZ / NHZ */
921b2167459SRichard Henderson         tmp = tcg_temp_new();
9226fd0c7bcSRichard Henderson         tcg_gen_subi_i64(tmp, res, d_repl * 0x00010001u);
9236fd0c7bcSRichard Henderson         tcg_gen_andc_i64(tmp, tmp, res);
9246fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80008000u);
925b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
926b2167459SRichard Henderson         break;
927b2167459SRichard Henderson 
928b2167459SRichard Henderson     case 4: /* SDC / NDC */
9296fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x88888888u);
930b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
931b2167459SRichard Henderson         break;
932b2167459SRichard Henderson 
933b2167459SRichard Henderson     case 6: /* SBC / NBC */
9346fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x80808080u);
935b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
936b2167459SRichard Henderson         break;
937b2167459SRichard Henderson 
938b2167459SRichard Henderson     case 7: /* SHC / NHC */
9396fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x80008000u);
940b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
941b2167459SRichard Henderson         break;
942b2167459SRichard Henderson 
943b2167459SRichard Henderson     default:
944b2167459SRichard Henderson         g_assert_not_reached();
945b2167459SRichard Henderson     }
946b2167459SRichard Henderson     if (cf & 1) {
947b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
948b2167459SRichard Henderson     }
949b2167459SRichard Henderson 
950b2167459SRichard Henderson     return cond;
951b2167459SRichard Henderson }
952b2167459SRichard Henderson 
9536fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d,
9546fd0c7bcSRichard Henderson                           TCGv_i64 cb, TCGv_i64 cb_msb)
95572ca8753SRichard Henderson {
95672ca8753SRichard Henderson     if (cond_need_ext(ctx, d)) {
9576fd0c7bcSRichard Henderson         TCGv_i64 t = tcg_temp_new();
9586fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, cb, 32, 1);
95972ca8753SRichard Henderson         return t;
96072ca8753SRichard Henderson     }
96172ca8753SRichard Henderson     return cb_msb;
96272ca8753SRichard Henderson }
96372ca8753SRichard Henderson 
9646fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d)
96572ca8753SRichard Henderson {
96672ca8753SRichard Henderson     return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb);
96772ca8753SRichard Henderson }
96872ca8753SRichard Henderson 
969b2167459SRichard Henderson /* Compute signed overflow for addition.  */
9706fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res,
9716fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
972b2167459SRichard Henderson {
9736fd0c7bcSRichard Henderson     TCGv_i64 sv = tcg_temp_new();
9746fd0c7bcSRichard Henderson     TCGv_i64 tmp = tcg_temp_new();
975b2167459SRichard Henderson 
9766fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
9776fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
9786fd0c7bcSRichard Henderson     tcg_gen_andc_i64(sv, sv, tmp);
979b2167459SRichard Henderson 
980b2167459SRichard Henderson     return sv;
981b2167459SRichard Henderson }
982b2167459SRichard Henderson 
983b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
9846fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res,
9856fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
986b2167459SRichard Henderson {
9876fd0c7bcSRichard Henderson     TCGv_i64 sv = tcg_temp_new();
9886fd0c7bcSRichard Henderson     TCGv_i64 tmp = tcg_temp_new();
989b2167459SRichard Henderson 
9906fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
9916fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
9926fd0c7bcSRichard Henderson     tcg_gen_and_i64(sv, sv, tmp);
993b2167459SRichard Henderson 
994b2167459SRichard Henderson     return sv;
995b2167459SRichard Henderson }
996b2167459SRichard Henderson 
9976fd0c7bcSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
9986fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned shift, bool is_l,
999faf97ba1SRichard Henderson                    bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d)
1000b2167459SRichard Henderson {
10016fd0c7bcSRichard Henderson     TCGv_i64 dest, cb, cb_msb, cb_cond, sv, tmp;
1002b2167459SRichard Henderson     unsigned c = cf >> 1;
1003b2167459SRichard Henderson     DisasCond cond;
1004b2167459SRichard Henderson 
1005b2167459SRichard Henderson     dest = tcg_temp_new();
1006f764718dSRichard Henderson     cb = NULL;
1007f764718dSRichard Henderson     cb_msb = NULL;
1008bdcccc17SRichard Henderson     cb_cond = NULL;
1009b2167459SRichard Henderson 
1010b2167459SRichard Henderson     if (shift) {
1011e12c6309SRichard Henderson         tmp = tcg_temp_new();
10126fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, in1, shift);
1013b2167459SRichard Henderson         in1 = tmp;
1014b2167459SRichard Henderson     }
1015b2167459SRichard Henderson 
1016b47a4a02SSven Schnelle     if (!is_l || cond_need_cb(c)) {
10176fd0c7bcSRichard Henderson         TCGv_i64 zero = tcg_constant_i64(0);
1018e12c6309SRichard Henderson         cb_msb = tcg_temp_new();
1019bdcccc17SRichard Henderson         cb = tcg_temp_new();
1020bdcccc17SRichard Henderson 
10216fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, zero, in2, zero);
1022b2167459SRichard Henderson         if (is_c) {
10236fd0c7bcSRichard Henderson             tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb,
1024bdcccc17SRichard Henderson                              get_psw_carry(ctx, d), zero);
1025b2167459SRichard Henderson         }
10266fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
10276fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1028bdcccc17SRichard Henderson         if (cond_need_cb(c)) {
1029bdcccc17SRichard Henderson             cb_cond = get_carry(ctx, d, cb, cb_msb);
1030b2167459SRichard Henderson         }
1031b2167459SRichard Henderson     } else {
10326fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
1033b2167459SRichard Henderson         if (is_c) {
10346fd0c7bcSRichard Henderson             tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d));
1035b2167459SRichard Henderson         }
1036b2167459SRichard Henderson     }
1037b2167459SRichard Henderson 
1038b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1039f764718dSRichard Henderson     sv = NULL;
1040b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1041b2167459SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
1042b2167459SRichard Henderson         if (is_tsv) {
1043b2167459SRichard Henderson             /* ??? Need to include overflow from shift.  */
1044ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1045b2167459SRichard Henderson         }
1046b2167459SRichard Henderson     }
1047b2167459SRichard Henderson 
1048b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1049a751eb31SRichard Henderson     cond = do_cond(ctx, cf, d, dest, cb_cond, sv);
1050b2167459SRichard Henderson     if (is_tc) {
1051b2167459SRichard Henderson         tmp = tcg_temp_new();
10526fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1053ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1054b2167459SRichard Henderson     }
1055b2167459SRichard Henderson 
1056b2167459SRichard Henderson     /* Write back the result.  */
1057b2167459SRichard Henderson     if (!is_l) {
1058b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
1059b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1060b2167459SRichard Henderson     }
1061b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1062b2167459SRichard Henderson 
1063b2167459SRichard Henderson     /* Install the new nullification.  */
1064b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1065b2167459SRichard Henderson     ctx->null_cond = cond;
1066b2167459SRichard Henderson }
1067b2167459SRichard Henderson 
1068faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a,
10690c982a28SRichard Henderson                        bool is_l, bool is_tsv, bool is_tc, bool is_c)
10700c982a28SRichard Henderson {
10716fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
10720c982a28SRichard Henderson 
10730c982a28SRichard Henderson     if (a->cf) {
10740c982a28SRichard Henderson         nullify_over(ctx);
10750c982a28SRichard Henderson     }
10760c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
10770c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1078faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l,
1079faf97ba1SRichard Henderson            is_tsv, is_tc, is_c, a->cf, a->d);
10800c982a28SRichard Henderson     return nullify_end(ctx);
10810c982a28SRichard Henderson }
10820c982a28SRichard Henderson 
10830588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a,
10840588e061SRichard Henderson                        bool is_tsv, bool is_tc)
10850588e061SRichard Henderson {
10866fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
10870588e061SRichard Henderson 
10880588e061SRichard Henderson     if (a->cf) {
10890588e061SRichard Henderson         nullify_over(ctx);
10900588e061SRichard Henderson     }
10916fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
10920588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
1093faf97ba1SRichard Henderson     /* All ADDI conditions are 32-bit. */
1094faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false);
10950588e061SRichard Henderson     return nullify_end(ctx);
10960588e061SRichard Henderson }
10970588e061SRichard Henderson 
10986fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
10996fd0c7bcSRichard Henderson                    TCGv_i64 in2, bool is_tsv, bool is_b,
110063c427c6SRichard Henderson                    bool is_tc, unsigned cf, bool d)
1101b2167459SRichard Henderson {
11026fd0c7bcSRichard Henderson     TCGv_i64 dest, sv, cb, cb_msb, zero, tmp;
1103b2167459SRichard Henderson     unsigned c = cf >> 1;
1104b2167459SRichard Henderson     DisasCond cond;
1105b2167459SRichard Henderson 
1106b2167459SRichard Henderson     dest = tcg_temp_new();
1107b2167459SRichard Henderson     cb = tcg_temp_new();
1108b2167459SRichard Henderson     cb_msb = tcg_temp_new();
1109b2167459SRichard Henderson 
11106fd0c7bcSRichard Henderson     zero = tcg_constant_i64(0);
1111b2167459SRichard Henderson     if (is_b) {
1112b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
11136fd0c7bcSRichard Henderson         tcg_gen_not_i64(cb, in2);
11146fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, zero, get_psw_carry(ctx, d), zero);
11156fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, zero);
11166fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, in1);
11176fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1118b2167459SRichard Henderson     } else {
1119bdcccc17SRichard Henderson         /*
1120bdcccc17SRichard Henderson          * DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
1121bdcccc17SRichard Henderson          * operations by seeding the high word with 1 and subtracting.
1122bdcccc17SRichard Henderson          */
11236fd0c7bcSRichard Henderson         TCGv_i64 one = tcg_constant_i64(1);
11246fd0c7bcSRichard Henderson         tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, zero);
11256fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(cb, in1, in2);
11266fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1127b2167459SRichard Henderson     }
1128b2167459SRichard Henderson 
1129b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1130f764718dSRichard Henderson     sv = NULL;
1131b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1132b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1133b2167459SRichard Henderson         if (is_tsv) {
1134ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1135b2167459SRichard Henderson         }
1136b2167459SRichard Henderson     }
1137b2167459SRichard Henderson 
1138b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
1139b2167459SRichard Henderson     if (!is_b) {
11404fe9533aSRichard Henderson         cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1141b2167459SRichard Henderson     } else {
1142a751eb31SRichard Henderson         cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv);
1143b2167459SRichard Henderson     }
1144b2167459SRichard Henderson 
1145b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1146b2167459SRichard Henderson     if (is_tc) {
1147b2167459SRichard Henderson         tmp = tcg_temp_new();
11486fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1149ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1150b2167459SRichard Henderson     }
1151b2167459SRichard Henderson 
1152b2167459SRichard Henderson     /* Write back the result.  */
1153b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
1154b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1155b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1156b2167459SRichard Henderson 
1157b2167459SRichard Henderson     /* Install the new nullification.  */
1158b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1159b2167459SRichard Henderson     ctx->null_cond = cond;
1160b2167459SRichard Henderson }
1161b2167459SRichard Henderson 
116263c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a,
11630c982a28SRichard Henderson                        bool is_tsv, bool is_b, bool is_tc)
11640c982a28SRichard Henderson {
11656fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
11660c982a28SRichard Henderson 
11670c982a28SRichard Henderson     if (a->cf) {
11680c982a28SRichard Henderson         nullify_over(ctx);
11690c982a28SRichard Henderson     }
11700c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
11710c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
117263c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d);
11730c982a28SRichard Henderson     return nullify_end(ctx);
11740c982a28SRichard Henderson }
11750c982a28SRichard Henderson 
11760588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv)
11770588e061SRichard Henderson {
11786fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
11790588e061SRichard Henderson 
11800588e061SRichard Henderson     if (a->cf) {
11810588e061SRichard Henderson         nullify_over(ctx);
11820588e061SRichard Henderson     }
11836fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
11840588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
118563c427c6SRichard Henderson     /* All SUBI conditions are 32-bit. */
118663c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false);
11870588e061SRichard Henderson     return nullify_end(ctx);
11880588e061SRichard Henderson }
11890588e061SRichard Henderson 
11906fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
11916fd0c7bcSRichard Henderson                       TCGv_i64 in2, unsigned cf, bool d)
1192b2167459SRichard Henderson {
11936fd0c7bcSRichard Henderson     TCGv_i64 dest, sv;
1194b2167459SRichard Henderson     DisasCond cond;
1195b2167459SRichard Henderson 
1196b2167459SRichard Henderson     dest = tcg_temp_new();
11976fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
1198b2167459SRichard Henderson 
1199b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1200f764718dSRichard Henderson     sv = NULL;
1201b47a4a02SSven Schnelle     if (cond_need_sv(cf >> 1)) {
1202b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1203b2167459SRichard Henderson     }
1204b2167459SRichard Henderson 
1205b2167459SRichard Henderson     /* Form the condition for the compare.  */
12064fe9533aSRichard Henderson     cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1207b2167459SRichard Henderson 
1208b2167459SRichard Henderson     /* Clear.  */
12096fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
1210b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1211b2167459SRichard Henderson 
1212b2167459SRichard Henderson     /* Install the new nullification.  */
1213b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1214b2167459SRichard Henderson     ctx->null_cond = cond;
1215b2167459SRichard Henderson }
1216b2167459SRichard Henderson 
12176fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12186fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned cf, bool d,
12196fd0c7bcSRichard Henderson                    void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1220b2167459SRichard Henderson {
12216fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, rt);
1222b2167459SRichard Henderson 
1223b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
1224b2167459SRichard Henderson     fn(dest, in1, in2);
1225b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1226b2167459SRichard Henderson 
1227b2167459SRichard Henderson     /* Install the new nullification.  */
1228b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1229b2167459SRichard Henderson     if (cf) {
1230b5af8423SRichard Henderson         ctx->null_cond = do_log_cond(ctx, cf, d, dest);
1231b2167459SRichard Henderson     }
1232b2167459SRichard Henderson }
1233b2167459SRichard Henderson 
1234fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a,
12356fd0c7bcSRichard Henderson                        void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
12360c982a28SRichard Henderson {
12376fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
12380c982a28SRichard Henderson 
12390c982a28SRichard Henderson     if (a->cf) {
12400c982a28SRichard Henderson         nullify_over(ctx);
12410c982a28SRichard Henderson     }
12420c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
12430c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1244fa8e3bedSRichard Henderson     do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn);
12450c982a28SRichard Henderson     return nullify_end(ctx);
12460c982a28SRichard Henderson }
12470c982a28SRichard Henderson 
12486fd0c7bcSRichard Henderson static void do_unit(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12496fd0c7bcSRichard Henderson                     TCGv_i64 in2, unsigned cf, bool d, bool is_tc,
12506fd0c7bcSRichard Henderson                     void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1251b2167459SRichard Henderson {
12526fd0c7bcSRichard Henderson     TCGv_i64 dest;
1253b2167459SRichard Henderson     DisasCond cond;
1254b2167459SRichard Henderson 
1255b2167459SRichard Henderson     if (cf == 0) {
1256b2167459SRichard Henderson         dest = dest_gpr(ctx, rt);
1257b2167459SRichard Henderson         fn(dest, in1, in2);
1258b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1259b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1260b2167459SRichard Henderson     } else {
1261b2167459SRichard Henderson         dest = tcg_temp_new();
1262b2167459SRichard Henderson         fn(dest, in1, in2);
1263b2167459SRichard Henderson 
126459963d8fSRichard Henderson         cond = do_unit_cond(cf, d, dest, in1, in2);
1265b2167459SRichard Henderson 
1266b2167459SRichard Henderson         if (is_tc) {
12676fd0c7bcSRichard Henderson             TCGv_i64 tmp = tcg_temp_new();
12686fd0c7bcSRichard Henderson             tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1269ad75a51eSRichard Henderson             gen_helper_tcond(tcg_env, tmp);
1270b2167459SRichard Henderson         }
1271b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1272b2167459SRichard Henderson 
1273b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1274b2167459SRichard Henderson         ctx->null_cond = cond;
1275b2167459SRichard Henderson     }
1276b2167459SRichard Henderson }
1277b2167459SRichard Henderson 
127886f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY
12798d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space
12808d6ae7fbSRichard Henderson    from the top 2 bits of the base register.  There are a few system
12818d6ae7fbSRichard Henderson    instructions that have a 3-bit space specifier, for which SR0 is
12828d6ae7fbSRichard Henderson    not special.  To handle this, pass ~SP.  */
12836fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base)
128486f8d05fSRichard Henderson {
128586f8d05fSRichard Henderson     TCGv_ptr ptr;
12866fd0c7bcSRichard Henderson     TCGv_i64 tmp;
128786f8d05fSRichard Henderson     TCGv_i64 spc;
128886f8d05fSRichard Henderson 
128986f8d05fSRichard Henderson     if (sp != 0) {
12908d6ae7fbSRichard Henderson         if (sp < 0) {
12918d6ae7fbSRichard Henderson             sp = ~sp;
12928d6ae7fbSRichard Henderson         }
12936fd0c7bcSRichard Henderson         spc = tcg_temp_new_i64();
12948d6ae7fbSRichard Henderson         load_spr(ctx, spc, sp);
12958d6ae7fbSRichard Henderson         return spc;
129686f8d05fSRichard Henderson     }
1297494737b7SRichard Henderson     if (ctx->tb_flags & TB_FLAG_SR_SAME) {
1298494737b7SRichard Henderson         return cpu_srH;
1299494737b7SRichard Henderson     }
130086f8d05fSRichard Henderson 
130186f8d05fSRichard Henderson     ptr = tcg_temp_new_ptr();
130286f8d05fSRichard Henderson     tmp = tcg_temp_new();
13036fd0c7bcSRichard Henderson     spc = tcg_temp_new_i64();
130486f8d05fSRichard Henderson 
1305698240d1SRichard Henderson     /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */
13066fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5);
13076fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, 030);
13086fd0c7bcSRichard Henderson     tcg_gen_trunc_i64_ptr(ptr, tmp);
130986f8d05fSRichard Henderson 
1310ad75a51eSRichard Henderson     tcg_gen_add_ptr(ptr, ptr, tcg_env);
131186f8d05fSRichard Henderson     tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4]));
131286f8d05fSRichard Henderson 
131386f8d05fSRichard Henderson     return spc;
131486f8d05fSRichard Henderson }
131586f8d05fSRichard Henderson #endif
131686f8d05fSRichard Henderson 
13176fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
1318c53e401eSRichard Henderson                      unsigned rb, unsigned rx, int scale, int64_t disp,
131986f8d05fSRichard Henderson                      unsigned sp, int modify, bool is_phys)
132086f8d05fSRichard Henderson {
13216fd0c7bcSRichard Henderson     TCGv_i64 base = load_gpr(ctx, rb);
13226fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13236fd0c7bcSRichard Henderson     TCGv_i64 addr;
132486f8d05fSRichard Henderson 
132586f8d05fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
132686f8d05fSRichard Henderson     if (rx) {
1327e12c6309SRichard Henderson         ofs = tcg_temp_new();
13286fd0c7bcSRichard Henderson         tcg_gen_shli_i64(ofs, cpu_gr[rx], scale);
13296fd0c7bcSRichard Henderson         tcg_gen_add_i64(ofs, ofs, base);
133086f8d05fSRichard Henderson     } else if (disp || modify) {
1331e12c6309SRichard Henderson         ofs = tcg_temp_new();
13326fd0c7bcSRichard Henderson         tcg_gen_addi_i64(ofs, base, disp);
133386f8d05fSRichard Henderson     } else {
133486f8d05fSRichard Henderson         ofs = base;
133586f8d05fSRichard Henderson     }
133686f8d05fSRichard Henderson 
133786f8d05fSRichard Henderson     *pofs = ofs;
13386fd0c7bcSRichard Henderson     *pgva = addr = tcg_temp_new_i64();
1339*967662cdSRichard Henderson     tcg_gen_andi_tl(addr, modify <= 0 ? ofs : base, gva_offset_mask(ctx));
1340698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY
134186f8d05fSRichard Henderson     if (!is_phys) {
134286f8d05fSRichard Henderson         tcg_gen_or_tl(addr, addr, space_select(ctx, sp, base));
134386f8d05fSRichard Henderson     }
134486f8d05fSRichard Henderson #endif
134586f8d05fSRichard Henderson }
134686f8d05fSRichard Henderson 
134796d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
134896d6407fSRichard Henderson  * < 0 for pre-modify,
134996d6407fSRichard Henderson  * > 0 for post-modify,
135096d6407fSRichard Henderson  * = 0 for no base register update.
135196d6407fSRichard Henderson  */
135296d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1353c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
135414776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
135596d6407fSRichard Henderson {
13566fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13576fd0c7bcSRichard Henderson     TCGv_i64 addr;
135896d6407fSRichard Henderson 
135996d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
136096d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
136196d6407fSRichard Henderson 
136286f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
136386f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1364c1f55d97SRichard Henderson     tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
136586f8d05fSRichard Henderson     if (modify) {
136686f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
136796d6407fSRichard Henderson     }
136896d6407fSRichard Henderson }
136996d6407fSRichard Henderson 
137096d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1371c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
137214776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
137396d6407fSRichard Henderson {
13746fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13756fd0c7bcSRichard Henderson     TCGv_i64 addr;
137696d6407fSRichard Henderson 
137796d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
137896d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
137996d6407fSRichard Henderson 
138086f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
138186f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1382217d1a5eSRichard Henderson     tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
138386f8d05fSRichard Henderson     if (modify) {
138486f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
138596d6407fSRichard Henderson     }
138696d6407fSRichard Henderson }
138796d6407fSRichard Henderson 
138896d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1389c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
139014776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
139196d6407fSRichard Henderson {
13926fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13936fd0c7bcSRichard Henderson     TCGv_i64 addr;
139496d6407fSRichard Henderson 
139596d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
139696d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
139796d6407fSRichard Henderson 
139886f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
139986f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1400217d1a5eSRichard Henderson     tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
140186f8d05fSRichard Henderson     if (modify) {
140286f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
140396d6407fSRichard Henderson     }
140496d6407fSRichard Henderson }
140596d6407fSRichard Henderson 
140696d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1407c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
140814776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
140996d6407fSRichard Henderson {
14106fd0c7bcSRichard Henderson     TCGv_i64 ofs;
14116fd0c7bcSRichard Henderson     TCGv_i64 addr;
141296d6407fSRichard Henderson 
141396d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
141496d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
141596d6407fSRichard Henderson 
141686f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
141786f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1418217d1a5eSRichard Henderson     tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
141986f8d05fSRichard Henderson     if (modify) {
142086f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
142196d6407fSRichard Henderson     }
142296d6407fSRichard Henderson }
142396d6407fSRichard Henderson 
14241cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1425c53e401eSRichard Henderson                     unsigned rx, int scale, int64_t disp,
142614776ab5STony Nguyen                     unsigned sp, int modify, MemOp mop)
142796d6407fSRichard Henderson {
14286fd0c7bcSRichard Henderson     TCGv_i64 dest;
142996d6407fSRichard Henderson 
143096d6407fSRichard Henderson     nullify_over(ctx);
143196d6407fSRichard Henderson 
143296d6407fSRichard Henderson     if (modify == 0) {
143396d6407fSRichard Henderson         /* No base register update.  */
143496d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
143596d6407fSRichard Henderson     } else {
143696d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
1437e12c6309SRichard Henderson         dest = tcg_temp_new();
143896d6407fSRichard Henderson     }
14396fd0c7bcSRichard Henderson     do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
144096d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
144196d6407fSRichard Henderson 
14421cd012a5SRichard Henderson     return nullify_end(ctx);
144396d6407fSRichard Henderson }
144496d6407fSRichard Henderson 
1445740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
1446c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
144786f8d05fSRichard Henderson                       unsigned sp, int modify)
144896d6407fSRichard Henderson {
144996d6407fSRichard Henderson     TCGv_i32 tmp;
145096d6407fSRichard Henderson 
145196d6407fSRichard Henderson     nullify_over(ctx);
145296d6407fSRichard Henderson 
145396d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
145486f8d05fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
145596d6407fSRichard Henderson     save_frw_i32(rt, tmp);
145696d6407fSRichard Henderson 
145796d6407fSRichard Henderson     if (rt == 0) {
1458ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
145996d6407fSRichard Henderson     }
146096d6407fSRichard Henderson 
1461740038d7SRichard Henderson     return nullify_end(ctx);
146296d6407fSRichard Henderson }
146396d6407fSRichard Henderson 
1464740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a)
1465740038d7SRichard Henderson {
1466740038d7SRichard Henderson     return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1467740038d7SRichard Henderson                      a->disp, a->sp, a->m);
1468740038d7SRichard Henderson }
1469740038d7SRichard Henderson 
1470740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1471c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
147286f8d05fSRichard Henderson                       unsigned sp, int modify)
147396d6407fSRichard Henderson {
147496d6407fSRichard Henderson     TCGv_i64 tmp;
147596d6407fSRichard Henderson 
147696d6407fSRichard Henderson     nullify_over(ctx);
147796d6407fSRichard Henderson 
147896d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
1479fc313c64SFrédéric Pétrot     do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
148096d6407fSRichard Henderson     save_frd(rt, tmp);
148196d6407fSRichard Henderson 
148296d6407fSRichard Henderson     if (rt == 0) {
1483ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
148496d6407fSRichard Henderson     }
148596d6407fSRichard Henderson 
1486740038d7SRichard Henderson     return nullify_end(ctx);
1487740038d7SRichard Henderson }
1488740038d7SRichard Henderson 
1489740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a)
1490740038d7SRichard Henderson {
1491740038d7SRichard Henderson     return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1492740038d7SRichard Henderson                      a->disp, a->sp, a->m);
149396d6407fSRichard Henderson }
149496d6407fSRichard Henderson 
14951cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb,
1496c53e401eSRichard Henderson                      int64_t disp, unsigned sp,
149714776ab5STony Nguyen                      int modify, MemOp mop)
149896d6407fSRichard Henderson {
149996d6407fSRichard Henderson     nullify_over(ctx);
15006fd0c7bcSRichard Henderson     do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
15011cd012a5SRichard Henderson     return nullify_end(ctx);
150296d6407fSRichard Henderson }
150396d6407fSRichard Henderson 
1504740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1505c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
150686f8d05fSRichard Henderson                        unsigned sp, int modify)
150796d6407fSRichard Henderson {
150896d6407fSRichard Henderson     TCGv_i32 tmp;
150996d6407fSRichard Henderson 
151096d6407fSRichard Henderson     nullify_over(ctx);
151196d6407fSRichard Henderson 
151296d6407fSRichard Henderson     tmp = load_frw_i32(rt);
151386f8d05fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
151496d6407fSRichard Henderson 
1515740038d7SRichard Henderson     return nullify_end(ctx);
151696d6407fSRichard Henderson }
151796d6407fSRichard Henderson 
1518740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a)
1519740038d7SRichard Henderson {
1520740038d7SRichard Henderson     return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1521740038d7SRichard Henderson                       a->disp, a->sp, a->m);
1522740038d7SRichard Henderson }
1523740038d7SRichard Henderson 
1524740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1525c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
152686f8d05fSRichard Henderson                        unsigned sp, int modify)
152796d6407fSRichard Henderson {
152896d6407fSRichard Henderson     TCGv_i64 tmp;
152996d6407fSRichard Henderson 
153096d6407fSRichard Henderson     nullify_over(ctx);
153196d6407fSRichard Henderson 
153296d6407fSRichard Henderson     tmp = load_frd(rt);
1533fc313c64SFrédéric Pétrot     do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
153496d6407fSRichard Henderson 
1535740038d7SRichard Henderson     return nullify_end(ctx);
1536740038d7SRichard Henderson }
1537740038d7SRichard Henderson 
1538740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a)
1539740038d7SRichard Henderson {
1540740038d7SRichard Henderson     return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1541740038d7SRichard Henderson                       a->disp, a->sp, a->m);
154296d6407fSRichard Henderson }
154396d6407fSRichard Henderson 
15441ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1545ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1546ebe9383cSRichard Henderson {
1547ebe9383cSRichard Henderson     TCGv_i32 tmp;
1548ebe9383cSRichard Henderson 
1549ebe9383cSRichard Henderson     nullify_over(ctx);
1550ebe9383cSRichard Henderson     tmp = load_frw0_i32(ra);
1551ebe9383cSRichard Henderson 
1552ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1553ebe9383cSRichard Henderson 
1554ebe9383cSRichard Henderson     save_frw_i32(rt, tmp);
15551ca74648SRichard Henderson     return nullify_end(ctx);
1556ebe9383cSRichard Henderson }
1557ebe9383cSRichard Henderson 
15581ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1559ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1560ebe9383cSRichard Henderson {
1561ebe9383cSRichard Henderson     TCGv_i32 dst;
1562ebe9383cSRichard Henderson     TCGv_i64 src;
1563ebe9383cSRichard Henderson 
1564ebe9383cSRichard Henderson     nullify_over(ctx);
1565ebe9383cSRichard Henderson     src = load_frd(ra);
1566ebe9383cSRichard Henderson     dst = tcg_temp_new_i32();
1567ebe9383cSRichard Henderson 
1568ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1569ebe9383cSRichard Henderson 
1570ebe9383cSRichard Henderson     save_frw_i32(rt, dst);
15711ca74648SRichard Henderson     return nullify_end(ctx);
1572ebe9383cSRichard Henderson }
1573ebe9383cSRichard Henderson 
15741ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1575ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1576ebe9383cSRichard Henderson {
1577ebe9383cSRichard Henderson     TCGv_i64 tmp;
1578ebe9383cSRichard Henderson 
1579ebe9383cSRichard Henderson     nullify_over(ctx);
1580ebe9383cSRichard Henderson     tmp = load_frd0(ra);
1581ebe9383cSRichard Henderson 
1582ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1583ebe9383cSRichard Henderson 
1584ebe9383cSRichard Henderson     save_frd(rt, tmp);
15851ca74648SRichard Henderson     return nullify_end(ctx);
1586ebe9383cSRichard Henderson }
1587ebe9383cSRichard Henderson 
15881ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1589ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1590ebe9383cSRichard Henderson {
1591ebe9383cSRichard Henderson     TCGv_i32 src;
1592ebe9383cSRichard Henderson     TCGv_i64 dst;
1593ebe9383cSRichard Henderson 
1594ebe9383cSRichard Henderson     nullify_over(ctx);
1595ebe9383cSRichard Henderson     src = load_frw0_i32(ra);
1596ebe9383cSRichard Henderson     dst = tcg_temp_new_i64();
1597ebe9383cSRichard Henderson 
1598ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1599ebe9383cSRichard Henderson 
1600ebe9383cSRichard Henderson     save_frd(rt, dst);
16011ca74648SRichard Henderson     return nullify_end(ctx);
1602ebe9383cSRichard Henderson }
1603ebe9383cSRichard Henderson 
16041ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt,
1605ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
160631234768SRichard Henderson                         void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
1607ebe9383cSRichard Henderson {
1608ebe9383cSRichard Henderson     TCGv_i32 a, b;
1609ebe9383cSRichard Henderson 
1610ebe9383cSRichard Henderson     nullify_over(ctx);
1611ebe9383cSRichard Henderson     a = load_frw0_i32(ra);
1612ebe9383cSRichard Henderson     b = load_frw0_i32(rb);
1613ebe9383cSRichard Henderson 
1614ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1615ebe9383cSRichard Henderson 
1616ebe9383cSRichard Henderson     save_frw_i32(rt, a);
16171ca74648SRichard Henderson     return nullify_end(ctx);
1618ebe9383cSRichard Henderson }
1619ebe9383cSRichard Henderson 
16201ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt,
1621ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
162231234768SRichard Henderson                         void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
1623ebe9383cSRichard Henderson {
1624ebe9383cSRichard Henderson     TCGv_i64 a, b;
1625ebe9383cSRichard Henderson 
1626ebe9383cSRichard Henderson     nullify_over(ctx);
1627ebe9383cSRichard Henderson     a = load_frd0(ra);
1628ebe9383cSRichard Henderson     b = load_frd0(rb);
1629ebe9383cSRichard Henderson 
1630ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1631ebe9383cSRichard Henderson 
1632ebe9383cSRichard Henderson     save_frd(rt, a);
16331ca74648SRichard Henderson     return nullify_end(ctx);
1634ebe9383cSRichard Henderson }
1635ebe9383cSRichard Henderson 
163698cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
163798cd9ca7SRichard Henderson    have already had nullification handled.  */
1638c53e401eSRichard Henderson static bool do_dbranch(DisasContext *ctx, uint64_t dest,
163998cd9ca7SRichard Henderson                        unsigned link, bool is_n)
164098cd9ca7SRichard Henderson {
164198cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
164298cd9ca7SRichard Henderson         if (link != 0) {
1643741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
164498cd9ca7SRichard Henderson         }
164598cd9ca7SRichard Henderson         ctx->iaoq_n = dest;
164698cd9ca7SRichard Henderson         if (is_n) {
164798cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
164898cd9ca7SRichard Henderson         }
164998cd9ca7SRichard Henderson     } else {
165098cd9ca7SRichard Henderson         nullify_over(ctx);
165198cd9ca7SRichard Henderson 
165298cd9ca7SRichard Henderson         if (link != 0) {
1653741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
165498cd9ca7SRichard Henderson         }
165598cd9ca7SRichard Henderson 
165698cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
165798cd9ca7SRichard Henderson             nullify_set(ctx, 0);
165898cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, dest, dest + 4);
165998cd9ca7SRichard Henderson         } else {
166098cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
166198cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
166298cd9ca7SRichard Henderson         }
166398cd9ca7SRichard Henderson 
166431234768SRichard Henderson         nullify_end(ctx);
166598cd9ca7SRichard Henderson 
166698cd9ca7SRichard Henderson         nullify_set(ctx, 0);
166798cd9ca7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
166831234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
166998cd9ca7SRichard Henderson     }
167001afb7beSRichard Henderson     return true;
167198cd9ca7SRichard Henderson }
167298cd9ca7SRichard Henderson 
167398cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
167498cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
1675c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n,
167698cd9ca7SRichard Henderson                        DisasCond *cond)
167798cd9ca7SRichard Henderson {
1678c53e401eSRichard Henderson     uint64_t dest = iaoq_dest(ctx, disp);
167998cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
168098cd9ca7SRichard Henderson     TCGCond c = cond->c;
168198cd9ca7SRichard Henderson     bool n;
168298cd9ca7SRichard Henderson 
168398cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
168498cd9ca7SRichard Henderson 
168598cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
168698cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
168701afb7beSRichard Henderson         return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
168898cd9ca7SRichard Henderson     }
168998cd9ca7SRichard Henderson     if (c == TCG_COND_NEVER) {
169001afb7beSRichard Henderson         return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
169198cd9ca7SRichard Henderson     }
169298cd9ca7SRichard Henderson 
169398cd9ca7SRichard Henderson     taken = gen_new_label();
16946fd0c7bcSRichard Henderson     tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken);
169598cd9ca7SRichard Henderson     cond_free(cond);
169698cd9ca7SRichard Henderson 
169798cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
169898cd9ca7SRichard Henderson     n = is_n && disp < 0;
169998cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
170098cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1701a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
170298cd9ca7SRichard Henderson     } else {
170398cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
170498cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
170598cd9ca7SRichard Henderson             ctx->null_lab = NULL;
170698cd9ca7SRichard Henderson         }
170798cd9ca7SRichard Henderson         nullify_set(ctx, n);
1708c301f34eSRichard Henderson         if (ctx->iaoq_n == -1) {
1709c301f34eSRichard Henderson             /* The temporary iaoq_n_var died at the branch above.
1710c301f34eSRichard Henderson                Regenerate it here instead of saving it.  */
17116fd0c7bcSRichard Henderson             tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
1712c301f34eSRichard Henderson         }
1713a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
171498cd9ca7SRichard Henderson     }
171598cd9ca7SRichard Henderson 
171698cd9ca7SRichard Henderson     gen_set_label(taken);
171798cd9ca7SRichard Henderson 
171898cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
171998cd9ca7SRichard Henderson     n = is_n && disp >= 0;
172098cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
172198cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1722a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, dest, dest + 4);
172398cd9ca7SRichard Henderson     } else {
172498cd9ca7SRichard Henderson         nullify_set(ctx, n);
1725a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
172698cd9ca7SRichard Henderson     }
172798cd9ca7SRichard Henderson 
172898cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
172998cd9ca7SRichard Henderson     if (ctx->null_lab) {
173098cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
173198cd9ca7SRichard Henderson         ctx->null_lab = NULL;
173231234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
173398cd9ca7SRichard Henderson     } else {
173431234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
173598cd9ca7SRichard Henderson     }
173601afb7beSRichard Henderson     return true;
173798cd9ca7SRichard Henderson }
173898cd9ca7SRichard Henderson 
173998cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target.  This handles
174098cd9ca7SRichard Henderson    nullification of the branch itself.  */
17416fd0c7bcSRichard Henderson static bool do_ibranch(DisasContext *ctx, TCGv_i64 dest,
174298cd9ca7SRichard Henderson                        unsigned link, bool is_n)
174398cd9ca7SRichard Henderson {
17446fd0c7bcSRichard Henderson     TCGv_i64 a0, a1, next, tmp;
174598cd9ca7SRichard Henderson     TCGCond c;
174698cd9ca7SRichard Henderson 
174798cd9ca7SRichard Henderson     assert(ctx->null_lab == NULL);
174898cd9ca7SRichard Henderson 
174998cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
175098cd9ca7SRichard Henderson         if (link != 0) {
1751741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
175298cd9ca7SRichard Henderson         }
1753e12c6309SRichard Henderson         next = tcg_temp_new();
17546fd0c7bcSRichard Henderson         tcg_gen_mov_i64(next, dest);
175598cd9ca7SRichard Henderson         if (is_n) {
1756c301f34eSRichard Henderson             if (use_nullify_skip(ctx)) {
1757a0180973SRichard Henderson                 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, next);
17586fd0c7bcSRichard Henderson                 tcg_gen_addi_i64(next, next, 4);
1759a0180973SRichard Henderson                 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
1760c301f34eSRichard Henderson                 nullify_set(ctx, 0);
176131234768SRichard Henderson                 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
176201afb7beSRichard Henderson                 return true;
1763c301f34eSRichard Henderson             }
176498cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
176598cd9ca7SRichard Henderson         }
1766c301f34eSRichard Henderson         ctx->iaoq_n = -1;
1767c301f34eSRichard Henderson         ctx->iaoq_n_var = next;
176898cd9ca7SRichard Henderson     } else if (is_n && use_nullify_skip(ctx)) {
176998cd9ca7SRichard Henderson         /* The (conditional) branch, B, nullifies the next insn, N,
177098cd9ca7SRichard Henderson            and we're allowed to skip execution N (no single-step or
17714137cb83SRichard Henderson            tracepoint in effect).  Since the goto_ptr that we must use
177298cd9ca7SRichard Henderson            for the indirect branch consumes no special resources, we
177398cd9ca7SRichard Henderson            can (conditionally) skip B and continue execution.  */
177498cd9ca7SRichard Henderson         /* The use_nullify_skip test implies we have a known control path.  */
177598cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_b != -1);
177698cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_n != -1);
177798cd9ca7SRichard Henderson 
177898cd9ca7SRichard Henderson         /* We do have to handle the non-local temporary, DEST, before
177998cd9ca7SRichard Henderson            branching.  Since IOAQ_F is not really live at this point, we
178098cd9ca7SRichard Henderson            can simply store DEST optimistically.  Similarly with IAOQ_B.  */
1781a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, dest);
1782a0180973SRichard Henderson         next = tcg_temp_new();
17836fd0c7bcSRichard Henderson         tcg_gen_addi_i64(next, dest, 4);
1784a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
178598cd9ca7SRichard Henderson 
178698cd9ca7SRichard Henderson         nullify_over(ctx);
178798cd9ca7SRichard Henderson         if (link != 0) {
17889a91dd84SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
178998cd9ca7SRichard Henderson         }
17907f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
179101afb7beSRichard Henderson         return nullify_end(ctx);
179298cd9ca7SRichard Henderson     } else {
179398cd9ca7SRichard Henderson         c = ctx->null_cond.c;
179498cd9ca7SRichard Henderson         a0 = ctx->null_cond.a0;
179598cd9ca7SRichard Henderson         a1 = ctx->null_cond.a1;
179698cd9ca7SRichard Henderson 
179798cd9ca7SRichard Henderson         tmp = tcg_temp_new();
1798e12c6309SRichard Henderson         next = tcg_temp_new();
179998cd9ca7SRichard Henderson 
1800741322f4SRichard Henderson         copy_iaoq_entry(ctx, tmp, ctx->iaoq_n, ctx->iaoq_n_var);
18016fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(c, next, a0, a1, tmp, dest);
180298cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
180398cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
180498cd9ca7SRichard Henderson 
180598cd9ca7SRichard Henderson         if (link != 0) {
18066fd0c7bcSRichard Henderson             tcg_gen_movcond_i64(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
180798cd9ca7SRichard Henderson         }
180898cd9ca7SRichard Henderson 
180998cd9ca7SRichard Henderson         if (is_n) {
181098cd9ca7SRichard Henderson             /* The branch nullifies the next insn, which means the state of N
181198cd9ca7SRichard Henderson                after the branch is the inverse of the state of N that applied
181298cd9ca7SRichard Henderson                to the branch.  */
18136fd0c7bcSRichard Henderson             tcg_gen_setcond_i64(tcg_invert_cond(c), cpu_psw_n, a0, a1);
181498cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
181598cd9ca7SRichard Henderson             ctx->null_cond = cond_make_n();
181698cd9ca7SRichard Henderson             ctx->psw_n_nonzero = true;
181798cd9ca7SRichard Henderson         } else {
181898cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
181998cd9ca7SRichard Henderson         }
182098cd9ca7SRichard Henderson     }
182101afb7beSRichard Henderson     return true;
182298cd9ca7SRichard Henderson }
182398cd9ca7SRichard Henderson 
1824660eefe1SRichard Henderson /* Implement
1825660eefe1SRichard Henderson  *    if (IAOQ_Front{30..31} < GR[b]{30..31})
1826660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← GR[b]{30..31};
1827660eefe1SRichard Henderson  *    else
1828660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← IAOQ_Front{30..31};
1829660eefe1SRichard Henderson  * which keeps the privilege level from being increased.
1830660eefe1SRichard Henderson  */
18316fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset)
1832660eefe1SRichard Henderson {
18336fd0c7bcSRichard Henderson     TCGv_i64 dest;
1834660eefe1SRichard Henderson     switch (ctx->privilege) {
1835660eefe1SRichard Henderson     case 0:
1836660eefe1SRichard Henderson         /* Privilege 0 is maximum and is allowed to decrease.  */
1837660eefe1SRichard Henderson         return offset;
1838660eefe1SRichard Henderson     case 3:
1839993119feSRichard Henderson         /* Privilege 3 is minimum and is never allowed to increase.  */
1840e12c6309SRichard Henderson         dest = tcg_temp_new();
18416fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, offset, 3);
1842660eefe1SRichard Henderson         break;
1843660eefe1SRichard Henderson     default:
1844e12c6309SRichard Henderson         dest = tcg_temp_new();
18456fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, offset, -4);
18466fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, ctx->privilege);
18476fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(TCG_COND_GTU, dest, dest, offset, dest, offset);
1848660eefe1SRichard Henderson         break;
1849660eefe1SRichard Henderson     }
1850660eefe1SRichard Henderson     return dest;
1851660eefe1SRichard Henderson }
1852660eefe1SRichard Henderson 
1853ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
18547ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
18557ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
18567ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
18577ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
18587ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
18597ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
18607ad439dfSRichard Henderson    aforementioned BE.  */
186131234768SRichard Henderson static void do_page_zero(DisasContext *ctx)
18627ad439dfSRichard Henderson {
18636fd0c7bcSRichard Henderson     TCGv_i64 tmp;
1864a0180973SRichard Henderson 
18657ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
18667ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
18678b81968cSMichael Tokarev        next insn within the privileged page.  */
18687ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
18697ad439dfSRichard Henderson     case TCG_COND_NEVER:
18707ad439dfSRichard Henderson         break;
18717ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
18726fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, 0);
18737ad439dfSRichard Henderson         goto do_sigill;
18747ad439dfSRichard Henderson     default:
18757ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
18767ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
18777ad439dfSRichard Henderson         g_assert_not_reached();
18787ad439dfSRichard Henderson     }
18797ad439dfSRichard Henderson 
18807ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
18817ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
18827ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
18837ad439dfSRichard Henderson        under such conditions.  */
18847ad439dfSRichard Henderson     if (ctx->iaoq_b != ctx->iaoq_f + 4) {
18857ad439dfSRichard Henderson         goto do_sigill;
18867ad439dfSRichard Henderson     }
18877ad439dfSRichard Henderson 
1888ebd0e151SRichard Henderson     switch (ctx->iaoq_f & -4) {
18897ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
18902986721dSRichard Henderson         gen_excp_1(EXCP_IMP);
189131234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
189231234768SRichard Henderson         break;
18937ad439dfSRichard Henderson 
18947ad439dfSRichard Henderson     case 0xb0: /* LWS */
18957ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
189631234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
189731234768SRichard Henderson         break;
18987ad439dfSRichard Henderson 
18997ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
19006fd0c7bcSRichard Henderson         tcg_gen_st_i64(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27]));
1901a0180973SRichard Henderson         tmp = tcg_temp_new();
19026fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_gr[31], 3);
1903a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
19046fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, 4);
1905a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
190631234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
190731234768SRichard Henderson         break;
19087ad439dfSRichard Henderson 
19097ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
19107ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
191131234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
191231234768SRichard Henderson         break;
19137ad439dfSRichard Henderson 
19147ad439dfSRichard Henderson     default:
19157ad439dfSRichard Henderson     do_sigill:
19162986721dSRichard Henderson         gen_excp_1(EXCP_ILL);
191731234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
191831234768SRichard Henderson         break;
19197ad439dfSRichard Henderson     }
19207ad439dfSRichard Henderson }
1921ba1d0b44SRichard Henderson #endif
19227ad439dfSRichard Henderson 
1923deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a)
1924b2167459SRichard Henderson {
1925b2167459SRichard Henderson     cond_free(&ctx->null_cond);
192631234768SRichard Henderson     return true;
1927b2167459SRichard Henderson }
1928b2167459SRichard Henderson 
192940f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a)
193098a9cb79SRichard Henderson {
193131234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_BREAK);
193298a9cb79SRichard Henderson }
193398a9cb79SRichard Henderson 
1934e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a)
193598a9cb79SRichard Henderson {
193698a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
193798a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
193898a9cb79SRichard Henderson 
193998a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
194031234768SRichard Henderson     return true;
194198a9cb79SRichard Henderson }
194298a9cb79SRichard Henderson 
1943c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a)
194498a9cb79SRichard Henderson {
1945c603e14aSRichard Henderson     unsigned rt = a->t;
19466fd0c7bcSRichard Henderson     TCGv_i64 tmp = dest_gpr(ctx, rt);
19476fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tmp, ctx->iaoq_f);
194898a9cb79SRichard Henderson     save_gpr(ctx, rt, tmp);
194998a9cb79SRichard Henderson 
195098a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
195131234768SRichard Henderson     return true;
195298a9cb79SRichard Henderson }
195398a9cb79SRichard Henderson 
1954c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a)
195598a9cb79SRichard Henderson {
1956c603e14aSRichard Henderson     unsigned rt = a->t;
1957c603e14aSRichard Henderson     unsigned rs = a->sp;
195833423472SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
195998a9cb79SRichard Henderson 
196033423472SRichard Henderson     load_spr(ctx, t0, rs);
196133423472SRichard Henderson     tcg_gen_shri_i64(t0, t0, 32);
196233423472SRichard Henderson 
1963*967662cdSRichard Henderson     save_gpr(ctx, rt, t0);
196498a9cb79SRichard Henderson 
196598a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
196631234768SRichard Henderson     return true;
196798a9cb79SRichard Henderson }
196898a9cb79SRichard Henderson 
1969c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a)
197098a9cb79SRichard Henderson {
1971c603e14aSRichard Henderson     unsigned rt = a->t;
1972c603e14aSRichard Henderson     unsigned ctl = a->r;
19736fd0c7bcSRichard Henderson     TCGv_i64 tmp;
197498a9cb79SRichard Henderson 
197598a9cb79SRichard Henderson     switch (ctl) {
197635136a77SRichard Henderson     case CR_SAR:
1977c603e14aSRichard Henderson         if (a->e == 0) {
197898a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
197998a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
19806fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
198198a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
198235136a77SRichard Henderson             goto done;
198398a9cb79SRichard Henderson         }
198498a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
198535136a77SRichard Henderson         goto done;
198635136a77SRichard Henderson     case CR_IT: /* Interval Timer */
198735136a77SRichard Henderson         /* FIXME: Respect PSW_S bit.  */
198835136a77SRichard Henderson         nullify_over(ctx);
198998a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
1990dfd1b812SRichard Henderson         if (translator_io_start(&ctx->base)) {
199149c29d6cSRichard Henderson             gen_helper_read_interval_timer(tmp);
199231234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
199349c29d6cSRichard Henderson         } else {
199449c29d6cSRichard Henderson             gen_helper_read_interval_timer(tmp);
199549c29d6cSRichard Henderson         }
199698a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
199731234768SRichard Henderson         return nullify_end(ctx);
199898a9cb79SRichard Henderson     case 26:
199998a9cb79SRichard Henderson     case 27:
200098a9cb79SRichard Henderson         break;
200198a9cb79SRichard Henderson     default:
200298a9cb79SRichard Henderson         /* All other control registers are privileged.  */
200335136a77SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
200435136a77SRichard Henderson         break;
200598a9cb79SRichard Henderson     }
200698a9cb79SRichard Henderson 
2007e12c6309SRichard Henderson     tmp = tcg_temp_new();
20086fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
200935136a77SRichard Henderson     save_gpr(ctx, rt, tmp);
201035136a77SRichard Henderson 
201135136a77SRichard Henderson  done:
201298a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
201331234768SRichard Henderson     return true;
201498a9cb79SRichard Henderson }
201598a9cb79SRichard Henderson 
2016c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
201733423472SRichard Henderson {
2018c603e14aSRichard Henderson     unsigned rr = a->r;
2019c603e14aSRichard Henderson     unsigned rs = a->sp;
2020*967662cdSRichard Henderson     TCGv_i64 tmp;
202133423472SRichard Henderson 
202233423472SRichard Henderson     if (rs >= 5) {
202333423472SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
202433423472SRichard Henderson     }
202533423472SRichard Henderson     nullify_over(ctx);
202633423472SRichard Henderson 
2027*967662cdSRichard Henderson     tmp = tcg_temp_new_i64();
2028*967662cdSRichard Henderson     tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32);
202933423472SRichard Henderson 
203033423472SRichard Henderson     if (rs >= 4) {
2031*967662cdSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs]));
2032494737b7SRichard Henderson         ctx->tb_flags &= ~TB_FLAG_SR_SAME;
203333423472SRichard Henderson     } else {
2034*967662cdSRichard Henderson         tcg_gen_mov_i64(cpu_sr[rs], tmp);
203533423472SRichard Henderson     }
203633423472SRichard Henderson 
203731234768SRichard Henderson     return nullify_end(ctx);
203833423472SRichard Henderson }
203933423472SRichard Henderson 
2040c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
204198a9cb79SRichard Henderson {
2042c603e14aSRichard Henderson     unsigned ctl = a->t;
20436fd0c7bcSRichard Henderson     TCGv_i64 reg;
20446fd0c7bcSRichard Henderson     TCGv_i64 tmp;
204598a9cb79SRichard Henderson 
204635136a77SRichard Henderson     if (ctl == CR_SAR) {
20474845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
204898a9cb79SRichard Henderson         tmp = tcg_temp_new();
20496fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31);
205098a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
205198a9cb79SRichard Henderson 
205298a9cb79SRichard Henderson         cond_free(&ctx->null_cond);
205331234768SRichard Henderson         return true;
205498a9cb79SRichard Henderson     }
205598a9cb79SRichard Henderson 
205635136a77SRichard Henderson     /* All other control registers are privileged or read-only.  */
205735136a77SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
205835136a77SRichard Henderson 
2059c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
206035136a77SRichard Henderson     nullify_over(ctx);
20614845f015SSven Schnelle     reg = load_gpr(ctx, a->r);
20624845f015SSven Schnelle 
206335136a77SRichard Henderson     switch (ctl) {
206435136a77SRichard Henderson     case CR_IT:
2065ad75a51eSRichard Henderson         gen_helper_write_interval_timer(tcg_env, reg);
206635136a77SRichard Henderson         break;
20674f5f2548SRichard Henderson     case CR_EIRR:
2068ad75a51eSRichard Henderson         gen_helper_write_eirr(tcg_env, reg);
20694f5f2548SRichard Henderson         break;
20704f5f2548SRichard Henderson     case CR_EIEM:
2071ad75a51eSRichard Henderson         gen_helper_write_eiem(tcg_env, reg);
207231234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
20734f5f2548SRichard Henderson         break;
20744f5f2548SRichard Henderson 
207535136a77SRichard Henderson     case CR_IIASQ:
207635136a77SRichard Henderson     case CR_IIAOQ:
207735136a77SRichard Henderson         /* FIXME: Respect PSW_Q bit */
207835136a77SRichard Henderson         /* The write advances the queue and stores to the back element.  */
2079e12c6309SRichard Henderson         tmp = tcg_temp_new();
20806fd0c7bcSRichard Henderson         tcg_gen_ld_i64(tmp, tcg_env,
208135136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
20826fd0c7bcSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
20836fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env,
208435136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
208535136a77SRichard Henderson         break;
208635136a77SRichard Henderson 
2087d5de20bdSSven Schnelle     case CR_PID1:
2088d5de20bdSSven Schnelle     case CR_PID2:
2089d5de20bdSSven Schnelle     case CR_PID3:
2090d5de20bdSSven Schnelle     case CR_PID4:
20916fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
2092d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY
2093ad75a51eSRichard Henderson         gen_helper_change_prot_id(tcg_env);
2094d5de20bdSSven Schnelle #endif
2095d5de20bdSSven Schnelle         break;
2096d5de20bdSSven Schnelle 
209735136a77SRichard Henderson     default:
20986fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
209935136a77SRichard Henderson         break;
210035136a77SRichard Henderson     }
210131234768SRichard Henderson     return nullify_end(ctx);
21024f5f2548SRichard Henderson #endif
210335136a77SRichard Henderson }
210435136a77SRichard Henderson 
2105c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
210698a9cb79SRichard Henderson {
21076fd0c7bcSRichard Henderson     TCGv_i64 tmp = tcg_temp_new();
210898a9cb79SRichard Henderson 
21096fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, load_gpr(ctx, a->r));
21106fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31);
211198a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
211298a9cb79SRichard Henderson 
211398a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
211431234768SRichard Henderson     return true;
211598a9cb79SRichard Henderson }
211698a9cb79SRichard Henderson 
2117e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a)
211898a9cb79SRichard Henderson {
21196fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
212098a9cb79SRichard Henderson 
21212330504cSHelge Deller #ifdef CONFIG_USER_ONLY
21222330504cSHelge Deller     /* We don't implement space registers in user mode. */
21236fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
21242330504cSHelge Deller #else
2125*967662cdSRichard Henderson     tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
2126*967662cdSRichard Henderson     tcg_gen_shri_i64(dest, dest, 32);
21272330504cSHelge Deller #endif
2128e36f27efSRichard Henderson     save_gpr(ctx, a->t, dest);
212998a9cb79SRichard Henderson 
213098a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
213131234768SRichard Henderson     return true;
213298a9cb79SRichard Henderson }
213398a9cb79SRichard Henderson 
2134e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a)
2135e36f27efSRichard Henderson {
2136e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2137e1b5a5edSRichard Henderson #ifndef CONFIG_USER_ONLY
21386fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2139e1b5a5edSRichard Henderson 
2140e1b5a5edSRichard Henderson     nullify_over(ctx);
2141e1b5a5edSRichard Henderson 
2142e12c6309SRichard Henderson     tmp = tcg_temp_new();
21436fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
21446fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ~a->i);
2145ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2146e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2147e1b5a5edSRichard Henderson 
2148e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_M.  */
214931234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
215031234768SRichard Henderson     return nullify_end(ctx);
2151e36f27efSRichard Henderson #endif
2152e1b5a5edSRichard Henderson }
2153e1b5a5edSRichard Henderson 
2154e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
2155e1b5a5edSRichard Henderson {
2156e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2157e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
21586fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2159e1b5a5edSRichard Henderson 
2160e1b5a5edSRichard Henderson     nullify_over(ctx);
2161e1b5a5edSRichard Henderson 
2162e12c6309SRichard Henderson     tmp = tcg_temp_new();
21636fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
21646fd0c7bcSRichard Henderson     tcg_gen_ori_i64(tmp, tmp, a->i);
2165ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2166e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2167e1b5a5edSRichard Henderson 
2168e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_I.  */
216931234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
217031234768SRichard Henderson     return nullify_end(ctx);
2171e36f27efSRichard Henderson #endif
2172e1b5a5edSRichard Henderson }
2173e1b5a5edSRichard Henderson 
2174c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
2175e1b5a5edSRichard Henderson {
2176e1b5a5edSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2177c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
21786fd0c7bcSRichard Henderson     TCGv_i64 tmp, reg;
2179e1b5a5edSRichard Henderson     nullify_over(ctx);
2180e1b5a5edSRichard Henderson 
2181c603e14aSRichard Henderson     reg = load_gpr(ctx, a->r);
2182e12c6309SRichard Henderson     tmp = tcg_temp_new();
2183ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, reg);
2184e1b5a5edSRichard Henderson 
2185e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts.  */
218631234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
218731234768SRichard Henderson     return nullify_end(ctx);
2188c603e14aSRichard Henderson #endif
2189e1b5a5edSRichard Henderson }
2190f49b3537SRichard Henderson 
2191e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r)
2192f49b3537SRichard Henderson {
2193f49b3537SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2194e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
2195f49b3537SRichard Henderson     nullify_over(ctx);
2196f49b3537SRichard Henderson 
2197e36f27efSRichard Henderson     if (rfi_r) {
2198ad75a51eSRichard Henderson         gen_helper_rfi_r(tcg_env);
2199f49b3537SRichard Henderson     } else {
2200ad75a51eSRichard Henderson         gen_helper_rfi(tcg_env);
2201f49b3537SRichard Henderson     }
220231234768SRichard Henderson     /* Exit the TB to recognize new interrupts.  */
220307ea28b4SRichard Henderson     tcg_gen_exit_tb(NULL, 0);
220431234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
2205f49b3537SRichard Henderson 
220631234768SRichard Henderson     return nullify_end(ctx);
2207e36f27efSRichard Henderson #endif
2208f49b3537SRichard Henderson }
22096210db05SHelge Deller 
2210e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a)
2211e36f27efSRichard Henderson {
2212e36f27efSRichard Henderson     return do_rfi(ctx, false);
2213e36f27efSRichard Henderson }
2214e36f27efSRichard Henderson 
2215e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a)
2216e36f27efSRichard Henderson {
2217e36f27efSRichard Henderson     return do_rfi(ctx, true);
2218e36f27efSRichard Henderson }
2219e36f27efSRichard Henderson 
222096927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a)
22216210db05SHelge Deller {
22226210db05SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
222396927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
22246210db05SHelge Deller     nullify_over(ctx);
2225ad75a51eSRichard Henderson     gen_helper_halt(tcg_env);
222631234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
222731234768SRichard Henderson     return nullify_end(ctx);
222896927adbSRichard Henderson #endif
22296210db05SHelge Deller }
223096927adbSRichard Henderson 
223196927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a)
223296927adbSRichard Henderson {
223396927adbSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
223496927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
223596927adbSRichard Henderson     nullify_over(ctx);
2236ad75a51eSRichard Henderson     gen_helper_reset(tcg_env);
223796927adbSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
223896927adbSRichard Henderson     return nullify_end(ctx);
223996927adbSRichard Henderson #endif
224096927adbSRichard Henderson }
2241e1b5a5edSRichard Henderson 
22424a4554c6SHelge Deller static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
22434a4554c6SHelge Deller {
22444a4554c6SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
22454a4554c6SHelge Deller #ifndef CONFIG_USER_ONLY
22464a4554c6SHelge Deller     nullify_over(ctx);
2247ad75a51eSRichard Henderson     gen_helper_getshadowregs(tcg_env);
22484a4554c6SHelge Deller     return nullify_end(ctx);
22494a4554c6SHelge Deller #endif
22504a4554c6SHelge Deller }
22514a4554c6SHelge Deller 
2252deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
225398a9cb79SRichard Henderson {
2254deee69a1SRichard Henderson     if (a->m) {
22556fd0c7bcSRichard Henderson         TCGv_i64 dest = dest_gpr(ctx, a->b);
22566fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->b);
22576fd0c7bcSRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->x);
225898a9cb79SRichard Henderson 
225998a9cb79SRichard Henderson         /* The only thing we need to do is the base register modification.  */
22606fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, src1, src2);
2261deee69a1SRichard Henderson         save_gpr(ctx, a->b, dest);
2262deee69a1SRichard Henderson     }
226398a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
226431234768SRichard Henderson     return true;
226598a9cb79SRichard Henderson }
226698a9cb79SRichard Henderson 
2267deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a)
226898a9cb79SRichard Henderson {
22696fd0c7bcSRichard Henderson     TCGv_i64 dest, ofs;
2270eed14219SRichard Henderson     TCGv_i32 level, want;
22716fd0c7bcSRichard Henderson     TCGv_i64 addr;
227298a9cb79SRichard Henderson 
227398a9cb79SRichard Henderson     nullify_over(ctx);
227498a9cb79SRichard Henderson 
2275deee69a1SRichard Henderson     dest = dest_gpr(ctx, a->t);
2276deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2277eed14219SRichard Henderson 
2278deee69a1SRichard Henderson     if (a->imm) {
227929dd6f64SRichard Henderson         level = tcg_constant_i32(a->ri);
228098a9cb79SRichard Henderson     } else {
2281eed14219SRichard Henderson         level = tcg_temp_new_i32();
22826fd0c7bcSRichard Henderson         tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri));
2283eed14219SRichard Henderson         tcg_gen_andi_i32(level, level, 3);
228498a9cb79SRichard Henderson     }
228529dd6f64SRichard Henderson     want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ);
2286eed14219SRichard Henderson 
2287ad75a51eSRichard Henderson     gen_helper_probe(dest, tcg_env, addr, level, want);
2288eed14219SRichard Henderson 
2289deee69a1SRichard Henderson     save_gpr(ctx, a->t, dest);
229031234768SRichard Henderson     return nullify_end(ctx);
229198a9cb79SRichard Henderson }
229298a9cb79SRichard Henderson 
2293deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
22948d6ae7fbSRichard Henderson {
22958577f354SRichard Henderson     if (ctx->is_pa20) {
22968577f354SRichard Henderson         return false;
22978577f354SRichard Henderson     }
2298deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2299deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
23006fd0c7bcSRichard Henderson     TCGv_i64 addr;
23016fd0c7bcSRichard Henderson     TCGv_i64 ofs, reg;
23028d6ae7fbSRichard Henderson 
23038d6ae7fbSRichard Henderson     nullify_over(ctx);
23048d6ae7fbSRichard Henderson 
2305deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2306deee69a1SRichard Henderson     reg = load_gpr(ctx, a->r);
2307deee69a1SRichard Henderson     if (a->addr) {
23088577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
23098d6ae7fbSRichard Henderson     } else {
23108577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
23118d6ae7fbSRichard Henderson     }
23128d6ae7fbSRichard Henderson 
231332dc7569SSven Schnelle     /* Exit TB for TLB change if mmu is enabled.  */
231432dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
231531234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
231631234768SRichard Henderson     }
231731234768SRichard Henderson     return nullify_end(ctx);
2318deee69a1SRichard Henderson #endif
23198d6ae7fbSRichard Henderson }
232063300a00SRichard Henderson 
2321deee69a1SRichard Henderson static bool trans_pxtlbx(DisasContext *ctx, arg_pxtlbx *a)
232263300a00SRichard Henderson {
2323deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2324deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
23256fd0c7bcSRichard Henderson     TCGv_i64 addr;
23266fd0c7bcSRichard Henderson     TCGv_i64 ofs;
232763300a00SRichard Henderson 
232863300a00SRichard Henderson     nullify_over(ctx);
232963300a00SRichard Henderson 
2330deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2331deee69a1SRichard Henderson     if (a->m) {
2332deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
233363300a00SRichard Henderson     }
2334deee69a1SRichard Henderson     if (a->local) {
2335ad75a51eSRichard Henderson         gen_helper_ptlbe(tcg_env);
233663300a00SRichard Henderson     } else {
2337ad75a51eSRichard Henderson         gen_helper_ptlb(tcg_env, addr);
233863300a00SRichard Henderson     }
233963300a00SRichard Henderson 
234063300a00SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
234132dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
234231234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
234331234768SRichard Henderson     }
234431234768SRichard Henderson     return nullify_end(ctx);
2345deee69a1SRichard Henderson #endif
234663300a00SRichard Henderson }
23472dfcca9fSRichard Henderson 
23486797c315SNick Hudson /*
23496797c315SNick Hudson  * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
23506797c315SNick Hudson  * See
23516797c315SNick Hudson  *     https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
23526797c315SNick Hudson  *     page 13-9 (195/206)
23536797c315SNick Hudson  */
23546797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
23556797c315SNick Hudson {
23568577f354SRichard Henderson     if (ctx->is_pa20) {
23578577f354SRichard Henderson         return false;
23588577f354SRichard Henderson     }
23596797c315SNick Hudson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
23606797c315SNick Hudson #ifndef CONFIG_USER_ONLY
23616fd0c7bcSRichard Henderson     TCGv_i64 addr, atl, stl;
23626fd0c7bcSRichard Henderson     TCGv_i64 reg;
23636797c315SNick Hudson 
23646797c315SNick Hudson     nullify_over(ctx);
23656797c315SNick Hudson 
23666797c315SNick Hudson     /*
23676797c315SNick Hudson      * FIXME:
23686797c315SNick Hudson      *  if (not (pcxl or pcxl2))
23696797c315SNick Hudson      *    return gen_illegal(ctx);
23706797c315SNick Hudson      */
23716797c315SNick Hudson 
23726fd0c7bcSRichard Henderson     atl = tcg_temp_new_i64();
23736fd0c7bcSRichard Henderson     stl = tcg_temp_new_i64();
23746fd0c7bcSRichard Henderson     addr = tcg_temp_new_i64();
23756797c315SNick Hudson 
2376ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(stl, tcg_env,
23776797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
23786797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIASQ]));
2379ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(atl, tcg_env,
23806797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
23816797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIAOQ]));
23826797c315SNick Hudson     tcg_gen_shli_i64(stl, stl, 32);
23836797c315SNick Hudson     tcg_gen_or_tl(addr, atl, stl);
23846797c315SNick Hudson 
23856797c315SNick Hudson     reg = load_gpr(ctx, a->r);
23866797c315SNick Hudson     if (a->addr) {
23878577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
23886797c315SNick Hudson     } else {
23898577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
23906797c315SNick Hudson     }
23916797c315SNick Hudson 
23926797c315SNick Hudson     /* Exit TB for TLB change if mmu is enabled.  */
23936797c315SNick Hudson     if (ctx->tb_flags & PSW_C) {
23946797c315SNick Hudson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
23956797c315SNick Hudson     }
23966797c315SNick Hudson     return nullify_end(ctx);
23976797c315SNick Hudson #endif
23986797c315SNick Hudson }
23996797c315SNick Hudson 
24008577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
24018577f354SRichard Henderson {
24028577f354SRichard Henderson     if (!ctx->is_pa20) {
24038577f354SRichard Henderson         return false;
24048577f354SRichard Henderson     }
24058577f354SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24068577f354SRichard Henderson #ifndef CONFIG_USER_ONLY
24078577f354SRichard Henderson     nullify_over(ctx);
24088577f354SRichard Henderson     {
24098577f354SRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
24108577f354SRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->r2);
24118577f354SRichard Henderson 
24128577f354SRichard Henderson         if (a->data) {
24138577f354SRichard Henderson             gen_helper_idtlbt_pa20(tcg_env, src1, src2);
24148577f354SRichard Henderson         } else {
24158577f354SRichard Henderson             gen_helper_iitlbt_pa20(tcg_env, src1, src2);
24168577f354SRichard Henderson         }
24178577f354SRichard Henderson     }
24188577f354SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
24198577f354SRichard Henderson     if (ctx->tb_flags & PSW_C) {
24208577f354SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
24218577f354SRichard Henderson     }
24228577f354SRichard Henderson     return nullify_end(ctx);
24238577f354SRichard Henderson #endif
24248577f354SRichard Henderson }
24258577f354SRichard Henderson 
2426deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
24272dfcca9fSRichard Henderson {
2428deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2429deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
24306fd0c7bcSRichard Henderson     TCGv_i64 vaddr;
24316fd0c7bcSRichard Henderson     TCGv_i64 ofs, paddr;
24322dfcca9fSRichard Henderson 
24332dfcca9fSRichard Henderson     nullify_over(ctx);
24342dfcca9fSRichard Henderson 
2435deee69a1SRichard Henderson     form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
24362dfcca9fSRichard Henderson 
24372dfcca9fSRichard Henderson     paddr = tcg_temp_new();
2438ad75a51eSRichard Henderson     gen_helper_lpa(paddr, tcg_env, vaddr);
24392dfcca9fSRichard Henderson 
24402dfcca9fSRichard Henderson     /* Note that physical address result overrides base modification.  */
2441deee69a1SRichard Henderson     if (a->m) {
2442deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
24432dfcca9fSRichard Henderson     }
2444deee69a1SRichard Henderson     save_gpr(ctx, a->t, paddr);
24452dfcca9fSRichard Henderson 
244631234768SRichard Henderson     return nullify_end(ctx);
2447deee69a1SRichard Henderson #endif
24482dfcca9fSRichard Henderson }
244943a97b81SRichard Henderson 
2450deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a)
245143a97b81SRichard Henderson {
245243a97b81SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
245343a97b81SRichard Henderson 
245443a97b81SRichard Henderson     /* The Coherence Index is an implementation-defined function of the
245543a97b81SRichard Henderson        physical address.  Two addresses with the same CI have a coherent
245643a97b81SRichard Henderson        view of the cache.  Our implementation is to return 0 for all,
245743a97b81SRichard Henderson        since the entire address space is coherent.  */
24586fd0c7bcSRichard Henderson     save_gpr(ctx, a->t, tcg_constant_i64(0));
245943a97b81SRichard Henderson 
246031234768SRichard Henderson     cond_free(&ctx->null_cond);
246131234768SRichard Henderson     return true;
246243a97b81SRichard Henderson }
246398a9cb79SRichard Henderson 
2464faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2465b2167459SRichard Henderson {
24660c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, false);
2467b2167459SRichard Henderson }
2468b2167459SRichard Henderson 
2469faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2470b2167459SRichard Henderson {
24710c982a28SRichard Henderson     return do_add_reg(ctx, a, true, false, false, false);
2472b2167459SRichard Henderson }
2473b2167459SRichard Henderson 
2474faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2475b2167459SRichard Henderson {
24760c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, false);
2477b2167459SRichard Henderson }
2478b2167459SRichard Henderson 
2479faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2480b2167459SRichard Henderson {
24810c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, true);
24820c982a28SRichard Henderson }
2483b2167459SRichard Henderson 
2484faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
24850c982a28SRichard Henderson {
24860c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, true);
24870c982a28SRichard Henderson }
24880c982a28SRichard Henderson 
248963c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
24900c982a28SRichard Henderson {
24910c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, false);
24920c982a28SRichard Henderson }
24930c982a28SRichard Henderson 
249463c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
24950c982a28SRichard Henderson {
24960c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, false);
24970c982a28SRichard Henderson }
24980c982a28SRichard Henderson 
249963c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
25000c982a28SRichard Henderson {
25010c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, true);
25020c982a28SRichard Henderson }
25030c982a28SRichard Henderson 
250463c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
25050c982a28SRichard Henderson {
25060c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, true);
25070c982a28SRichard Henderson }
25080c982a28SRichard Henderson 
250963c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
25100c982a28SRichard Henderson {
25110c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, true, false);
25120c982a28SRichard Henderson }
25130c982a28SRichard Henderson 
251463c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
25150c982a28SRichard Henderson {
25160c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, true, false);
25170c982a28SRichard Henderson }
25180c982a28SRichard Henderson 
2519fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
25200c982a28SRichard Henderson {
25216fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_andc_i64);
25220c982a28SRichard Henderson }
25230c982a28SRichard Henderson 
2524fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
25250c982a28SRichard Henderson {
25266fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_and_i64);
25270c982a28SRichard Henderson }
25280c982a28SRichard Henderson 
2529fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
25300c982a28SRichard Henderson {
25310c982a28SRichard Henderson     if (a->cf == 0) {
25320c982a28SRichard Henderson         unsigned r2 = a->r2;
25330c982a28SRichard Henderson         unsigned r1 = a->r1;
25340c982a28SRichard Henderson         unsigned rt = a->t;
25350c982a28SRichard Henderson 
25367aee8189SRichard Henderson         if (rt == 0) { /* NOP */
25377aee8189SRichard Henderson             cond_free(&ctx->null_cond);
25387aee8189SRichard Henderson             return true;
25397aee8189SRichard Henderson         }
25407aee8189SRichard Henderson         if (r2 == 0) { /* COPY */
2541b2167459SRichard Henderson             if (r1 == 0) {
25426fd0c7bcSRichard Henderson                 TCGv_i64 dest = dest_gpr(ctx, rt);
25436fd0c7bcSRichard Henderson                 tcg_gen_movi_i64(dest, 0);
2544b2167459SRichard Henderson                 save_gpr(ctx, rt, dest);
2545b2167459SRichard Henderson             } else {
2546b2167459SRichard Henderson                 save_gpr(ctx, rt, cpu_gr[r1]);
2547b2167459SRichard Henderson             }
2548b2167459SRichard Henderson             cond_free(&ctx->null_cond);
254931234768SRichard Henderson             return true;
2550b2167459SRichard Henderson         }
25517aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY
25527aee8189SRichard Henderson         /* These are QEMU extensions and are nops in the real architecture:
25537aee8189SRichard Henderson          *
25547aee8189SRichard Henderson          * or %r10,%r10,%r10 -- idle loop; wait for interrupt
25557aee8189SRichard Henderson          * or %r31,%r31,%r31 -- death loop; offline cpu
25567aee8189SRichard Henderson          *                      currently implemented as idle.
25577aee8189SRichard Henderson          */
25587aee8189SRichard Henderson         if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
25597aee8189SRichard Henderson             /* No need to check for supervisor, as userland can only pause
25607aee8189SRichard Henderson                until the next timer interrupt.  */
25617aee8189SRichard Henderson             nullify_over(ctx);
25627aee8189SRichard Henderson 
25637aee8189SRichard Henderson             /* Advance the instruction queue.  */
2564741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
2565741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
25667aee8189SRichard Henderson             nullify_set(ctx, 0);
25677aee8189SRichard Henderson 
25687aee8189SRichard Henderson             /* Tell the qemu main loop to halt until this cpu has work.  */
2569ad75a51eSRichard Henderson             tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
257029dd6f64SRichard Henderson                            offsetof(CPUState, halted) - offsetof(HPPACPU, env));
25717aee8189SRichard Henderson             gen_excp_1(EXCP_HALTED);
25727aee8189SRichard Henderson             ctx->base.is_jmp = DISAS_NORETURN;
25737aee8189SRichard Henderson 
25747aee8189SRichard Henderson             return nullify_end(ctx);
25757aee8189SRichard Henderson         }
25767aee8189SRichard Henderson #endif
25777aee8189SRichard Henderson     }
25786fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_or_i64);
25797aee8189SRichard Henderson }
2580b2167459SRichard Henderson 
2581fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
2582b2167459SRichard Henderson {
25836fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_xor_i64);
25840c982a28SRichard Henderson }
25850c982a28SRichard Henderson 
2586345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
25870c982a28SRichard Henderson {
25886fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2589b2167459SRichard Henderson 
25900c982a28SRichard Henderson     if (a->cf) {
2591b2167459SRichard Henderson         nullify_over(ctx);
2592b2167459SRichard Henderson     }
25930c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
25940c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2595345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
259631234768SRichard Henderson     return nullify_end(ctx);
2597b2167459SRichard Henderson }
2598b2167459SRichard Henderson 
2599af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
2600b2167459SRichard Henderson {
26016fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2602b2167459SRichard Henderson 
26030c982a28SRichard Henderson     if (a->cf) {
2604b2167459SRichard Henderson         nullify_over(ctx);
2605b2167459SRichard Henderson     }
26060c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26070c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
26086fd0c7bcSRichard Henderson     do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64);
260931234768SRichard Henderson     return nullify_end(ctx);
2610b2167459SRichard Henderson }
2611b2167459SRichard Henderson 
2612af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
2613b2167459SRichard Henderson {
26146fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, tmp;
2615b2167459SRichard Henderson 
26160c982a28SRichard Henderson     if (a->cf) {
2617b2167459SRichard Henderson         nullify_over(ctx);
2618b2167459SRichard Henderson     }
26190c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26200c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2621e12c6309SRichard Henderson     tmp = tcg_temp_new();
26226fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, tcg_r2);
26236fd0c7bcSRichard Henderson     do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64);
262431234768SRichard Henderson     return nullify_end(ctx);
2625b2167459SRichard Henderson }
2626b2167459SRichard Henderson 
2627af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
2628b2167459SRichard Henderson {
26290c982a28SRichard Henderson     return do_uaddcm(ctx, a, false);
26300c982a28SRichard Henderson }
26310c982a28SRichard Henderson 
2632af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
26330c982a28SRichard Henderson {
26340c982a28SRichard Henderson     return do_uaddcm(ctx, a, true);
26350c982a28SRichard Henderson }
26360c982a28SRichard Henderson 
2637af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
26380c982a28SRichard Henderson {
26396fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2640b2167459SRichard Henderson 
2641b2167459SRichard Henderson     nullify_over(ctx);
2642b2167459SRichard Henderson 
2643e12c6309SRichard Henderson     tmp = tcg_temp_new();
26446fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, cpu_psw_cb, 3);
2645b2167459SRichard Henderson     if (!is_i) {
26466fd0c7bcSRichard Henderson         tcg_gen_not_i64(tmp, tmp);
2647b2167459SRichard Henderson     }
26486fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
26496fd0c7bcSRichard Henderson     tcg_gen_muli_i64(tmp, tmp, 6);
2650af240753SRichard Henderson     do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false,
26516fd0c7bcSRichard Henderson             is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64);
265231234768SRichard Henderson     return nullify_end(ctx);
2653b2167459SRichard Henderson }
2654b2167459SRichard Henderson 
2655af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
2656b2167459SRichard Henderson {
26570c982a28SRichard Henderson     return do_dcor(ctx, a, false);
26580c982a28SRichard Henderson }
26590c982a28SRichard Henderson 
2660af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
26610c982a28SRichard Henderson {
26620c982a28SRichard Henderson     return do_dcor(ctx, a, true);
26630c982a28SRichard Henderson }
26640c982a28SRichard Henderson 
26650c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
26660c982a28SRichard Henderson {
26676fd0c7bcSRichard Henderson     TCGv_i64 dest, add1, add2, addc, zero, in1, in2;
26686fd0c7bcSRichard Henderson     TCGv_i64 cout;
2669b2167459SRichard Henderson 
2670b2167459SRichard Henderson     nullify_over(ctx);
2671b2167459SRichard Henderson 
26720c982a28SRichard Henderson     in1 = load_gpr(ctx, a->r1);
26730c982a28SRichard Henderson     in2 = load_gpr(ctx, a->r2);
2674b2167459SRichard Henderson 
2675b2167459SRichard Henderson     add1 = tcg_temp_new();
2676b2167459SRichard Henderson     add2 = tcg_temp_new();
2677b2167459SRichard Henderson     addc = tcg_temp_new();
2678b2167459SRichard Henderson     dest = tcg_temp_new();
26796fd0c7bcSRichard Henderson     zero = tcg_constant_i64(0);
2680b2167459SRichard Henderson 
2681b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
26826fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, in1, in1);
26836fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
2684b2167459SRichard Henderson 
268572ca8753SRichard Henderson     /*
268672ca8753SRichard Henderson      * Add or subtract R2, depending on PSW[V].  Proper computation of
268772ca8753SRichard Henderson      * carry requires that we subtract via + ~R2 + 1, as described in
268872ca8753SRichard Henderson      * the manual.  By extracting and masking V, we can produce the
268972ca8753SRichard Henderson      * proper inputs to the addition without movcond.
269072ca8753SRichard Henderson      */
26916fd0c7bcSRichard Henderson     tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
26926fd0c7bcSRichard Henderson     tcg_gen_xor_i64(add2, in2, addc);
26936fd0c7bcSRichard Henderson     tcg_gen_andi_i64(addc, addc, 1);
269472ca8753SRichard Henderson 
26956fd0c7bcSRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
26966fd0c7bcSRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
2697b2167459SRichard Henderson 
2698b2167459SRichard Henderson     /* Write back the result register.  */
26990c982a28SRichard Henderson     save_gpr(ctx, a->t, dest);
2700b2167459SRichard Henderson 
2701b2167459SRichard Henderson     /* Write back PSW[CB].  */
27026fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
27036fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
2704b2167459SRichard Henderson 
2705b2167459SRichard Henderson     /* Write back PSW[V] for the division step.  */
270672ca8753SRichard Henderson     cout = get_psw_carry(ctx, false);
27076fd0c7bcSRichard Henderson     tcg_gen_neg_i64(cpu_psw_v, cout);
27086fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
2709b2167459SRichard Henderson 
2710b2167459SRichard Henderson     /* Install the new nullification.  */
27110c982a28SRichard Henderson     if (a->cf) {
27126fd0c7bcSRichard Henderson         TCGv_i64 sv = NULL;
2713b47a4a02SSven Schnelle         if (cond_need_sv(a->cf >> 1)) {
2714b2167459SRichard Henderson             /* ??? The lshift is supposed to contribute to overflow.  */
2715b2167459SRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2);
2716b2167459SRichard Henderson         }
2717a751eb31SRichard Henderson         ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv);
2718b2167459SRichard Henderson     }
2719b2167459SRichard Henderson 
272031234768SRichard Henderson     return nullify_end(ctx);
2721b2167459SRichard Henderson }
2722b2167459SRichard Henderson 
27230588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a)
2724b2167459SRichard Henderson {
27250588e061SRichard Henderson     return do_add_imm(ctx, a, false, false);
27260588e061SRichard Henderson }
27270588e061SRichard Henderson 
27280588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a)
27290588e061SRichard Henderson {
27300588e061SRichard Henderson     return do_add_imm(ctx, a, true, false);
27310588e061SRichard Henderson }
27320588e061SRichard Henderson 
27330588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a)
27340588e061SRichard Henderson {
27350588e061SRichard Henderson     return do_add_imm(ctx, a, false, true);
27360588e061SRichard Henderson }
27370588e061SRichard Henderson 
27380588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a)
27390588e061SRichard Henderson {
27400588e061SRichard Henderson     return do_add_imm(ctx, a, true, true);
27410588e061SRichard Henderson }
27420588e061SRichard Henderson 
27430588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a)
27440588e061SRichard Henderson {
27450588e061SRichard Henderson     return do_sub_imm(ctx, a, false);
27460588e061SRichard Henderson }
27470588e061SRichard Henderson 
27480588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
27490588e061SRichard Henderson {
27500588e061SRichard Henderson     return do_sub_imm(ctx, a, true);
27510588e061SRichard Henderson }
27520588e061SRichard Henderson 
2753345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
27540588e061SRichard Henderson {
27556fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
2756b2167459SRichard Henderson 
27570588e061SRichard Henderson     if (a->cf) {
2758b2167459SRichard Henderson         nullify_over(ctx);
2759b2167459SRichard Henderson     }
2760b2167459SRichard Henderson 
27616fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
27620588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
2763345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
2764b2167459SRichard Henderson 
276531234768SRichard Henderson     return nullify_end(ctx);
2766b2167459SRichard Henderson }
2767b2167459SRichard Henderson 
27681cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a)
276996d6407fSRichard Henderson {
2770c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
27710786a3b6SHelge Deller         return gen_illegal(ctx);
2772c53e401eSRichard Henderson     }
27731cd012a5SRichard Henderson     return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
27741cd012a5SRichard Henderson                    a->disp, a->sp, a->m, a->size | MO_TE);
277596d6407fSRichard Henderson }
277696d6407fSRichard Henderson 
27771cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a)
277896d6407fSRichard Henderson {
27791cd012a5SRichard Henderson     assert(a->x == 0 && a->scale == 0);
2780c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
27810786a3b6SHelge Deller         return gen_illegal(ctx);
278296d6407fSRichard Henderson     }
2783c53e401eSRichard Henderson     return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
27840786a3b6SHelge Deller }
278596d6407fSRichard Henderson 
27861cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
278796d6407fSRichard Henderson {
2788b1af755cSRichard Henderson     MemOp mop = MO_TE | MO_ALIGN | a->size;
27896fd0c7bcSRichard Henderson     TCGv_i64 zero, dest, ofs;
27906fd0c7bcSRichard Henderson     TCGv_i64 addr;
279196d6407fSRichard Henderson 
2792c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
279351416c4eSRichard Henderson         return gen_illegal(ctx);
279451416c4eSRichard Henderson     }
279551416c4eSRichard Henderson 
279696d6407fSRichard Henderson     nullify_over(ctx);
279796d6407fSRichard Henderson 
27981cd012a5SRichard Henderson     if (a->m) {
279986f8d05fSRichard Henderson         /* Base register modification.  Make sure if RT == RB,
280086f8d05fSRichard Henderson            we see the result of the load.  */
2801e12c6309SRichard Henderson         dest = tcg_temp_new();
280296d6407fSRichard Henderson     } else {
28031cd012a5SRichard Henderson         dest = dest_gpr(ctx, a->t);
280496d6407fSRichard Henderson     }
280596d6407fSRichard Henderson 
28061cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0,
28071cd012a5SRichard Henderson              a->disp, a->sp, a->m, ctx->mmu_idx == MMU_PHYS_IDX);
2808b1af755cSRichard Henderson 
2809b1af755cSRichard Henderson     /*
2810b1af755cSRichard Henderson      * For hppa1.1, LDCW is undefined unless aligned mod 16.
2811b1af755cSRichard Henderson      * However actual hardware succeeds with aligned mod 4.
2812b1af755cSRichard Henderson      * Detect this case and log a GUEST_ERROR.
2813b1af755cSRichard Henderson      *
2814b1af755cSRichard Henderson      * TODO: HPPA64 relaxes the over-alignment requirement
2815b1af755cSRichard Henderson      * with the ,co completer.
2816b1af755cSRichard Henderson      */
2817b1af755cSRichard Henderson     gen_helper_ldc_check(addr);
2818b1af755cSRichard Henderson 
28196fd0c7bcSRichard Henderson     zero = tcg_constant_i64(0);
28206fd0c7bcSRichard Henderson     tcg_gen_atomic_xchg_i64(dest, addr, zero, ctx->mmu_idx, mop);
2821b1af755cSRichard Henderson 
28221cd012a5SRichard Henderson     if (a->m) {
28231cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
282496d6407fSRichard Henderson     }
28251cd012a5SRichard Henderson     save_gpr(ctx, a->t, dest);
282696d6407fSRichard Henderson 
282731234768SRichard Henderson     return nullify_end(ctx);
282896d6407fSRichard Henderson }
282996d6407fSRichard Henderson 
28301cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a)
283196d6407fSRichard Henderson {
28326fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
28336fd0c7bcSRichard Henderson     TCGv_i64 addr;
283496d6407fSRichard Henderson 
283596d6407fSRichard Henderson     nullify_over(ctx);
283696d6407fSRichard Henderson 
28371cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
283886f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
28391cd012a5SRichard Henderson     val = load_gpr(ctx, a->r);
28401cd012a5SRichard Henderson     if (a->a) {
2841f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
2842ad75a51eSRichard Henderson             gen_helper_stby_e_parallel(tcg_env, addr, val);
2843f9f46db4SEmilio G. Cota         } else {
2844ad75a51eSRichard Henderson             gen_helper_stby_e(tcg_env, addr, val);
2845f9f46db4SEmilio G. Cota         }
2846f9f46db4SEmilio G. Cota     } else {
2847f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
2848ad75a51eSRichard Henderson             gen_helper_stby_b_parallel(tcg_env, addr, val);
284996d6407fSRichard Henderson         } else {
2850ad75a51eSRichard Henderson             gen_helper_stby_b(tcg_env, addr, val);
285196d6407fSRichard Henderson         }
2852f9f46db4SEmilio G. Cota     }
28531cd012a5SRichard Henderson     if (a->m) {
28546fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~3);
28551cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
285696d6407fSRichard Henderson     }
285796d6407fSRichard Henderson 
285831234768SRichard Henderson     return nullify_end(ctx);
285996d6407fSRichard Henderson }
286096d6407fSRichard Henderson 
286125460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a)
286225460fc5SRichard Henderson {
28636fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
28646fd0c7bcSRichard Henderson     TCGv_i64 addr;
286525460fc5SRichard Henderson 
286625460fc5SRichard Henderson     if (!ctx->is_pa20) {
286725460fc5SRichard Henderson         return false;
286825460fc5SRichard Henderson     }
286925460fc5SRichard Henderson     nullify_over(ctx);
287025460fc5SRichard Henderson 
287125460fc5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
287225460fc5SRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
287325460fc5SRichard Henderson     val = load_gpr(ctx, a->r);
287425460fc5SRichard Henderson     if (a->a) {
287525460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
287625460fc5SRichard Henderson             gen_helper_stdby_e_parallel(tcg_env, addr, val);
287725460fc5SRichard Henderson         } else {
287825460fc5SRichard Henderson             gen_helper_stdby_e(tcg_env, addr, val);
287925460fc5SRichard Henderson         }
288025460fc5SRichard Henderson     } else {
288125460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
288225460fc5SRichard Henderson             gen_helper_stdby_b_parallel(tcg_env, addr, val);
288325460fc5SRichard Henderson         } else {
288425460fc5SRichard Henderson             gen_helper_stdby_b(tcg_env, addr, val);
288525460fc5SRichard Henderson         }
288625460fc5SRichard Henderson     }
288725460fc5SRichard Henderson     if (a->m) {
28886fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~7);
288925460fc5SRichard Henderson         save_gpr(ctx, a->b, ofs);
289025460fc5SRichard Henderson     }
289125460fc5SRichard Henderson 
289225460fc5SRichard Henderson     return nullify_end(ctx);
289325460fc5SRichard Henderson }
289425460fc5SRichard Henderson 
28951cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a)
2896d0a851ccSRichard Henderson {
2897d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
2898d0a851ccSRichard Henderson 
2899d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2900d0a851ccSRichard Henderson     ctx->mmu_idx = MMU_PHYS_IDX;
29011cd012a5SRichard Henderson     trans_ld(ctx, a);
2902d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
290331234768SRichard Henderson     return true;
2904d0a851ccSRichard Henderson }
2905d0a851ccSRichard Henderson 
29061cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a)
2907d0a851ccSRichard Henderson {
2908d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
2909d0a851ccSRichard Henderson 
2910d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2911d0a851ccSRichard Henderson     ctx->mmu_idx = MMU_PHYS_IDX;
29121cd012a5SRichard Henderson     trans_st(ctx, a);
2913d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
291431234768SRichard Henderson     return true;
2915d0a851ccSRichard Henderson }
291695412a61SRichard Henderson 
29170588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
2918b2167459SRichard Henderson {
29196fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
2920b2167459SRichard Henderson 
29216fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tcg_rt, a->i);
29220588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
2923b2167459SRichard Henderson     cond_free(&ctx->null_cond);
292431234768SRichard Henderson     return true;
2925b2167459SRichard Henderson }
2926b2167459SRichard Henderson 
29270588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a)
2928b2167459SRichard Henderson {
29296fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
29306fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
2931b2167459SRichard Henderson 
29326fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
2933b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
2934b2167459SRichard Henderson     cond_free(&ctx->null_cond);
293531234768SRichard Henderson     return true;
2936b2167459SRichard Henderson }
2937b2167459SRichard Henderson 
29380588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
2939b2167459SRichard Henderson {
29406fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
2941b2167459SRichard Henderson 
2942b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
2943b2167459SRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_tl.  */
29440588e061SRichard Henderson     if (a->b == 0) {
29456fd0c7bcSRichard Henderson         tcg_gen_movi_i64(tcg_rt, a->i);
2946b2167459SRichard Henderson     } else {
29476fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
2948b2167459SRichard Henderson     }
29490588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
2950b2167459SRichard Henderson     cond_free(&ctx->null_cond);
295131234768SRichard Henderson     return true;
2952b2167459SRichard Henderson }
2953b2167459SRichard Henderson 
29546fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
2955e9efd4bcSRichard Henderson                     unsigned c, unsigned f, bool d, unsigned n, int disp)
295698cd9ca7SRichard Henderson {
29576fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv;
295898cd9ca7SRichard Henderson     DisasCond cond;
295998cd9ca7SRichard Henderson 
296098cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
2961e12c6309SRichard Henderson     dest = tcg_temp_new();
296298cd9ca7SRichard Henderson 
29636fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
296498cd9ca7SRichard Henderson 
2965f764718dSRichard Henderson     sv = NULL;
2966b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
296798cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
296898cd9ca7SRichard Henderson     }
296998cd9ca7SRichard Henderson 
29704fe9533aSRichard Henderson     cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
297101afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
297298cd9ca7SRichard Henderson }
297398cd9ca7SRichard Henderson 
297401afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
297598cd9ca7SRichard Henderson {
2976e9efd4bcSRichard Henderson     if (!ctx->is_pa20 && a->d) {
2977e9efd4bcSRichard Henderson         return false;
2978e9efd4bcSRichard Henderson     }
297901afb7beSRichard Henderson     nullify_over(ctx);
2980e9efd4bcSRichard Henderson     return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
2981e9efd4bcSRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
298201afb7beSRichard Henderson }
298301afb7beSRichard Henderson 
298401afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
298501afb7beSRichard Henderson {
2986c65c3ee1SRichard Henderson     if (!ctx->is_pa20 && a->d) {
2987c65c3ee1SRichard Henderson         return false;
2988c65c3ee1SRichard Henderson     }
298901afb7beSRichard Henderson     nullify_over(ctx);
29906fd0c7bcSRichard Henderson     return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
2991c65c3ee1SRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
299201afb7beSRichard Henderson }
299301afb7beSRichard Henderson 
29946fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
299501afb7beSRichard Henderson                     unsigned c, unsigned f, unsigned n, int disp)
299601afb7beSRichard Henderson {
29976fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv, cb_cond;
299898cd9ca7SRichard Henderson     DisasCond cond;
2999bdcccc17SRichard Henderson     bool d = false;
300098cd9ca7SRichard Henderson 
3001f25d3160SRichard Henderson     /*
3002f25d3160SRichard Henderson      * For hppa64, the ADDB conditions change with PSW.W,
3003f25d3160SRichard Henderson      * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3004f25d3160SRichard Henderson      */
3005f25d3160SRichard Henderson     if (ctx->tb_flags & PSW_W) {
3006f25d3160SRichard Henderson         d = c >= 5;
3007f25d3160SRichard Henderson         if (d) {
3008f25d3160SRichard Henderson             c &= 3;
3009f25d3160SRichard Henderson         }
3010f25d3160SRichard Henderson     }
3011f25d3160SRichard Henderson 
301298cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
301343675d20SSven Schnelle     dest = tcg_temp_new();
3014f764718dSRichard Henderson     sv = NULL;
3015bdcccc17SRichard Henderson     cb_cond = NULL;
301698cd9ca7SRichard Henderson 
3017b47a4a02SSven Schnelle     if (cond_need_cb(c)) {
30186fd0c7bcSRichard Henderson         TCGv_i64 cb = tcg_temp_new();
30196fd0c7bcSRichard Henderson         TCGv_i64 cb_msb = tcg_temp_new();
3020bdcccc17SRichard Henderson 
30216fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cb_msb, 0);
30226fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
30236fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
30246fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
3025bdcccc17SRichard Henderson         cb_cond = get_carry(ctx, d, cb, cb_msb);
3026b47a4a02SSven Schnelle     } else {
30276fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
3028b47a4a02SSven Schnelle     }
3029b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
303098cd9ca7SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
303198cd9ca7SRichard Henderson     }
303298cd9ca7SRichard Henderson 
3033a751eb31SRichard Henderson     cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
303443675d20SSven Schnelle     save_gpr(ctx, r, dest);
303501afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
303698cd9ca7SRichard Henderson }
303798cd9ca7SRichard Henderson 
303801afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a)
303998cd9ca7SRichard Henderson {
304001afb7beSRichard Henderson     nullify_over(ctx);
304101afb7beSRichard Henderson     return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
304201afb7beSRichard Henderson }
304301afb7beSRichard Henderson 
304401afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
304501afb7beSRichard Henderson {
304601afb7beSRichard Henderson     nullify_over(ctx);
30476fd0c7bcSRichard Henderson     return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
304801afb7beSRichard Henderson }
304901afb7beSRichard Henderson 
305001afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
305101afb7beSRichard Henderson {
30526fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
305398cd9ca7SRichard Henderson     DisasCond cond;
305498cd9ca7SRichard Henderson 
305598cd9ca7SRichard Henderson     nullify_over(ctx);
305698cd9ca7SRichard Henderson 
305798cd9ca7SRichard Henderson     tmp = tcg_temp_new();
305801afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
305984e224d4SRichard Henderson     if (cond_need_ext(ctx, a->d)) {
30601e9ab9fbSRichard Henderson         /* Force shift into [32,63] */
30616fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_sar, 32);
30626fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, tmp);
30631e9ab9fbSRichard Henderson     } else {
30646fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
30651e9ab9fbSRichard Henderson     }
306698cd9ca7SRichard Henderson 
30671e9ab9fbSRichard Henderson     cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
306801afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
306998cd9ca7SRichard Henderson }
307098cd9ca7SRichard Henderson 
307101afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
307298cd9ca7SRichard Henderson {
30736fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
307401afb7beSRichard Henderson     DisasCond cond;
30751e9ab9fbSRichard Henderson     int p;
307601afb7beSRichard Henderson 
307701afb7beSRichard Henderson     nullify_over(ctx);
307801afb7beSRichard Henderson 
307901afb7beSRichard Henderson     tmp = tcg_temp_new();
308001afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
308184e224d4SRichard Henderson     p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0);
30826fd0c7bcSRichard Henderson     tcg_gen_shli_i64(tmp, tcg_r, p);
308301afb7beSRichard Henderson 
308401afb7beSRichard Henderson     cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
308501afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
308601afb7beSRichard Henderson }
308701afb7beSRichard Henderson 
308801afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a)
308901afb7beSRichard Henderson {
30906fd0c7bcSRichard Henderson     TCGv_i64 dest;
309198cd9ca7SRichard Henderson     DisasCond cond;
309298cd9ca7SRichard Henderson 
309398cd9ca7SRichard Henderson     nullify_over(ctx);
309498cd9ca7SRichard Henderson 
309501afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r2);
309601afb7beSRichard Henderson     if (a->r1 == 0) {
30976fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, 0);
309898cd9ca7SRichard Henderson     } else {
30996fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
310098cd9ca7SRichard Henderson     }
310198cd9ca7SRichard Henderson 
31024fa52edfSRichard Henderson     /* All MOVB conditions are 32-bit. */
31034fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
310401afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
310501afb7beSRichard Henderson }
310601afb7beSRichard Henderson 
310701afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
310801afb7beSRichard Henderson {
31096fd0c7bcSRichard Henderson     TCGv_i64 dest;
311001afb7beSRichard Henderson     DisasCond cond;
311101afb7beSRichard Henderson 
311201afb7beSRichard Henderson     nullify_over(ctx);
311301afb7beSRichard Henderson 
311401afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r);
31156fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, a->i);
311601afb7beSRichard Henderson 
31174fa52edfSRichard Henderson     /* All MOVBI conditions are 32-bit. */
31184fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
311901afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
312098cd9ca7SRichard Henderson }
312198cd9ca7SRichard Henderson 
3122f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
31230b1347d2SRichard Henderson {
31246fd0c7bcSRichard Henderson     TCGv_i64 dest, src2;
31250b1347d2SRichard Henderson 
3126f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3127f7b775a9SRichard Henderson         return false;
3128f7b775a9SRichard Henderson     }
312930878590SRichard Henderson     if (a->c) {
31300b1347d2SRichard Henderson         nullify_over(ctx);
31310b1347d2SRichard Henderson     }
31320b1347d2SRichard Henderson 
313330878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
3134f7b775a9SRichard Henderson     src2 = load_gpr(ctx, a->r2);
313530878590SRichard Henderson     if (a->r1 == 0) {
3136f7b775a9SRichard Henderson         if (a->d) {
31376fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src2, cpu_sar);
3138f7b775a9SRichard Henderson         } else {
31396fd0c7bcSRichard Henderson             TCGv_i64 tmp = tcg_temp_new();
3140f7b775a9SRichard Henderson 
31416fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src2);
31426fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
31436fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, dest, tmp);
3144f7b775a9SRichard Henderson         }
314530878590SRichard Henderson     } else if (a->r1 == a->r2) {
3146f7b775a9SRichard Henderson         if (a->d) {
31476fd0c7bcSRichard Henderson             tcg_gen_rotr_i64(dest, src2, cpu_sar);
3148f7b775a9SRichard Henderson         } else {
31490b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
3150e1d635e8SRichard Henderson             TCGv_i32 s32 = tcg_temp_new_i32();
3151e1d635e8SRichard Henderson 
31526fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, src2);
31536fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(s32, cpu_sar);
3154f7b775a9SRichard Henderson             tcg_gen_andi_i32(s32, s32, 31);
3155e1d635e8SRichard Henderson             tcg_gen_rotr_i32(t32, t32, s32);
31566fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
3157f7b775a9SRichard Henderson         }
3158f7b775a9SRichard Henderson     } else {
31596fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
3160f7b775a9SRichard Henderson 
3161f7b775a9SRichard Henderson         if (a->d) {
31626fd0c7bcSRichard Henderson             TCGv_i64 t = tcg_temp_new();
31636fd0c7bcSRichard Henderson             TCGv_i64 n = tcg_temp_new();
3164f7b775a9SRichard Henderson 
31656fd0c7bcSRichard Henderson             tcg_gen_xori_i64(n, cpu_sar, 63);
31666fd0c7bcSRichard Henderson             tcg_gen_shl_i64(t, src2, n);
31676fd0c7bcSRichard Henderson             tcg_gen_shli_i64(t, t, 1);
31686fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src1, cpu_sar);
31696fd0c7bcSRichard Henderson             tcg_gen_or_i64(dest, dest, t);
31700b1347d2SRichard Henderson         } else {
31710b1347d2SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
31720b1347d2SRichard Henderson             TCGv_i64 s = tcg_temp_new_i64();
31730b1347d2SRichard Henderson 
31746fd0c7bcSRichard Henderson             tcg_gen_concat32_i64(t, src2, src1);
3175*967662cdSRichard Henderson             tcg_gen_andi_i64(s, cpu_sar, 31);
3176*967662cdSRichard Henderson             tcg_gen_shr_i64(dest, t, s);
31770b1347d2SRichard Henderson         }
3178f7b775a9SRichard Henderson     }
317930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
31800b1347d2SRichard Henderson 
31810b1347d2SRichard Henderson     /* Install the new nullification.  */
31820b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
318330878590SRichard Henderson     if (a->c) {
31844fa52edfSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
31850b1347d2SRichard Henderson     }
318631234768SRichard Henderson     return nullify_end(ctx);
31870b1347d2SRichard Henderson }
31880b1347d2SRichard Henderson 
3189f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
31900b1347d2SRichard Henderson {
3191f7b775a9SRichard Henderson     unsigned width, sa;
31926fd0c7bcSRichard Henderson     TCGv_i64 dest, t2;
31930b1347d2SRichard Henderson 
3194f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3195f7b775a9SRichard Henderson         return false;
3196f7b775a9SRichard Henderson     }
319730878590SRichard Henderson     if (a->c) {
31980b1347d2SRichard Henderson         nullify_over(ctx);
31990b1347d2SRichard Henderson     }
32000b1347d2SRichard Henderson 
3201f7b775a9SRichard Henderson     width = a->d ? 64 : 32;
3202f7b775a9SRichard Henderson     sa = width - 1 - a->cpos;
3203f7b775a9SRichard Henderson 
320430878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
320530878590SRichard Henderson     t2 = load_gpr(ctx, a->r2);
320605bfd4dbSRichard Henderson     if (a->r1 == 0) {
32076fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, t2, sa, width - sa);
3208c53e401eSRichard Henderson     } else if (width == TARGET_LONG_BITS) {
32096fd0c7bcSRichard Henderson         tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
3210f7b775a9SRichard Henderson     } else {
3211f7b775a9SRichard Henderson         assert(!a->d);
3212f7b775a9SRichard Henderson         if (a->r1 == a->r2) {
32130b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
32146fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, t2);
32150b1347d2SRichard Henderson             tcg_gen_rotri_i32(t32, t32, sa);
32166fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
32170b1347d2SRichard Henderson         } else {
3218*967662cdSRichard Henderson             tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]);
3219*967662cdSRichard Henderson             tcg_gen_extract_i64(dest, dest, sa, 32);
32200b1347d2SRichard Henderson         }
3221f7b775a9SRichard Henderson     }
322230878590SRichard Henderson     save_gpr(ctx, a->t, dest);
32230b1347d2SRichard Henderson 
32240b1347d2SRichard Henderson     /* Install the new nullification.  */
32250b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
322630878590SRichard Henderson     if (a->c) {
32274fa52edfSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
32280b1347d2SRichard Henderson     }
322931234768SRichard Henderson     return nullify_end(ctx);
32300b1347d2SRichard Henderson }
32310b1347d2SRichard Henderson 
3232bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
32330b1347d2SRichard Henderson {
3234bd792da3SRichard Henderson     unsigned widthm1 = a->d ? 63 : 31;
32356fd0c7bcSRichard Henderson     TCGv_i64 dest, src, tmp;
32360b1347d2SRichard Henderson 
3237bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3238bd792da3SRichard Henderson         return false;
3239bd792da3SRichard Henderson     }
324030878590SRichard Henderson     if (a->c) {
32410b1347d2SRichard Henderson         nullify_over(ctx);
32420b1347d2SRichard Henderson     }
32430b1347d2SRichard Henderson 
324430878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
324530878590SRichard Henderson     src = load_gpr(ctx, a->r);
32460b1347d2SRichard Henderson     tmp = tcg_temp_new();
32470b1347d2SRichard Henderson 
32480b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
32496fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
32506fd0c7bcSRichard Henderson     tcg_gen_xori_i64(tmp, tmp, widthm1);
3251d781cb77SRichard Henderson 
325230878590SRichard Henderson     if (a->se) {
3253bd792da3SRichard Henderson         if (!a->d) {
32546fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(dest, src);
3255bd792da3SRichard Henderson             src = dest;
3256bd792da3SRichard Henderson         }
32576fd0c7bcSRichard Henderson         tcg_gen_sar_i64(dest, src, tmp);
32586fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, dest, 0, a->len);
32590b1347d2SRichard Henderson     } else {
3260bd792da3SRichard Henderson         if (!a->d) {
32616fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src);
3262bd792da3SRichard Henderson             src = dest;
3263bd792da3SRichard Henderson         }
32646fd0c7bcSRichard Henderson         tcg_gen_shr_i64(dest, src, tmp);
32656fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, dest, 0, a->len);
32660b1347d2SRichard Henderson     }
326730878590SRichard Henderson     save_gpr(ctx, a->t, dest);
32680b1347d2SRichard Henderson 
32690b1347d2SRichard Henderson     /* Install the new nullification.  */
32700b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
327130878590SRichard Henderson     if (a->c) {
3272bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
32730b1347d2SRichard Henderson     }
327431234768SRichard Henderson     return nullify_end(ctx);
32750b1347d2SRichard Henderson }
32760b1347d2SRichard Henderson 
3277bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
32780b1347d2SRichard Henderson {
3279bd792da3SRichard Henderson     unsigned len, cpos, width;
32806fd0c7bcSRichard Henderson     TCGv_i64 dest, src;
32810b1347d2SRichard Henderson 
3282bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3283bd792da3SRichard Henderson         return false;
3284bd792da3SRichard Henderson     }
328530878590SRichard Henderson     if (a->c) {
32860b1347d2SRichard Henderson         nullify_over(ctx);
32870b1347d2SRichard Henderson     }
32880b1347d2SRichard Henderson 
3289bd792da3SRichard Henderson     len = a->len;
3290bd792da3SRichard Henderson     width = a->d ? 64 : 32;
3291bd792da3SRichard Henderson     cpos = width - 1 - a->pos;
3292bd792da3SRichard Henderson     if (cpos + len > width) {
3293bd792da3SRichard Henderson         len = width - cpos;
3294bd792da3SRichard Henderson     }
3295bd792da3SRichard Henderson 
329630878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
329730878590SRichard Henderson     src = load_gpr(ctx, a->r);
329830878590SRichard Henderson     if (a->se) {
32996fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, src, cpos, len);
33000b1347d2SRichard Henderson     } else {
33016fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, src, cpos, len);
33020b1347d2SRichard Henderson     }
330330878590SRichard Henderson     save_gpr(ctx, a->t, dest);
33040b1347d2SRichard Henderson 
33050b1347d2SRichard Henderson     /* Install the new nullification.  */
33060b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
330730878590SRichard Henderson     if (a->c) {
3308bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
33090b1347d2SRichard Henderson     }
331031234768SRichard Henderson     return nullify_end(ctx);
33110b1347d2SRichard Henderson }
33120b1347d2SRichard Henderson 
331372ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
33140b1347d2SRichard Henderson {
331572ae4f2bSRichard Henderson     unsigned len, width;
3316c53e401eSRichard Henderson     uint64_t mask0, mask1;
33176fd0c7bcSRichard Henderson     TCGv_i64 dest;
33180b1347d2SRichard Henderson 
331972ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
332072ae4f2bSRichard Henderson         return false;
332172ae4f2bSRichard Henderson     }
332230878590SRichard Henderson     if (a->c) {
33230b1347d2SRichard Henderson         nullify_over(ctx);
33240b1347d2SRichard Henderson     }
332572ae4f2bSRichard Henderson 
332672ae4f2bSRichard Henderson     len = a->len;
332772ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
332872ae4f2bSRichard Henderson     if (a->cpos + len > width) {
332972ae4f2bSRichard Henderson         len = width - a->cpos;
33300b1347d2SRichard Henderson     }
33310b1347d2SRichard Henderson 
333230878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
333330878590SRichard Henderson     mask0 = deposit64(0, a->cpos, len, a->i);
333430878590SRichard Henderson     mask1 = deposit64(-1, a->cpos, len, a->i);
33350b1347d2SRichard Henderson 
333630878590SRichard Henderson     if (a->nz) {
33376fd0c7bcSRichard Henderson         TCGv_i64 src = load_gpr(ctx, a->t);
33386fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, src, mask1);
33396fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, mask0);
33400b1347d2SRichard Henderson     } else {
33416fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, mask0);
33420b1347d2SRichard Henderson     }
334330878590SRichard Henderson     save_gpr(ctx, a->t, dest);
33440b1347d2SRichard Henderson 
33450b1347d2SRichard Henderson     /* Install the new nullification.  */
33460b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
334730878590SRichard Henderson     if (a->c) {
334872ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
33490b1347d2SRichard Henderson     }
335031234768SRichard Henderson     return nullify_end(ctx);
33510b1347d2SRichard Henderson }
33520b1347d2SRichard Henderson 
335372ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
33540b1347d2SRichard Henderson {
335530878590SRichard Henderson     unsigned rs = a->nz ? a->t : 0;
335672ae4f2bSRichard Henderson     unsigned len, width;
33576fd0c7bcSRichard Henderson     TCGv_i64 dest, val;
33580b1347d2SRichard Henderson 
335972ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
336072ae4f2bSRichard Henderson         return false;
336172ae4f2bSRichard Henderson     }
336230878590SRichard Henderson     if (a->c) {
33630b1347d2SRichard Henderson         nullify_over(ctx);
33640b1347d2SRichard Henderson     }
336572ae4f2bSRichard Henderson 
336672ae4f2bSRichard Henderson     len = a->len;
336772ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
336872ae4f2bSRichard Henderson     if (a->cpos + len > width) {
336972ae4f2bSRichard Henderson         len = width - a->cpos;
33700b1347d2SRichard Henderson     }
33710b1347d2SRichard Henderson 
337230878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
337330878590SRichard Henderson     val = load_gpr(ctx, a->r);
33740b1347d2SRichard Henderson     if (rs == 0) {
33756fd0c7bcSRichard Henderson         tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
33760b1347d2SRichard Henderson     } else {
33776fd0c7bcSRichard Henderson         tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
33780b1347d2SRichard Henderson     }
337930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
33800b1347d2SRichard Henderson 
33810b1347d2SRichard Henderson     /* Install the new nullification.  */
33820b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
338330878590SRichard Henderson     if (a->c) {
338472ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
33850b1347d2SRichard Henderson     }
338631234768SRichard Henderson     return nullify_end(ctx);
33870b1347d2SRichard Henderson }
33880b1347d2SRichard Henderson 
338972ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
33906fd0c7bcSRichard Henderson                        bool d, bool nz, unsigned len, TCGv_i64 val)
33910b1347d2SRichard Henderson {
33920b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
339372ae4f2bSRichard Henderson     unsigned widthm1 = d ? 63 : 31;
33946fd0c7bcSRichard Henderson     TCGv_i64 mask, tmp, shift, dest;
3395c53e401eSRichard Henderson     uint64_t msb = 1ULL << (len - 1);
33960b1347d2SRichard Henderson 
33970b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
33980b1347d2SRichard Henderson     shift = tcg_temp_new();
33990b1347d2SRichard Henderson     tmp = tcg_temp_new();
34000b1347d2SRichard Henderson 
34010b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
34026fd0c7bcSRichard Henderson     tcg_gen_andi_i64(shift, cpu_sar, widthm1);
34036fd0c7bcSRichard Henderson     tcg_gen_xori_i64(shift, shift, widthm1);
34040b1347d2SRichard Henderson 
34050992a930SRichard Henderson     mask = tcg_temp_new();
34066fd0c7bcSRichard Henderson     tcg_gen_movi_i64(mask, msb + (msb - 1));
34076fd0c7bcSRichard Henderson     tcg_gen_and_i64(tmp, val, mask);
34080b1347d2SRichard Henderson     if (rs) {
34096fd0c7bcSRichard Henderson         tcg_gen_shl_i64(mask, mask, shift);
34106fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tmp, shift);
34116fd0c7bcSRichard Henderson         tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
34126fd0c7bcSRichard Henderson         tcg_gen_or_i64(dest, dest, tmp);
34130b1347d2SRichard Henderson     } else {
34146fd0c7bcSRichard Henderson         tcg_gen_shl_i64(dest, tmp, shift);
34150b1347d2SRichard Henderson     }
34160b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
34170b1347d2SRichard Henderson 
34180b1347d2SRichard Henderson     /* Install the new nullification.  */
34190b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
34200b1347d2SRichard Henderson     if (c) {
342172ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, c, d, dest);
34220b1347d2SRichard Henderson     }
342331234768SRichard Henderson     return nullify_end(ctx);
34240b1347d2SRichard Henderson }
34250b1347d2SRichard Henderson 
342672ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
342730878590SRichard Henderson {
342872ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
342972ae4f2bSRichard Henderson         return false;
343072ae4f2bSRichard Henderson     }
3431a6deecceSSven Schnelle     if (a->c) {
3432a6deecceSSven Schnelle         nullify_over(ctx);
3433a6deecceSSven Schnelle     }
343472ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
343572ae4f2bSRichard Henderson                       load_gpr(ctx, a->r));
343630878590SRichard Henderson }
343730878590SRichard Henderson 
343872ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
343930878590SRichard Henderson {
344072ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
344172ae4f2bSRichard Henderson         return false;
344272ae4f2bSRichard Henderson     }
3443a6deecceSSven Schnelle     if (a->c) {
3444a6deecceSSven Schnelle         nullify_over(ctx);
3445a6deecceSSven Schnelle     }
344672ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
34476fd0c7bcSRichard Henderson                       tcg_constant_i64(a->i));
344830878590SRichard Henderson }
34490b1347d2SRichard Henderson 
34508340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a)
345198cd9ca7SRichard Henderson {
34526fd0c7bcSRichard Henderson     TCGv_i64 tmp;
345398cd9ca7SRichard Henderson 
3454c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
345598cd9ca7SRichard Henderson     /* ??? It seems like there should be a good way of using
345698cd9ca7SRichard Henderson        "be disp(sr2, r0)", the canonical gateway entry mechanism
345798cd9ca7SRichard Henderson        to our advantage.  But that appears to be inconvenient to
345898cd9ca7SRichard Henderson        manage along side branch delay slots.  Therefore we handle
345998cd9ca7SRichard Henderson        entry into the gateway page via absolute address.  */
346098cd9ca7SRichard Henderson     /* Since we don't implement spaces, just branch.  Do notice the special
346198cd9ca7SRichard Henderson        case of "be disp(*,r0)" using a direct branch to disp, so that we can
346298cd9ca7SRichard Henderson        goto_tb to the TB containing the syscall.  */
34638340f534SRichard Henderson     if (a->b == 0) {
34648340f534SRichard Henderson         return do_dbranch(ctx, a->disp, a->l, a->n);
346598cd9ca7SRichard Henderson     }
3466c301f34eSRichard Henderson #else
3467c301f34eSRichard Henderson     nullify_over(ctx);
3468660eefe1SRichard Henderson #endif
3469660eefe1SRichard Henderson 
3470e12c6309SRichard Henderson     tmp = tcg_temp_new();
34716fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp);
3472660eefe1SRichard Henderson     tmp = do_ibranch_priv(ctx, tmp);
3473c301f34eSRichard Henderson 
3474c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
34758340f534SRichard Henderson     return do_ibranch(ctx, tmp, a->l, a->n);
3476c301f34eSRichard Henderson #else
3477c301f34eSRichard Henderson     TCGv_i64 new_spc = tcg_temp_new_i64();
3478c301f34eSRichard Henderson 
34798340f534SRichard Henderson     load_spr(ctx, new_spc, a->sp);
34808340f534SRichard Henderson     if (a->l) {
3481741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
3482c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f);
3483c301f34eSRichard Henderson     }
34848340f534SRichard Henderson     if (a->n && use_nullify_skip(ctx)) {
3485a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
34866fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, 4);
3487a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3488c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, new_spc);
3489c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f);
3490c301f34eSRichard Henderson     } else {
3491741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3492c301f34eSRichard Henderson         if (ctx->iaoq_b == -1) {
3493c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3494c301f34eSRichard Henderson         }
3495a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3496c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, new_spc);
34978340f534SRichard Henderson         nullify_set(ctx, a->n);
3498c301f34eSRichard Henderson     }
3499c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
350031234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
350131234768SRichard Henderson     return nullify_end(ctx);
3502c301f34eSRichard Henderson #endif
350398cd9ca7SRichard Henderson }
350498cd9ca7SRichard Henderson 
35058340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a)
350698cd9ca7SRichard Henderson {
35078340f534SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n);
350898cd9ca7SRichard Henderson }
350998cd9ca7SRichard Henderson 
35108340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
351143e05652SRichard Henderson {
3512c53e401eSRichard Henderson     uint64_t dest = iaoq_dest(ctx, a->disp);
351343e05652SRichard Henderson 
35146e5f5300SSven Schnelle     nullify_over(ctx);
35156e5f5300SSven Schnelle 
351643e05652SRichard Henderson     /* Make sure the caller hasn't done something weird with the queue.
351743e05652SRichard Henderson      * ??? This is not quite the same as the PSW[B] bit, which would be
351843e05652SRichard Henderson      * expensive to track.  Real hardware will trap for
351943e05652SRichard Henderson      *    b  gateway
352043e05652SRichard Henderson      *    b  gateway+4  (in delay slot of first branch)
352143e05652SRichard Henderson      * However, checking for a non-sequential instruction queue *will*
352243e05652SRichard Henderson      * diagnose the security hole
352343e05652SRichard Henderson      *    b  gateway
352443e05652SRichard Henderson      *    b  evil
352543e05652SRichard Henderson      * in which instructions at evil would run with increased privs.
352643e05652SRichard Henderson      */
352743e05652SRichard Henderson     if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) {
352843e05652SRichard Henderson         return gen_illegal(ctx);
352943e05652SRichard Henderson     }
353043e05652SRichard Henderson 
353143e05652SRichard Henderson #ifndef CONFIG_USER_ONLY
353243e05652SRichard Henderson     if (ctx->tb_flags & PSW_C) {
3533b77af26eSRichard Henderson         CPUHPPAState *env = cpu_env(ctx->cs);
353443e05652SRichard Henderson         int type = hppa_artype_for_page(env, ctx->base.pc_next);
353543e05652SRichard Henderson         /* If we could not find a TLB entry, then we need to generate an
353643e05652SRichard Henderson            ITLB miss exception so the kernel will provide it.
353743e05652SRichard Henderson            The resulting TLB fill operation will invalidate this TB and
353843e05652SRichard Henderson            we will re-translate, at which point we *will* be able to find
353943e05652SRichard Henderson            the TLB entry and determine if this is in fact a gateway page.  */
354043e05652SRichard Henderson         if (type < 0) {
354131234768SRichard Henderson             gen_excp(ctx, EXCP_ITLB_MISS);
354231234768SRichard Henderson             return true;
354343e05652SRichard Henderson         }
354443e05652SRichard Henderson         /* No change for non-gateway pages or for priv decrease.  */
354543e05652SRichard Henderson         if (type >= 4 && type - 4 < ctx->privilege) {
354643e05652SRichard Henderson             dest = deposit32(dest, 0, 2, type - 4);
354743e05652SRichard Henderson         }
354843e05652SRichard Henderson     } else {
354943e05652SRichard Henderson         dest &= -4;  /* priv = 0 */
355043e05652SRichard Henderson     }
355143e05652SRichard Henderson #endif
355243e05652SRichard Henderson 
35536e5f5300SSven Schnelle     if (a->l) {
35546fd0c7bcSRichard Henderson         TCGv_i64 tmp = dest_gpr(ctx, a->l);
35556e5f5300SSven Schnelle         if (ctx->privilege < 3) {
35566fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, tmp, -4);
35576e5f5300SSven Schnelle         }
35586fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
35596e5f5300SSven Schnelle         save_gpr(ctx, a->l, tmp);
35606e5f5300SSven Schnelle     }
35616e5f5300SSven Schnelle 
35626e5f5300SSven Schnelle     return do_dbranch(ctx, dest, 0, a->n);
356343e05652SRichard Henderson }
356443e05652SRichard Henderson 
35658340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a)
356698cd9ca7SRichard Henderson {
3567b35aec85SRichard Henderson     if (a->x) {
35686fd0c7bcSRichard Henderson         TCGv_i64 tmp = tcg_temp_new();
35696fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3);
35706fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8);
3571660eefe1SRichard Henderson         /* The computation here never changes privilege level.  */
35728340f534SRichard Henderson         return do_ibranch(ctx, tmp, a->l, a->n);
3573b35aec85SRichard Henderson     } else {
3574b35aec85SRichard Henderson         /* BLR R0,RX is a good way to load PC+8 into RX.  */
3575b35aec85SRichard Henderson         return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n);
3576b35aec85SRichard Henderson     }
357798cd9ca7SRichard Henderson }
357898cd9ca7SRichard Henderson 
35798340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a)
358098cd9ca7SRichard Henderson {
35816fd0c7bcSRichard Henderson     TCGv_i64 dest;
358298cd9ca7SRichard Henderson 
35838340f534SRichard Henderson     if (a->x == 0) {
35848340f534SRichard Henderson         dest = load_gpr(ctx, a->b);
358598cd9ca7SRichard Henderson     } else {
3586e12c6309SRichard Henderson         dest = tcg_temp_new();
35876fd0c7bcSRichard Henderson         tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
35886fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
358998cd9ca7SRichard Henderson     }
3590660eefe1SRichard Henderson     dest = do_ibranch_priv(ctx, dest);
35918340f534SRichard Henderson     return do_ibranch(ctx, dest, 0, a->n);
359298cd9ca7SRichard Henderson }
359398cd9ca7SRichard Henderson 
35948340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a)
359598cd9ca7SRichard Henderson {
35966fd0c7bcSRichard Henderson     TCGv_i64 dest;
359798cd9ca7SRichard Henderson 
3598c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
35998340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
36008340f534SRichard Henderson     return do_ibranch(ctx, dest, a->l, a->n);
3601c301f34eSRichard Henderson #else
3602c301f34eSRichard Henderson     nullify_over(ctx);
36038340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
3604c301f34eSRichard Henderson 
3605741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3606c301f34eSRichard Henderson     if (ctx->iaoq_b == -1) {
3607c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3608c301f34eSRichard Henderson     }
3609741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest);
3610c301f34eSRichard Henderson     tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
36118340f534SRichard Henderson     if (a->l) {
3612741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var);
3613c301f34eSRichard Henderson     }
36148340f534SRichard Henderson     nullify_set(ctx, a->n);
3615c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
361631234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
361731234768SRichard Henderson     return nullify_end(ctx);
3618c301f34eSRichard Henderson #endif
361998cd9ca7SRichard Henderson }
362098cd9ca7SRichard Henderson 
3621a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
3622a8966ba7SRichard Henderson {
3623a8966ba7SRichard Henderson     /* All branch target stack instructions implement as nop. */
3624a8966ba7SRichard Henderson     return ctx->is_pa20;
3625a8966ba7SRichard Henderson }
3626a8966ba7SRichard Henderson 
36271ca74648SRichard Henderson /*
36281ca74648SRichard Henderson  * Float class 0
36291ca74648SRichard Henderson  */
3630ebe9383cSRichard Henderson 
36311ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3632ebe9383cSRichard Henderson {
3633ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
3634ebe9383cSRichard Henderson }
3635ebe9383cSRichard Henderson 
363659f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
363759f8c04bSHelge Deller {
3638a300dad3SRichard Henderson     uint64_t ret;
3639a300dad3SRichard Henderson 
3640c53e401eSRichard Henderson     if (ctx->is_pa20) {
3641a300dad3SRichard Henderson         ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
3642a300dad3SRichard Henderson     } else {
3643a300dad3SRichard Henderson         ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
3644a300dad3SRichard Henderson     }
3645a300dad3SRichard Henderson 
364659f8c04bSHelge Deller     nullify_over(ctx);
3647a300dad3SRichard Henderson     save_frd(0, tcg_constant_i64(ret));
364859f8c04bSHelge Deller     return nullify_end(ctx);
364959f8c04bSHelge Deller }
365059f8c04bSHelge Deller 
36511ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a)
36521ca74648SRichard Henderson {
36531ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f);
36541ca74648SRichard Henderson }
36551ca74648SRichard Henderson 
3656ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3657ebe9383cSRichard Henderson {
3658ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
3659ebe9383cSRichard Henderson }
3660ebe9383cSRichard Henderson 
36611ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a)
36621ca74648SRichard Henderson {
36631ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d);
36641ca74648SRichard Henderson }
36651ca74648SRichard Henderson 
36661ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3667ebe9383cSRichard Henderson {
3668ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
3669ebe9383cSRichard Henderson }
3670ebe9383cSRichard Henderson 
36711ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a)
36721ca74648SRichard Henderson {
36731ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fabs_f);
36741ca74648SRichard Henderson }
36751ca74648SRichard Henderson 
3676ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3677ebe9383cSRichard Henderson {
3678ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
3679ebe9383cSRichard Henderson }
3680ebe9383cSRichard Henderson 
36811ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a)
36821ca74648SRichard Henderson {
36831ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fabs_d);
36841ca74648SRichard Henderson }
36851ca74648SRichard Henderson 
36861ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a)
36871ca74648SRichard Henderson {
36881ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s);
36891ca74648SRichard Henderson }
36901ca74648SRichard Henderson 
36911ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a)
36921ca74648SRichard Henderson {
36931ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d);
36941ca74648SRichard Henderson }
36951ca74648SRichard Henderson 
36961ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a)
36971ca74648SRichard Henderson {
36981ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s);
36991ca74648SRichard Henderson }
37001ca74648SRichard Henderson 
37011ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a)
37021ca74648SRichard Henderson {
37031ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d);
37041ca74648SRichard Henderson }
37051ca74648SRichard Henderson 
37061ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3707ebe9383cSRichard Henderson {
3708ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
3709ebe9383cSRichard Henderson }
3710ebe9383cSRichard Henderson 
37111ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a)
37121ca74648SRichard Henderson {
37131ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fneg_f);
37141ca74648SRichard Henderson }
37151ca74648SRichard Henderson 
3716ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3717ebe9383cSRichard Henderson {
3718ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
3719ebe9383cSRichard Henderson }
3720ebe9383cSRichard Henderson 
37211ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a)
37221ca74648SRichard Henderson {
37231ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fneg_d);
37241ca74648SRichard Henderson }
37251ca74648SRichard Henderson 
37261ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3727ebe9383cSRichard Henderson {
3728ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
3729ebe9383cSRichard Henderson }
3730ebe9383cSRichard Henderson 
37311ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a)
37321ca74648SRichard Henderson {
37331ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f);
37341ca74648SRichard Henderson }
37351ca74648SRichard Henderson 
3736ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3737ebe9383cSRichard Henderson {
3738ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
3739ebe9383cSRichard Henderson }
3740ebe9383cSRichard Henderson 
37411ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a)
37421ca74648SRichard Henderson {
37431ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d);
37441ca74648SRichard Henderson }
37451ca74648SRichard Henderson 
37461ca74648SRichard Henderson /*
37471ca74648SRichard Henderson  * Float class 1
37481ca74648SRichard Henderson  */
37491ca74648SRichard Henderson 
37501ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a)
37511ca74648SRichard Henderson {
37521ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s);
37531ca74648SRichard Henderson }
37541ca74648SRichard Henderson 
37551ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a)
37561ca74648SRichard Henderson {
37571ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d);
37581ca74648SRichard Henderson }
37591ca74648SRichard Henderson 
37601ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a)
37611ca74648SRichard Henderson {
37621ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s);
37631ca74648SRichard Henderson }
37641ca74648SRichard Henderson 
37651ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a)
37661ca74648SRichard Henderson {
37671ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s);
37681ca74648SRichard Henderson }
37691ca74648SRichard Henderson 
37701ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a)
37711ca74648SRichard Henderson {
37721ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d);
37731ca74648SRichard Henderson }
37741ca74648SRichard Henderson 
37751ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a)
37761ca74648SRichard Henderson {
37771ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d);
37781ca74648SRichard Henderson }
37791ca74648SRichard Henderson 
37801ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a)
37811ca74648SRichard Henderson {
37821ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w);
37831ca74648SRichard Henderson }
37841ca74648SRichard Henderson 
37851ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a)
37861ca74648SRichard Henderson {
37871ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w);
37881ca74648SRichard Henderson }
37891ca74648SRichard Henderson 
37901ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a)
37911ca74648SRichard Henderson {
37921ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw);
37931ca74648SRichard Henderson }
37941ca74648SRichard Henderson 
37951ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a)
37961ca74648SRichard Henderson {
37971ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw);
37981ca74648SRichard Henderson }
37991ca74648SRichard Henderson 
38001ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a)
38011ca74648SRichard Henderson {
38021ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w);
38031ca74648SRichard Henderson }
38041ca74648SRichard Henderson 
38051ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a)
38061ca74648SRichard Henderson {
38071ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w);
38081ca74648SRichard Henderson }
38091ca74648SRichard Henderson 
38101ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a)
38111ca74648SRichard Henderson {
38121ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw);
38131ca74648SRichard Henderson }
38141ca74648SRichard Henderson 
38151ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a)
38161ca74648SRichard Henderson {
38171ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw);
38181ca74648SRichard Henderson }
38191ca74648SRichard Henderson 
38201ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a)
38211ca74648SRichard Henderson {
38221ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s);
38231ca74648SRichard Henderson }
38241ca74648SRichard Henderson 
38251ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a)
38261ca74648SRichard Henderson {
38271ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s);
38281ca74648SRichard Henderson }
38291ca74648SRichard Henderson 
38301ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a)
38311ca74648SRichard Henderson {
38321ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d);
38331ca74648SRichard Henderson }
38341ca74648SRichard Henderson 
38351ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a)
38361ca74648SRichard Henderson {
38371ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d);
38381ca74648SRichard Henderson }
38391ca74648SRichard Henderson 
38401ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a)
38411ca74648SRichard Henderson {
38421ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw);
38431ca74648SRichard Henderson }
38441ca74648SRichard Henderson 
38451ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a)
38461ca74648SRichard Henderson {
38471ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw);
38481ca74648SRichard Henderson }
38491ca74648SRichard Henderson 
38501ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a)
38511ca74648SRichard Henderson {
38521ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw);
38531ca74648SRichard Henderson }
38541ca74648SRichard Henderson 
38551ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a)
38561ca74648SRichard Henderson {
38571ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw);
38581ca74648SRichard Henderson }
38591ca74648SRichard Henderson 
38601ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a)
38611ca74648SRichard Henderson {
38621ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw);
38631ca74648SRichard Henderson }
38641ca74648SRichard Henderson 
38651ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a)
38661ca74648SRichard Henderson {
38671ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw);
38681ca74648SRichard Henderson }
38691ca74648SRichard Henderson 
38701ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a)
38711ca74648SRichard Henderson {
38721ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw);
38731ca74648SRichard Henderson }
38741ca74648SRichard Henderson 
38751ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a)
38761ca74648SRichard Henderson {
38771ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw);
38781ca74648SRichard Henderson }
38791ca74648SRichard Henderson 
38801ca74648SRichard Henderson /*
38811ca74648SRichard Henderson  * Float class 2
38821ca74648SRichard Henderson  */
38831ca74648SRichard Henderson 
38841ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a)
3885ebe9383cSRichard Henderson {
3886ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
3887ebe9383cSRichard Henderson 
3888ebe9383cSRichard Henderson     nullify_over(ctx);
3889ebe9383cSRichard Henderson 
38901ca74648SRichard Henderson     ta = load_frw0_i32(a->r1);
38911ca74648SRichard Henderson     tb = load_frw0_i32(a->r2);
389229dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
389329dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
3894ebe9383cSRichard Henderson 
3895ad75a51eSRichard Henderson     gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc);
3896ebe9383cSRichard Henderson 
38971ca74648SRichard Henderson     return nullify_end(ctx);
3898ebe9383cSRichard Henderson }
3899ebe9383cSRichard Henderson 
39001ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
3901ebe9383cSRichard Henderson {
3902ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
3903ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
3904ebe9383cSRichard Henderson 
3905ebe9383cSRichard Henderson     nullify_over(ctx);
3906ebe9383cSRichard Henderson 
39071ca74648SRichard Henderson     ta = load_frd0(a->r1);
39081ca74648SRichard Henderson     tb = load_frd0(a->r2);
390929dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
391029dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
3911ebe9383cSRichard Henderson 
3912ad75a51eSRichard Henderson     gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc);
3913ebe9383cSRichard Henderson 
391431234768SRichard Henderson     return nullify_end(ctx);
3915ebe9383cSRichard Henderson }
3916ebe9383cSRichard Henderson 
39171ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
3918ebe9383cSRichard Henderson {
39196fd0c7bcSRichard Henderson     TCGv_i64 t;
3920ebe9383cSRichard Henderson 
3921ebe9383cSRichard Henderson     nullify_over(ctx);
3922ebe9383cSRichard Henderson 
3923e12c6309SRichard Henderson     t = tcg_temp_new();
39246fd0c7bcSRichard Henderson     tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
3925ebe9383cSRichard Henderson 
39261ca74648SRichard Henderson     if (a->y == 1) {
3927ebe9383cSRichard Henderson         int mask;
3928ebe9383cSRichard Henderson         bool inv = false;
3929ebe9383cSRichard Henderson 
39301ca74648SRichard Henderson         switch (a->c) {
3931ebe9383cSRichard Henderson         case 0: /* simple */
39326fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, 0x4000000);
3933ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3934ebe9383cSRichard Henderson             goto done;
3935ebe9383cSRichard Henderson         case 2: /* rej */
3936ebe9383cSRichard Henderson             inv = true;
3937ebe9383cSRichard Henderson             /* fallthru */
3938ebe9383cSRichard Henderson         case 1: /* acc */
3939ebe9383cSRichard Henderson             mask = 0x43ff800;
3940ebe9383cSRichard Henderson             break;
3941ebe9383cSRichard Henderson         case 6: /* rej8 */
3942ebe9383cSRichard Henderson             inv = true;
3943ebe9383cSRichard Henderson             /* fallthru */
3944ebe9383cSRichard Henderson         case 5: /* acc8 */
3945ebe9383cSRichard Henderson             mask = 0x43f8000;
3946ebe9383cSRichard Henderson             break;
3947ebe9383cSRichard Henderson         case 9: /* acc6 */
3948ebe9383cSRichard Henderson             mask = 0x43e0000;
3949ebe9383cSRichard Henderson             break;
3950ebe9383cSRichard Henderson         case 13: /* acc4 */
3951ebe9383cSRichard Henderson             mask = 0x4380000;
3952ebe9383cSRichard Henderson             break;
3953ebe9383cSRichard Henderson         case 17: /* acc2 */
3954ebe9383cSRichard Henderson             mask = 0x4200000;
3955ebe9383cSRichard Henderson             break;
3956ebe9383cSRichard Henderson         default:
39571ca74648SRichard Henderson             gen_illegal(ctx);
39581ca74648SRichard Henderson             return true;
3959ebe9383cSRichard Henderson         }
3960ebe9383cSRichard Henderson         if (inv) {
39616fd0c7bcSRichard Henderson             TCGv_i64 c = tcg_constant_i64(mask);
39626fd0c7bcSRichard Henderson             tcg_gen_or_i64(t, t, c);
3963ebe9383cSRichard Henderson             ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
3964ebe9383cSRichard Henderson         } else {
39656fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, mask);
3966ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
3967ebe9383cSRichard Henderson         }
39681ca74648SRichard Henderson     } else {
39691ca74648SRichard Henderson         unsigned cbit = (a->y ^ 1) - 1;
39701ca74648SRichard Henderson 
39716fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, t, 21 - cbit, 1);
39721ca74648SRichard Henderson         ctx->null_cond = cond_make_0(TCG_COND_NE, t);
39731ca74648SRichard Henderson     }
39741ca74648SRichard Henderson 
3975ebe9383cSRichard Henderson  done:
397631234768SRichard Henderson     return nullify_end(ctx);
3977ebe9383cSRichard Henderson }
3978ebe9383cSRichard Henderson 
39791ca74648SRichard Henderson /*
39801ca74648SRichard Henderson  * Float class 2
39811ca74648SRichard Henderson  */
39821ca74648SRichard Henderson 
39831ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a)
3984ebe9383cSRichard Henderson {
39851ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s);
39861ca74648SRichard Henderson }
39871ca74648SRichard Henderson 
39881ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a)
39891ca74648SRichard Henderson {
39901ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d);
39911ca74648SRichard Henderson }
39921ca74648SRichard Henderson 
39931ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a)
39941ca74648SRichard Henderson {
39951ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s);
39961ca74648SRichard Henderson }
39971ca74648SRichard Henderson 
39981ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a)
39991ca74648SRichard Henderson {
40001ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d);
40011ca74648SRichard Henderson }
40021ca74648SRichard Henderson 
40031ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a)
40041ca74648SRichard Henderson {
40051ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s);
40061ca74648SRichard Henderson }
40071ca74648SRichard Henderson 
40081ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a)
40091ca74648SRichard Henderson {
40101ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d);
40111ca74648SRichard Henderson }
40121ca74648SRichard Henderson 
40131ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a)
40141ca74648SRichard Henderson {
40151ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s);
40161ca74648SRichard Henderson }
40171ca74648SRichard Henderson 
40181ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a)
40191ca74648SRichard Henderson {
40201ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d);
40211ca74648SRichard Henderson }
40221ca74648SRichard Henderson 
40231ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a)
40241ca74648SRichard Henderson {
40251ca74648SRichard Henderson     TCGv_i64 x, y;
4026ebe9383cSRichard Henderson 
4027ebe9383cSRichard Henderson     nullify_over(ctx);
4028ebe9383cSRichard Henderson 
40291ca74648SRichard Henderson     x = load_frw0_i64(a->r1);
40301ca74648SRichard Henderson     y = load_frw0_i64(a->r2);
40311ca74648SRichard Henderson     tcg_gen_mul_i64(x, x, y);
40321ca74648SRichard Henderson     save_frd(a->t, x);
4033ebe9383cSRichard Henderson 
403431234768SRichard Henderson     return nullify_end(ctx);
4035ebe9383cSRichard Henderson }
4036ebe9383cSRichard Henderson 
4037ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
4038ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
4039ebe9383cSRichard Henderson {
4040ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
4041ebe9383cSRichard Henderson }
4042ebe9383cSRichard Henderson 
4043b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4044ebe9383cSRichard Henderson {
4045b1e2af57SRichard Henderson     int tm = fmpyadd_s_reg(a->tm);
4046b1e2af57SRichard Henderson     int ra = fmpyadd_s_reg(a->ra);
4047b1e2af57SRichard Henderson     int ta = fmpyadd_s_reg(a->ta);
4048b1e2af57SRichard Henderson     int rm2 = fmpyadd_s_reg(a->rm2);
4049b1e2af57SRichard Henderson     int rm1 = fmpyadd_s_reg(a->rm1);
4050ebe9383cSRichard Henderson 
4051ebe9383cSRichard Henderson     nullify_over(ctx);
4052ebe9383cSRichard Henderson 
4053ebe9383cSRichard Henderson     do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4054ebe9383cSRichard Henderson     do_fop_weww(ctx, ta, ta, ra,
4055ebe9383cSRichard Henderson                 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
4056ebe9383cSRichard Henderson 
405731234768SRichard Henderson     return nullify_end(ctx);
4058ebe9383cSRichard Henderson }
4059ebe9383cSRichard Henderson 
4060b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4061b1e2af57SRichard Henderson {
4062b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, false);
4063b1e2af57SRichard Henderson }
4064b1e2af57SRichard Henderson 
4065b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4066b1e2af57SRichard Henderson {
4067b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, true);
4068b1e2af57SRichard Henderson }
4069b1e2af57SRichard Henderson 
4070b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4071b1e2af57SRichard Henderson {
4072b1e2af57SRichard Henderson     nullify_over(ctx);
4073b1e2af57SRichard Henderson 
4074b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4075b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4076b1e2af57SRichard Henderson                 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4077b1e2af57SRichard Henderson 
4078b1e2af57SRichard Henderson     return nullify_end(ctx);
4079b1e2af57SRichard Henderson }
4080b1e2af57SRichard Henderson 
4081b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4082b1e2af57SRichard Henderson {
4083b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, false);
4084b1e2af57SRichard Henderson }
4085b1e2af57SRichard Henderson 
4086b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4087b1e2af57SRichard Henderson {
4088b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, true);
4089b1e2af57SRichard Henderson }
4090b1e2af57SRichard Henderson 
4091c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a)
4092ebe9383cSRichard Henderson {
4093c3bad4f8SRichard Henderson     TCGv_i32 x, y, z;
4094ebe9383cSRichard Henderson 
4095ebe9383cSRichard Henderson     nullify_over(ctx);
4096c3bad4f8SRichard Henderson     x = load_frw0_i32(a->rm1);
4097c3bad4f8SRichard Henderson     y = load_frw0_i32(a->rm2);
4098c3bad4f8SRichard Henderson     z = load_frw0_i32(a->ra3);
4099ebe9383cSRichard Henderson 
4100c3bad4f8SRichard Henderson     if (a->neg) {
4101ad75a51eSRichard Henderson         gen_helper_fmpynfadd_s(x, tcg_env, x, y, z);
4102ebe9383cSRichard Henderson     } else {
4103ad75a51eSRichard Henderson         gen_helper_fmpyfadd_s(x, tcg_env, x, y, z);
4104ebe9383cSRichard Henderson     }
4105ebe9383cSRichard Henderson 
4106c3bad4f8SRichard Henderson     save_frw_i32(a->t, x);
410731234768SRichard Henderson     return nullify_end(ctx);
4108ebe9383cSRichard Henderson }
4109ebe9383cSRichard Henderson 
4110c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
4111ebe9383cSRichard Henderson {
4112c3bad4f8SRichard Henderson     TCGv_i64 x, y, z;
4113ebe9383cSRichard Henderson 
4114ebe9383cSRichard Henderson     nullify_over(ctx);
4115c3bad4f8SRichard Henderson     x = load_frd0(a->rm1);
4116c3bad4f8SRichard Henderson     y = load_frd0(a->rm2);
4117c3bad4f8SRichard Henderson     z = load_frd0(a->ra3);
4118ebe9383cSRichard Henderson 
4119c3bad4f8SRichard Henderson     if (a->neg) {
4120ad75a51eSRichard Henderson         gen_helper_fmpynfadd_d(x, tcg_env, x, y, z);
4121ebe9383cSRichard Henderson     } else {
4122ad75a51eSRichard Henderson         gen_helper_fmpyfadd_d(x, tcg_env, x, y, z);
4123ebe9383cSRichard Henderson     }
4124ebe9383cSRichard Henderson 
4125c3bad4f8SRichard Henderson     save_frd(a->t, x);
412631234768SRichard Henderson     return nullify_end(ctx);
4127ebe9383cSRichard Henderson }
4128ebe9383cSRichard Henderson 
412915da177bSSven Schnelle static bool trans_diag(DisasContext *ctx, arg_diag *a)
413015da177bSSven Schnelle {
4131cf6b28d4SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4132cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY
4133cf6b28d4SHelge Deller     if (a->i == 0x100) {
4134cf6b28d4SHelge Deller         /* emulate PDC BTLB, called by SeaBIOS-hppa */
4135ad75a51eSRichard Henderson         nullify_over(ctx);
4136ad75a51eSRichard Henderson         gen_helper_diag_btlb(tcg_env);
4137cf6b28d4SHelge Deller         return nullify_end(ctx);
413815da177bSSven Schnelle     }
4139ad75a51eSRichard Henderson #endif
4140ad75a51eSRichard Henderson     qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i);
4141ad75a51eSRichard Henderson     return true;
4142ad75a51eSRichard Henderson }
414315da177bSSven Schnelle 
4144b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
414561766fe9SRichard Henderson {
414651b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4147f764718dSRichard Henderson     int bound;
414861766fe9SRichard Henderson 
414951b061fbSRichard Henderson     ctx->cs = cs;
4150494737b7SRichard Henderson     ctx->tb_flags = ctx->base.tb->flags;
4151bd6243a3SRichard Henderson     ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
41523d68ee7bSRichard Henderson 
41533d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY
4154c01e5dfbSHelge Deller     ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX);
41553d68ee7bSRichard Henderson     ctx->mmu_idx = MMU_USER_IDX;
4156c01e5dfbSHelge Deller     ctx->iaoq_f = ctx->base.pc_first | ctx->privilege;
4157c01e5dfbSHelge Deller     ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege;
4158217d1a5eSRichard Henderson     ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
4159c301f34eSRichard Henderson #else
4160494737b7SRichard Henderson     ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
4161bb67ec32SRichard Henderson     ctx->mmu_idx = (ctx->tb_flags & PSW_D
4162bb67ec32SRichard Henderson                     ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
4163bb67ec32SRichard Henderson                     : MMU_PHYS_IDX);
41643d68ee7bSRichard Henderson 
4165c301f34eSRichard Henderson     /* Recover the IAOQ values from the GVA + PRIV.  */
4166c301f34eSRichard Henderson     uint64_t cs_base = ctx->base.tb->cs_base;
4167c301f34eSRichard Henderson     uint64_t iasq_f = cs_base & ~0xffffffffull;
4168c301f34eSRichard Henderson     int32_t diff = cs_base;
4169c301f34eSRichard Henderson 
4170c301f34eSRichard Henderson     ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
4171c301f34eSRichard Henderson     ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1);
4172c301f34eSRichard Henderson #endif
417351b061fbSRichard Henderson     ctx->iaoq_n = -1;
4174f764718dSRichard Henderson     ctx->iaoq_n_var = NULL;
417561766fe9SRichard Henderson 
41763d68ee7bSRichard Henderson     /* Bound the number of instructions by those left on the page.  */
41773d68ee7bSRichard Henderson     bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
4178b542683dSEmilio G. Cota     ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
417961766fe9SRichard Henderson }
418061766fe9SRichard Henderson 
418151b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
418251b061fbSRichard Henderson {
418351b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
418461766fe9SRichard Henderson 
41853d68ee7bSRichard Henderson     /* Seed the nullification status from PSW[N], as saved in TB->FLAGS.  */
418651b061fbSRichard Henderson     ctx->null_cond = cond_make_f();
418751b061fbSRichard Henderson     ctx->psw_n_nonzero = false;
4188494737b7SRichard Henderson     if (ctx->tb_flags & PSW_N) {
418951b061fbSRichard Henderson         ctx->null_cond.c = TCG_COND_ALWAYS;
419051b061fbSRichard Henderson         ctx->psw_n_nonzero = true;
4191129e9cc3SRichard Henderson     }
419251b061fbSRichard Henderson     ctx->null_lab = NULL;
419361766fe9SRichard Henderson }
419461766fe9SRichard Henderson 
419551b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
419651b061fbSRichard Henderson {
419751b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
419851b061fbSRichard Henderson 
419951b061fbSRichard Henderson     tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b);
420051b061fbSRichard Henderson }
420151b061fbSRichard Henderson 
420251b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
420351b061fbSRichard Henderson {
420451b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4205b77af26eSRichard Henderson     CPUHPPAState *env = cpu_env(cs);
420651b061fbSRichard Henderson     DisasJumpType ret;
420751b061fbSRichard Henderson 
420851b061fbSRichard Henderson     /* Execute one insn.  */
4209ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4210c301f34eSRichard Henderson     if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
421131234768SRichard Henderson         do_page_zero(ctx);
421231234768SRichard Henderson         ret = ctx->base.is_jmp;
4213869051eaSRichard Henderson         assert(ret != DISAS_NEXT);
4214ba1d0b44SRichard Henderson     } else
4215ba1d0b44SRichard Henderson #endif
4216ba1d0b44SRichard Henderson     {
421761766fe9SRichard Henderson         /* Always fetch the insn, even if nullified, so that we check
421861766fe9SRichard Henderson            the page permissions for execute.  */
42194e116893SIlya Leoshkevich         uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next);
422061766fe9SRichard Henderson 
422161766fe9SRichard Henderson         /* Set up the IA queue for the next insn.
422261766fe9SRichard Henderson            This will be overwritten by a branch.  */
422351b061fbSRichard Henderson         if (ctx->iaoq_b == -1) {
422451b061fbSRichard Henderson             ctx->iaoq_n = -1;
4225e12c6309SRichard Henderson             ctx->iaoq_n_var = tcg_temp_new();
42266fd0c7bcSRichard Henderson             tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
422761766fe9SRichard Henderson         } else {
422851b061fbSRichard Henderson             ctx->iaoq_n = ctx->iaoq_b + 4;
4229f764718dSRichard Henderson             ctx->iaoq_n_var = NULL;
423061766fe9SRichard Henderson         }
423161766fe9SRichard Henderson 
423251b061fbSRichard Henderson         if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
423351b061fbSRichard Henderson             ctx->null_cond.c = TCG_COND_NEVER;
4234869051eaSRichard Henderson             ret = DISAS_NEXT;
4235129e9cc3SRichard Henderson         } else {
42361a19da0dSRichard Henderson             ctx->insn = insn;
423731274b46SRichard Henderson             if (!decode(ctx, insn)) {
423831274b46SRichard Henderson                 gen_illegal(ctx);
423931274b46SRichard Henderson             }
424031234768SRichard Henderson             ret = ctx->base.is_jmp;
424151b061fbSRichard Henderson             assert(ctx->null_lab == NULL);
4242129e9cc3SRichard Henderson         }
424361766fe9SRichard Henderson     }
424461766fe9SRichard Henderson 
42453d68ee7bSRichard Henderson     /* Advance the insn queue.  Note that this check also detects
42463d68ee7bSRichard Henderson        a priority change within the instruction queue.  */
424751b061fbSRichard Henderson     if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
4248c301f34eSRichard Henderson         if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1
4249c301f34eSRichard Henderson             && use_goto_tb(ctx, ctx->iaoq_b)
4250c301f34eSRichard Henderson             && (ctx->null_cond.c == TCG_COND_NEVER
4251c301f34eSRichard Henderson                 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
425251b061fbSRichard Henderson             nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
425351b061fbSRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
425431234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_NORETURN;
4255129e9cc3SRichard Henderson         } else {
425631234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE;
425761766fe9SRichard Henderson         }
4258129e9cc3SRichard Henderson     }
425951b061fbSRichard Henderson     ctx->iaoq_f = ctx->iaoq_b;
426051b061fbSRichard Henderson     ctx->iaoq_b = ctx->iaoq_n;
4261c301f34eSRichard Henderson     ctx->base.pc_next += 4;
426261766fe9SRichard Henderson 
4263c5d0aec2SRichard Henderson     switch (ret) {
4264c5d0aec2SRichard Henderson     case DISAS_NORETURN:
4265c5d0aec2SRichard Henderson     case DISAS_IAQ_N_UPDATED:
4266c5d0aec2SRichard Henderson         break;
4267c5d0aec2SRichard Henderson 
4268c5d0aec2SRichard Henderson     case DISAS_NEXT:
4269c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE:
4270c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
427151b061fbSRichard Henderson         if (ctx->iaoq_f == -1) {
4272a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b);
4273741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
4274c301f34eSRichard Henderson #ifndef CONFIG_USER_ONLY
4275c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
4276c301f34eSRichard Henderson #endif
427751b061fbSRichard Henderson             nullify_save(ctx);
4278c5d0aec2SRichard Henderson             ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT
4279c5d0aec2SRichard Henderson                                 ? DISAS_EXIT
4280c5d0aec2SRichard Henderson                                 : DISAS_IAQ_N_UPDATED);
428151b061fbSRichard Henderson         } else if (ctx->iaoq_b == -1) {
4282a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var);
428361766fe9SRichard Henderson         }
4284c5d0aec2SRichard Henderson         break;
4285c5d0aec2SRichard Henderson 
4286c5d0aec2SRichard Henderson     default:
4287c5d0aec2SRichard Henderson         g_assert_not_reached();
4288c5d0aec2SRichard Henderson     }
428961766fe9SRichard Henderson }
429061766fe9SRichard Henderson 
429151b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
429251b061fbSRichard Henderson {
429351b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4294e1b5a5edSRichard Henderson     DisasJumpType is_jmp = ctx->base.is_jmp;
429551b061fbSRichard Henderson 
4296e1b5a5edSRichard Henderson     switch (is_jmp) {
4297869051eaSRichard Henderson     case DISAS_NORETURN:
429861766fe9SRichard Henderson         break;
429951b061fbSRichard Henderson     case DISAS_TOO_MANY:
4300869051eaSRichard Henderson     case DISAS_IAQ_N_STALE:
4301e1b5a5edSRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
4302741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
4303741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
430451b061fbSRichard Henderson         nullify_save(ctx);
430561766fe9SRichard Henderson         /* FALLTHRU */
4306869051eaSRichard Henderson     case DISAS_IAQ_N_UPDATED:
43078532a14eSRichard Henderson         if (is_jmp != DISAS_IAQ_N_STALE_EXIT) {
43087f11636dSEmilio G. Cota             tcg_gen_lookup_and_goto_ptr();
43098532a14eSRichard Henderson             break;
431061766fe9SRichard Henderson         }
4311c5d0aec2SRichard Henderson         /* FALLTHRU */
4312c5d0aec2SRichard Henderson     case DISAS_EXIT:
4313c5d0aec2SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
431461766fe9SRichard Henderson         break;
431561766fe9SRichard Henderson     default:
431651b061fbSRichard Henderson         g_assert_not_reached();
431761766fe9SRichard Henderson     }
431851b061fbSRichard Henderson }
431961766fe9SRichard Henderson 
43208eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase,
43218eb806a7SRichard Henderson                               CPUState *cs, FILE *logfile)
432251b061fbSRichard Henderson {
4323c301f34eSRichard Henderson     target_ulong pc = dcbase->pc_first;
432461766fe9SRichard Henderson 
4325ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4326ba1d0b44SRichard Henderson     switch (pc) {
43277ad439dfSRichard Henderson     case 0x00:
43288eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000000:  (null)\n");
4329ba1d0b44SRichard Henderson         return;
43307ad439dfSRichard Henderson     case 0xb0:
43318eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000b0:  light-weight-syscall\n");
4332ba1d0b44SRichard Henderson         return;
43337ad439dfSRichard Henderson     case 0xe0:
43348eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000e0:  set-thread-pointer-syscall\n");
4335ba1d0b44SRichard Henderson         return;
43367ad439dfSRichard Henderson     case 0x100:
43378eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000100:  syscall\n");
4338ba1d0b44SRichard Henderson         return;
43397ad439dfSRichard Henderson     }
4340ba1d0b44SRichard Henderson #endif
4341ba1d0b44SRichard Henderson 
43428eb806a7SRichard Henderson     fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
43438eb806a7SRichard Henderson     target_disas(logfile, cs, pc, dcbase->tb->size);
434461766fe9SRichard Henderson }
434551b061fbSRichard Henderson 
434651b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = {
434751b061fbSRichard Henderson     .init_disas_context = hppa_tr_init_disas_context,
434851b061fbSRichard Henderson     .tb_start           = hppa_tr_tb_start,
434951b061fbSRichard Henderson     .insn_start         = hppa_tr_insn_start,
435051b061fbSRichard Henderson     .translate_insn     = hppa_tr_translate_insn,
435151b061fbSRichard Henderson     .tb_stop            = hppa_tr_tb_stop,
435251b061fbSRichard Henderson     .disas_log          = hppa_tr_disas_log,
435351b061fbSRichard Henderson };
435451b061fbSRichard Henderson 
4355597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
4356306c8721SRichard Henderson                            target_ulong pc, void *host_pc)
435751b061fbSRichard Henderson {
435851b061fbSRichard Henderson     DisasContext ctx;
4359306c8721SRichard Henderson     translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
436061766fe9SRichard Henderson }
4361