xref: /openbmc/qemu/target/hppa/translate.c (revision 6fd0c7bc91d81244c8a0f418ac8d19bca0c20577)
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 
36eaa3783bSRichard Henderson /* Since we have a distinction between register size and address size,
37eaa3783bSRichard Henderson    we need to redefine all of these.  */
38eaa3783bSRichard Henderson 
39eaa3783bSRichard Henderson #define tcg_gen_extu_reg_tl  tcg_gen_mov_i64
40eaa3783bSRichard Henderson #define tcg_gen_trunc_i64_reg tcg_gen_mov_i64
41eaa3783bSRichard Henderson #define tcg_gen_extu_reg_i64 tcg_gen_mov_i64
42eaa3783bSRichard Henderson #define tcg_gen_ext_reg_i64  tcg_gen_mov_i64
43*6fd0c7bcSRichard Henderson 
44eaa3783bSRichard Henderson 
4561766fe9SRichard Henderson typedef struct DisasCond {
4661766fe9SRichard Henderson     TCGCond c;
47*6fd0c7bcSRichard Henderson     TCGv_i64 a0, a1;
4861766fe9SRichard Henderson } DisasCond;
4961766fe9SRichard Henderson 
5061766fe9SRichard Henderson typedef struct DisasContext {
51d01a3625SRichard Henderson     DisasContextBase base;
5261766fe9SRichard Henderson     CPUState *cs;
5361766fe9SRichard Henderson 
54c53e401eSRichard Henderson     uint64_t iaoq_f;
55c53e401eSRichard Henderson     uint64_t iaoq_b;
56c53e401eSRichard Henderson     uint64_t iaoq_n;
57*6fd0c7bcSRichard Henderson     TCGv_i64 iaoq_n_var;
5861766fe9SRichard Henderson 
5961766fe9SRichard Henderson     DisasCond null_cond;
6061766fe9SRichard Henderson     TCGLabel *null_lab;
6161766fe9SRichard Henderson 
621a19da0dSRichard Henderson     uint32_t insn;
63494737b7SRichard Henderson     uint32_t tb_flags;
643d68ee7bSRichard Henderson     int mmu_idx;
653d68ee7bSRichard Henderson     int privilege;
6661766fe9SRichard Henderson     bool psw_n_nonzero;
67bd6243a3SRichard Henderson     bool is_pa20;
68217d1a5eSRichard Henderson 
69217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
70217d1a5eSRichard Henderson     MemOp unalign;
71217d1a5eSRichard Henderson #endif
7261766fe9SRichard Henderson } DisasContext;
7361766fe9SRichard Henderson 
74217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
75217d1a5eSRichard Henderson #define UNALIGN(C)  (C)->unalign
76217d1a5eSRichard Henderson #else
772d4afb03SRichard Henderson #define UNALIGN(C)  MO_ALIGN
78217d1a5eSRichard Henderson #endif
79217d1a5eSRichard Henderson 
80e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently.  */
81451e4ffdSRichard Henderson static int expand_sm_imm(DisasContext *ctx, int val)
82e36f27efSRichard Henderson {
83e36f27efSRichard Henderson     if (val & PSW_SM_E) {
84e36f27efSRichard Henderson         val = (val & ~PSW_SM_E) | PSW_E;
85e36f27efSRichard Henderson     }
86e36f27efSRichard Henderson     if (val & PSW_SM_W) {
87e36f27efSRichard Henderson         val = (val & ~PSW_SM_W) | PSW_W;
88e36f27efSRichard Henderson     }
89e36f27efSRichard Henderson     return val;
90e36f27efSRichard Henderson }
91e36f27efSRichard Henderson 
92deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base.  */
93451e4ffdSRichard Henderson static int expand_sr3x(DisasContext *ctx, int val)
94deee69a1SRichard Henderson {
95deee69a1SRichard Henderson     return ~val;
96deee69a1SRichard Henderson }
97deee69a1SRichard Henderson 
981cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value
991cd012a5SRichard Henderson    we use for the final M.  */
100451e4ffdSRichard Henderson static int ma_to_m(DisasContext *ctx, int val)
1011cd012a5SRichard Henderson {
1021cd012a5SRichard Henderson     return val & 2 ? (val & 1 ? -1 : 1) : 0;
1031cd012a5SRichard Henderson }
1041cd012a5SRichard Henderson 
105740038d7SRichard Henderson /* Convert the sign of the displacement to a pre or post-modify.  */
106451e4ffdSRichard Henderson static int pos_to_m(DisasContext *ctx, int val)
107740038d7SRichard Henderson {
108740038d7SRichard Henderson     return val ? 1 : -1;
109740038d7SRichard Henderson }
110740038d7SRichard Henderson 
111451e4ffdSRichard Henderson static int neg_to_m(DisasContext *ctx, int val)
112740038d7SRichard Henderson {
113740038d7SRichard Henderson     return val ? -1 : 1;
114740038d7SRichard Henderson }
115740038d7SRichard Henderson 
116740038d7SRichard Henderson /* Used for branch targets and fp memory ops.  */
117451e4ffdSRichard Henderson static int expand_shl2(DisasContext *ctx, int val)
11801afb7beSRichard Henderson {
11901afb7beSRichard Henderson     return val << 2;
12001afb7beSRichard Henderson }
12101afb7beSRichard Henderson 
122740038d7SRichard Henderson /* Used for fp memory ops.  */
123451e4ffdSRichard Henderson static int expand_shl3(DisasContext *ctx, int val)
124740038d7SRichard Henderson {
125740038d7SRichard Henderson     return val << 3;
126740038d7SRichard Henderson }
127740038d7SRichard Henderson 
1280588e061SRichard Henderson /* Used for assemble_21.  */
129451e4ffdSRichard Henderson static int expand_shl11(DisasContext *ctx, int val)
1300588e061SRichard Henderson {
1310588e061SRichard Henderson     return val << 11;
1320588e061SRichard Henderson }
1330588e061SRichard Henderson 
13472ae4f2bSRichard Henderson static int assemble_6(DisasContext *ctx, int val)
13572ae4f2bSRichard Henderson {
13672ae4f2bSRichard Henderson     /*
13772ae4f2bSRichard Henderson      * Officially, 32 * x + 32 - y.
13872ae4f2bSRichard Henderson      * Here, x is already in bit 5, and y is [4:0].
13972ae4f2bSRichard Henderson      * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1,
14072ae4f2bSRichard Henderson      * with the overflow from bit 4 summing with x.
14172ae4f2bSRichard Henderson      */
14272ae4f2bSRichard Henderson     return (val ^ 31) + 1;
14372ae4f2bSRichard Henderson }
14472ae4f2bSRichard Henderson 
145c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */
146c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val)
147c65c3ee1SRichard Henderson {
148c65c3ee1SRichard Henderson     return val ? val : 4; /* 0 == "*<<" */
149c65c3ee1SRichard Henderson }
150c65c3ee1SRichard Henderson 
15101afb7beSRichard Henderson 
15240f9f908SRichard Henderson /* Include the auto-generated decoder.  */
153abff1abfSPaolo Bonzini #include "decode-insns.c.inc"
15440f9f908SRichard Henderson 
15561766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated
15661766fe9SRichard Henderson    the iaq (for whatever reason), so don't do it again on exit.  */
157869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED  DISAS_TARGET_0
15861766fe9SRichard Henderson 
15961766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor
16061766fe9SRichard Henderson    updated the iaq for the next instruction to be executed.  */
161869051eaSRichard Henderson #define DISAS_IAQ_N_STALE    DISAS_TARGET_1
16261766fe9SRichard Henderson 
163e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately
164e1b5a5edSRichard Henderson    to recognize unmasked interrupts.  */
165e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT      DISAS_TARGET_2
166c5d0aec2SRichard Henderson #define DISAS_EXIT                  DISAS_TARGET_3
167e1b5a5edSRichard Henderson 
16861766fe9SRichard Henderson /* global register indexes */
169*6fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32];
17033423472SRichard Henderson static TCGv_i64 cpu_sr[4];
171494737b7SRichard Henderson static TCGv_i64 cpu_srH;
172*6fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f;
173*6fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b;
174c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f;
175c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b;
176*6fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar;
177*6fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n;
178*6fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v;
179*6fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb;
180*6fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb;
18161766fe9SRichard Henderson 
18261766fe9SRichard Henderson void hppa_translate_init(void)
18361766fe9SRichard Henderson {
18461766fe9SRichard Henderson #define DEF_VAR(V)  { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
18561766fe9SRichard Henderson 
186*6fd0c7bcSRichard Henderson     typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar;
18761766fe9SRichard Henderson     static const GlobalVar vars[] = {
18835136a77SRichard Henderson         { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) },
18961766fe9SRichard Henderson         DEF_VAR(psw_n),
19061766fe9SRichard Henderson         DEF_VAR(psw_v),
19161766fe9SRichard Henderson         DEF_VAR(psw_cb),
19261766fe9SRichard Henderson         DEF_VAR(psw_cb_msb),
19361766fe9SRichard Henderson         DEF_VAR(iaoq_f),
19461766fe9SRichard Henderson         DEF_VAR(iaoq_b),
19561766fe9SRichard Henderson     };
19661766fe9SRichard Henderson 
19761766fe9SRichard Henderson #undef DEF_VAR
19861766fe9SRichard Henderson 
19961766fe9SRichard Henderson     /* Use the symbolic register names that match the disassembler.  */
20061766fe9SRichard Henderson     static const char gr_names[32][4] = {
20161766fe9SRichard Henderson         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
20261766fe9SRichard Henderson         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
20361766fe9SRichard Henderson         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
20461766fe9SRichard Henderson         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
20561766fe9SRichard Henderson     };
20633423472SRichard Henderson     /* SR[4-7] are not global registers so that we can index them.  */
207494737b7SRichard Henderson     static const char sr_names[5][4] = {
208494737b7SRichard Henderson         "sr0", "sr1", "sr2", "sr3", "srH"
20933423472SRichard Henderson     };
21061766fe9SRichard Henderson 
21161766fe9SRichard Henderson     int i;
21261766fe9SRichard Henderson 
213f764718dSRichard Henderson     cpu_gr[0] = NULL;
21461766fe9SRichard Henderson     for (i = 1; i < 32; i++) {
215ad75a51eSRichard Henderson         cpu_gr[i] = tcg_global_mem_new(tcg_env,
21661766fe9SRichard Henderson                                        offsetof(CPUHPPAState, gr[i]),
21761766fe9SRichard Henderson                                        gr_names[i]);
21861766fe9SRichard Henderson     }
21933423472SRichard Henderson     for (i = 0; i < 4; i++) {
220ad75a51eSRichard Henderson         cpu_sr[i] = tcg_global_mem_new_i64(tcg_env,
22133423472SRichard Henderson                                            offsetof(CPUHPPAState, sr[i]),
22233423472SRichard Henderson                                            sr_names[i]);
22333423472SRichard Henderson     }
224ad75a51eSRichard Henderson     cpu_srH = tcg_global_mem_new_i64(tcg_env,
225494737b7SRichard Henderson                                      offsetof(CPUHPPAState, sr[4]),
226494737b7SRichard Henderson                                      sr_names[4]);
22761766fe9SRichard Henderson 
22861766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(vars); ++i) {
22961766fe9SRichard Henderson         const GlobalVar *v = &vars[i];
230ad75a51eSRichard Henderson         *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name);
23161766fe9SRichard Henderson     }
232c301f34eSRichard Henderson 
233ad75a51eSRichard Henderson     cpu_iasq_f = tcg_global_mem_new_i64(tcg_env,
234c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_f),
235c301f34eSRichard Henderson                                         "iasq_f");
236ad75a51eSRichard Henderson     cpu_iasq_b = tcg_global_mem_new_i64(tcg_env,
237c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_b),
238c301f34eSRichard Henderson                                         "iasq_b");
23961766fe9SRichard Henderson }
24061766fe9SRichard Henderson 
241129e9cc3SRichard Henderson static DisasCond cond_make_f(void)
242129e9cc3SRichard Henderson {
243f764718dSRichard Henderson     return (DisasCond){
244f764718dSRichard Henderson         .c = TCG_COND_NEVER,
245f764718dSRichard Henderson         .a0 = NULL,
246f764718dSRichard Henderson         .a1 = NULL,
247f764718dSRichard Henderson     };
248129e9cc3SRichard Henderson }
249129e9cc3SRichard Henderson 
250df0232feSRichard Henderson static DisasCond cond_make_t(void)
251df0232feSRichard Henderson {
252df0232feSRichard Henderson     return (DisasCond){
253df0232feSRichard Henderson         .c = TCG_COND_ALWAYS,
254df0232feSRichard Henderson         .a0 = NULL,
255df0232feSRichard Henderson         .a1 = NULL,
256df0232feSRichard Henderson     };
257df0232feSRichard Henderson }
258df0232feSRichard Henderson 
259129e9cc3SRichard Henderson static DisasCond cond_make_n(void)
260129e9cc3SRichard Henderson {
261f764718dSRichard Henderson     return (DisasCond){
262f764718dSRichard Henderson         .c = TCG_COND_NE,
263f764718dSRichard Henderson         .a0 = cpu_psw_n,
264*6fd0c7bcSRichard Henderson         .a1 = tcg_constant_i64(0)
265f764718dSRichard Henderson     };
266129e9cc3SRichard Henderson }
267129e9cc3SRichard Henderson 
268*6fd0c7bcSRichard Henderson static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
269b47a4a02SSven Schnelle {
270b47a4a02SSven Schnelle     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
2714fe9533aSRichard Henderson     return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 };
2724fe9533aSRichard Henderson }
2734fe9533aSRichard Henderson 
274*6fd0c7bcSRichard Henderson static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0)
2754fe9533aSRichard Henderson {
276*6fd0c7bcSRichard Henderson     return cond_make_tmp(c, a0, tcg_constant_i64(0));
277b47a4a02SSven Schnelle }
278b47a4a02SSven Schnelle 
279*6fd0c7bcSRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0)
280129e9cc3SRichard Henderson {
281*6fd0c7bcSRichard Henderson     TCGv_i64 tmp = tcg_temp_new();
282*6fd0c7bcSRichard Henderson     tcg_gen_mov_i64(tmp, a0);
283b47a4a02SSven Schnelle     return cond_make_0_tmp(c, tmp);
284129e9cc3SRichard Henderson }
285129e9cc3SRichard Henderson 
286*6fd0c7bcSRichard Henderson static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
287129e9cc3SRichard Henderson {
288*6fd0c7bcSRichard Henderson     TCGv_i64 t0 = tcg_temp_new();
289*6fd0c7bcSRichard Henderson     TCGv_i64 t1 = tcg_temp_new();
290129e9cc3SRichard Henderson 
291*6fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t0, a0);
292*6fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t1, a1);
2934fe9533aSRichard Henderson     return cond_make_tmp(c, t0, t1);
294129e9cc3SRichard Henderson }
295129e9cc3SRichard Henderson 
296129e9cc3SRichard Henderson static void cond_free(DisasCond *cond)
297129e9cc3SRichard Henderson {
298129e9cc3SRichard Henderson     switch (cond->c) {
299129e9cc3SRichard Henderson     default:
300f764718dSRichard Henderson         cond->a0 = NULL;
301f764718dSRichard Henderson         cond->a1 = NULL;
302129e9cc3SRichard Henderson         /* fallthru */
303129e9cc3SRichard Henderson     case TCG_COND_ALWAYS:
304129e9cc3SRichard Henderson         cond->c = TCG_COND_NEVER;
305129e9cc3SRichard Henderson         break;
306129e9cc3SRichard Henderson     case TCG_COND_NEVER:
307129e9cc3SRichard Henderson         break;
308129e9cc3SRichard Henderson     }
309129e9cc3SRichard Henderson }
310129e9cc3SRichard Henderson 
311*6fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg)
31261766fe9SRichard Henderson {
31361766fe9SRichard Henderson     if (reg == 0) {
314*6fd0c7bcSRichard Henderson         TCGv_i64 t = tcg_temp_new();
315*6fd0c7bcSRichard Henderson         tcg_gen_movi_i64(t, 0);
31661766fe9SRichard Henderson         return t;
31761766fe9SRichard Henderson     } else {
31861766fe9SRichard Henderson         return cpu_gr[reg];
31961766fe9SRichard Henderson     }
32061766fe9SRichard Henderson }
32161766fe9SRichard Henderson 
322*6fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg)
32361766fe9SRichard Henderson {
324129e9cc3SRichard Henderson     if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
325e12c6309SRichard Henderson         return tcg_temp_new();
32661766fe9SRichard Henderson     } else {
32761766fe9SRichard Henderson         return cpu_gr[reg];
32861766fe9SRichard Henderson     }
32961766fe9SRichard Henderson }
33061766fe9SRichard Henderson 
331*6fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t)
332129e9cc3SRichard Henderson {
333129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
334*6fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0,
335129e9cc3SRichard Henderson                             ctx->null_cond.a1, dest, t);
336129e9cc3SRichard Henderson     } else {
337*6fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, t);
338129e9cc3SRichard Henderson     }
339129e9cc3SRichard Henderson }
340129e9cc3SRichard Henderson 
341*6fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t)
342129e9cc3SRichard Henderson {
343129e9cc3SRichard Henderson     if (reg != 0) {
344129e9cc3SRichard Henderson         save_or_nullify(ctx, cpu_gr[reg], t);
345129e9cc3SRichard Henderson     }
346129e9cc3SRichard Henderson }
347129e9cc3SRichard Henderson 
348e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
34996d6407fSRichard Henderson # define HI_OFS  0
35096d6407fSRichard Henderson # define LO_OFS  4
35196d6407fSRichard Henderson #else
35296d6407fSRichard Henderson # define HI_OFS  4
35396d6407fSRichard Henderson # define LO_OFS  0
35496d6407fSRichard Henderson #endif
35596d6407fSRichard Henderson 
35696d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt)
35796d6407fSRichard Henderson {
35896d6407fSRichard Henderson     TCGv_i32 ret = tcg_temp_new_i32();
359ad75a51eSRichard Henderson     tcg_gen_ld_i32(ret, tcg_env,
36096d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
36196d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
36296d6407fSRichard Henderson     return ret;
36396d6407fSRichard Henderson }
36496d6407fSRichard Henderson 
365ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt)
366ebe9383cSRichard Henderson {
367ebe9383cSRichard Henderson     if (rt == 0) {
3680992a930SRichard Henderson         TCGv_i32 ret = tcg_temp_new_i32();
3690992a930SRichard Henderson         tcg_gen_movi_i32(ret, 0);
3700992a930SRichard Henderson         return ret;
371ebe9383cSRichard Henderson     } else {
372ebe9383cSRichard Henderson         return load_frw_i32(rt);
373ebe9383cSRichard Henderson     }
374ebe9383cSRichard Henderson }
375ebe9383cSRichard Henderson 
376ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt)
377ebe9383cSRichard Henderson {
378ebe9383cSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
3790992a930SRichard Henderson     if (rt == 0) {
3800992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
3810992a930SRichard Henderson     } else {
382ad75a51eSRichard Henderson         tcg_gen_ld32u_i64(ret, tcg_env,
383ebe9383cSRichard Henderson                           offsetof(CPUHPPAState, fr[rt & 31])
384ebe9383cSRichard Henderson                           + (rt & 32 ? LO_OFS : HI_OFS));
385ebe9383cSRichard Henderson     }
3860992a930SRichard Henderson     return ret;
387ebe9383cSRichard Henderson }
388ebe9383cSRichard Henderson 
38996d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val)
39096d6407fSRichard Henderson {
391ad75a51eSRichard Henderson     tcg_gen_st_i32(val, tcg_env,
39296d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
39396d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
39496d6407fSRichard Henderson }
39596d6407fSRichard Henderson 
39696d6407fSRichard Henderson #undef HI_OFS
39796d6407fSRichard Henderson #undef LO_OFS
39896d6407fSRichard Henderson 
39996d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt)
40096d6407fSRichard Henderson {
40196d6407fSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
402ad75a51eSRichard Henderson     tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt]));
40396d6407fSRichard Henderson     return ret;
40496d6407fSRichard Henderson }
40596d6407fSRichard Henderson 
406ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt)
407ebe9383cSRichard Henderson {
408ebe9383cSRichard Henderson     if (rt == 0) {
4090992a930SRichard Henderson         TCGv_i64 ret = tcg_temp_new_i64();
4100992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
4110992a930SRichard Henderson         return ret;
412ebe9383cSRichard Henderson     } else {
413ebe9383cSRichard Henderson         return load_frd(rt);
414ebe9383cSRichard Henderson     }
415ebe9383cSRichard Henderson }
416ebe9383cSRichard Henderson 
41796d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val)
41896d6407fSRichard Henderson {
419ad75a51eSRichard Henderson     tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt]));
42096d6407fSRichard Henderson }
42196d6407fSRichard Henderson 
42233423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg)
42333423472SRichard Henderson {
42433423472SRichard Henderson #ifdef CONFIG_USER_ONLY
42533423472SRichard Henderson     tcg_gen_movi_i64(dest, 0);
42633423472SRichard Henderson #else
42733423472SRichard Henderson     if (reg < 4) {
42833423472SRichard Henderson         tcg_gen_mov_i64(dest, cpu_sr[reg]);
429494737b7SRichard Henderson     } else if (ctx->tb_flags & TB_FLAG_SR_SAME) {
430494737b7SRichard Henderson         tcg_gen_mov_i64(dest, cpu_srH);
43133423472SRichard Henderson     } else {
432ad75a51eSRichard Henderson         tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg]));
43333423472SRichard Henderson     }
43433423472SRichard Henderson #endif
43533423472SRichard Henderson }
43633423472SRichard Henderson 
437129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified.
438129e9cc3SRichard Henderson    Use this when the insn is too complex for a conditional move.  */
439129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx)
440129e9cc3SRichard Henderson {
441129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
442129e9cc3SRichard Henderson         /* The always condition should have been handled in the main loop.  */
443129e9cc3SRichard Henderson         assert(ctx->null_cond.c != TCG_COND_ALWAYS);
444129e9cc3SRichard Henderson 
445129e9cc3SRichard Henderson         ctx->null_lab = gen_new_label();
446129e9cc3SRichard Henderson 
447129e9cc3SRichard Henderson         /* If we're using PSW[N], copy it to a temp because... */
4486e94937aSRichard Henderson         if (ctx->null_cond.a0 == cpu_psw_n) {
449129e9cc3SRichard Henderson             ctx->null_cond.a0 = tcg_temp_new();
450*6fd0c7bcSRichard Henderson             tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n);
451129e9cc3SRichard Henderson         }
452129e9cc3SRichard Henderson         /* ... we clear it before branching over the implementation,
453129e9cc3SRichard Henderson            so that (1) it's clear after nullifying this insn and
454129e9cc3SRichard Henderson            (2) if this insn nullifies the next, PSW[N] is valid.  */
455129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
456129e9cc3SRichard Henderson             ctx->psw_n_nonzero = false;
457*6fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
458129e9cc3SRichard Henderson         }
459129e9cc3SRichard Henderson 
460*6fd0c7bcSRichard Henderson         tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0,
461129e9cc3SRichard Henderson                            ctx->null_cond.a1, ctx->null_lab);
462129e9cc3SRichard Henderson         cond_free(&ctx->null_cond);
463129e9cc3SRichard Henderson     }
464129e9cc3SRichard Henderson }
465129e9cc3SRichard Henderson 
466129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N].  */
467129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx)
468129e9cc3SRichard Henderson {
469129e9cc3SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
470129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
471*6fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
472129e9cc3SRichard Henderson         }
473129e9cc3SRichard Henderson         return;
474129e9cc3SRichard Henderson     }
4756e94937aSRichard Henderson     if (ctx->null_cond.a0 != cpu_psw_n) {
476*6fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n,
477129e9cc3SRichard Henderson                             ctx->null_cond.a0, ctx->null_cond.a1);
478129e9cc3SRichard Henderson         ctx->psw_n_nonzero = true;
479129e9cc3SRichard Henderson     }
480129e9cc3SRichard Henderson     cond_free(&ctx->null_cond);
481129e9cc3SRichard Henderson }
482129e9cc3SRichard Henderson 
483129e9cc3SRichard Henderson /* Set a PSW[N] to X.  The intention is that this is used immediately
484129e9cc3SRichard Henderson    before a goto_tb/exit_tb, so that there is no fallthru path to other
485129e9cc3SRichard Henderson    code within the TB.  Therefore we do not update psw_n_nonzero.  */
486129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x)
487129e9cc3SRichard Henderson {
488129e9cc3SRichard Henderson     if (ctx->psw_n_nonzero || x) {
489*6fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, x);
490129e9cc3SRichard Henderson     }
491129e9cc3SRichard Henderson }
492129e9cc3SRichard Henderson 
493129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified.
49440f9f908SRichard Henderson    This is the pair to nullify_over.  Always returns true so that
49540f9f908SRichard Henderson    it may be tail-called from a translate function.  */
49631234768SRichard Henderson static bool nullify_end(DisasContext *ctx)
497129e9cc3SRichard Henderson {
498129e9cc3SRichard Henderson     TCGLabel *null_lab = ctx->null_lab;
49931234768SRichard Henderson     DisasJumpType status = ctx->base.is_jmp;
500129e9cc3SRichard Henderson 
501f49b3537SRichard Henderson     /* For NEXT, NORETURN, STALE, we can easily continue (or exit).
502f49b3537SRichard Henderson        For UPDATED, we cannot update on the nullified path.  */
503f49b3537SRichard Henderson     assert(status != DISAS_IAQ_N_UPDATED);
504f49b3537SRichard Henderson 
505129e9cc3SRichard Henderson     if (likely(null_lab == NULL)) {
506129e9cc3SRichard Henderson         /* The current insn wasn't conditional or handled the condition
507129e9cc3SRichard Henderson            applied to it without a branch, so the (new) setting of
508129e9cc3SRichard Henderson            NULL_COND can be applied directly to the next insn.  */
50931234768SRichard Henderson         return true;
510129e9cc3SRichard Henderson     }
511129e9cc3SRichard Henderson     ctx->null_lab = NULL;
512129e9cc3SRichard Henderson 
513129e9cc3SRichard Henderson     if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
514129e9cc3SRichard Henderson         /* The next instruction will be unconditional,
515129e9cc3SRichard Henderson            and NULL_COND already reflects that.  */
516129e9cc3SRichard Henderson         gen_set_label(null_lab);
517129e9cc3SRichard Henderson     } else {
518129e9cc3SRichard Henderson         /* The insn that we just executed is itself nullifying the next
519129e9cc3SRichard Henderson            instruction.  Store the condition in the PSW[N] global.
520129e9cc3SRichard Henderson            We asserted PSW[N] = 0 in nullify_over, so that after the
521129e9cc3SRichard Henderson            label we have the proper value in place.  */
522129e9cc3SRichard Henderson         nullify_save(ctx);
523129e9cc3SRichard Henderson         gen_set_label(null_lab);
524129e9cc3SRichard Henderson         ctx->null_cond = cond_make_n();
525129e9cc3SRichard Henderson     }
526869051eaSRichard Henderson     if (status == DISAS_NORETURN) {
52731234768SRichard Henderson         ctx->base.is_jmp = DISAS_NEXT;
528129e9cc3SRichard Henderson     }
52931234768SRichard Henderson     return true;
530129e9cc3SRichard Henderson }
531129e9cc3SRichard Henderson 
532c53e401eSRichard Henderson static uint64_t gva_offset_mask(DisasContext *ctx)
533698240d1SRichard Henderson {
534698240d1SRichard Henderson     return (ctx->tb_flags & PSW_W
535698240d1SRichard Henderson             ? MAKE_64BIT_MASK(0, 62)
536698240d1SRichard Henderson             : MAKE_64BIT_MASK(0, 32));
537698240d1SRichard Henderson }
538698240d1SRichard Henderson 
539*6fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest,
540*6fd0c7bcSRichard Henderson                             uint64_t ival, TCGv_i64 vval)
54161766fe9SRichard Henderson {
542c53e401eSRichard Henderson     uint64_t mask = gva_offset_mask(ctx);
543f13bf343SRichard Henderson 
544f13bf343SRichard Henderson     if (ival != -1) {
545*6fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, ival & mask);
546f13bf343SRichard Henderson         return;
547f13bf343SRichard Henderson     }
548f13bf343SRichard Henderson     tcg_debug_assert(vval != NULL);
549f13bf343SRichard Henderson 
550f13bf343SRichard Henderson     /*
551f13bf343SRichard Henderson      * We know that the IAOQ is already properly masked.
552f13bf343SRichard Henderson      * This optimization is primarily for "iaoq_f = iaoq_b".
553f13bf343SRichard Henderson      */
554f13bf343SRichard Henderson     if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) {
555*6fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, vval);
55661766fe9SRichard Henderson     } else {
557*6fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, vval, mask);
55861766fe9SRichard Henderson     }
55961766fe9SRichard Henderson }
56061766fe9SRichard Henderson 
561c53e401eSRichard Henderson static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp)
56261766fe9SRichard Henderson {
56361766fe9SRichard Henderson     return ctx->iaoq_f + disp + 8;
56461766fe9SRichard Henderson }
56561766fe9SRichard Henderson 
56661766fe9SRichard Henderson static void gen_excp_1(int exception)
56761766fe9SRichard Henderson {
568ad75a51eSRichard Henderson     gen_helper_excp(tcg_env, tcg_constant_i32(exception));
56961766fe9SRichard Henderson }
57061766fe9SRichard Henderson 
57131234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception)
57261766fe9SRichard Henderson {
573741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
574741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
575129e9cc3SRichard Henderson     nullify_save(ctx);
57661766fe9SRichard Henderson     gen_excp_1(exception);
57731234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
57861766fe9SRichard Henderson }
57961766fe9SRichard Henderson 
58031234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc)
5811a19da0dSRichard Henderson {
58231234768SRichard Henderson     nullify_over(ctx);
583*6fd0c7bcSRichard Henderson     tcg_gen_st_i64(tcg_constant_i64(ctx->insn),
584ad75a51eSRichard Henderson                    tcg_env, offsetof(CPUHPPAState, cr[CR_IIR]));
58531234768SRichard Henderson     gen_excp(ctx, exc);
58631234768SRichard Henderson     return nullify_end(ctx);
5871a19da0dSRichard Henderson }
5881a19da0dSRichard Henderson 
58931234768SRichard Henderson static bool gen_illegal(DisasContext *ctx)
59061766fe9SRichard Henderson {
59131234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_ILL);
59261766fe9SRichard Henderson }
59361766fe9SRichard Henderson 
59440f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY
59540f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
59640f9f908SRichard Henderson     return gen_excp_iir(ctx, EXCP)
59740f9f908SRichard Henderson #else
598e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
599e1b5a5edSRichard Henderson     do {                                     \
600e1b5a5edSRichard Henderson         if (ctx->privilege != 0) {           \
60131234768SRichard Henderson             return gen_excp_iir(ctx, EXCP);  \
602e1b5a5edSRichard Henderson         }                                    \
603e1b5a5edSRichard Henderson     } while (0)
60440f9f908SRichard Henderson #endif
605e1b5a5edSRichard Henderson 
606c53e401eSRichard Henderson static bool use_goto_tb(DisasContext *ctx, uint64_t dest)
60761766fe9SRichard Henderson {
60857f91498SRichard Henderson     return translator_use_goto_tb(&ctx->base, dest);
60961766fe9SRichard Henderson }
61061766fe9SRichard Henderson 
611129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page,
612129e9cc3SRichard Henderson    and we're not attempting to set a breakpoint on it, then we can
613129e9cc3SRichard Henderson    totally skip the nullified insn.  This avoids creating and
614129e9cc3SRichard Henderson    executing a TB that merely branches to the next TB.  */
615129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx)
616129e9cc3SRichard Henderson {
617129e9cc3SRichard Henderson     return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
618129e9cc3SRichard Henderson             && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
619129e9cc3SRichard Henderson }
620129e9cc3SRichard Henderson 
62161766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which,
622c53e401eSRichard Henderson                         uint64_t f, uint64_t b)
62361766fe9SRichard Henderson {
62461766fe9SRichard Henderson     if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
62561766fe9SRichard Henderson         tcg_gen_goto_tb(which);
626a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, f, NULL);
627a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, b, NULL);
62807ea28b4SRichard Henderson         tcg_gen_exit_tb(ctx->base.tb, which);
62961766fe9SRichard Henderson     } else {
630741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, f, cpu_iaoq_b);
631741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, b, ctx->iaoq_n_var);
6327f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
63361766fe9SRichard Henderson     }
63461766fe9SRichard Henderson }
63561766fe9SRichard Henderson 
636b47a4a02SSven Schnelle static bool cond_need_sv(int c)
637b47a4a02SSven Schnelle {
638b47a4a02SSven Schnelle     return c == 2 || c == 3 || c == 6;
639b47a4a02SSven Schnelle }
640b47a4a02SSven Schnelle 
641b47a4a02SSven Schnelle static bool cond_need_cb(int c)
642b47a4a02SSven Schnelle {
643b47a4a02SSven Schnelle     return c == 4 || c == 5;
644b47a4a02SSven Schnelle }
645b47a4a02SSven Schnelle 
646*6fd0c7bcSRichard Henderson /* Need extensions from TCGv_i32 to TCGv_i64. */
64772ca8753SRichard Henderson static bool cond_need_ext(DisasContext *ctx, bool d)
64872ca8753SRichard Henderson {
649c53e401eSRichard Henderson     return !(ctx->is_pa20 && d);
65072ca8753SRichard Henderson }
65172ca8753SRichard Henderson 
652b47a4a02SSven Schnelle /*
653b47a4a02SSven Schnelle  * Compute conditional for arithmetic.  See Page 5-3, Table 5-1, of
654b47a4a02SSven Schnelle  * the Parisc 1.1 Architecture Reference Manual for details.
655b47a4a02SSven Schnelle  */
656b2167459SRichard Henderson 
657a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d,
658*6fd0c7bcSRichard Henderson                          TCGv_i64 res, TCGv_i64 cb_msb, TCGv_i64 sv)
659b2167459SRichard Henderson {
660b2167459SRichard Henderson     DisasCond cond;
661*6fd0c7bcSRichard Henderson     TCGv_i64 tmp;
662b2167459SRichard Henderson 
663b2167459SRichard Henderson     switch (cf >> 1) {
664b47a4a02SSven Schnelle     case 0: /* Never / TR    (0 / 1) */
665b2167459SRichard Henderson         cond = cond_make_f();
666b2167459SRichard Henderson         break;
667b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
668a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
669a751eb31SRichard Henderson             tmp = tcg_temp_new();
670*6fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
671a751eb31SRichard Henderson             res = tmp;
672a751eb31SRichard Henderson         }
673b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, res);
674b2167459SRichard Henderson         break;
675b47a4a02SSven Schnelle     case 2: /* < / >=        (N ^ V / !(N ^ V) */
676b47a4a02SSven Schnelle         tmp = tcg_temp_new();
677*6fd0c7bcSRichard Henderson         tcg_gen_xor_i64(tmp, res, sv);
678a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
679*6fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, tmp);
680a751eb31SRichard Henderson         }
681b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_LT, tmp);
682b2167459SRichard Henderson         break;
683b47a4a02SSven Schnelle     case 3: /* <= / >        (N ^ V) | Z / !((N ^ V) | Z) */
684b47a4a02SSven Schnelle         /*
685b47a4a02SSven Schnelle          * Simplify:
686b47a4a02SSven Schnelle          *   (N ^ V) | Z
687b47a4a02SSven Schnelle          *   ((res < 0) ^ (sv < 0)) | !res
688b47a4a02SSven Schnelle          *   ((res ^ sv) < 0) | !res
689b47a4a02SSven Schnelle          *   (~(res ^ sv) >= 0) | !res
690b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31) | !res
691b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31 & res)
692b47a4a02SSven Schnelle          */
693b47a4a02SSven Schnelle         tmp = tcg_temp_new();
694*6fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(tmp, res, sv);
695a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
696*6fd0c7bcSRichard Henderson             tcg_gen_sextract_i64(tmp, tmp, 31, 1);
697*6fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
698*6fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
699a751eb31SRichard Henderson         } else {
700*6fd0c7bcSRichard Henderson             tcg_gen_sari_i64(tmp, tmp, 63);
701*6fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
702a751eb31SRichard Henderson         }
703b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
704b2167459SRichard Henderson         break;
705b2167459SRichard Henderson     case 4: /* NUV / UV      (!C / C) */
706a751eb31SRichard Henderson         /* Only bit 0 of cb_msb is ever set. */
707b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, cb_msb);
708b2167459SRichard Henderson         break;
709b2167459SRichard Henderson     case 5: /* ZNV / VNZ     (!C | Z / C & !Z) */
710b2167459SRichard Henderson         tmp = tcg_temp_new();
711*6fd0c7bcSRichard Henderson         tcg_gen_neg_i64(tmp, cb_msb);
712*6fd0c7bcSRichard Henderson         tcg_gen_and_i64(tmp, tmp, res);
713a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
714*6fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
715a751eb31SRichard Henderson         }
716b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
717b2167459SRichard Henderson         break;
718b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
719a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
720a751eb31SRichard Henderson             tmp = tcg_temp_new();
721*6fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, sv);
722a751eb31SRichard Henderson             sv = tmp;
723a751eb31SRichard Henderson         }
724b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, sv);
725b2167459SRichard Henderson         break;
726b2167459SRichard Henderson     case 7: /* OD / EV */
727b2167459SRichard Henderson         tmp = tcg_temp_new();
728*6fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, res, 1);
729b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_NE, tmp);
730b2167459SRichard Henderson         break;
731b2167459SRichard Henderson     default:
732b2167459SRichard Henderson         g_assert_not_reached();
733b2167459SRichard Henderson     }
734b2167459SRichard Henderson     if (cf & 1) {
735b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
736b2167459SRichard Henderson     }
737b2167459SRichard Henderson 
738b2167459SRichard Henderson     return cond;
739b2167459SRichard Henderson }
740b2167459SRichard Henderson 
741b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
742b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
743b2167459SRichard Henderson    deleted as unused.  */
744b2167459SRichard Henderson 
7454fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d,
746*6fd0c7bcSRichard Henderson                              TCGv_i64 res, TCGv_i64 in1,
747*6fd0c7bcSRichard Henderson                              TCGv_i64 in2, TCGv_i64 sv)
748b2167459SRichard Henderson {
7494fe9533aSRichard Henderson     TCGCond tc;
7504fe9533aSRichard Henderson     bool ext_uns;
751b2167459SRichard Henderson 
752b2167459SRichard Henderson     switch (cf >> 1) {
753b2167459SRichard Henderson     case 1: /* = / <> */
7544fe9533aSRichard Henderson         tc = TCG_COND_EQ;
7554fe9533aSRichard Henderson         ext_uns = true;
756b2167459SRichard Henderson         break;
757b2167459SRichard Henderson     case 2: /* < / >= */
7584fe9533aSRichard Henderson         tc = TCG_COND_LT;
7594fe9533aSRichard Henderson         ext_uns = false;
760b2167459SRichard Henderson         break;
761b2167459SRichard Henderson     case 3: /* <= / > */
7624fe9533aSRichard Henderson         tc = TCG_COND_LE;
7634fe9533aSRichard Henderson         ext_uns = false;
764b2167459SRichard Henderson         break;
765b2167459SRichard Henderson     case 4: /* << / >>= */
7664fe9533aSRichard Henderson         tc = TCG_COND_LTU;
7674fe9533aSRichard Henderson         ext_uns = true;
768b2167459SRichard Henderson         break;
769b2167459SRichard Henderson     case 5: /* <<= / >> */
7704fe9533aSRichard Henderson         tc = TCG_COND_LEU;
7714fe9533aSRichard Henderson         ext_uns = true;
772b2167459SRichard Henderson         break;
773b2167459SRichard Henderson     default:
774a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, sv);
775b2167459SRichard Henderson     }
776b2167459SRichard Henderson 
7774fe9533aSRichard Henderson     if (cf & 1) {
7784fe9533aSRichard Henderson         tc = tcg_invert_cond(tc);
7794fe9533aSRichard Henderson     }
7804fe9533aSRichard Henderson     if (cond_need_ext(ctx, d)) {
781*6fd0c7bcSRichard Henderson         TCGv_i64 t1 = tcg_temp_new();
782*6fd0c7bcSRichard Henderson         TCGv_i64 t2 = tcg_temp_new();
7834fe9533aSRichard Henderson 
7844fe9533aSRichard Henderson         if (ext_uns) {
785*6fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t1, in1);
786*6fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t2, in2);
7874fe9533aSRichard Henderson         } else {
788*6fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t1, in1);
789*6fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t2, in2);
7904fe9533aSRichard Henderson         }
7914fe9533aSRichard Henderson         return cond_make_tmp(tc, t1, t2);
7924fe9533aSRichard Henderson     }
7934fe9533aSRichard Henderson     return cond_make(tc, in1, in2);
794b2167459SRichard Henderson }
795b2167459SRichard Henderson 
796df0232feSRichard Henderson /*
797df0232feSRichard Henderson  * Similar, but for logicals, where the carry and overflow bits are not
798df0232feSRichard Henderson  * computed, and use of them is undefined.
799df0232feSRichard Henderson  *
800df0232feSRichard Henderson  * Undefined or not, hardware does not trap.  It seems reasonable to
801df0232feSRichard Henderson  * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's
802df0232feSRichard Henderson  * how cases c={2,3} are treated.
803df0232feSRichard Henderson  */
804b2167459SRichard Henderson 
805b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d,
806*6fd0c7bcSRichard Henderson                              TCGv_i64 res)
807b2167459SRichard Henderson {
808b5af8423SRichard Henderson     TCGCond tc;
809b5af8423SRichard Henderson     bool ext_uns;
810a751eb31SRichard Henderson 
811df0232feSRichard Henderson     switch (cf) {
812df0232feSRichard Henderson     case 0:  /* never */
813df0232feSRichard Henderson     case 9:  /* undef, C */
814df0232feSRichard Henderson     case 11: /* undef, C & !Z */
815df0232feSRichard Henderson     case 12: /* undef, V */
816df0232feSRichard Henderson         return cond_make_f();
817df0232feSRichard Henderson 
818df0232feSRichard Henderson     case 1:  /* true */
819df0232feSRichard Henderson     case 8:  /* undef, !C */
820df0232feSRichard Henderson     case 10: /* undef, !C | Z */
821df0232feSRichard Henderson     case 13: /* undef, !V */
822df0232feSRichard Henderson         return cond_make_t();
823df0232feSRichard Henderson 
824df0232feSRichard Henderson     case 2:  /* == */
825b5af8423SRichard Henderson         tc = TCG_COND_EQ;
826b5af8423SRichard Henderson         ext_uns = true;
827b5af8423SRichard Henderson         break;
828df0232feSRichard Henderson     case 3:  /* <> */
829b5af8423SRichard Henderson         tc = TCG_COND_NE;
830b5af8423SRichard Henderson         ext_uns = true;
831b5af8423SRichard Henderson         break;
832df0232feSRichard Henderson     case 4:  /* < */
833b5af8423SRichard Henderson         tc = TCG_COND_LT;
834b5af8423SRichard Henderson         ext_uns = false;
835b5af8423SRichard Henderson         break;
836df0232feSRichard Henderson     case 5:  /* >= */
837b5af8423SRichard Henderson         tc = TCG_COND_GE;
838b5af8423SRichard Henderson         ext_uns = false;
839b5af8423SRichard Henderson         break;
840df0232feSRichard Henderson     case 6:  /* <= */
841b5af8423SRichard Henderson         tc = TCG_COND_LE;
842b5af8423SRichard Henderson         ext_uns = false;
843b5af8423SRichard Henderson         break;
844df0232feSRichard Henderson     case 7:  /* > */
845b5af8423SRichard Henderson         tc = TCG_COND_GT;
846b5af8423SRichard Henderson         ext_uns = false;
847b5af8423SRichard Henderson         break;
848df0232feSRichard Henderson 
849df0232feSRichard Henderson     case 14: /* OD */
850df0232feSRichard Henderson     case 15: /* EV */
851a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, NULL);
852df0232feSRichard Henderson 
853df0232feSRichard Henderson     default:
854df0232feSRichard Henderson         g_assert_not_reached();
855b2167459SRichard Henderson     }
856b5af8423SRichard Henderson 
857b5af8423SRichard Henderson     if (cond_need_ext(ctx, d)) {
858*6fd0c7bcSRichard Henderson         TCGv_i64 tmp = tcg_temp_new();
859b5af8423SRichard Henderson 
860b5af8423SRichard Henderson         if (ext_uns) {
861*6fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
862b5af8423SRichard Henderson         } else {
863*6fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, res);
864b5af8423SRichard Henderson         }
865b5af8423SRichard Henderson         return cond_make_0_tmp(tc, tmp);
866b5af8423SRichard Henderson     }
867b5af8423SRichard Henderson     return cond_make_0(tc, res);
868b2167459SRichard Henderson }
869b2167459SRichard Henderson 
87098cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
87198cd9ca7SRichard Henderson 
8724fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d,
873*6fd0c7bcSRichard Henderson                              TCGv_i64 res)
87498cd9ca7SRichard Henderson {
87598cd9ca7SRichard Henderson     unsigned c, f;
87698cd9ca7SRichard Henderson 
87798cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
87898cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
87998cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
88098cd9ca7SRichard Henderson     c = orig & 3;
88198cd9ca7SRichard Henderson     if (c == 3) {
88298cd9ca7SRichard Henderson         c = 7;
88398cd9ca7SRichard Henderson     }
88498cd9ca7SRichard Henderson     f = (orig & 4) / 4;
88598cd9ca7SRichard Henderson 
886b5af8423SRichard Henderson     return do_log_cond(ctx, c * 2 + f, d, res);
88798cd9ca7SRichard Henderson }
88898cd9ca7SRichard Henderson 
889b2167459SRichard Henderson /* Similar, but for unit conditions.  */
890b2167459SRichard Henderson 
891*6fd0c7bcSRichard Henderson static DisasCond do_unit_cond(unsigned cf, bool d, TCGv_i64 res,
892*6fd0c7bcSRichard Henderson                               TCGv_i64 in1, TCGv_i64 in2)
893b2167459SRichard Henderson {
894b2167459SRichard Henderson     DisasCond cond;
895*6fd0c7bcSRichard Henderson     TCGv_i64 tmp, cb = NULL;
896c53e401eSRichard Henderson     uint64_t d_repl = d ? 0x0000000100000001ull : 1;
897b2167459SRichard Henderson 
898b2167459SRichard Henderson     if (cf & 8) {
899b2167459SRichard Henderson         /* Since we want to test lots of carry-out bits all at once, do not
900b2167459SRichard Henderson          * do our normal thing and compute carry-in of bit B+1 since that
901b2167459SRichard Henderson          * leaves us with carry bits spread across two words.
902b2167459SRichard Henderson          */
903b2167459SRichard Henderson         cb = tcg_temp_new();
904b2167459SRichard Henderson         tmp = tcg_temp_new();
905*6fd0c7bcSRichard Henderson         tcg_gen_or_i64(cb, in1, in2);
906*6fd0c7bcSRichard Henderson         tcg_gen_and_i64(tmp, in1, in2);
907*6fd0c7bcSRichard Henderson         tcg_gen_andc_i64(cb, cb, res);
908*6fd0c7bcSRichard Henderson         tcg_gen_or_i64(cb, cb, tmp);
909b2167459SRichard Henderson     }
910b2167459SRichard Henderson 
911b2167459SRichard Henderson     switch (cf >> 1) {
912b2167459SRichard Henderson     case 0: /* never / TR */
913b2167459SRichard Henderson     case 1: /* undefined */
914b2167459SRichard Henderson     case 5: /* undefined */
915b2167459SRichard Henderson         cond = cond_make_f();
916b2167459SRichard Henderson         break;
917b2167459SRichard Henderson 
918b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
919b2167459SRichard Henderson         /* See hasless(v,1) from
920b2167459SRichard Henderson          * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
921b2167459SRichard Henderson          */
922b2167459SRichard Henderson         tmp = tcg_temp_new();
923*6fd0c7bcSRichard Henderson         tcg_gen_subi_i64(tmp, res, d_repl * 0x01010101u);
924*6fd0c7bcSRichard Henderson         tcg_gen_andc_i64(tmp, tmp, res);
925*6fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80808080u);
926b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
927b2167459SRichard Henderson         break;
928b2167459SRichard Henderson 
929b2167459SRichard Henderson     case 3: /* SHZ / NHZ */
930b2167459SRichard Henderson         tmp = tcg_temp_new();
931*6fd0c7bcSRichard Henderson         tcg_gen_subi_i64(tmp, res, d_repl * 0x00010001u);
932*6fd0c7bcSRichard Henderson         tcg_gen_andc_i64(tmp, tmp, res);
933*6fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80008000u);
934b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
935b2167459SRichard Henderson         break;
936b2167459SRichard Henderson 
937b2167459SRichard Henderson     case 4: /* SDC / NDC */
938*6fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x88888888u);
939b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
940b2167459SRichard Henderson         break;
941b2167459SRichard Henderson 
942b2167459SRichard Henderson     case 6: /* SBC / NBC */
943*6fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x80808080u);
944b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
945b2167459SRichard Henderson         break;
946b2167459SRichard Henderson 
947b2167459SRichard Henderson     case 7: /* SHC / NHC */
948*6fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x80008000u);
949b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
950b2167459SRichard Henderson         break;
951b2167459SRichard Henderson 
952b2167459SRichard Henderson     default:
953b2167459SRichard Henderson         g_assert_not_reached();
954b2167459SRichard Henderson     }
955b2167459SRichard Henderson     if (cf & 1) {
956b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
957b2167459SRichard Henderson     }
958b2167459SRichard Henderson 
959b2167459SRichard Henderson     return cond;
960b2167459SRichard Henderson }
961b2167459SRichard Henderson 
962*6fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d,
963*6fd0c7bcSRichard Henderson                           TCGv_i64 cb, TCGv_i64 cb_msb)
96472ca8753SRichard Henderson {
96572ca8753SRichard Henderson     if (cond_need_ext(ctx, d)) {
966*6fd0c7bcSRichard Henderson         TCGv_i64 t = tcg_temp_new();
967*6fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, cb, 32, 1);
96872ca8753SRichard Henderson         return t;
96972ca8753SRichard Henderson     }
97072ca8753SRichard Henderson     return cb_msb;
97172ca8753SRichard Henderson }
97272ca8753SRichard Henderson 
973*6fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d)
97472ca8753SRichard Henderson {
97572ca8753SRichard Henderson     return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb);
97672ca8753SRichard Henderson }
97772ca8753SRichard Henderson 
978b2167459SRichard Henderson /* Compute signed overflow for addition.  */
979*6fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res,
980*6fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
981b2167459SRichard Henderson {
982*6fd0c7bcSRichard Henderson     TCGv_i64 sv = tcg_temp_new();
983*6fd0c7bcSRichard Henderson     TCGv_i64 tmp = tcg_temp_new();
984b2167459SRichard Henderson 
985*6fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
986*6fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
987*6fd0c7bcSRichard Henderson     tcg_gen_andc_i64(sv, sv, tmp);
988b2167459SRichard Henderson 
989b2167459SRichard Henderson     return sv;
990b2167459SRichard Henderson }
991b2167459SRichard Henderson 
992b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
993*6fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res,
994*6fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
995b2167459SRichard Henderson {
996*6fd0c7bcSRichard Henderson     TCGv_i64 sv = tcg_temp_new();
997*6fd0c7bcSRichard Henderson     TCGv_i64 tmp = tcg_temp_new();
998b2167459SRichard Henderson 
999*6fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
1000*6fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
1001*6fd0c7bcSRichard Henderson     tcg_gen_and_i64(sv, sv, tmp);
1002b2167459SRichard Henderson 
1003b2167459SRichard Henderson     return sv;
1004b2167459SRichard Henderson }
1005b2167459SRichard Henderson 
1006*6fd0c7bcSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
1007*6fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned shift, bool is_l,
1008faf97ba1SRichard Henderson                    bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d)
1009b2167459SRichard Henderson {
1010*6fd0c7bcSRichard Henderson     TCGv_i64 dest, cb, cb_msb, cb_cond, sv, tmp;
1011b2167459SRichard Henderson     unsigned c = cf >> 1;
1012b2167459SRichard Henderson     DisasCond cond;
1013b2167459SRichard Henderson 
1014b2167459SRichard Henderson     dest = tcg_temp_new();
1015f764718dSRichard Henderson     cb = NULL;
1016f764718dSRichard Henderson     cb_msb = NULL;
1017bdcccc17SRichard Henderson     cb_cond = NULL;
1018b2167459SRichard Henderson 
1019b2167459SRichard Henderson     if (shift) {
1020e12c6309SRichard Henderson         tmp = tcg_temp_new();
1021*6fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, in1, shift);
1022b2167459SRichard Henderson         in1 = tmp;
1023b2167459SRichard Henderson     }
1024b2167459SRichard Henderson 
1025b47a4a02SSven Schnelle     if (!is_l || cond_need_cb(c)) {
1026*6fd0c7bcSRichard Henderson         TCGv_i64 zero = tcg_constant_i64(0);
1027e12c6309SRichard Henderson         cb_msb = tcg_temp_new();
1028bdcccc17SRichard Henderson         cb = tcg_temp_new();
1029bdcccc17SRichard Henderson 
1030*6fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, zero, in2, zero);
1031b2167459SRichard Henderson         if (is_c) {
1032*6fd0c7bcSRichard Henderson             tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb,
1033bdcccc17SRichard Henderson                              get_psw_carry(ctx, d), zero);
1034b2167459SRichard Henderson         }
1035*6fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
1036*6fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1037bdcccc17SRichard Henderson         if (cond_need_cb(c)) {
1038bdcccc17SRichard Henderson             cb_cond = get_carry(ctx, d, cb, cb_msb);
1039b2167459SRichard Henderson         }
1040b2167459SRichard Henderson     } else {
1041*6fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
1042b2167459SRichard Henderson         if (is_c) {
1043*6fd0c7bcSRichard Henderson             tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d));
1044b2167459SRichard Henderson         }
1045b2167459SRichard Henderson     }
1046b2167459SRichard Henderson 
1047b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1048f764718dSRichard Henderson     sv = NULL;
1049b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1050b2167459SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
1051b2167459SRichard Henderson         if (is_tsv) {
1052b2167459SRichard Henderson             /* ??? Need to include overflow from shift.  */
1053ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1054b2167459SRichard Henderson         }
1055b2167459SRichard Henderson     }
1056b2167459SRichard Henderson 
1057b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1058a751eb31SRichard Henderson     cond = do_cond(ctx, cf, d, dest, cb_cond, sv);
1059b2167459SRichard Henderson     if (is_tc) {
1060b2167459SRichard Henderson         tmp = tcg_temp_new();
1061*6fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1062ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1063b2167459SRichard Henderson     }
1064b2167459SRichard Henderson 
1065b2167459SRichard Henderson     /* Write back the result.  */
1066b2167459SRichard Henderson     if (!is_l) {
1067b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
1068b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1069b2167459SRichard Henderson     }
1070b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1071b2167459SRichard Henderson 
1072b2167459SRichard Henderson     /* Install the new nullification.  */
1073b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1074b2167459SRichard Henderson     ctx->null_cond = cond;
1075b2167459SRichard Henderson }
1076b2167459SRichard Henderson 
1077faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a,
10780c982a28SRichard Henderson                        bool is_l, bool is_tsv, bool is_tc, bool is_c)
10790c982a28SRichard Henderson {
1080*6fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
10810c982a28SRichard Henderson 
10820c982a28SRichard Henderson     if (a->cf) {
10830c982a28SRichard Henderson         nullify_over(ctx);
10840c982a28SRichard Henderson     }
10850c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
10860c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1087faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l,
1088faf97ba1SRichard Henderson            is_tsv, is_tc, is_c, a->cf, a->d);
10890c982a28SRichard Henderson     return nullify_end(ctx);
10900c982a28SRichard Henderson }
10910c982a28SRichard Henderson 
10920588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a,
10930588e061SRichard Henderson                        bool is_tsv, bool is_tc)
10940588e061SRichard Henderson {
1095*6fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
10960588e061SRichard Henderson 
10970588e061SRichard Henderson     if (a->cf) {
10980588e061SRichard Henderson         nullify_over(ctx);
10990588e061SRichard Henderson     }
1100*6fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
11010588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
1102faf97ba1SRichard Henderson     /* All ADDI conditions are 32-bit. */
1103faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false);
11040588e061SRichard Henderson     return nullify_end(ctx);
11050588e061SRichard Henderson }
11060588e061SRichard Henderson 
1107*6fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
1108*6fd0c7bcSRichard Henderson                    TCGv_i64 in2, bool is_tsv, bool is_b,
110963c427c6SRichard Henderson                    bool is_tc, unsigned cf, bool d)
1110b2167459SRichard Henderson {
1111*6fd0c7bcSRichard Henderson     TCGv_i64 dest, sv, cb, cb_msb, zero, tmp;
1112b2167459SRichard Henderson     unsigned c = cf >> 1;
1113b2167459SRichard Henderson     DisasCond cond;
1114b2167459SRichard Henderson 
1115b2167459SRichard Henderson     dest = tcg_temp_new();
1116b2167459SRichard Henderson     cb = tcg_temp_new();
1117b2167459SRichard Henderson     cb_msb = tcg_temp_new();
1118b2167459SRichard Henderson 
1119*6fd0c7bcSRichard Henderson     zero = tcg_constant_i64(0);
1120b2167459SRichard Henderson     if (is_b) {
1121b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
1122*6fd0c7bcSRichard Henderson         tcg_gen_not_i64(cb, in2);
1123*6fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, zero, get_psw_carry(ctx, d), zero);
1124*6fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, zero);
1125*6fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, in1);
1126*6fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1127b2167459SRichard Henderson     } else {
1128bdcccc17SRichard Henderson         /*
1129bdcccc17SRichard Henderson          * DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
1130bdcccc17SRichard Henderson          * operations by seeding the high word with 1 and subtracting.
1131bdcccc17SRichard Henderson          */
1132*6fd0c7bcSRichard Henderson         TCGv_i64 one = tcg_constant_i64(1);
1133*6fd0c7bcSRichard Henderson         tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, zero);
1134*6fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(cb, in1, in2);
1135*6fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1136b2167459SRichard Henderson     }
1137b2167459SRichard Henderson 
1138b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1139f764718dSRichard Henderson     sv = NULL;
1140b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1141b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1142b2167459SRichard Henderson         if (is_tsv) {
1143ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1144b2167459SRichard Henderson         }
1145b2167459SRichard Henderson     }
1146b2167459SRichard Henderson 
1147b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
1148b2167459SRichard Henderson     if (!is_b) {
11494fe9533aSRichard Henderson         cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1150b2167459SRichard Henderson     } else {
1151a751eb31SRichard Henderson         cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv);
1152b2167459SRichard Henderson     }
1153b2167459SRichard Henderson 
1154b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1155b2167459SRichard Henderson     if (is_tc) {
1156b2167459SRichard Henderson         tmp = tcg_temp_new();
1157*6fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1158ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1159b2167459SRichard Henderson     }
1160b2167459SRichard Henderson 
1161b2167459SRichard Henderson     /* Write back the result.  */
1162b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
1163b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1164b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1165b2167459SRichard Henderson 
1166b2167459SRichard Henderson     /* Install the new nullification.  */
1167b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1168b2167459SRichard Henderson     ctx->null_cond = cond;
1169b2167459SRichard Henderson }
1170b2167459SRichard Henderson 
117163c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a,
11720c982a28SRichard Henderson                        bool is_tsv, bool is_b, bool is_tc)
11730c982a28SRichard Henderson {
1174*6fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
11750c982a28SRichard Henderson 
11760c982a28SRichard Henderson     if (a->cf) {
11770c982a28SRichard Henderson         nullify_over(ctx);
11780c982a28SRichard Henderson     }
11790c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
11800c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
118163c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d);
11820c982a28SRichard Henderson     return nullify_end(ctx);
11830c982a28SRichard Henderson }
11840c982a28SRichard Henderson 
11850588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv)
11860588e061SRichard Henderson {
1187*6fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
11880588e061SRichard Henderson 
11890588e061SRichard Henderson     if (a->cf) {
11900588e061SRichard Henderson         nullify_over(ctx);
11910588e061SRichard Henderson     }
1192*6fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
11930588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
119463c427c6SRichard Henderson     /* All SUBI conditions are 32-bit. */
119563c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false);
11960588e061SRichard Henderson     return nullify_end(ctx);
11970588e061SRichard Henderson }
11980588e061SRichard Henderson 
1199*6fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
1200*6fd0c7bcSRichard Henderson                       TCGv_i64 in2, unsigned cf, bool d)
1201b2167459SRichard Henderson {
1202*6fd0c7bcSRichard Henderson     TCGv_i64 dest, sv;
1203b2167459SRichard Henderson     DisasCond cond;
1204b2167459SRichard Henderson 
1205b2167459SRichard Henderson     dest = tcg_temp_new();
1206*6fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
1207b2167459SRichard Henderson 
1208b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1209f764718dSRichard Henderson     sv = NULL;
1210b47a4a02SSven Schnelle     if (cond_need_sv(cf >> 1)) {
1211b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1212b2167459SRichard Henderson     }
1213b2167459SRichard Henderson 
1214b2167459SRichard Henderson     /* Form the condition for the compare.  */
12154fe9533aSRichard Henderson     cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1216b2167459SRichard Henderson 
1217b2167459SRichard Henderson     /* Clear.  */
1218*6fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
1219b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1220b2167459SRichard Henderson 
1221b2167459SRichard Henderson     /* Install the new nullification.  */
1222b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1223b2167459SRichard Henderson     ctx->null_cond = cond;
1224b2167459SRichard Henderson }
1225b2167459SRichard Henderson 
1226*6fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
1227*6fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned cf, bool d,
1228*6fd0c7bcSRichard Henderson                    void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1229b2167459SRichard Henderson {
1230*6fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, rt);
1231b2167459SRichard Henderson 
1232b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
1233b2167459SRichard Henderson     fn(dest, in1, in2);
1234b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1235b2167459SRichard Henderson 
1236b2167459SRichard Henderson     /* Install the new nullification.  */
1237b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1238b2167459SRichard Henderson     if (cf) {
1239b5af8423SRichard Henderson         ctx->null_cond = do_log_cond(ctx, cf, d, dest);
1240b2167459SRichard Henderson     }
1241b2167459SRichard Henderson }
1242b2167459SRichard Henderson 
1243fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a,
1244*6fd0c7bcSRichard Henderson                        void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
12450c982a28SRichard Henderson {
1246*6fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
12470c982a28SRichard Henderson 
12480c982a28SRichard Henderson     if (a->cf) {
12490c982a28SRichard Henderson         nullify_over(ctx);
12500c982a28SRichard Henderson     }
12510c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
12520c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1253fa8e3bedSRichard Henderson     do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn);
12540c982a28SRichard Henderson     return nullify_end(ctx);
12550c982a28SRichard Henderson }
12560c982a28SRichard Henderson 
1257*6fd0c7bcSRichard Henderson static void do_unit(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
1258*6fd0c7bcSRichard Henderson                     TCGv_i64 in2, unsigned cf, bool d, bool is_tc,
1259*6fd0c7bcSRichard Henderson                     void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1260b2167459SRichard Henderson {
1261*6fd0c7bcSRichard Henderson     TCGv_i64 dest;
1262b2167459SRichard Henderson     DisasCond cond;
1263b2167459SRichard Henderson 
1264b2167459SRichard Henderson     if (cf == 0) {
1265b2167459SRichard Henderson         dest = dest_gpr(ctx, rt);
1266b2167459SRichard Henderson         fn(dest, in1, in2);
1267b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1268b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1269b2167459SRichard Henderson     } else {
1270b2167459SRichard Henderson         dest = tcg_temp_new();
1271b2167459SRichard Henderson         fn(dest, in1, in2);
1272b2167459SRichard Henderson 
127359963d8fSRichard Henderson         cond = do_unit_cond(cf, d, dest, in1, in2);
1274b2167459SRichard Henderson 
1275b2167459SRichard Henderson         if (is_tc) {
1276*6fd0c7bcSRichard Henderson             TCGv_i64 tmp = tcg_temp_new();
1277*6fd0c7bcSRichard Henderson             tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1278ad75a51eSRichard Henderson             gen_helper_tcond(tcg_env, tmp);
1279b2167459SRichard Henderson         }
1280b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1281b2167459SRichard Henderson 
1282b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1283b2167459SRichard Henderson         ctx->null_cond = cond;
1284b2167459SRichard Henderson     }
1285b2167459SRichard Henderson }
1286b2167459SRichard Henderson 
128786f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY
12888d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space
12898d6ae7fbSRichard Henderson    from the top 2 bits of the base register.  There are a few system
12908d6ae7fbSRichard Henderson    instructions that have a 3-bit space specifier, for which SR0 is
12918d6ae7fbSRichard Henderson    not special.  To handle this, pass ~SP.  */
1292*6fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base)
129386f8d05fSRichard Henderson {
129486f8d05fSRichard Henderson     TCGv_ptr ptr;
1295*6fd0c7bcSRichard Henderson     TCGv_i64 tmp;
129686f8d05fSRichard Henderson     TCGv_i64 spc;
129786f8d05fSRichard Henderson 
129886f8d05fSRichard Henderson     if (sp != 0) {
12998d6ae7fbSRichard Henderson         if (sp < 0) {
13008d6ae7fbSRichard Henderson             sp = ~sp;
13018d6ae7fbSRichard Henderson         }
1302*6fd0c7bcSRichard Henderson         spc = tcg_temp_new_i64();
13038d6ae7fbSRichard Henderson         load_spr(ctx, spc, sp);
13048d6ae7fbSRichard Henderson         return spc;
130586f8d05fSRichard Henderson     }
1306494737b7SRichard Henderson     if (ctx->tb_flags & TB_FLAG_SR_SAME) {
1307494737b7SRichard Henderson         return cpu_srH;
1308494737b7SRichard Henderson     }
130986f8d05fSRichard Henderson 
131086f8d05fSRichard Henderson     ptr = tcg_temp_new_ptr();
131186f8d05fSRichard Henderson     tmp = tcg_temp_new();
1312*6fd0c7bcSRichard Henderson     spc = tcg_temp_new_i64();
131386f8d05fSRichard Henderson 
1314698240d1SRichard Henderson     /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */
1315*6fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5);
1316*6fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, 030);
1317*6fd0c7bcSRichard Henderson     tcg_gen_trunc_i64_ptr(ptr, tmp);
131886f8d05fSRichard Henderson 
1319ad75a51eSRichard Henderson     tcg_gen_add_ptr(ptr, ptr, tcg_env);
132086f8d05fSRichard Henderson     tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4]));
132186f8d05fSRichard Henderson 
132286f8d05fSRichard Henderson     return spc;
132386f8d05fSRichard Henderson }
132486f8d05fSRichard Henderson #endif
132586f8d05fSRichard Henderson 
1326*6fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
1327c53e401eSRichard Henderson                      unsigned rb, unsigned rx, int scale, int64_t disp,
132886f8d05fSRichard Henderson                      unsigned sp, int modify, bool is_phys)
132986f8d05fSRichard Henderson {
1330*6fd0c7bcSRichard Henderson     TCGv_i64 base = load_gpr(ctx, rb);
1331*6fd0c7bcSRichard Henderson     TCGv_i64 ofs;
1332*6fd0c7bcSRichard Henderson     TCGv_i64 addr;
133386f8d05fSRichard Henderson 
133486f8d05fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
133586f8d05fSRichard Henderson     if (rx) {
1336e12c6309SRichard Henderson         ofs = tcg_temp_new();
1337*6fd0c7bcSRichard Henderson         tcg_gen_shli_i64(ofs, cpu_gr[rx], scale);
1338*6fd0c7bcSRichard Henderson         tcg_gen_add_i64(ofs, ofs, base);
133986f8d05fSRichard Henderson     } else if (disp || modify) {
1340e12c6309SRichard Henderson         ofs = tcg_temp_new();
1341*6fd0c7bcSRichard Henderson         tcg_gen_addi_i64(ofs, base, disp);
134286f8d05fSRichard Henderson     } else {
134386f8d05fSRichard Henderson         ofs = base;
134486f8d05fSRichard Henderson     }
134586f8d05fSRichard Henderson 
134686f8d05fSRichard Henderson     *pofs = ofs;
1347*6fd0c7bcSRichard Henderson     *pgva = addr = tcg_temp_new_i64();
134886f8d05fSRichard Henderson     tcg_gen_extu_reg_tl(addr, modify <= 0 ? ofs : base);
1349698240d1SRichard Henderson     tcg_gen_andi_tl(addr, addr, gva_offset_mask(ctx));
1350698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY
135186f8d05fSRichard Henderson     if (!is_phys) {
135286f8d05fSRichard Henderson         tcg_gen_or_tl(addr, addr, space_select(ctx, sp, base));
135386f8d05fSRichard Henderson     }
135486f8d05fSRichard Henderson #endif
135586f8d05fSRichard Henderson }
135686f8d05fSRichard Henderson 
135796d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
135896d6407fSRichard Henderson  * < 0 for pre-modify,
135996d6407fSRichard Henderson  * > 0 for post-modify,
136096d6407fSRichard Henderson  * = 0 for no base register update.
136196d6407fSRichard Henderson  */
136296d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1363c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
136414776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
136596d6407fSRichard Henderson {
1366*6fd0c7bcSRichard Henderson     TCGv_i64 ofs;
1367*6fd0c7bcSRichard Henderson     TCGv_i64 addr;
136896d6407fSRichard Henderson 
136996d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
137096d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
137196d6407fSRichard Henderson 
137286f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
137386f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1374c1f55d97SRichard Henderson     tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
137586f8d05fSRichard Henderson     if (modify) {
137686f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
137796d6407fSRichard Henderson     }
137896d6407fSRichard Henderson }
137996d6407fSRichard Henderson 
138096d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1381c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
138214776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
138396d6407fSRichard Henderson {
1384*6fd0c7bcSRichard Henderson     TCGv_i64 ofs;
1385*6fd0c7bcSRichard Henderson     TCGv_i64 addr;
138696d6407fSRichard Henderson 
138796d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
138896d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
138996d6407fSRichard Henderson 
139086f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
139186f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1392217d1a5eSRichard Henderson     tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
139386f8d05fSRichard Henderson     if (modify) {
139486f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
139596d6407fSRichard Henderson     }
139696d6407fSRichard Henderson }
139796d6407fSRichard Henderson 
139896d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1399c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
140014776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
140196d6407fSRichard Henderson {
1402*6fd0c7bcSRichard Henderson     TCGv_i64 ofs;
1403*6fd0c7bcSRichard Henderson     TCGv_i64 addr;
140496d6407fSRichard Henderson 
140596d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
140696d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
140796d6407fSRichard Henderson 
140886f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
140986f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1410217d1a5eSRichard Henderson     tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
141186f8d05fSRichard Henderson     if (modify) {
141286f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
141396d6407fSRichard Henderson     }
141496d6407fSRichard Henderson }
141596d6407fSRichard Henderson 
141696d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1417c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
141814776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
141996d6407fSRichard Henderson {
1420*6fd0c7bcSRichard Henderson     TCGv_i64 ofs;
1421*6fd0c7bcSRichard Henderson     TCGv_i64 addr;
142296d6407fSRichard Henderson 
142396d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
142496d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
142596d6407fSRichard Henderson 
142686f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
142786f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1428217d1a5eSRichard Henderson     tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
142986f8d05fSRichard Henderson     if (modify) {
143086f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
143196d6407fSRichard Henderson     }
143296d6407fSRichard Henderson }
143396d6407fSRichard Henderson 
14341cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1435c53e401eSRichard Henderson                     unsigned rx, int scale, int64_t disp,
143614776ab5STony Nguyen                     unsigned sp, int modify, MemOp mop)
143796d6407fSRichard Henderson {
1438*6fd0c7bcSRichard Henderson     TCGv_i64 dest;
143996d6407fSRichard Henderson 
144096d6407fSRichard Henderson     nullify_over(ctx);
144196d6407fSRichard Henderson 
144296d6407fSRichard Henderson     if (modify == 0) {
144396d6407fSRichard Henderson         /* No base register update.  */
144496d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
144596d6407fSRichard Henderson     } else {
144696d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
1447e12c6309SRichard Henderson         dest = tcg_temp_new();
144896d6407fSRichard Henderson     }
1449*6fd0c7bcSRichard Henderson     do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
145096d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
145196d6407fSRichard Henderson 
14521cd012a5SRichard Henderson     return nullify_end(ctx);
145396d6407fSRichard Henderson }
145496d6407fSRichard Henderson 
1455740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
1456c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
145786f8d05fSRichard Henderson                       unsigned sp, int modify)
145896d6407fSRichard Henderson {
145996d6407fSRichard Henderson     TCGv_i32 tmp;
146096d6407fSRichard Henderson 
146196d6407fSRichard Henderson     nullify_over(ctx);
146296d6407fSRichard Henderson 
146396d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
146486f8d05fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
146596d6407fSRichard Henderson     save_frw_i32(rt, tmp);
146696d6407fSRichard Henderson 
146796d6407fSRichard Henderson     if (rt == 0) {
1468ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
146996d6407fSRichard Henderson     }
147096d6407fSRichard Henderson 
1471740038d7SRichard Henderson     return nullify_end(ctx);
147296d6407fSRichard Henderson }
147396d6407fSRichard Henderson 
1474740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a)
1475740038d7SRichard Henderson {
1476740038d7SRichard Henderson     return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1477740038d7SRichard Henderson                      a->disp, a->sp, a->m);
1478740038d7SRichard Henderson }
1479740038d7SRichard Henderson 
1480740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1481c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
148286f8d05fSRichard Henderson                       unsigned sp, int modify)
148396d6407fSRichard Henderson {
148496d6407fSRichard Henderson     TCGv_i64 tmp;
148596d6407fSRichard Henderson 
148696d6407fSRichard Henderson     nullify_over(ctx);
148796d6407fSRichard Henderson 
148896d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
1489fc313c64SFrédéric Pétrot     do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
149096d6407fSRichard Henderson     save_frd(rt, tmp);
149196d6407fSRichard Henderson 
149296d6407fSRichard Henderson     if (rt == 0) {
1493ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
149496d6407fSRichard Henderson     }
149596d6407fSRichard Henderson 
1496740038d7SRichard Henderson     return nullify_end(ctx);
1497740038d7SRichard Henderson }
1498740038d7SRichard Henderson 
1499740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a)
1500740038d7SRichard Henderson {
1501740038d7SRichard Henderson     return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1502740038d7SRichard Henderson                      a->disp, a->sp, a->m);
150396d6407fSRichard Henderson }
150496d6407fSRichard Henderson 
15051cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb,
1506c53e401eSRichard Henderson                      int64_t disp, unsigned sp,
150714776ab5STony Nguyen                      int modify, MemOp mop)
150896d6407fSRichard Henderson {
150996d6407fSRichard Henderson     nullify_over(ctx);
1510*6fd0c7bcSRichard Henderson     do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
15111cd012a5SRichard Henderson     return nullify_end(ctx);
151296d6407fSRichard Henderson }
151396d6407fSRichard Henderson 
1514740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1515c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
151686f8d05fSRichard Henderson                        unsigned sp, int modify)
151796d6407fSRichard Henderson {
151896d6407fSRichard Henderson     TCGv_i32 tmp;
151996d6407fSRichard Henderson 
152096d6407fSRichard Henderson     nullify_over(ctx);
152196d6407fSRichard Henderson 
152296d6407fSRichard Henderson     tmp = load_frw_i32(rt);
152386f8d05fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
152496d6407fSRichard Henderson 
1525740038d7SRichard Henderson     return nullify_end(ctx);
152696d6407fSRichard Henderson }
152796d6407fSRichard Henderson 
1528740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a)
1529740038d7SRichard Henderson {
1530740038d7SRichard Henderson     return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1531740038d7SRichard Henderson                       a->disp, a->sp, a->m);
1532740038d7SRichard Henderson }
1533740038d7SRichard Henderson 
1534740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1535c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
153686f8d05fSRichard Henderson                        unsigned sp, int modify)
153796d6407fSRichard Henderson {
153896d6407fSRichard Henderson     TCGv_i64 tmp;
153996d6407fSRichard Henderson 
154096d6407fSRichard Henderson     nullify_over(ctx);
154196d6407fSRichard Henderson 
154296d6407fSRichard Henderson     tmp = load_frd(rt);
1543fc313c64SFrédéric Pétrot     do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
154496d6407fSRichard Henderson 
1545740038d7SRichard Henderson     return nullify_end(ctx);
1546740038d7SRichard Henderson }
1547740038d7SRichard Henderson 
1548740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a)
1549740038d7SRichard Henderson {
1550740038d7SRichard Henderson     return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1551740038d7SRichard Henderson                       a->disp, a->sp, a->m);
155296d6407fSRichard Henderson }
155396d6407fSRichard Henderson 
15541ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1555ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1556ebe9383cSRichard Henderson {
1557ebe9383cSRichard Henderson     TCGv_i32 tmp;
1558ebe9383cSRichard Henderson 
1559ebe9383cSRichard Henderson     nullify_over(ctx);
1560ebe9383cSRichard Henderson     tmp = load_frw0_i32(ra);
1561ebe9383cSRichard Henderson 
1562ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1563ebe9383cSRichard Henderson 
1564ebe9383cSRichard Henderson     save_frw_i32(rt, tmp);
15651ca74648SRichard Henderson     return nullify_end(ctx);
1566ebe9383cSRichard Henderson }
1567ebe9383cSRichard Henderson 
15681ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1569ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1570ebe9383cSRichard Henderson {
1571ebe9383cSRichard Henderson     TCGv_i32 dst;
1572ebe9383cSRichard Henderson     TCGv_i64 src;
1573ebe9383cSRichard Henderson 
1574ebe9383cSRichard Henderson     nullify_over(ctx);
1575ebe9383cSRichard Henderson     src = load_frd(ra);
1576ebe9383cSRichard Henderson     dst = tcg_temp_new_i32();
1577ebe9383cSRichard Henderson 
1578ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1579ebe9383cSRichard Henderson 
1580ebe9383cSRichard Henderson     save_frw_i32(rt, dst);
15811ca74648SRichard Henderson     return nullify_end(ctx);
1582ebe9383cSRichard Henderson }
1583ebe9383cSRichard Henderson 
15841ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1585ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1586ebe9383cSRichard Henderson {
1587ebe9383cSRichard Henderson     TCGv_i64 tmp;
1588ebe9383cSRichard Henderson 
1589ebe9383cSRichard Henderson     nullify_over(ctx);
1590ebe9383cSRichard Henderson     tmp = load_frd0(ra);
1591ebe9383cSRichard Henderson 
1592ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1593ebe9383cSRichard Henderson 
1594ebe9383cSRichard Henderson     save_frd(rt, tmp);
15951ca74648SRichard Henderson     return nullify_end(ctx);
1596ebe9383cSRichard Henderson }
1597ebe9383cSRichard Henderson 
15981ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1599ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1600ebe9383cSRichard Henderson {
1601ebe9383cSRichard Henderson     TCGv_i32 src;
1602ebe9383cSRichard Henderson     TCGv_i64 dst;
1603ebe9383cSRichard Henderson 
1604ebe9383cSRichard Henderson     nullify_over(ctx);
1605ebe9383cSRichard Henderson     src = load_frw0_i32(ra);
1606ebe9383cSRichard Henderson     dst = tcg_temp_new_i64();
1607ebe9383cSRichard Henderson 
1608ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1609ebe9383cSRichard Henderson 
1610ebe9383cSRichard Henderson     save_frd(rt, dst);
16111ca74648SRichard Henderson     return nullify_end(ctx);
1612ebe9383cSRichard Henderson }
1613ebe9383cSRichard Henderson 
16141ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt,
1615ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
161631234768SRichard Henderson                         void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
1617ebe9383cSRichard Henderson {
1618ebe9383cSRichard Henderson     TCGv_i32 a, b;
1619ebe9383cSRichard Henderson 
1620ebe9383cSRichard Henderson     nullify_over(ctx);
1621ebe9383cSRichard Henderson     a = load_frw0_i32(ra);
1622ebe9383cSRichard Henderson     b = load_frw0_i32(rb);
1623ebe9383cSRichard Henderson 
1624ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1625ebe9383cSRichard Henderson 
1626ebe9383cSRichard Henderson     save_frw_i32(rt, a);
16271ca74648SRichard Henderson     return nullify_end(ctx);
1628ebe9383cSRichard Henderson }
1629ebe9383cSRichard Henderson 
16301ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt,
1631ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
163231234768SRichard Henderson                         void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
1633ebe9383cSRichard Henderson {
1634ebe9383cSRichard Henderson     TCGv_i64 a, b;
1635ebe9383cSRichard Henderson 
1636ebe9383cSRichard Henderson     nullify_over(ctx);
1637ebe9383cSRichard Henderson     a = load_frd0(ra);
1638ebe9383cSRichard Henderson     b = load_frd0(rb);
1639ebe9383cSRichard Henderson 
1640ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1641ebe9383cSRichard Henderson 
1642ebe9383cSRichard Henderson     save_frd(rt, a);
16431ca74648SRichard Henderson     return nullify_end(ctx);
1644ebe9383cSRichard Henderson }
1645ebe9383cSRichard Henderson 
164698cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
164798cd9ca7SRichard Henderson    have already had nullification handled.  */
1648c53e401eSRichard Henderson static bool do_dbranch(DisasContext *ctx, uint64_t dest,
164998cd9ca7SRichard Henderson                        unsigned link, bool is_n)
165098cd9ca7SRichard Henderson {
165198cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
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         ctx->iaoq_n = dest;
165698cd9ca7SRichard Henderson         if (is_n) {
165798cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
165898cd9ca7SRichard Henderson         }
165998cd9ca7SRichard Henderson     } else {
166098cd9ca7SRichard Henderson         nullify_over(ctx);
166198cd9ca7SRichard Henderson 
166298cd9ca7SRichard Henderson         if (link != 0) {
1663741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
166498cd9ca7SRichard Henderson         }
166598cd9ca7SRichard Henderson 
166698cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
166798cd9ca7SRichard Henderson             nullify_set(ctx, 0);
166898cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, dest, dest + 4);
166998cd9ca7SRichard Henderson         } else {
167098cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
167198cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
167298cd9ca7SRichard Henderson         }
167398cd9ca7SRichard Henderson 
167431234768SRichard Henderson         nullify_end(ctx);
167598cd9ca7SRichard Henderson 
167698cd9ca7SRichard Henderson         nullify_set(ctx, 0);
167798cd9ca7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
167831234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
167998cd9ca7SRichard Henderson     }
168001afb7beSRichard Henderson     return true;
168198cd9ca7SRichard Henderson }
168298cd9ca7SRichard Henderson 
168398cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
168498cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
1685c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n,
168698cd9ca7SRichard Henderson                        DisasCond *cond)
168798cd9ca7SRichard Henderson {
1688c53e401eSRichard Henderson     uint64_t dest = iaoq_dest(ctx, disp);
168998cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
169098cd9ca7SRichard Henderson     TCGCond c = cond->c;
169198cd9ca7SRichard Henderson     bool n;
169298cd9ca7SRichard Henderson 
169398cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
169498cd9ca7SRichard Henderson 
169598cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
169698cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
169701afb7beSRichard Henderson         return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
169898cd9ca7SRichard Henderson     }
169998cd9ca7SRichard Henderson     if (c == TCG_COND_NEVER) {
170001afb7beSRichard Henderson         return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
170198cd9ca7SRichard Henderson     }
170298cd9ca7SRichard Henderson 
170398cd9ca7SRichard Henderson     taken = gen_new_label();
1704*6fd0c7bcSRichard Henderson     tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken);
170598cd9ca7SRichard Henderson     cond_free(cond);
170698cd9ca7SRichard Henderson 
170798cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
170898cd9ca7SRichard Henderson     n = is_n && disp < 0;
170998cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
171098cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1711a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
171298cd9ca7SRichard Henderson     } else {
171398cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
171498cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
171598cd9ca7SRichard Henderson             ctx->null_lab = NULL;
171698cd9ca7SRichard Henderson         }
171798cd9ca7SRichard Henderson         nullify_set(ctx, n);
1718c301f34eSRichard Henderson         if (ctx->iaoq_n == -1) {
1719c301f34eSRichard Henderson             /* The temporary iaoq_n_var died at the branch above.
1720c301f34eSRichard Henderson                Regenerate it here instead of saving it.  */
1721*6fd0c7bcSRichard Henderson             tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
1722c301f34eSRichard Henderson         }
1723a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
172498cd9ca7SRichard Henderson     }
172598cd9ca7SRichard Henderson 
172698cd9ca7SRichard Henderson     gen_set_label(taken);
172798cd9ca7SRichard Henderson 
172898cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
172998cd9ca7SRichard Henderson     n = is_n && disp >= 0;
173098cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
173198cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1732a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, dest, dest + 4);
173398cd9ca7SRichard Henderson     } else {
173498cd9ca7SRichard Henderson         nullify_set(ctx, n);
1735a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
173698cd9ca7SRichard Henderson     }
173798cd9ca7SRichard Henderson 
173898cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
173998cd9ca7SRichard Henderson     if (ctx->null_lab) {
174098cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
174198cd9ca7SRichard Henderson         ctx->null_lab = NULL;
174231234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
174398cd9ca7SRichard Henderson     } else {
174431234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
174598cd9ca7SRichard Henderson     }
174601afb7beSRichard Henderson     return true;
174798cd9ca7SRichard Henderson }
174898cd9ca7SRichard Henderson 
174998cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target.  This handles
175098cd9ca7SRichard Henderson    nullification of the branch itself.  */
1751*6fd0c7bcSRichard Henderson static bool do_ibranch(DisasContext *ctx, TCGv_i64 dest,
175298cd9ca7SRichard Henderson                        unsigned link, bool is_n)
175398cd9ca7SRichard Henderson {
1754*6fd0c7bcSRichard Henderson     TCGv_i64 a0, a1, next, tmp;
175598cd9ca7SRichard Henderson     TCGCond c;
175698cd9ca7SRichard Henderson 
175798cd9ca7SRichard Henderson     assert(ctx->null_lab == NULL);
175898cd9ca7SRichard Henderson 
175998cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
176098cd9ca7SRichard Henderson         if (link != 0) {
1761741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
176298cd9ca7SRichard Henderson         }
1763e12c6309SRichard Henderson         next = tcg_temp_new();
1764*6fd0c7bcSRichard Henderson         tcg_gen_mov_i64(next, dest);
176598cd9ca7SRichard Henderson         if (is_n) {
1766c301f34eSRichard Henderson             if (use_nullify_skip(ctx)) {
1767a0180973SRichard Henderson                 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, next);
1768*6fd0c7bcSRichard Henderson                 tcg_gen_addi_i64(next, next, 4);
1769a0180973SRichard Henderson                 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
1770c301f34eSRichard Henderson                 nullify_set(ctx, 0);
177131234768SRichard Henderson                 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
177201afb7beSRichard Henderson                 return true;
1773c301f34eSRichard Henderson             }
177498cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
177598cd9ca7SRichard Henderson         }
1776c301f34eSRichard Henderson         ctx->iaoq_n = -1;
1777c301f34eSRichard Henderson         ctx->iaoq_n_var = next;
177898cd9ca7SRichard Henderson     } else if (is_n && use_nullify_skip(ctx)) {
177998cd9ca7SRichard Henderson         /* The (conditional) branch, B, nullifies the next insn, N,
178098cd9ca7SRichard Henderson            and we're allowed to skip execution N (no single-step or
17814137cb83SRichard Henderson            tracepoint in effect).  Since the goto_ptr that we must use
178298cd9ca7SRichard Henderson            for the indirect branch consumes no special resources, we
178398cd9ca7SRichard Henderson            can (conditionally) skip B and continue execution.  */
178498cd9ca7SRichard Henderson         /* The use_nullify_skip test implies we have a known control path.  */
178598cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_b != -1);
178698cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_n != -1);
178798cd9ca7SRichard Henderson 
178898cd9ca7SRichard Henderson         /* We do have to handle the non-local temporary, DEST, before
178998cd9ca7SRichard Henderson            branching.  Since IOAQ_F is not really live at this point, we
179098cd9ca7SRichard Henderson            can simply store DEST optimistically.  Similarly with IAOQ_B.  */
1791a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, dest);
1792a0180973SRichard Henderson         next = tcg_temp_new();
1793*6fd0c7bcSRichard Henderson         tcg_gen_addi_i64(next, dest, 4);
1794a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
179598cd9ca7SRichard Henderson 
179698cd9ca7SRichard Henderson         nullify_over(ctx);
179798cd9ca7SRichard Henderson         if (link != 0) {
17989a91dd84SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
179998cd9ca7SRichard Henderson         }
18007f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
180101afb7beSRichard Henderson         return nullify_end(ctx);
180298cd9ca7SRichard Henderson     } else {
180398cd9ca7SRichard Henderson         c = ctx->null_cond.c;
180498cd9ca7SRichard Henderson         a0 = ctx->null_cond.a0;
180598cd9ca7SRichard Henderson         a1 = ctx->null_cond.a1;
180698cd9ca7SRichard Henderson 
180798cd9ca7SRichard Henderson         tmp = tcg_temp_new();
1808e12c6309SRichard Henderson         next = tcg_temp_new();
180998cd9ca7SRichard Henderson 
1810741322f4SRichard Henderson         copy_iaoq_entry(ctx, tmp, ctx->iaoq_n, ctx->iaoq_n_var);
1811*6fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(c, next, a0, a1, tmp, dest);
181298cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
181398cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
181498cd9ca7SRichard Henderson 
181598cd9ca7SRichard Henderson         if (link != 0) {
1816*6fd0c7bcSRichard Henderson             tcg_gen_movcond_i64(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
181798cd9ca7SRichard Henderson         }
181898cd9ca7SRichard Henderson 
181998cd9ca7SRichard Henderson         if (is_n) {
182098cd9ca7SRichard Henderson             /* The branch nullifies the next insn, which means the state of N
182198cd9ca7SRichard Henderson                after the branch is the inverse of the state of N that applied
182298cd9ca7SRichard Henderson                to the branch.  */
1823*6fd0c7bcSRichard Henderson             tcg_gen_setcond_i64(tcg_invert_cond(c), cpu_psw_n, a0, a1);
182498cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
182598cd9ca7SRichard Henderson             ctx->null_cond = cond_make_n();
182698cd9ca7SRichard Henderson             ctx->psw_n_nonzero = true;
182798cd9ca7SRichard Henderson         } else {
182898cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
182998cd9ca7SRichard Henderson         }
183098cd9ca7SRichard Henderson     }
183101afb7beSRichard Henderson     return true;
183298cd9ca7SRichard Henderson }
183398cd9ca7SRichard Henderson 
1834660eefe1SRichard Henderson /* Implement
1835660eefe1SRichard Henderson  *    if (IAOQ_Front{30..31} < GR[b]{30..31})
1836660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← GR[b]{30..31};
1837660eefe1SRichard Henderson  *    else
1838660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← IAOQ_Front{30..31};
1839660eefe1SRichard Henderson  * which keeps the privilege level from being increased.
1840660eefe1SRichard Henderson  */
1841*6fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset)
1842660eefe1SRichard Henderson {
1843*6fd0c7bcSRichard Henderson     TCGv_i64 dest;
1844660eefe1SRichard Henderson     switch (ctx->privilege) {
1845660eefe1SRichard Henderson     case 0:
1846660eefe1SRichard Henderson         /* Privilege 0 is maximum and is allowed to decrease.  */
1847660eefe1SRichard Henderson         return offset;
1848660eefe1SRichard Henderson     case 3:
1849993119feSRichard Henderson         /* Privilege 3 is minimum and is never allowed to increase.  */
1850e12c6309SRichard Henderson         dest = tcg_temp_new();
1851*6fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, offset, 3);
1852660eefe1SRichard Henderson         break;
1853660eefe1SRichard Henderson     default:
1854e12c6309SRichard Henderson         dest = tcg_temp_new();
1855*6fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, offset, -4);
1856*6fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, ctx->privilege);
1857*6fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(TCG_COND_GTU, dest, dest, offset, dest, offset);
1858660eefe1SRichard Henderson         break;
1859660eefe1SRichard Henderson     }
1860660eefe1SRichard Henderson     return dest;
1861660eefe1SRichard Henderson }
1862660eefe1SRichard Henderson 
1863ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
18647ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
18657ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
18667ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
18677ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
18687ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
18697ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
18707ad439dfSRichard Henderson    aforementioned BE.  */
187131234768SRichard Henderson static void do_page_zero(DisasContext *ctx)
18727ad439dfSRichard Henderson {
1873*6fd0c7bcSRichard Henderson     TCGv_i64 tmp;
1874a0180973SRichard Henderson 
18757ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
18767ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
18778b81968cSMichael Tokarev        next insn within the privileged page.  */
18787ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
18797ad439dfSRichard Henderson     case TCG_COND_NEVER:
18807ad439dfSRichard Henderson         break;
18817ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
1882*6fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, 0);
18837ad439dfSRichard Henderson         goto do_sigill;
18847ad439dfSRichard Henderson     default:
18857ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
18867ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
18877ad439dfSRichard Henderson         g_assert_not_reached();
18887ad439dfSRichard Henderson     }
18897ad439dfSRichard Henderson 
18907ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
18917ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
18927ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
18937ad439dfSRichard Henderson        under such conditions.  */
18947ad439dfSRichard Henderson     if (ctx->iaoq_b != ctx->iaoq_f + 4) {
18957ad439dfSRichard Henderson         goto do_sigill;
18967ad439dfSRichard Henderson     }
18977ad439dfSRichard Henderson 
1898ebd0e151SRichard Henderson     switch (ctx->iaoq_f & -4) {
18997ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
19002986721dSRichard Henderson         gen_excp_1(EXCP_IMP);
190131234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
190231234768SRichard Henderson         break;
19037ad439dfSRichard Henderson 
19047ad439dfSRichard Henderson     case 0xb0: /* LWS */
19057ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
190631234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
190731234768SRichard Henderson         break;
19087ad439dfSRichard Henderson 
19097ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
1910*6fd0c7bcSRichard Henderson         tcg_gen_st_i64(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27]));
1911a0180973SRichard Henderson         tmp = tcg_temp_new();
1912*6fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_gr[31], 3);
1913a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
1914*6fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, 4);
1915a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
191631234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
191731234768SRichard Henderson         break;
19187ad439dfSRichard Henderson 
19197ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
19207ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
192131234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
192231234768SRichard Henderson         break;
19237ad439dfSRichard Henderson 
19247ad439dfSRichard Henderson     default:
19257ad439dfSRichard Henderson     do_sigill:
19262986721dSRichard Henderson         gen_excp_1(EXCP_ILL);
192731234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
192831234768SRichard Henderson         break;
19297ad439dfSRichard Henderson     }
19307ad439dfSRichard Henderson }
1931ba1d0b44SRichard Henderson #endif
19327ad439dfSRichard Henderson 
1933deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a)
1934b2167459SRichard Henderson {
1935b2167459SRichard Henderson     cond_free(&ctx->null_cond);
193631234768SRichard Henderson     return true;
1937b2167459SRichard Henderson }
1938b2167459SRichard Henderson 
193940f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a)
194098a9cb79SRichard Henderson {
194131234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_BREAK);
194298a9cb79SRichard Henderson }
194398a9cb79SRichard Henderson 
1944e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a)
194598a9cb79SRichard Henderson {
194698a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
194798a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
194898a9cb79SRichard Henderson 
194998a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
195031234768SRichard Henderson     return true;
195198a9cb79SRichard Henderson }
195298a9cb79SRichard Henderson 
1953c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a)
195498a9cb79SRichard Henderson {
1955c603e14aSRichard Henderson     unsigned rt = a->t;
1956*6fd0c7bcSRichard Henderson     TCGv_i64 tmp = dest_gpr(ctx, rt);
1957*6fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tmp, ctx->iaoq_f);
195898a9cb79SRichard Henderson     save_gpr(ctx, rt, tmp);
195998a9cb79SRichard Henderson 
196098a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
196131234768SRichard Henderson     return true;
196298a9cb79SRichard Henderson }
196398a9cb79SRichard Henderson 
1964c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a)
196598a9cb79SRichard Henderson {
1966c603e14aSRichard Henderson     unsigned rt = a->t;
1967c603e14aSRichard Henderson     unsigned rs = a->sp;
196833423472SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
1969*6fd0c7bcSRichard Henderson     TCGv_i64 t1 = tcg_temp_new();
197098a9cb79SRichard Henderson 
197133423472SRichard Henderson     load_spr(ctx, t0, rs);
197233423472SRichard Henderson     tcg_gen_shri_i64(t0, t0, 32);
197333423472SRichard Henderson     tcg_gen_trunc_i64_reg(t1, t0);
197433423472SRichard Henderson 
197533423472SRichard Henderson     save_gpr(ctx, rt, t1);
197698a9cb79SRichard Henderson 
197798a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
197831234768SRichard Henderson     return true;
197998a9cb79SRichard Henderson }
198098a9cb79SRichard Henderson 
1981c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a)
198298a9cb79SRichard Henderson {
1983c603e14aSRichard Henderson     unsigned rt = a->t;
1984c603e14aSRichard Henderson     unsigned ctl = a->r;
1985*6fd0c7bcSRichard Henderson     TCGv_i64 tmp;
198698a9cb79SRichard Henderson 
198798a9cb79SRichard Henderson     switch (ctl) {
198835136a77SRichard Henderson     case CR_SAR:
1989c603e14aSRichard Henderson         if (a->e == 0) {
199098a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
199198a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
1992*6fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
199398a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
199435136a77SRichard Henderson             goto done;
199598a9cb79SRichard Henderson         }
199698a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
199735136a77SRichard Henderson         goto done;
199835136a77SRichard Henderson     case CR_IT: /* Interval Timer */
199935136a77SRichard Henderson         /* FIXME: Respect PSW_S bit.  */
200035136a77SRichard Henderson         nullify_over(ctx);
200198a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
2002dfd1b812SRichard Henderson         if (translator_io_start(&ctx->base)) {
200349c29d6cSRichard Henderson             gen_helper_read_interval_timer(tmp);
200431234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
200549c29d6cSRichard Henderson         } else {
200649c29d6cSRichard Henderson             gen_helper_read_interval_timer(tmp);
200749c29d6cSRichard Henderson         }
200898a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
200931234768SRichard Henderson         return nullify_end(ctx);
201098a9cb79SRichard Henderson     case 26:
201198a9cb79SRichard Henderson     case 27:
201298a9cb79SRichard Henderson         break;
201398a9cb79SRichard Henderson     default:
201498a9cb79SRichard Henderson         /* All other control registers are privileged.  */
201535136a77SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
201635136a77SRichard Henderson         break;
201798a9cb79SRichard Henderson     }
201898a9cb79SRichard Henderson 
2019e12c6309SRichard Henderson     tmp = tcg_temp_new();
2020*6fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
202135136a77SRichard Henderson     save_gpr(ctx, rt, tmp);
202235136a77SRichard Henderson 
202335136a77SRichard Henderson  done:
202498a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
202531234768SRichard Henderson     return true;
202698a9cb79SRichard Henderson }
202798a9cb79SRichard Henderson 
2028c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
202933423472SRichard Henderson {
2030c603e14aSRichard Henderson     unsigned rr = a->r;
2031c603e14aSRichard Henderson     unsigned rs = a->sp;
203233423472SRichard Henderson     TCGv_i64 t64;
203333423472SRichard Henderson 
203433423472SRichard Henderson     if (rs >= 5) {
203533423472SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
203633423472SRichard Henderson     }
203733423472SRichard Henderson     nullify_over(ctx);
203833423472SRichard Henderson 
203933423472SRichard Henderson     t64 = tcg_temp_new_i64();
204033423472SRichard Henderson     tcg_gen_extu_reg_i64(t64, load_gpr(ctx, rr));
204133423472SRichard Henderson     tcg_gen_shli_i64(t64, t64, 32);
204233423472SRichard Henderson 
204333423472SRichard Henderson     if (rs >= 4) {
2044ad75a51eSRichard Henderson         tcg_gen_st_i64(t64, tcg_env, offsetof(CPUHPPAState, sr[rs]));
2045494737b7SRichard Henderson         ctx->tb_flags &= ~TB_FLAG_SR_SAME;
204633423472SRichard Henderson     } else {
204733423472SRichard Henderson         tcg_gen_mov_i64(cpu_sr[rs], t64);
204833423472SRichard Henderson     }
204933423472SRichard Henderson 
205031234768SRichard Henderson     return nullify_end(ctx);
205133423472SRichard Henderson }
205233423472SRichard Henderson 
2053c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
205498a9cb79SRichard Henderson {
2055c603e14aSRichard Henderson     unsigned ctl = a->t;
2056*6fd0c7bcSRichard Henderson     TCGv_i64 reg;
2057*6fd0c7bcSRichard Henderson     TCGv_i64 tmp;
205898a9cb79SRichard Henderson 
205935136a77SRichard Henderson     if (ctl == CR_SAR) {
20604845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
206198a9cb79SRichard Henderson         tmp = tcg_temp_new();
2062*6fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31);
206398a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
206498a9cb79SRichard Henderson 
206598a9cb79SRichard Henderson         cond_free(&ctx->null_cond);
206631234768SRichard Henderson         return true;
206798a9cb79SRichard Henderson     }
206898a9cb79SRichard Henderson 
206935136a77SRichard Henderson     /* All other control registers are privileged or read-only.  */
207035136a77SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
207135136a77SRichard Henderson 
2072c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
207335136a77SRichard Henderson     nullify_over(ctx);
20744845f015SSven Schnelle     reg = load_gpr(ctx, a->r);
20754845f015SSven Schnelle 
207635136a77SRichard Henderson     switch (ctl) {
207735136a77SRichard Henderson     case CR_IT:
2078ad75a51eSRichard Henderson         gen_helper_write_interval_timer(tcg_env, reg);
207935136a77SRichard Henderson         break;
20804f5f2548SRichard Henderson     case CR_EIRR:
2081ad75a51eSRichard Henderson         gen_helper_write_eirr(tcg_env, reg);
20824f5f2548SRichard Henderson         break;
20834f5f2548SRichard Henderson     case CR_EIEM:
2084ad75a51eSRichard Henderson         gen_helper_write_eiem(tcg_env, reg);
208531234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
20864f5f2548SRichard Henderson         break;
20874f5f2548SRichard Henderson 
208835136a77SRichard Henderson     case CR_IIASQ:
208935136a77SRichard Henderson     case CR_IIAOQ:
209035136a77SRichard Henderson         /* FIXME: Respect PSW_Q bit */
209135136a77SRichard Henderson         /* The write advances the queue and stores to the back element.  */
2092e12c6309SRichard Henderson         tmp = tcg_temp_new();
2093*6fd0c7bcSRichard Henderson         tcg_gen_ld_i64(tmp, tcg_env,
209435136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
2095*6fd0c7bcSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
2096*6fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env,
209735136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
209835136a77SRichard Henderson         break;
209935136a77SRichard Henderson 
2100d5de20bdSSven Schnelle     case CR_PID1:
2101d5de20bdSSven Schnelle     case CR_PID2:
2102d5de20bdSSven Schnelle     case CR_PID3:
2103d5de20bdSSven Schnelle     case CR_PID4:
2104*6fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
2105d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY
2106ad75a51eSRichard Henderson         gen_helper_change_prot_id(tcg_env);
2107d5de20bdSSven Schnelle #endif
2108d5de20bdSSven Schnelle         break;
2109d5de20bdSSven Schnelle 
211035136a77SRichard Henderson     default:
2111*6fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
211235136a77SRichard Henderson         break;
211335136a77SRichard Henderson     }
211431234768SRichard Henderson     return nullify_end(ctx);
21154f5f2548SRichard Henderson #endif
211635136a77SRichard Henderson }
211735136a77SRichard Henderson 
2118c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
211998a9cb79SRichard Henderson {
2120*6fd0c7bcSRichard Henderson     TCGv_i64 tmp = tcg_temp_new();
212198a9cb79SRichard Henderson 
2122*6fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, load_gpr(ctx, a->r));
2123*6fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31);
212498a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
212598a9cb79SRichard Henderson 
212698a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
212731234768SRichard Henderson     return true;
212898a9cb79SRichard Henderson }
212998a9cb79SRichard Henderson 
2130e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a)
213198a9cb79SRichard Henderson {
2132*6fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
213398a9cb79SRichard Henderson 
21342330504cSHelge Deller #ifdef CONFIG_USER_ONLY
21352330504cSHelge Deller     /* We don't implement space registers in user mode. */
2136*6fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
21372330504cSHelge Deller #else
21382330504cSHelge Deller     TCGv_i64 t0 = tcg_temp_new_i64();
21392330504cSHelge Deller 
2140e36f27efSRichard Henderson     tcg_gen_mov_i64(t0, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
21412330504cSHelge Deller     tcg_gen_shri_i64(t0, t0, 32);
21422330504cSHelge Deller     tcg_gen_trunc_i64_reg(dest, t0);
21432330504cSHelge Deller #endif
2144e36f27efSRichard Henderson     save_gpr(ctx, a->t, dest);
214598a9cb79SRichard Henderson 
214698a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
214731234768SRichard Henderson     return true;
214898a9cb79SRichard Henderson }
214998a9cb79SRichard Henderson 
2150e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a)
2151e36f27efSRichard Henderson {
2152e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2153e1b5a5edSRichard Henderson #ifndef CONFIG_USER_ONLY
2154*6fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2155e1b5a5edSRichard Henderson 
2156e1b5a5edSRichard Henderson     nullify_over(ctx);
2157e1b5a5edSRichard Henderson 
2158e12c6309SRichard Henderson     tmp = tcg_temp_new();
2159*6fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
2160*6fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ~a->i);
2161ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2162e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2163e1b5a5edSRichard Henderson 
2164e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_M.  */
216531234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
216631234768SRichard Henderson     return nullify_end(ctx);
2167e36f27efSRichard Henderson #endif
2168e1b5a5edSRichard Henderson }
2169e1b5a5edSRichard Henderson 
2170e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
2171e1b5a5edSRichard Henderson {
2172e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2173e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
2174*6fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2175e1b5a5edSRichard Henderson 
2176e1b5a5edSRichard Henderson     nullify_over(ctx);
2177e1b5a5edSRichard Henderson 
2178e12c6309SRichard Henderson     tmp = tcg_temp_new();
2179*6fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
2180*6fd0c7bcSRichard Henderson     tcg_gen_ori_i64(tmp, tmp, a->i);
2181ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2182e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2183e1b5a5edSRichard Henderson 
2184e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_I.  */
218531234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
218631234768SRichard Henderson     return nullify_end(ctx);
2187e36f27efSRichard Henderson #endif
2188e1b5a5edSRichard Henderson }
2189e1b5a5edSRichard Henderson 
2190c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
2191e1b5a5edSRichard Henderson {
2192e1b5a5edSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2193c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
2194*6fd0c7bcSRichard Henderson     TCGv_i64 tmp, reg;
2195e1b5a5edSRichard Henderson     nullify_over(ctx);
2196e1b5a5edSRichard Henderson 
2197c603e14aSRichard Henderson     reg = load_gpr(ctx, a->r);
2198e12c6309SRichard Henderson     tmp = tcg_temp_new();
2199ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, reg);
2200e1b5a5edSRichard Henderson 
2201e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts.  */
220231234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
220331234768SRichard Henderson     return nullify_end(ctx);
2204c603e14aSRichard Henderson #endif
2205e1b5a5edSRichard Henderson }
2206f49b3537SRichard Henderson 
2207e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r)
2208f49b3537SRichard Henderson {
2209f49b3537SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2210e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
2211f49b3537SRichard Henderson     nullify_over(ctx);
2212f49b3537SRichard Henderson 
2213e36f27efSRichard Henderson     if (rfi_r) {
2214ad75a51eSRichard Henderson         gen_helper_rfi_r(tcg_env);
2215f49b3537SRichard Henderson     } else {
2216ad75a51eSRichard Henderson         gen_helper_rfi(tcg_env);
2217f49b3537SRichard Henderson     }
221831234768SRichard Henderson     /* Exit the TB to recognize new interrupts.  */
221907ea28b4SRichard Henderson     tcg_gen_exit_tb(NULL, 0);
222031234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
2221f49b3537SRichard Henderson 
222231234768SRichard Henderson     return nullify_end(ctx);
2223e36f27efSRichard Henderson #endif
2224f49b3537SRichard Henderson }
22256210db05SHelge Deller 
2226e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a)
2227e36f27efSRichard Henderson {
2228e36f27efSRichard Henderson     return do_rfi(ctx, false);
2229e36f27efSRichard Henderson }
2230e36f27efSRichard Henderson 
2231e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a)
2232e36f27efSRichard Henderson {
2233e36f27efSRichard Henderson     return do_rfi(ctx, true);
2234e36f27efSRichard Henderson }
2235e36f27efSRichard Henderson 
223696927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a)
22376210db05SHelge Deller {
22386210db05SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
223996927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
22406210db05SHelge Deller     nullify_over(ctx);
2241ad75a51eSRichard Henderson     gen_helper_halt(tcg_env);
224231234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
224331234768SRichard Henderson     return nullify_end(ctx);
224496927adbSRichard Henderson #endif
22456210db05SHelge Deller }
224696927adbSRichard Henderson 
224796927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a)
224896927adbSRichard Henderson {
224996927adbSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
225096927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
225196927adbSRichard Henderson     nullify_over(ctx);
2252ad75a51eSRichard Henderson     gen_helper_reset(tcg_env);
225396927adbSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
225496927adbSRichard Henderson     return nullify_end(ctx);
225596927adbSRichard Henderson #endif
225696927adbSRichard Henderson }
2257e1b5a5edSRichard Henderson 
22584a4554c6SHelge Deller static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
22594a4554c6SHelge Deller {
22604a4554c6SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
22614a4554c6SHelge Deller #ifndef CONFIG_USER_ONLY
22624a4554c6SHelge Deller     nullify_over(ctx);
2263ad75a51eSRichard Henderson     gen_helper_getshadowregs(tcg_env);
22644a4554c6SHelge Deller     return nullify_end(ctx);
22654a4554c6SHelge Deller #endif
22664a4554c6SHelge Deller }
22674a4554c6SHelge Deller 
2268deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
226998a9cb79SRichard Henderson {
2270deee69a1SRichard Henderson     if (a->m) {
2271*6fd0c7bcSRichard Henderson         TCGv_i64 dest = dest_gpr(ctx, a->b);
2272*6fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->b);
2273*6fd0c7bcSRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->x);
227498a9cb79SRichard Henderson 
227598a9cb79SRichard Henderson         /* The only thing we need to do is the base register modification.  */
2276*6fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, src1, src2);
2277deee69a1SRichard Henderson         save_gpr(ctx, a->b, dest);
2278deee69a1SRichard Henderson     }
227998a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
228031234768SRichard Henderson     return true;
228198a9cb79SRichard Henderson }
228298a9cb79SRichard Henderson 
2283deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a)
228498a9cb79SRichard Henderson {
2285*6fd0c7bcSRichard Henderson     TCGv_i64 dest, ofs;
2286eed14219SRichard Henderson     TCGv_i32 level, want;
2287*6fd0c7bcSRichard Henderson     TCGv_i64 addr;
228898a9cb79SRichard Henderson 
228998a9cb79SRichard Henderson     nullify_over(ctx);
229098a9cb79SRichard Henderson 
2291deee69a1SRichard Henderson     dest = dest_gpr(ctx, a->t);
2292deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2293eed14219SRichard Henderson 
2294deee69a1SRichard Henderson     if (a->imm) {
229529dd6f64SRichard Henderson         level = tcg_constant_i32(a->ri);
229698a9cb79SRichard Henderson     } else {
2297eed14219SRichard Henderson         level = tcg_temp_new_i32();
2298*6fd0c7bcSRichard Henderson         tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri));
2299eed14219SRichard Henderson         tcg_gen_andi_i32(level, level, 3);
230098a9cb79SRichard Henderson     }
230129dd6f64SRichard Henderson     want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ);
2302eed14219SRichard Henderson 
2303ad75a51eSRichard Henderson     gen_helper_probe(dest, tcg_env, addr, level, want);
2304eed14219SRichard Henderson 
2305deee69a1SRichard Henderson     save_gpr(ctx, a->t, dest);
230631234768SRichard Henderson     return nullify_end(ctx);
230798a9cb79SRichard Henderson }
230898a9cb79SRichard Henderson 
2309deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
23108d6ae7fbSRichard Henderson {
23118577f354SRichard Henderson     if (ctx->is_pa20) {
23128577f354SRichard Henderson         return false;
23138577f354SRichard Henderson     }
2314deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2315deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
2316*6fd0c7bcSRichard Henderson     TCGv_i64 addr;
2317*6fd0c7bcSRichard Henderson     TCGv_i64 ofs, reg;
23188d6ae7fbSRichard Henderson 
23198d6ae7fbSRichard Henderson     nullify_over(ctx);
23208d6ae7fbSRichard Henderson 
2321deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2322deee69a1SRichard Henderson     reg = load_gpr(ctx, a->r);
2323deee69a1SRichard Henderson     if (a->addr) {
23248577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
23258d6ae7fbSRichard Henderson     } else {
23268577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
23278d6ae7fbSRichard Henderson     }
23288d6ae7fbSRichard Henderson 
232932dc7569SSven Schnelle     /* Exit TB for TLB change if mmu is enabled.  */
233032dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
233131234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
233231234768SRichard Henderson     }
233331234768SRichard Henderson     return nullify_end(ctx);
2334deee69a1SRichard Henderson #endif
23358d6ae7fbSRichard Henderson }
233663300a00SRichard Henderson 
2337deee69a1SRichard Henderson static bool trans_pxtlbx(DisasContext *ctx, arg_pxtlbx *a)
233863300a00SRichard Henderson {
2339deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2340deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
2341*6fd0c7bcSRichard Henderson     TCGv_i64 addr;
2342*6fd0c7bcSRichard Henderson     TCGv_i64 ofs;
234363300a00SRichard Henderson 
234463300a00SRichard Henderson     nullify_over(ctx);
234563300a00SRichard Henderson 
2346deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2347deee69a1SRichard Henderson     if (a->m) {
2348deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
234963300a00SRichard Henderson     }
2350deee69a1SRichard Henderson     if (a->local) {
2351ad75a51eSRichard Henderson         gen_helper_ptlbe(tcg_env);
235263300a00SRichard Henderson     } else {
2353ad75a51eSRichard Henderson         gen_helper_ptlb(tcg_env, addr);
235463300a00SRichard Henderson     }
235563300a00SRichard Henderson 
235663300a00SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
235732dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
235831234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
235931234768SRichard Henderson     }
236031234768SRichard Henderson     return nullify_end(ctx);
2361deee69a1SRichard Henderson #endif
236263300a00SRichard Henderson }
23632dfcca9fSRichard Henderson 
23646797c315SNick Hudson /*
23656797c315SNick Hudson  * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
23666797c315SNick Hudson  * See
23676797c315SNick Hudson  *     https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
23686797c315SNick Hudson  *     page 13-9 (195/206)
23696797c315SNick Hudson  */
23706797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
23716797c315SNick Hudson {
23728577f354SRichard Henderson     if (ctx->is_pa20) {
23738577f354SRichard Henderson         return false;
23748577f354SRichard Henderson     }
23756797c315SNick Hudson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
23766797c315SNick Hudson #ifndef CONFIG_USER_ONLY
2377*6fd0c7bcSRichard Henderson     TCGv_i64 addr, atl, stl;
2378*6fd0c7bcSRichard Henderson     TCGv_i64 reg;
23796797c315SNick Hudson 
23806797c315SNick Hudson     nullify_over(ctx);
23816797c315SNick Hudson 
23826797c315SNick Hudson     /*
23836797c315SNick Hudson      * FIXME:
23846797c315SNick Hudson      *  if (not (pcxl or pcxl2))
23856797c315SNick Hudson      *    return gen_illegal(ctx);
23866797c315SNick Hudson      */
23876797c315SNick Hudson 
2388*6fd0c7bcSRichard Henderson     atl = tcg_temp_new_i64();
2389*6fd0c7bcSRichard Henderson     stl = tcg_temp_new_i64();
2390*6fd0c7bcSRichard Henderson     addr = tcg_temp_new_i64();
23916797c315SNick Hudson 
2392ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(stl, tcg_env,
23936797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
23946797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIASQ]));
2395ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(atl, tcg_env,
23966797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
23976797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIAOQ]));
23986797c315SNick Hudson     tcg_gen_shli_i64(stl, stl, 32);
23996797c315SNick Hudson     tcg_gen_or_tl(addr, atl, stl);
24006797c315SNick Hudson 
24016797c315SNick Hudson     reg = load_gpr(ctx, a->r);
24026797c315SNick Hudson     if (a->addr) {
24038577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
24046797c315SNick Hudson     } else {
24058577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
24066797c315SNick Hudson     }
24076797c315SNick Hudson 
24086797c315SNick Hudson     /* Exit TB for TLB change if mmu is enabled.  */
24096797c315SNick Hudson     if (ctx->tb_flags & PSW_C) {
24106797c315SNick Hudson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
24116797c315SNick Hudson     }
24126797c315SNick Hudson     return nullify_end(ctx);
24136797c315SNick Hudson #endif
24146797c315SNick Hudson }
24156797c315SNick Hudson 
24168577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
24178577f354SRichard Henderson {
24188577f354SRichard Henderson     if (!ctx->is_pa20) {
24198577f354SRichard Henderson         return false;
24208577f354SRichard Henderson     }
24218577f354SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24228577f354SRichard Henderson #ifndef CONFIG_USER_ONLY
24238577f354SRichard Henderson     nullify_over(ctx);
24248577f354SRichard Henderson     {
24258577f354SRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
24268577f354SRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->r2);
24278577f354SRichard Henderson 
24288577f354SRichard Henderson         if (a->data) {
24298577f354SRichard Henderson             gen_helper_idtlbt_pa20(tcg_env, src1, src2);
24308577f354SRichard Henderson         } else {
24318577f354SRichard Henderson             gen_helper_iitlbt_pa20(tcg_env, src1, src2);
24328577f354SRichard Henderson         }
24338577f354SRichard Henderson     }
24348577f354SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
24358577f354SRichard Henderson     if (ctx->tb_flags & PSW_C) {
24368577f354SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
24378577f354SRichard Henderson     }
24388577f354SRichard Henderson     return nullify_end(ctx);
24398577f354SRichard Henderson #endif
24408577f354SRichard Henderson }
24418577f354SRichard Henderson 
2442deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
24432dfcca9fSRichard Henderson {
2444deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2445deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
2446*6fd0c7bcSRichard Henderson     TCGv_i64 vaddr;
2447*6fd0c7bcSRichard Henderson     TCGv_i64 ofs, paddr;
24482dfcca9fSRichard Henderson 
24492dfcca9fSRichard Henderson     nullify_over(ctx);
24502dfcca9fSRichard Henderson 
2451deee69a1SRichard Henderson     form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
24522dfcca9fSRichard Henderson 
24532dfcca9fSRichard Henderson     paddr = tcg_temp_new();
2454ad75a51eSRichard Henderson     gen_helper_lpa(paddr, tcg_env, vaddr);
24552dfcca9fSRichard Henderson 
24562dfcca9fSRichard Henderson     /* Note that physical address result overrides base modification.  */
2457deee69a1SRichard Henderson     if (a->m) {
2458deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
24592dfcca9fSRichard Henderson     }
2460deee69a1SRichard Henderson     save_gpr(ctx, a->t, paddr);
24612dfcca9fSRichard Henderson 
246231234768SRichard Henderson     return nullify_end(ctx);
2463deee69a1SRichard Henderson #endif
24642dfcca9fSRichard Henderson }
246543a97b81SRichard Henderson 
2466deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a)
246743a97b81SRichard Henderson {
246843a97b81SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
246943a97b81SRichard Henderson 
247043a97b81SRichard Henderson     /* The Coherence Index is an implementation-defined function of the
247143a97b81SRichard Henderson        physical address.  Two addresses with the same CI have a coherent
247243a97b81SRichard Henderson        view of the cache.  Our implementation is to return 0 for all,
247343a97b81SRichard Henderson        since the entire address space is coherent.  */
2474*6fd0c7bcSRichard Henderson     save_gpr(ctx, a->t, tcg_constant_i64(0));
247543a97b81SRichard Henderson 
247631234768SRichard Henderson     cond_free(&ctx->null_cond);
247731234768SRichard Henderson     return true;
247843a97b81SRichard Henderson }
247998a9cb79SRichard Henderson 
2480faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2481b2167459SRichard Henderson {
24820c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, false);
2483b2167459SRichard Henderson }
2484b2167459SRichard Henderson 
2485faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2486b2167459SRichard Henderson {
24870c982a28SRichard Henderson     return do_add_reg(ctx, a, true, false, false, false);
2488b2167459SRichard Henderson }
2489b2167459SRichard Henderson 
2490faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2491b2167459SRichard Henderson {
24920c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, false);
2493b2167459SRichard Henderson }
2494b2167459SRichard Henderson 
2495faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2496b2167459SRichard Henderson {
24970c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, true);
24980c982a28SRichard Henderson }
2499b2167459SRichard Henderson 
2500faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
25010c982a28SRichard Henderson {
25020c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, true);
25030c982a28SRichard Henderson }
25040c982a28SRichard Henderson 
250563c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
25060c982a28SRichard Henderson {
25070c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, false);
25080c982a28SRichard Henderson }
25090c982a28SRichard Henderson 
251063c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
25110c982a28SRichard Henderson {
25120c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, false);
25130c982a28SRichard Henderson }
25140c982a28SRichard Henderson 
251563c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
25160c982a28SRichard Henderson {
25170c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, true);
25180c982a28SRichard Henderson }
25190c982a28SRichard Henderson 
252063c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
25210c982a28SRichard Henderson {
25220c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, true);
25230c982a28SRichard Henderson }
25240c982a28SRichard Henderson 
252563c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
25260c982a28SRichard Henderson {
25270c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, true, false);
25280c982a28SRichard Henderson }
25290c982a28SRichard Henderson 
253063c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
25310c982a28SRichard Henderson {
25320c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, true, false);
25330c982a28SRichard Henderson }
25340c982a28SRichard Henderson 
2535fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
25360c982a28SRichard Henderson {
2537*6fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_andc_i64);
25380c982a28SRichard Henderson }
25390c982a28SRichard Henderson 
2540fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
25410c982a28SRichard Henderson {
2542*6fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_and_i64);
25430c982a28SRichard Henderson }
25440c982a28SRichard Henderson 
2545fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
25460c982a28SRichard Henderson {
25470c982a28SRichard Henderson     if (a->cf == 0) {
25480c982a28SRichard Henderson         unsigned r2 = a->r2;
25490c982a28SRichard Henderson         unsigned r1 = a->r1;
25500c982a28SRichard Henderson         unsigned rt = a->t;
25510c982a28SRichard Henderson 
25527aee8189SRichard Henderson         if (rt == 0) { /* NOP */
25537aee8189SRichard Henderson             cond_free(&ctx->null_cond);
25547aee8189SRichard Henderson             return true;
25557aee8189SRichard Henderson         }
25567aee8189SRichard Henderson         if (r2 == 0) { /* COPY */
2557b2167459SRichard Henderson             if (r1 == 0) {
2558*6fd0c7bcSRichard Henderson                 TCGv_i64 dest = dest_gpr(ctx, rt);
2559*6fd0c7bcSRichard Henderson                 tcg_gen_movi_i64(dest, 0);
2560b2167459SRichard Henderson                 save_gpr(ctx, rt, dest);
2561b2167459SRichard Henderson             } else {
2562b2167459SRichard Henderson                 save_gpr(ctx, rt, cpu_gr[r1]);
2563b2167459SRichard Henderson             }
2564b2167459SRichard Henderson             cond_free(&ctx->null_cond);
256531234768SRichard Henderson             return true;
2566b2167459SRichard Henderson         }
25677aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY
25687aee8189SRichard Henderson         /* These are QEMU extensions and are nops in the real architecture:
25697aee8189SRichard Henderson          *
25707aee8189SRichard Henderson          * or %r10,%r10,%r10 -- idle loop; wait for interrupt
25717aee8189SRichard Henderson          * or %r31,%r31,%r31 -- death loop; offline cpu
25727aee8189SRichard Henderson          *                      currently implemented as idle.
25737aee8189SRichard Henderson          */
25747aee8189SRichard Henderson         if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
25757aee8189SRichard Henderson             /* No need to check for supervisor, as userland can only pause
25767aee8189SRichard Henderson                until the next timer interrupt.  */
25777aee8189SRichard Henderson             nullify_over(ctx);
25787aee8189SRichard Henderson 
25797aee8189SRichard Henderson             /* Advance the instruction queue.  */
2580741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
2581741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
25827aee8189SRichard Henderson             nullify_set(ctx, 0);
25837aee8189SRichard Henderson 
25847aee8189SRichard Henderson             /* Tell the qemu main loop to halt until this cpu has work.  */
2585ad75a51eSRichard Henderson             tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
258629dd6f64SRichard Henderson                            offsetof(CPUState, halted) - offsetof(HPPACPU, env));
25877aee8189SRichard Henderson             gen_excp_1(EXCP_HALTED);
25887aee8189SRichard Henderson             ctx->base.is_jmp = DISAS_NORETURN;
25897aee8189SRichard Henderson 
25907aee8189SRichard Henderson             return nullify_end(ctx);
25917aee8189SRichard Henderson         }
25927aee8189SRichard Henderson #endif
25937aee8189SRichard Henderson     }
2594*6fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_or_i64);
25957aee8189SRichard Henderson }
2596b2167459SRichard Henderson 
2597fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
2598b2167459SRichard Henderson {
2599*6fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_xor_i64);
26000c982a28SRichard Henderson }
26010c982a28SRichard Henderson 
2602345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
26030c982a28SRichard Henderson {
2604*6fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2605b2167459SRichard Henderson 
26060c982a28SRichard Henderson     if (a->cf) {
2607b2167459SRichard Henderson         nullify_over(ctx);
2608b2167459SRichard Henderson     }
26090c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26100c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2611345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
261231234768SRichard Henderson     return nullify_end(ctx);
2613b2167459SRichard Henderson }
2614b2167459SRichard Henderson 
2615af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
2616b2167459SRichard Henderson {
2617*6fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2618b2167459SRichard Henderson 
26190c982a28SRichard Henderson     if (a->cf) {
2620b2167459SRichard Henderson         nullify_over(ctx);
2621b2167459SRichard Henderson     }
26220c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26230c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2624*6fd0c7bcSRichard Henderson     do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64);
262531234768SRichard Henderson     return nullify_end(ctx);
2626b2167459SRichard Henderson }
2627b2167459SRichard Henderson 
2628af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
2629b2167459SRichard Henderson {
2630*6fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, tmp;
2631b2167459SRichard Henderson 
26320c982a28SRichard Henderson     if (a->cf) {
2633b2167459SRichard Henderson         nullify_over(ctx);
2634b2167459SRichard Henderson     }
26350c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26360c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2637e12c6309SRichard Henderson     tmp = tcg_temp_new();
2638*6fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, tcg_r2);
2639*6fd0c7bcSRichard Henderson     do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64);
264031234768SRichard Henderson     return nullify_end(ctx);
2641b2167459SRichard Henderson }
2642b2167459SRichard Henderson 
2643af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
2644b2167459SRichard Henderson {
26450c982a28SRichard Henderson     return do_uaddcm(ctx, a, false);
26460c982a28SRichard Henderson }
26470c982a28SRichard Henderson 
2648af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
26490c982a28SRichard Henderson {
26500c982a28SRichard Henderson     return do_uaddcm(ctx, a, true);
26510c982a28SRichard Henderson }
26520c982a28SRichard Henderson 
2653af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
26540c982a28SRichard Henderson {
2655*6fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2656b2167459SRichard Henderson 
2657b2167459SRichard Henderson     nullify_over(ctx);
2658b2167459SRichard Henderson 
2659e12c6309SRichard Henderson     tmp = tcg_temp_new();
2660*6fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, cpu_psw_cb, 3);
2661b2167459SRichard Henderson     if (!is_i) {
2662*6fd0c7bcSRichard Henderson         tcg_gen_not_i64(tmp, tmp);
2663b2167459SRichard Henderson     }
2664*6fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
2665*6fd0c7bcSRichard Henderson     tcg_gen_muli_i64(tmp, tmp, 6);
2666af240753SRichard Henderson     do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false,
2667*6fd0c7bcSRichard Henderson             is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64);
266831234768SRichard Henderson     return nullify_end(ctx);
2669b2167459SRichard Henderson }
2670b2167459SRichard Henderson 
2671af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
2672b2167459SRichard Henderson {
26730c982a28SRichard Henderson     return do_dcor(ctx, a, false);
26740c982a28SRichard Henderson }
26750c982a28SRichard Henderson 
2676af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
26770c982a28SRichard Henderson {
26780c982a28SRichard Henderson     return do_dcor(ctx, a, true);
26790c982a28SRichard Henderson }
26800c982a28SRichard Henderson 
26810c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
26820c982a28SRichard Henderson {
2683*6fd0c7bcSRichard Henderson     TCGv_i64 dest, add1, add2, addc, zero, in1, in2;
2684*6fd0c7bcSRichard Henderson     TCGv_i64 cout;
2685b2167459SRichard Henderson 
2686b2167459SRichard Henderson     nullify_over(ctx);
2687b2167459SRichard Henderson 
26880c982a28SRichard Henderson     in1 = load_gpr(ctx, a->r1);
26890c982a28SRichard Henderson     in2 = load_gpr(ctx, a->r2);
2690b2167459SRichard Henderson 
2691b2167459SRichard Henderson     add1 = tcg_temp_new();
2692b2167459SRichard Henderson     add2 = tcg_temp_new();
2693b2167459SRichard Henderson     addc = tcg_temp_new();
2694b2167459SRichard Henderson     dest = tcg_temp_new();
2695*6fd0c7bcSRichard Henderson     zero = tcg_constant_i64(0);
2696b2167459SRichard Henderson 
2697b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
2698*6fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, in1, in1);
2699*6fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
2700b2167459SRichard Henderson 
270172ca8753SRichard Henderson     /*
270272ca8753SRichard Henderson      * Add or subtract R2, depending on PSW[V].  Proper computation of
270372ca8753SRichard Henderson      * carry requires that we subtract via + ~R2 + 1, as described in
270472ca8753SRichard Henderson      * the manual.  By extracting and masking V, we can produce the
270572ca8753SRichard Henderson      * proper inputs to the addition without movcond.
270672ca8753SRichard Henderson      */
2707*6fd0c7bcSRichard Henderson     tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
2708*6fd0c7bcSRichard Henderson     tcg_gen_xor_i64(add2, in2, addc);
2709*6fd0c7bcSRichard Henderson     tcg_gen_andi_i64(addc, addc, 1);
271072ca8753SRichard Henderson 
2711*6fd0c7bcSRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
2712*6fd0c7bcSRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
2713b2167459SRichard Henderson 
2714b2167459SRichard Henderson     /* Write back the result register.  */
27150c982a28SRichard Henderson     save_gpr(ctx, a->t, dest);
2716b2167459SRichard Henderson 
2717b2167459SRichard Henderson     /* Write back PSW[CB].  */
2718*6fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
2719*6fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
2720b2167459SRichard Henderson 
2721b2167459SRichard Henderson     /* Write back PSW[V] for the division step.  */
272272ca8753SRichard Henderson     cout = get_psw_carry(ctx, false);
2723*6fd0c7bcSRichard Henderson     tcg_gen_neg_i64(cpu_psw_v, cout);
2724*6fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
2725b2167459SRichard Henderson 
2726b2167459SRichard Henderson     /* Install the new nullification.  */
27270c982a28SRichard Henderson     if (a->cf) {
2728*6fd0c7bcSRichard Henderson         TCGv_i64 sv = NULL;
2729b47a4a02SSven Schnelle         if (cond_need_sv(a->cf >> 1)) {
2730b2167459SRichard Henderson             /* ??? The lshift is supposed to contribute to overflow.  */
2731b2167459SRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2);
2732b2167459SRichard Henderson         }
2733a751eb31SRichard Henderson         ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv);
2734b2167459SRichard Henderson     }
2735b2167459SRichard Henderson 
273631234768SRichard Henderson     return nullify_end(ctx);
2737b2167459SRichard Henderson }
2738b2167459SRichard Henderson 
27390588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a)
2740b2167459SRichard Henderson {
27410588e061SRichard Henderson     return do_add_imm(ctx, a, false, false);
27420588e061SRichard Henderson }
27430588e061SRichard Henderson 
27440588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a)
27450588e061SRichard Henderson {
27460588e061SRichard Henderson     return do_add_imm(ctx, a, true, false);
27470588e061SRichard Henderson }
27480588e061SRichard Henderson 
27490588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a)
27500588e061SRichard Henderson {
27510588e061SRichard Henderson     return do_add_imm(ctx, a, false, true);
27520588e061SRichard Henderson }
27530588e061SRichard Henderson 
27540588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a)
27550588e061SRichard Henderson {
27560588e061SRichard Henderson     return do_add_imm(ctx, a, true, true);
27570588e061SRichard Henderson }
27580588e061SRichard Henderson 
27590588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a)
27600588e061SRichard Henderson {
27610588e061SRichard Henderson     return do_sub_imm(ctx, a, false);
27620588e061SRichard Henderson }
27630588e061SRichard Henderson 
27640588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
27650588e061SRichard Henderson {
27660588e061SRichard Henderson     return do_sub_imm(ctx, a, true);
27670588e061SRichard Henderson }
27680588e061SRichard Henderson 
2769345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
27700588e061SRichard Henderson {
2771*6fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
2772b2167459SRichard Henderson 
27730588e061SRichard Henderson     if (a->cf) {
2774b2167459SRichard Henderson         nullify_over(ctx);
2775b2167459SRichard Henderson     }
2776b2167459SRichard Henderson 
2777*6fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
27780588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
2779345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
2780b2167459SRichard Henderson 
278131234768SRichard Henderson     return nullify_end(ctx);
2782b2167459SRichard Henderson }
2783b2167459SRichard Henderson 
27841cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a)
278596d6407fSRichard Henderson {
2786c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
27870786a3b6SHelge Deller         return gen_illegal(ctx);
2788c53e401eSRichard Henderson     }
27891cd012a5SRichard Henderson     return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
27901cd012a5SRichard Henderson                    a->disp, a->sp, a->m, a->size | MO_TE);
279196d6407fSRichard Henderson }
279296d6407fSRichard Henderson 
27931cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a)
279496d6407fSRichard Henderson {
27951cd012a5SRichard Henderson     assert(a->x == 0 && a->scale == 0);
2796c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
27970786a3b6SHelge Deller         return gen_illegal(ctx);
279896d6407fSRichard Henderson     }
2799c53e401eSRichard Henderson     return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
28000786a3b6SHelge Deller }
280196d6407fSRichard Henderson 
28021cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
280396d6407fSRichard Henderson {
2804b1af755cSRichard Henderson     MemOp mop = MO_TE | MO_ALIGN | a->size;
2805*6fd0c7bcSRichard Henderson     TCGv_i64 zero, dest, ofs;
2806*6fd0c7bcSRichard Henderson     TCGv_i64 addr;
280796d6407fSRichard Henderson 
2808c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
280951416c4eSRichard Henderson         return gen_illegal(ctx);
281051416c4eSRichard Henderson     }
281151416c4eSRichard Henderson 
281296d6407fSRichard Henderson     nullify_over(ctx);
281396d6407fSRichard Henderson 
28141cd012a5SRichard Henderson     if (a->m) {
281586f8d05fSRichard Henderson         /* Base register modification.  Make sure if RT == RB,
281686f8d05fSRichard Henderson            we see the result of the load.  */
2817e12c6309SRichard Henderson         dest = tcg_temp_new();
281896d6407fSRichard Henderson     } else {
28191cd012a5SRichard Henderson         dest = dest_gpr(ctx, a->t);
282096d6407fSRichard Henderson     }
282196d6407fSRichard Henderson 
28221cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0,
28231cd012a5SRichard Henderson              a->disp, a->sp, a->m, ctx->mmu_idx == MMU_PHYS_IDX);
2824b1af755cSRichard Henderson 
2825b1af755cSRichard Henderson     /*
2826b1af755cSRichard Henderson      * For hppa1.1, LDCW is undefined unless aligned mod 16.
2827b1af755cSRichard Henderson      * However actual hardware succeeds with aligned mod 4.
2828b1af755cSRichard Henderson      * Detect this case and log a GUEST_ERROR.
2829b1af755cSRichard Henderson      *
2830b1af755cSRichard Henderson      * TODO: HPPA64 relaxes the over-alignment requirement
2831b1af755cSRichard Henderson      * with the ,co completer.
2832b1af755cSRichard Henderson      */
2833b1af755cSRichard Henderson     gen_helper_ldc_check(addr);
2834b1af755cSRichard Henderson 
2835*6fd0c7bcSRichard Henderson     zero = tcg_constant_i64(0);
2836*6fd0c7bcSRichard Henderson     tcg_gen_atomic_xchg_i64(dest, addr, zero, ctx->mmu_idx, mop);
2837b1af755cSRichard Henderson 
28381cd012a5SRichard Henderson     if (a->m) {
28391cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
284096d6407fSRichard Henderson     }
28411cd012a5SRichard Henderson     save_gpr(ctx, a->t, dest);
284296d6407fSRichard Henderson 
284331234768SRichard Henderson     return nullify_end(ctx);
284496d6407fSRichard Henderson }
284596d6407fSRichard Henderson 
28461cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a)
284796d6407fSRichard Henderson {
2848*6fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
2849*6fd0c7bcSRichard Henderson     TCGv_i64 addr;
285096d6407fSRichard Henderson 
285196d6407fSRichard Henderson     nullify_over(ctx);
285296d6407fSRichard Henderson 
28531cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
285486f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
28551cd012a5SRichard Henderson     val = load_gpr(ctx, a->r);
28561cd012a5SRichard Henderson     if (a->a) {
2857f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
2858ad75a51eSRichard Henderson             gen_helper_stby_e_parallel(tcg_env, addr, val);
2859f9f46db4SEmilio G. Cota         } else {
2860ad75a51eSRichard Henderson             gen_helper_stby_e(tcg_env, addr, val);
2861f9f46db4SEmilio G. Cota         }
2862f9f46db4SEmilio G. Cota     } else {
2863f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
2864ad75a51eSRichard Henderson             gen_helper_stby_b_parallel(tcg_env, addr, val);
286596d6407fSRichard Henderson         } else {
2866ad75a51eSRichard Henderson             gen_helper_stby_b(tcg_env, addr, val);
286796d6407fSRichard Henderson         }
2868f9f46db4SEmilio G. Cota     }
28691cd012a5SRichard Henderson     if (a->m) {
2870*6fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~3);
28711cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
287296d6407fSRichard Henderson     }
287396d6407fSRichard Henderson 
287431234768SRichard Henderson     return nullify_end(ctx);
287596d6407fSRichard Henderson }
287696d6407fSRichard Henderson 
287725460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a)
287825460fc5SRichard Henderson {
2879*6fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
2880*6fd0c7bcSRichard Henderson     TCGv_i64 addr;
288125460fc5SRichard Henderson 
288225460fc5SRichard Henderson     if (!ctx->is_pa20) {
288325460fc5SRichard Henderson         return false;
288425460fc5SRichard Henderson     }
288525460fc5SRichard Henderson     nullify_over(ctx);
288625460fc5SRichard Henderson 
288725460fc5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
288825460fc5SRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
288925460fc5SRichard Henderson     val = load_gpr(ctx, a->r);
289025460fc5SRichard Henderson     if (a->a) {
289125460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
289225460fc5SRichard Henderson             gen_helper_stdby_e_parallel(tcg_env, addr, val);
289325460fc5SRichard Henderson         } else {
289425460fc5SRichard Henderson             gen_helper_stdby_e(tcg_env, addr, val);
289525460fc5SRichard Henderson         }
289625460fc5SRichard Henderson     } else {
289725460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
289825460fc5SRichard Henderson             gen_helper_stdby_b_parallel(tcg_env, addr, val);
289925460fc5SRichard Henderson         } else {
290025460fc5SRichard Henderson             gen_helper_stdby_b(tcg_env, addr, val);
290125460fc5SRichard Henderson         }
290225460fc5SRichard Henderson     }
290325460fc5SRichard Henderson     if (a->m) {
2904*6fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~7);
290525460fc5SRichard Henderson         save_gpr(ctx, a->b, ofs);
290625460fc5SRichard Henderson     }
290725460fc5SRichard Henderson 
290825460fc5SRichard Henderson     return nullify_end(ctx);
290925460fc5SRichard Henderson }
291025460fc5SRichard Henderson 
29111cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a)
2912d0a851ccSRichard Henderson {
2913d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
2914d0a851ccSRichard Henderson 
2915d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2916d0a851ccSRichard Henderson     ctx->mmu_idx = MMU_PHYS_IDX;
29171cd012a5SRichard Henderson     trans_ld(ctx, a);
2918d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
291931234768SRichard Henderson     return true;
2920d0a851ccSRichard Henderson }
2921d0a851ccSRichard Henderson 
29221cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a)
2923d0a851ccSRichard Henderson {
2924d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
2925d0a851ccSRichard Henderson 
2926d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2927d0a851ccSRichard Henderson     ctx->mmu_idx = MMU_PHYS_IDX;
29281cd012a5SRichard Henderson     trans_st(ctx, a);
2929d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
293031234768SRichard Henderson     return true;
2931d0a851ccSRichard Henderson }
293295412a61SRichard Henderson 
29330588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
2934b2167459SRichard Henderson {
2935*6fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
2936b2167459SRichard Henderson 
2937*6fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tcg_rt, a->i);
29380588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
2939b2167459SRichard Henderson     cond_free(&ctx->null_cond);
294031234768SRichard Henderson     return true;
2941b2167459SRichard Henderson }
2942b2167459SRichard Henderson 
29430588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a)
2944b2167459SRichard Henderson {
2945*6fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
2946*6fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
2947b2167459SRichard Henderson 
2948*6fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
2949b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
2950b2167459SRichard Henderson     cond_free(&ctx->null_cond);
295131234768SRichard Henderson     return true;
2952b2167459SRichard Henderson }
2953b2167459SRichard Henderson 
29540588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
2955b2167459SRichard Henderson {
2956*6fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
2957b2167459SRichard Henderson 
2958b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
2959b2167459SRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_tl.  */
29600588e061SRichard Henderson     if (a->b == 0) {
2961*6fd0c7bcSRichard Henderson         tcg_gen_movi_i64(tcg_rt, a->i);
2962b2167459SRichard Henderson     } else {
2963*6fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
2964b2167459SRichard Henderson     }
29650588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
2966b2167459SRichard Henderson     cond_free(&ctx->null_cond);
296731234768SRichard Henderson     return true;
2968b2167459SRichard Henderson }
2969b2167459SRichard Henderson 
2970*6fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
2971e9efd4bcSRichard Henderson                     unsigned c, unsigned f, bool d, unsigned n, int disp)
297298cd9ca7SRichard Henderson {
2973*6fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv;
297498cd9ca7SRichard Henderson     DisasCond cond;
297598cd9ca7SRichard Henderson 
297698cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
2977e12c6309SRichard Henderson     dest = tcg_temp_new();
297898cd9ca7SRichard Henderson 
2979*6fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
298098cd9ca7SRichard Henderson 
2981f764718dSRichard Henderson     sv = NULL;
2982b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
298398cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
298498cd9ca7SRichard Henderson     }
298598cd9ca7SRichard Henderson 
29864fe9533aSRichard Henderson     cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
298701afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
298898cd9ca7SRichard Henderson }
298998cd9ca7SRichard Henderson 
299001afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
299198cd9ca7SRichard Henderson {
2992e9efd4bcSRichard Henderson     if (!ctx->is_pa20 && a->d) {
2993e9efd4bcSRichard Henderson         return false;
2994e9efd4bcSRichard Henderson     }
299501afb7beSRichard Henderson     nullify_over(ctx);
2996e9efd4bcSRichard Henderson     return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
2997e9efd4bcSRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
299801afb7beSRichard Henderson }
299901afb7beSRichard Henderson 
300001afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
300101afb7beSRichard Henderson {
3002c65c3ee1SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3003c65c3ee1SRichard Henderson         return false;
3004c65c3ee1SRichard Henderson     }
300501afb7beSRichard Henderson     nullify_over(ctx);
3006*6fd0c7bcSRichard Henderson     return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
3007c65c3ee1SRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
300801afb7beSRichard Henderson }
300901afb7beSRichard Henderson 
3010*6fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
301101afb7beSRichard Henderson                     unsigned c, unsigned f, unsigned n, int disp)
301201afb7beSRichard Henderson {
3013*6fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv, cb_cond;
301498cd9ca7SRichard Henderson     DisasCond cond;
3015bdcccc17SRichard Henderson     bool d = false;
301698cd9ca7SRichard Henderson 
3017f25d3160SRichard Henderson     /*
3018f25d3160SRichard Henderson      * For hppa64, the ADDB conditions change with PSW.W,
3019f25d3160SRichard Henderson      * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3020f25d3160SRichard Henderson      */
3021f25d3160SRichard Henderson     if (ctx->tb_flags & PSW_W) {
3022f25d3160SRichard Henderson         d = c >= 5;
3023f25d3160SRichard Henderson         if (d) {
3024f25d3160SRichard Henderson             c &= 3;
3025f25d3160SRichard Henderson         }
3026f25d3160SRichard Henderson     }
3027f25d3160SRichard Henderson 
302898cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
302943675d20SSven Schnelle     dest = tcg_temp_new();
3030f764718dSRichard Henderson     sv = NULL;
3031bdcccc17SRichard Henderson     cb_cond = NULL;
303298cd9ca7SRichard Henderson 
3033b47a4a02SSven Schnelle     if (cond_need_cb(c)) {
3034*6fd0c7bcSRichard Henderson         TCGv_i64 cb = tcg_temp_new();
3035*6fd0c7bcSRichard Henderson         TCGv_i64 cb_msb = tcg_temp_new();
3036bdcccc17SRichard Henderson 
3037*6fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cb_msb, 0);
3038*6fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
3039*6fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
3040*6fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
3041bdcccc17SRichard Henderson         cb_cond = get_carry(ctx, d, cb, cb_msb);
3042b47a4a02SSven Schnelle     } else {
3043*6fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
3044b47a4a02SSven Schnelle     }
3045b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
304698cd9ca7SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
304798cd9ca7SRichard Henderson     }
304898cd9ca7SRichard Henderson 
3049a751eb31SRichard Henderson     cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
305043675d20SSven Schnelle     save_gpr(ctx, r, dest);
305101afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
305298cd9ca7SRichard Henderson }
305398cd9ca7SRichard Henderson 
305401afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a)
305598cd9ca7SRichard Henderson {
305601afb7beSRichard Henderson     nullify_over(ctx);
305701afb7beSRichard Henderson     return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
305801afb7beSRichard Henderson }
305901afb7beSRichard Henderson 
306001afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
306101afb7beSRichard Henderson {
306201afb7beSRichard Henderson     nullify_over(ctx);
3063*6fd0c7bcSRichard Henderson     return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
306401afb7beSRichard Henderson }
306501afb7beSRichard Henderson 
306601afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
306701afb7beSRichard Henderson {
3068*6fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
306998cd9ca7SRichard Henderson     DisasCond cond;
307098cd9ca7SRichard Henderson 
307198cd9ca7SRichard Henderson     nullify_over(ctx);
307298cd9ca7SRichard Henderson 
307398cd9ca7SRichard Henderson     tmp = tcg_temp_new();
307401afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
307584e224d4SRichard Henderson     if (cond_need_ext(ctx, a->d)) {
30761e9ab9fbSRichard Henderson         /* Force shift into [32,63] */
3077*6fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_sar, 32);
3078*6fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, tmp);
30791e9ab9fbSRichard Henderson     } else {
3080*6fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
30811e9ab9fbSRichard Henderson     }
308298cd9ca7SRichard Henderson 
30831e9ab9fbSRichard Henderson     cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
308401afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
308598cd9ca7SRichard Henderson }
308698cd9ca7SRichard Henderson 
308701afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
308898cd9ca7SRichard Henderson {
3089*6fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
309001afb7beSRichard Henderson     DisasCond cond;
30911e9ab9fbSRichard Henderson     int p;
309201afb7beSRichard Henderson 
309301afb7beSRichard Henderson     nullify_over(ctx);
309401afb7beSRichard Henderson 
309501afb7beSRichard Henderson     tmp = tcg_temp_new();
309601afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
309784e224d4SRichard Henderson     p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0);
3098*6fd0c7bcSRichard Henderson     tcg_gen_shli_i64(tmp, tcg_r, p);
309901afb7beSRichard Henderson 
310001afb7beSRichard Henderson     cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
310101afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
310201afb7beSRichard Henderson }
310301afb7beSRichard Henderson 
310401afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a)
310501afb7beSRichard Henderson {
3106*6fd0c7bcSRichard Henderson     TCGv_i64 dest;
310798cd9ca7SRichard Henderson     DisasCond cond;
310898cd9ca7SRichard Henderson 
310998cd9ca7SRichard Henderson     nullify_over(ctx);
311098cd9ca7SRichard Henderson 
311101afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r2);
311201afb7beSRichard Henderson     if (a->r1 == 0) {
3113*6fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, 0);
311498cd9ca7SRichard Henderson     } else {
3115*6fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
311698cd9ca7SRichard Henderson     }
311798cd9ca7SRichard Henderson 
31184fa52edfSRichard Henderson     /* All MOVB conditions are 32-bit. */
31194fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
312001afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
312101afb7beSRichard Henderson }
312201afb7beSRichard Henderson 
312301afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
312401afb7beSRichard Henderson {
3125*6fd0c7bcSRichard Henderson     TCGv_i64 dest;
312601afb7beSRichard Henderson     DisasCond cond;
312701afb7beSRichard Henderson 
312801afb7beSRichard Henderson     nullify_over(ctx);
312901afb7beSRichard Henderson 
313001afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r);
3131*6fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, a->i);
313201afb7beSRichard Henderson 
31334fa52edfSRichard Henderson     /* All MOVBI conditions are 32-bit. */
31344fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
313501afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
313698cd9ca7SRichard Henderson }
313798cd9ca7SRichard Henderson 
3138f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
31390b1347d2SRichard Henderson {
3140*6fd0c7bcSRichard Henderson     TCGv_i64 dest, src2;
31410b1347d2SRichard Henderson 
3142f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3143f7b775a9SRichard Henderson         return false;
3144f7b775a9SRichard Henderson     }
314530878590SRichard Henderson     if (a->c) {
31460b1347d2SRichard Henderson         nullify_over(ctx);
31470b1347d2SRichard Henderson     }
31480b1347d2SRichard Henderson 
314930878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
3150f7b775a9SRichard Henderson     src2 = load_gpr(ctx, a->r2);
315130878590SRichard Henderson     if (a->r1 == 0) {
3152f7b775a9SRichard Henderson         if (a->d) {
3153*6fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src2, cpu_sar);
3154f7b775a9SRichard Henderson         } else {
3155*6fd0c7bcSRichard Henderson             TCGv_i64 tmp = tcg_temp_new();
3156f7b775a9SRichard Henderson 
3157*6fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src2);
3158*6fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
3159*6fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, dest, tmp);
3160f7b775a9SRichard Henderson         }
316130878590SRichard Henderson     } else if (a->r1 == a->r2) {
3162f7b775a9SRichard Henderson         if (a->d) {
3163*6fd0c7bcSRichard Henderson             tcg_gen_rotr_i64(dest, src2, cpu_sar);
3164f7b775a9SRichard Henderson         } else {
31650b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
3166e1d635e8SRichard Henderson             TCGv_i32 s32 = tcg_temp_new_i32();
3167e1d635e8SRichard Henderson 
3168*6fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, src2);
3169*6fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(s32, cpu_sar);
3170f7b775a9SRichard Henderson             tcg_gen_andi_i32(s32, s32, 31);
3171e1d635e8SRichard Henderson             tcg_gen_rotr_i32(t32, t32, s32);
3172*6fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
3173f7b775a9SRichard Henderson         }
3174f7b775a9SRichard Henderson     } else {
3175*6fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
3176f7b775a9SRichard Henderson 
3177f7b775a9SRichard Henderson         if (a->d) {
3178*6fd0c7bcSRichard Henderson             TCGv_i64 t = tcg_temp_new();
3179*6fd0c7bcSRichard Henderson             TCGv_i64 n = tcg_temp_new();
3180f7b775a9SRichard Henderson 
3181*6fd0c7bcSRichard Henderson             tcg_gen_xori_i64(n, cpu_sar, 63);
3182*6fd0c7bcSRichard Henderson             tcg_gen_shl_i64(t, src2, n);
3183*6fd0c7bcSRichard Henderson             tcg_gen_shli_i64(t, t, 1);
3184*6fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src1, cpu_sar);
3185*6fd0c7bcSRichard Henderson             tcg_gen_or_i64(dest, dest, t);
31860b1347d2SRichard Henderson         } else {
31870b1347d2SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
31880b1347d2SRichard Henderson             TCGv_i64 s = tcg_temp_new_i64();
31890b1347d2SRichard Henderson 
3190*6fd0c7bcSRichard Henderson             tcg_gen_concat32_i64(t, src2, src1);
3191eaa3783bSRichard Henderson             tcg_gen_extu_reg_i64(s, cpu_sar);
3192f7b775a9SRichard Henderson             tcg_gen_andi_i64(s, s, 31);
31930b1347d2SRichard Henderson             tcg_gen_shr_i64(t, t, s);
3194eaa3783bSRichard Henderson             tcg_gen_trunc_i64_reg(dest, t);
31950b1347d2SRichard Henderson         }
3196f7b775a9SRichard Henderson     }
319730878590SRichard Henderson     save_gpr(ctx, a->t, dest);
31980b1347d2SRichard Henderson 
31990b1347d2SRichard Henderson     /* Install the new nullification.  */
32000b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
320130878590SRichard Henderson     if (a->c) {
32024fa52edfSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
32030b1347d2SRichard Henderson     }
320431234768SRichard Henderson     return nullify_end(ctx);
32050b1347d2SRichard Henderson }
32060b1347d2SRichard Henderson 
3207f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
32080b1347d2SRichard Henderson {
3209f7b775a9SRichard Henderson     unsigned width, sa;
3210*6fd0c7bcSRichard Henderson     TCGv_i64 dest, t2;
32110b1347d2SRichard Henderson 
3212f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3213f7b775a9SRichard Henderson         return false;
3214f7b775a9SRichard Henderson     }
321530878590SRichard Henderson     if (a->c) {
32160b1347d2SRichard Henderson         nullify_over(ctx);
32170b1347d2SRichard Henderson     }
32180b1347d2SRichard Henderson 
3219f7b775a9SRichard Henderson     width = a->d ? 64 : 32;
3220f7b775a9SRichard Henderson     sa = width - 1 - a->cpos;
3221f7b775a9SRichard Henderson 
322230878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
322330878590SRichard Henderson     t2 = load_gpr(ctx, a->r2);
322405bfd4dbSRichard Henderson     if (a->r1 == 0) {
3225*6fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, t2, sa, width - sa);
3226c53e401eSRichard Henderson     } else if (width == TARGET_LONG_BITS) {
3227*6fd0c7bcSRichard Henderson         tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
3228f7b775a9SRichard Henderson     } else {
3229f7b775a9SRichard Henderson         assert(!a->d);
3230f7b775a9SRichard Henderson         if (a->r1 == a->r2) {
32310b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
3232*6fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, t2);
32330b1347d2SRichard Henderson             tcg_gen_rotri_i32(t32, t32, sa);
3234*6fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
32350b1347d2SRichard Henderson         } else {
323605bfd4dbSRichard Henderson             TCGv_i64 t64 = tcg_temp_new_i64();
3237*6fd0c7bcSRichard Henderson             tcg_gen_concat32_i64(t64, t2, cpu_gr[a->r1]);
323805bfd4dbSRichard Henderson             tcg_gen_shri_i64(t64, t64, sa);
323905bfd4dbSRichard Henderson             tcg_gen_trunc_i64_reg(dest, t64);
32400b1347d2SRichard Henderson         }
3241f7b775a9SRichard Henderson     }
324230878590SRichard Henderson     save_gpr(ctx, a->t, dest);
32430b1347d2SRichard Henderson 
32440b1347d2SRichard Henderson     /* Install the new nullification.  */
32450b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
324630878590SRichard Henderson     if (a->c) {
32474fa52edfSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
32480b1347d2SRichard Henderson     }
324931234768SRichard Henderson     return nullify_end(ctx);
32500b1347d2SRichard Henderson }
32510b1347d2SRichard Henderson 
3252bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
32530b1347d2SRichard Henderson {
3254bd792da3SRichard Henderson     unsigned widthm1 = a->d ? 63 : 31;
3255*6fd0c7bcSRichard Henderson     TCGv_i64 dest, src, tmp;
32560b1347d2SRichard Henderson 
3257bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3258bd792da3SRichard Henderson         return false;
3259bd792da3SRichard Henderson     }
326030878590SRichard Henderson     if (a->c) {
32610b1347d2SRichard Henderson         nullify_over(ctx);
32620b1347d2SRichard Henderson     }
32630b1347d2SRichard Henderson 
326430878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
326530878590SRichard Henderson     src = load_gpr(ctx, a->r);
32660b1347d2SRichard Henderson     tmp = tcg_temp_new();
32670b1347d2SRichard Henderson 
32680b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
3269*6fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
3270*6fd0c7bcSRichard Henderson     tcg_gen_xori_i64(tmp, tmp, widthm1);
3271d781cb77SRichard Henderson 
327230878590SRichard Henderson     if (a->se) {
3273bd792da3SRichard Henderson         if (!a->d) {
3274*6fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(dest, src);
3275bd792da3SRichard Henderson             src = dest;
3276bd792da3SRichard Henderson         }
3277*6fd0c7bcSRichard Henderson         tcg_gen_sar_i64(dest, src, tmp);
3278*6fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, dest, 0, a->len);
32790b1347d2SRichard Henderson     } else {
3280bd792da3SRichard Henderson         if (!a->d) {
3281*6fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src);
3282bd792da3SRichard Henderson             src = dest;
3283bd792da3SRichard Henderson         }
3284*6fd0c7bcSRichard Henderson         tcg_gen_shr_i64(dest, src, tmp);
3285*6fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, dest, 0, a->len);
32860b1347d2SRichard Henderson     }
328730878590SRichard Henderson     save_gpr(ctx, a->t, dest);
32880b1347d2SRichard Henderson 
32890b1347d2SRichard Henderson     /* Install the new nullification.  */
32900b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
329130878590SRichard Henderson     if (a->c) {
3292bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
32930b1347d2SRichard Henderson     }
329431234768SRichard Henderson     return nullify_end(ctx);
32950b1347d2SRichard Henderson }
32960b1347d2SRichard Henderson 
3297bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
32980b1347d2SRichard Henderson {
3299bd792da3SRichard Henderson     unsigned len, cpos, width;
3300*6fd0c7bcSRichard Henderson     TCGv_i64 dest, src;
33010b1347d2SRichard Henderson 
3302bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3303bd792da3SRichard Henderson         return false;
3304bd792da3SRichard Henderson     }
330530878590SRichard Henderson     if (a->c) {
33060b1347d2SRichard Henderson         nullify_over(ctx);
33070b1347d2SRichard Henderson     }
33080b1347d2SRichard Henderson 
3309bd792da3SRichard Henderson     len = a->len;
3310bd792da3SRichard Henderson     width = a->d ? 64 : 32;
3311bd792da3SRichard Henderson     cpos = width - 1 - a->pos;
3312bd792da3SRichard Henderson     if (cpos + len > width) {
3313bd792da3SRichard Henderson         len = width - cpos;
3314bd792da3SRichard Henderson     }
3315bd792da3SRichard Henderson 
331630878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
331730878590SRichard Henderson     src = load_gpr(ctx, a->r);
331830878590SRichard Henderson     if (a->se) {
3319*6fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, src, cpos, len);
33200b1347d2SRichard Henderson     } else {
3321*6fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, src, cpos, len);
33220b1347d2SRichard Henderson     }
332330878590SRichard Henderson     save_gpr(ctx, a->t, dest);
33240b1347d2SRichard Henderson 
33250b1347d2SRichard Henderson     /* Install the new nullification.  */
33260b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
332730878590SRichard Henderson     if (a->c) {
3328bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
33290b1347d2SRichard Henderson     }
333031234768SRichard Henderson     return nullify_end(ctx);
33310b1347d2SRichard Henderson }
33320b1347d2SRichard Henderson 
333372ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
33340b1347d2SRichard Henderson {
333572ae4f2bSRichard Henderson     unsigned len, width;
3336c53e401eSRichard Henderson     uint64_t mask0, mask1;
3337*6fd0c7bcSRichard Henderson     TCGv_i64 dest;
33380b1347d2SRichard Henderson 
333972ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
334072ae4f2bSRichard Henderson         return false;
334172ae4f2bSRichard Henderson     }
334230878590SRichard Henderson     if (a->c) {
33430b1347d2SRichard Henderson         nullify_over(ctx);
33440b1347d2SRichard Henderson     }
334572ae4f2bSRichard Henderson 
334672ae4f2bSRichard Henderson     len = a->len;
334772ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
334872ae4f2bSRichard Henderson     if (a->cpos + len > width) {
334972ae4f2bSRichard Henderson         len = width - a->cpos;
33500b1347d2SRichard Henderson     }
33510b1347d2SRichard Henderson 
335230878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
335330878590SRichard Henderson     mask0 = deposit64(0, a->cpos, len, a->i);
335430878590SRichard Henderson     mask1 = deposit64(-1, a->cpos, len, a->i);
33550b1347d2SRichard Henderson 
335630878590SRichard Henderson     if (a->nz) {
3357*6fd0c7bcSRichard Henderson         TCGv_i64 src = load_gpr(ctx, a->t);
3358*6fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, src, mask1);
3359*6fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, mask0);
33600b1347d2SRichard Henderson     } else {
3361*6fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, mask0);
33620b1347d2SRichard Henderson     }
336330878590SRichard Henderson     save_gpr(ctx, a->t, dest);
33640b1347d2SRichard Henderson 
33650b1347d2SRichard Henderson     /* Install the new nullification.  */
33660b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
336730878590SRichard Henderson     if (a->c) {
336872ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
33690b1347d2SRichard Henderson     }
337031234768SRichard Henderson     return nullify_end(ctx);
33710b1347d2SRichard Henderson }
33720b1347d2SRichard Henderson 
337372ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
33740b1347d2SRichard Henderson {
337530878590SRichard Henderson     unsigned rs = a->nz ? a->t : 0;
337672ae4f2bSRichard Henderson     unsigned len, width;
3377*6fd0c7bcSRichard Henderson     TCGv_i64 dest, val;
33780b1347d2SRichard Henderson 
337972ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
338072ae4f2bSRichard Henderson         return false;
338172ae4f2bSRichard Henderson     }
338230878590SRichard Henderson     if (a->c) {
33830b1347d2SRichard Henderson         nullify_over(ctx);
33840b1347d2SRichard Henderson     }
338572ae4f2bSRichard Henderson 
338672ae4f2bSRichard Henderson     len = a->len;
338772ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
338872ae4f2bSRichard Henderson     if (a->cpos + len > width) {
338972ae4f2bSRichard Henderson         len = width - a->cpos;
33900b1347d2SRichard Henderson     }
33910b1347d2SRichard Henderson 
339230878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
339330878590SRichard Henderson     val = load_gpr(ctx, a->r);
33940b1347d2SRichard Henderson     if (rs == 0) {
3395*6fd0c7bcSRichard Henderson         tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
33960b1347d2SRichard Henderson     } else {
3397*6fd0c7bcSRichard Henderson         tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
33980b1347d2SRichard Henderson     }
339930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
34000b1347d2SRichard Henderson 
34010b1347d2SRichard Henderson     /* Install the new nullification.  */
34020b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
340330878590SRichard Henderson     if (a->c) {
340472ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
34050b1347d2SRichard Henderson     }
340631234768SRichard Henderson     return nullify_end(ctx);
34070b1347d2SRichard Henderson }
34080b1347d2SRichard Henderson 
340972ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
3410*6fd0c7bcSRichard Henderson                        bool d, bool nz, unsigned len, TCGv_i64 val)
34110b1347d2SRichard Henderson {
34120b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
341372ae4f2bSRichard Henderson     unsigned widthm1 = d ? 63 : 31;
3414*6fd0c7bcSRichard Henderson     TCGv_i64 mask, tmp, shift, dest;
3415c53e401eSRichard Henderson     uint64_t msb = 1ULL << (len - 1);
34160b1347d2SRichard Henderson 
34170b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
34180b1347d2SRichard Henderson     shift = tcg_temp_new();
34190b1347d2SRichard Henderson     tmp = tcg_temp_new();
34200b1347d2SRichard Henderson 
34210b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
3422*6fd0c7bcSRichard Henderson     tcg_gen_andi_i64(shift, cpu_sar, widthm1);
3423*6fd0c7bcSRichard Henderson     tcg_gen_xori_i64(shift, shift, widthm1);
34240b1347d2SRichard Henderson 
34250992a930SRichard Henderson     mask = tcg_temp_new();
3426*6fd0c7bcSRichard Henderson     tcg_gen_movi_i64(mask, msb + (msb - 1));
3427*6fd0c7bcSRichard Henderson     tcg_gen_and_i64(tmp, val, mask);
34280b1347d2SRichard Henderson     if (rs) {
3429*6fd0c7bcSRichard Henderson         tcg_gen_shl_i64(mask, mask, shift);
3430*6fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tmp, shift);
3431*6fd0c7bcSRichard Henderson         tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
3432*6fd0c7bcSRichard Henderson         tcg_gen_or_i64(dest, dest, tmp);
34330b1347d2SRichard Henderson     } else {
3434*6fd0c7bcSRichard Henderson         tcg_gen_shl_i64(dest, tmp, shift);
34350b1347d2SRichard Henderson     }
34360b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
34370b1347d2SRichard Henderson 
34380b1347d2SRichard Henderson     /* Install the new nullification.  */
34390b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
34400b1347d2SRichard Henderson     if (c) {
344172ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, c, d, dest);
34420b1347d2SRichard Henderson     }
344331234768SRichard Henderson     return nullify_end(ctx);
34440b1347d2SRichard Henderson }
34450b1347d2SRichard Henderson 
344672ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
344730878590SRichard Henderson {
344872ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
344972ae4f2bSRichard Henderson         return false;
345072ae4f2bSRichard Henderson     }
3451a6deecceSSven Schnelle     if (a->c) {
3452a6deecceSSven Schnelle         nullify_over(ctx);
3453a6deecceSSven Schnelle     }
345472ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
345572ae4f2bSRichard Henderson                       load_gpr(ctx, a->r));
345630878590SRichard Henderson }
345730878590SRichard Henderson 
345872ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
345930878590SRichard Henderson {
346072ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
346172ae4f2bSRichard Henderson         return false;
346272ae4f2bSRichard Henderson     }
3463a6deecceSSven Schnelle     if (a->c) {
3464a6deecceSSven Schnelle         nullify_over(ctx);
3465a6deecceSSven Schnelle     }
346672ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
3467*6fd0c7bcSRichard Henderson                       tcg_constant_i64(a->i));
346830878590SRichard Henderson }
34690b1347d2SRichard Henderson 
34708340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a)
347198cd9ca7SRichard Henderson {
3472*6fd0c7bcSRichard Henderson     TCGv_i64 tmp;
347398cd9ca7SRichard Henderson 
3474c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
347598cd9ca7SRichard Henderson     /* ??? It seems like there should be a good way of using
347698cd9ca7SRichard Henderson        "be disp(sr2, r0)", the canonical gateway entry mechanism
347798cd9ca7SRichard Henderson        to our advantage.  But that appears to be inconvenient to
347898cd9ca7SRichard Henderson        manage along side branch delay slots.  Therefore we handle
347998cd9ca7SRichard Henderson        entry into the gateway page via absolute address.  */
348098cd9ca7SRichard Henderson     /* Since we don't implement spaces, just branch.  Do notice the special
348198cd9ca7SRichard Henderson        case of "be disp(*,r0)" using a direct branch to disp, so that we can
348298cd9ca7SRichard Henderson        goto_tb to the TB containing the syscall.  */
34838340f534SRichard Henderson     if (a->b == 0) {
34848340f534SRichard Henderson         return do_dbranch(ctx, a->disp, a->l, a->n);
348598cd9ca7SRichard Henderson     }
3486c301f34eSRichard Henderson #else
3487c301f34eSRichard Henderson     nullify_over(ctx);
3488660eefe1SRichard Henderson #endif
3489660eefe1SRichard Henderson 
3490e12c6309SRichard Henderson     tmp = tcg_temp_new();
3491*6fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp);
3492660eefe1SRichard Henderson     tmp = do_ibranch_priv(ctx, tmp);
3493c301f34eSRichard Henderson 
3494c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
34958340f534SRichard Henderson     return do_ibranch(ctx, tmp, a->l, a->n);
3496c301f34eSRichard Henderson #else
3497c301f34eSRichard Henderson     TCGv_i64 new_spc = tcg_temp_new_i64();
3498c301f34eSRichard Henderson 
34998340f534SRichard Henderson     load_spr(ctx, new_spc, a->sp);
35008340f534SRichard Henderson     if (a->l) {
3501741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
3502c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f);
3503c301f34eSRichard Henderson     }
35048340f534SRichard Henderson     if (a->n && use_nullify_skip(ctx)) {
3505a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
3506*6fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, 4);
3507a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3508c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, new_spc);
3509c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f);
3510c301f34eSRichard Henderson     } else {
3511741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3512c301f34eSRichard Henderson         if (ctx->iaoq_b == -1) {
3513c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3514c301f34eSRichard Henderson         }
3515a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3516c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, new_spc);
35178340f534SRichard Henderson         nullify_set(ctx, a->n);
3518c301f34eSRichard Henderson     }
3519c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
352031234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
352131234768SRichard Henderson     return nullify_end(ctx);
3522c301f34eSRichard Henderson #endif
352398cd9ca7SRichard Henderson }
352498cd9ca7SRichard Henderson 
35258340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a)
352698cd9ca7SRichard Henderson {
35278340f534SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n);
352898cd9ca7SRichard Henderson }
352998cd9ca7SRichard Henderson 
35308340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
353143e05652SRichard Henderson {
3532c53e401eSRichard Henderson     uint64_t dest = iaoq_dest(ctx, a->disp);
353343e05652SRichard Henderson 
35346e5f5300SSven Schnelle     nullify_over(ctx);
35356e5f5300SSven Schnelle 
353643e05652SRichard Henderson     /* Make sure the caller hasn't done something weird with the queue.
353743e05652SRichard Henderson      * ??? This is not quite the same as the PSW[B] bit, which would be
353843e05652SRichard Henderson      * expensive to track.  Real hardware will trap for
353943e05652SRichard Henderson      *    b  gateway
354043e05652SRichard Henderson      *    b  gateway+4  (in delay slot of first branch)
354143e05652SRichard Henderson      * However, checking for a non-sequential instruction queue *will*
354243e05652SRichard Henderson      * diagnose the security hole
354343e05652SRichard Henderson      *    b  gateway
354443e05652SRichard Henderson      *    b  evil
354543e05652SRichard Henderson      * in which instructions at evil would run with increased privs.
354643e05652SRichard Henderson      */
354743e05652SRichard Henderson     if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) {
354843e05652SRichard Henderson         return gen_illegal(ctx);
354943e05652SRichard Henderson     }
355043e05652SRichard Henderson 
355143e05652SRichard Henderson #ifndef CONFIG_USER_ONLY
355243e05652SRichard Henderson     if (ctx->tb_flags & PSW_C) {
3553b77af26eSRichard Henderson         CPUHPPAState *env = cpu_env(ctx->cs);
355443e05652SRichard Henderson         int type = hppa_artype_for_page(env, ctx->base.pc_next);
355543e05652SRichard Henderson         /* If we could not find a TLB entry, then we need to generate an
355643e05652SRichard Henderson            ITLB miss exception so the kernel will provide it.
355743e05652SRichard Henderson            The resulting TLB fill operation will invalidate this TB and
355843e05652SRichard Henderson            we will re-translate, at which point we *will* be able to find
355943e05652SRichard Henderson            the TLB entry and determine if this is in fact a gateway page.  */
356043e05652SRichard Henderson         if (type < 0) {
356131234768SRichard Henderson             gen_excp(ctx, EXCP_ITLB_MISS);
356231234768SRichard Henderson             return true;
356343e05652SRichard Henderson         }
356443e05652SRichard Henderson         /* No change for non-gateway pages or for priv decrease.  */
356543e05652SRichard Henderson         if (type >= 4 && type - 4 < ctx->privilege) {
356643e05652SRichard Henderson             dest = deposit32(dest, 0, 2, type - 4);
356743e05652SRichard Henderson         }
356843e05652SRichard Henderson     } else {
356943e05652SRichard Henderson         dest &= -4;  /* priv = 0 */
357043e05652SRichard Henderson     }
357143e05652SRichard Henderson #endif
357243e05652SRichard Henderson 
35736e5f5300SSven Schnelle     if (a->l) {
3574*6fd0c7bcSRichard Henderson         TCGv_i64 tmp = dest_gpr(ctx, a->l);
35756e5f5300SSven Schnelle         if (ctx->privilege < 3) {
3576*6fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, tmp, -4);
35776e5f5300SSven Schnelle         }
3578*6fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
35796e5f5300SSven Schnelle         save_gpr(ctx, a->l, tmp);
35806e5f5300SSven Schnelle     }
35816e5f5300SSven Schnelle 
35826e5f5300SSven Schnelle     return do_dbranch(ctx, dest, 0, a->n);
358343e05652SRichard Henderson }
358443e05652SRichard Henderson 
35858340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a)
358698cd9ca7SRichard Henderson {
3587b35aec85SRichard Henderson     if (a->x) {
3588*6fd0c7bcSRichard Henderson         TCGv_i64 tmp = tcg_temp_new();
3589*6fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3);
3590*6fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8);
3591660eefe1SRichard Henderson         /* The computation here never changes privilege level.  */
35928340f534SRichard Henderson         return do_ibranch(ctx, tmp, a->l, a->n);
3593b35aec85SRichard Henderson     } else {
3594b35aec85SRichard Henderson         /* BLR R0,RX is a good way to load PC+8 into RX.  */
3595b35aec85SRichard Henderson         return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n);
3596b35aec85SRichard Henderson     }
359798cd9ca7SRichard Henderson }
359898cd9ca7SRichard Henderson 
35998340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a)
360098cd9ca7SRichard Henderson {
3601*6fd0c7bcSRichard Henderson     TCGv_i64 dest;
360298cd9ca7SRichard Henderson 
36038340f534SRichard Henderson     if (a->x == 0) {
36048340f534SRichard Henderson         dest = load_gpr(ctx, a->b);
360598cd9ca7SRichard Henderson     } else {
3606e12c6309SRichard Henderson         dest = tcg_temp_new();
3607*6fd0c7bcSRichard Henderson         tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
3608*6fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
360998cd9ca7SRichard Henderson     }
3610660eefe1SRichard Henderson     dest = do_ibranch_priv(ctx, dest);
36118340f534SRichard Henderson     return do_ibranch(ctx, dest, 0, a->n);
361298cd9ca7SRichard Henderson }
361398cd9ca7SRichard Henderson 
36148340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a)
361598cd9ca7SRichard Henderson {
3616*6fd0c7bcSRichard Henderson     TCGv_i64 dest;
361798cd9ca7SRichard Henderson 
3618c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
36198340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
36208340f534SRichard Henderson     return do_ibranch(ctx, dest, a->l, a->n);
3621c301f34eSRichard Henderson #else
3622c301f34eSRichard Henderson     nullify_over(ctx);
36238340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
3624c301f34eSRichard Henderson 
3625741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3626c301f34eSRichard Henderson     if (ctx->iaoq_b == -1) {
3627c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3628c301f34eSRichard Henderson     }
3629741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest);
3630c301f34eSRichard Henderson     tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
36318340f534SRichard Henderson     if (a->l) {
3632741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var);
3633c301f34eSRichard Henderson     }
36348340f534SRichard Henderson     nullify_set(ctx, a->n);
3635c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
363631234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
363731234768SRichard Henderson     return nullify_end(ctx);
3638c301f34eSRichard Henderson #endif
363998cd9ca7SRichard Henderson }
364098cd9ca7SRichard Henderson 
3641a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
3642a8966ba7SRichard Henderson {
3643a8966ba7SRichard Henderson     /* All branch target stack instructions implement as nop. */
3644a8966ba7SRichard Henderson     return ctx->is_pa20;
3645a8966ba7SRichard Henderson }
3646a8966ba7SRichard Henderson 
36471ca74648SRichard Henderson /*
36481ca74648SRichard Henderson  * Float class 0
36491ca74648SRichard Henderson  */
3650ebe9383cSRichard Henderson 
36511ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3652ebe9383cSRichard Henderson {
3653ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
3654ebe9383cSRichard Henderson }
3655ebe9383cSRichard Henderson 
365659f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
365759f8c04bSHelge Deller {
3658a300dad3SRichard Henderson     uint64_t ret;
3659a300dad3SRichard Henderson 
3660c53e401eSRichard Henderson     if (ctx->is_pa20) {
3661a300dad3SRichard Henderson         ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
3662a300dad3SRichard Henderson     } else {
3663a300dad3SRichard Henderson         ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
3664a300dad3SRichard Henderson     }
3665a300dad3SRichard Henderson 
366659f8c04bSHelge Deller     nullify_over(ctx);
3667a300dad3SRichard Henderson     save_frd(0, tcg_constant_i64(ret));
366859f8c04bSHelge Deller     return nullify_end(ctx);
366959f8c04bSHelge Deller }
367059f8c04bSHelge Deller 
36711ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a)
36721ca74648SRichard Henderson {
36731ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f);
36741ca74648SRichard Henderson }
36751ca74648SRichard Henderson 
3676ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3677ebe9383cSRichard Henderson {
3678ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
3679ebe9383cSRichard Henderson }
3680ebe9383cSRichard Henderson 
36811ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a)
36821ca74648SRichard Henderson {
36831ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d);
36841ca74648SRichard Henderson }
36851ca74648SRichard Henderson 
36861ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3687ebe9383cSRichard Henderson {
3688ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
3689ebe9383cSRichard Henderson }
3690ebe9383cSRichard Henderson 
36911ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a)
36921ca74648SRichard Henderson {
36931ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fabs_f);
36941ca74648SRichard Henderson }
36951ca74648SRichard Henderson 
3696ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3697ebe9383cSRichard Henderson {
3698ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
3699ebe9383cSRichard Henderson }
3700ebe9383cSRichard Henderson 
37011ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a)
37021ca74648SRichard Henderson {
37031ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fabs_d);
37041ca74648SRichard Henderson }
37051ca74648SRichard Henderson 
37061ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a)
37071ca74648SRichard Henderson {
37081ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s);
37091ca74648SRichard Henderson }
37101ca74648SRichard Henderson 
37111ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a)
37121ca74648SRichard Henderson {
37131ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d);
37141ca74648SRichard Henderson }
37151ca74648SRichard Henderson 
37161ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a)
37171ca74648SRichard Henderson {
37181ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s);
37191ca74648SRichard Henderson }
37201ca74648SRichard Henderson 
37211ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a)
37221ca74648SRichard Henderson {
37231ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d);
37241ca74648SRichard Henderson }
37251ca74648SRichard Henderson 
37261ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3727ebe9383cSRichard Henderson {
3728ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
3729ebe9383cSRichard Henderson }
3730ebe9383cSRichard Henderson 
37311ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a)
37321ca74648SRichard Henderson {
37331ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fneg_f);
37341ca74648SRichard Henderson }
37351ca74648SRichard Henderson 
3736ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3737ebe9383cSRichard Henderson {
3738ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
3739ebe9383cSRichard Henderson }
3740ebe9383cSRichard Henderson 
37411ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a)
37421ca74648SRichard Henderson {
37431ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fneg_d);
37441ca74648SRichard Henderson }
37451ca74648SRichard Henderson 
37461ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3747ebe9383cSRichard Henderson {
3748ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
3749ebe9383cSRichard Henderson }
3750ebe9383cSRichard Henderson 
37511ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a)
37521ca74648SRichard Henderson {
37531ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f);
37541ca74648SRichard Henderson }
37551ca74648SRichard Henderson 
3756ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3757ebe9383cSRichard Henderson {
3758ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
3759ebe9383cSRichard Henderson }
3760ebe9383cSRichard Henderson 
37611ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a)
37621ca74648SRichard Henderson {
37631ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d);
37641ca74648SRichard Henderson }
37651ca74648SRichard Henderson 
37661ca74648SRichard Henderson /*
37671ca74648SRichard Henderson  * Float class 1
37681ca74648SRichard Henderson  */
37691ca74648SRichard Henderson 
37701ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a)
37711ca74648SRichard Henderson {
37721ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s);
37731ca74648SRichard Henderson }
37741ca74648SRichard Henderson 
37751ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a)
37761ca74648SRichard Henderson {
37771ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d);
37781ca74648SRichard Henderson }
37791ca74648SRichard Henderson 
37801ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a)
37811ca74648SRichard Henderson {
37821ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s);
37831ca74648SRichard Henderson }
37841ca74648SRichard Henderson 
37851ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a)
37861ca74648SRichard Henderson {
37871ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s);
37881ca74648SRichard Henderson }
37891ca74648SRichard Henderson 
37901ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a)
37911ca74648SRichard Henderson {
37921ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d);
37931ca74648SRichard Henderson }
37941ca74648SRichard Henderson 
37951ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a)
37961ca74648SRichard Henderson {
37971ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d);
37981ca74648SRichard Henderson }
37991ca74648SRichard Henderson 
38001ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a)
38011ca74648SRichard Henderson {
38021ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w);
38031ca74648SRichard Henderson }
38041ca74648SRichard Henderson 
38051ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a)
38061ca74648SRichard Henderson {
38071ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w);
38081ca74648SRichard Henderson }
38091ca74648SRichard Henderson 
38101ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a)
38111ca74648SRichard Henderson {
38121ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw);
38131ca74648SRichard Henderson }
38141ca74648SRichard Henderson 
38151ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a)
38161ca74648SRichard Henderson {
38171ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw);
38181ca74648SRichard Henderson }
38191ca74648SRichard Henderson 
38201ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a)
38211ca74648SRichard Henderson {
38221ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w);
38231ca74648SRichard Henderson }
38241ca74648SRichard Henderson 
38251ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a)
38261ca74648SRichard Henderson {
38271ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w);
38281ca74648SRichard Henderson }
38291ca74648SRichard Henderson 
38301ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a)
38311ca74648SRichard Henderson {
38321ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw);
38331ca74648SRichard Henderson }
38341ca74648SRichard Henderson 
38351ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a)
38361ca74648SRichard Henderson {
38371ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw);
38381ca74648SRichard Henderson }
38391ca74648SRichard Henderson 
38401ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a)
38411ca74648SRichard Henderson {
38421ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s);
38431ca74648SRichard Henderson }
38441ca74648SRichard Henderson 
38451ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a)
38461ca74648SRichard Henderson {
38471ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s);
38481ca74648SRichard Henderson }
38491ca74648SRichard Henderson 
38501ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a)
38511ca74648SRichard Henderson {
38521ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d);
38531ca74648SRichard Henderson }
38541ca74648SRichard Henderson 
38551ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a)
38561ca74648SRichard Henderson {
38571ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d);
38581ca74648SRichard Henderson }
38591ca74648SRichard Henderson 
38601ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a)
38611ca74648SRichard Henderson {
38621ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw);
38631ca74648SRichard Henderson }
38641ca74648SRichard Henderson 
38651ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a)
38661ca74648SRichard Henderson {
38671ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw);
38681ca74648SRichard Henderson }
38691ca74648SRichard Henderson 
38701ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a)
38711ca74648SRichard Henderson {
38721ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw);
38731ca74648SRichard Henderson }
38741ca74648SRichard Henderson 
38751ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a)
38761ca74648SRichard Henderson {
38771ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw);
38781ca74648SRichard Henderson }
38791ca74648SRichard Henderson 
38801ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a)
38811ca74648SRichard Henderson {
38821ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw);
38831ca74648SRichard Henderson }
38841ca74648SRichard Henderson 
38851ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a)
38861ca74648SRichard Henderson {
38871ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw);
38881ca74648SRichard Henderson }
38891ca74648SRichard Henderson 
38901ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a)
38911ca74648SRichard Henderson {
38921ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw);
38931ca74648SRichard Henderson }
38941ca74648SRichard Henderson 
38951ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a)
38961ca74648SRichard Henderson {
38971ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw);
38981ca74648SRichard Henderson }
38991ca74648SRichard Henderson 
39001ca74648SRichard Henderson /*
39011ca74648SRichard Henderson  * Float class 2
39021ca74648SRichard Henderson  */
39031ca74648SRichard Henderson 
39041ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a)
3905ebe9383cSRichard Henderson {
3906ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
3907ebe9383cSRichard Henderson 
3908ebe9383cSRichard Henderson     nullify_over(ctx);
3909ebe9383cSRichard Henderson 
39101ca74648SRichard Henderson     ta = load_frw0_i32(a->r1);
39111ca74648SRichard Henderson     tb = load_frw0_i32(a->r2);
391229dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
391329dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
3914ebe9383cSRichard Henderson 
3915ad75a51eSRichard Henderson     gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc);
3916ebe9383cSRichard Henderson 
39171ca74648SRichard Henderson     return nullify_end(ctx);
3918ebe9383cSRichard Henderson }
3919ebe9383cSRichard Henderson 
39201ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
3921ebe9383cSRichard Henderson {
3922ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
3923ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
3924ebe9383cSRichard Henderson 
3925ebe9383cSRichard Henderson     nullify_over(ctx);
3926ebe9383cSRichard Henderson 
39271ca74648SRichard Henderson     ta = load_frd0(a->r1);
39281ca74648SRichard Henderson     tb = load_frd0(a->r2);
392929dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
393029dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
3931ebe9383cSRichard Henderson 
3932ad75a51eSRichard Henderson     gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc);
3933ebe9383cSRichard Henderson 
393431234768SRichard Henderson     return nullify_end(ctx);
3935ebe9383cSRichard Henderson }
3936ebe9383cSRichard Henderson 
39371ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
3938ebe9383cSRichard Henderson {
3939*6fd0c7bcSRichard Henderson     TCGv_i64 t;
3940ebe9383cSRichard Henderson 
3941ebe9383cSRichard Henderson     nullify_over(ctx);
3942ebe9383cSRichard Henderson 
3943e12c6309SRichard Henderson     t = tcg_temp_new();
3944*6fd0c7bcSRichard Henderson     tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
3945ebe9383cSRichard Henderson 
39461ca74648SRichard Henderson     if (a->y == 1) {
3947ebe9383cSRichard Henderson         int mask;
3948ebe9383cSRichard Henderson         bool inv = false;
3949ebe9383cSRichard Henderson 
39501ca74648SRichard Henderson         switch (a->c) {
3951ebe9383cSRichard Henderson         case 0: /* simple */
3952*6fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, 0x4000000);
3953ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3954ebe9383cSRichard Henderson             goto done;
3955ebe9383cSRichard Henderson         case 2: /* rej */
3956ebe9383cSRichard Henderson             inv = true;
3957ebe9383cSRichard Henderson             /* fallthru */
3958ebe9383cSRichard Henderson         case 1: /* acc */
3959ebe9383cSRichard Henderson             mask = 0x43ff800;
3960ebe9383cSRichard Henderson             break;
3961ebe9383cSRichard Henderson         case 6: /* rej8 */
3962ebe9383cSRichard Henderson             inv = true;
3963ebe9383cSRichard Henderson             /* fallthru */
3964ebe9383cSRichard Henderson         case 5: /* acc8 */
3965ebe9383cSRichard Henderson             mask = 0x43f8000;
3966ebe9383cSRichard Henderson             break;
3967ebe9383cSRichard Henderson         case 9: /* acc6 */
3968ebe9383cSRichard Henderson             mask = 0x43e0000;
3969ebe9383cSRichard Henderson             break;
3970ebe9383cSRichard Henderson         case 13: /* acc4 */
3971ebe9383cSRichard Henderson             mask = 0x4380000;
3972ebe9383cSRichard Henderson             break;
3973ebe9383cSRichard Henderson         case 17: /* acc2 */
3974ebe9383cSRichard Henderson             mask = 0x4200000;
3975ebe9383cSRichard Henderson             break;
3976ebe9383cSRichard Henderson         default:
39771ca74648SRichard Henderson             gen_illegal(ctx);
39781ca74648SRichard Henderson             return true;
3979ebe9383cSRichard Henderson         }
3980ebe9383cSRichard Henderson         if (inv) {
3981*6fd0c7bcSRichard Henderson             TCGv_i64 c = tcg_constant_i64(mask);
3982*6fd0c7bcSRichard Henderson             tcg_gen_or_i64(t, t, c);
3983ebe9383cSRichard Henderson             ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
3984ebe9383cSRichard Henderson         } else {
3985*6fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, mask);
3986ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
3987ebe9383cSRichard Henderson         }
39881ca74648SRichard Henderson     } else {
39891ca74648SRichard Henderson         unsigned cbit = (a->y ^ 1) - 1;
39901ca74648SRichard Henderson 
3991*6fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, t, 21 - cbit, 1);
39921ca74648SRichard Henderson         ctx->null_cond = cond_make_0(TCG_COND_NE, t);
39931ca74648SRichard Henderson     }
39941ca74648SRichard Henderson 
3995ebe9383cSRichard Henderson  done:
399631234768SRichard Henderson     return nullify_end(ctx);
3997ebe9383cSRichard Henderson }
3998ebe9383cSRichard Henderson 
39991ca74648SRichard Henderson /*
40001ca74648SRichard Henderson  * Float class 2
40011ca74648SRichard Henderson  */
40021ca74648SRichard Henderson 
40031ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a)
4004ebe9383cSRichard Henderson {
40051ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s);
40061ca74648SRichard Henderson }
40071ca74648SRichard Henderson 
40081ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a)
40091ca74648SRichard Henderson {
40101ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d);
40111ca74648SRichard Henderson }
40121ca74648SRichard Henderson 
40131ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a)
40141ca74648SRichard Henderson {
40151ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s);
40161ca74648SRichard Henderson }
40171ca74648SRichard Henderson 
40181ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a)
40191ca74648SRichard Henderson {
40201ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d);
40211ca74648SRichard Henderson }
40221ca74648SRichard Henderson 
40231ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a)
40241ca74648SRichard Henderson {
40251ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s);
40261ca74648SRichard Henderson }
40271ca74648SRichard Henderson 
40281ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a)
40291ca74648SRichard Henderson {
40301ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d);
40311ca74648SRichard Henderson }
40321ca74648SRichard Henderson 
40331ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a)
40341ca74648SRichard Henderson {
40351ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s);
40361ca74648SRichard Henderson }
40371ca74648SRichard Henderson 
40381ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a)
40391ca74648SRichard Henderson {
40401ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d);
40411ca74648SRichard Henderson }
40421ca74648SRichard Henderson 
40431ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a)
40441ca74648SRichard Henderson {
40451ca74648SRichard Henderson     TCGv_i64 x, y;
4046ebe9383cSRichard Henderson 
4047ebe9383cSRichard Henderson     nullify_over(ctx);
4048ebe9383cSRichard Henderson 
40491ca74648SRichard Henderson     x = load_frw0_i64(a->r1);
40501ca74648SRichard Henderson     y = load_frw0_i64(a->r2);
40511ca74648SRichard Henderson     tcg_gen_mul_i64(x, x, y);
40521ca74648SRichard Henderson     save_frd(a->t, x);
4053ebe9383cSRichard Henderson 
405431234768SRichard Henderson     return nullify_end(ctx);
4055ebe9383cSRichard Henderson }
4056ebe9383cSRichard Henderson 
4057ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
4058ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
4059ebe9383cSRichard Henderson {
4060ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
4061ebe9383cSRichard Henderson }
4062ebe9383cSRichard Henderson 
4063b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4064ebe9383cSRichard Henderson {
4065b1e2af57SRichard Henderson     int tm = fmpyadd_s_reg(a->tm);
4066b1e2af57SRichard Henderson     int ra = fmpyadd_s_reg(a->ra);
4067b1e2af57SRichard Henderson     int ta = fmpyadd_s_reg(a->ta);
4068b1e2af57SRichard Henderson     int rm2 = fmpyadd_s_reg(a->rm2);
4069b1e2af57SRichard Henderson     int rm1 = fmpyadd_s_reg(a->rm1);
4070ebe9383cSRichard Henderson 
4071ebe9383cSRichard Henderson     nullify_over(ctx);
4072ebe9383cSRichard Henderson 
4073ebe9383cSRichard Henderson     do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4074ebe9383cSRichard Henderson     do_fop_weww(ctx, ta, ta, ra,
4075ebe9383cSRichard Henderson                 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
4076ebe9383cSRichard Henderson 
407731234768SRichard Henderson     return nullify_end(ctx);
4078ebe9383cSRichard Henderson }
4079ebe9383cSRichard Henderson 
4080b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4081b1e2af57SRichard Henderson {
4082b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, false);
4083b1e2af57SRichard Henderson }
4084b1e2af57SRichard Henderson 
4085b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4086b1e2af57SRichard Henderson {
4087b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, true);
4088b1e2af57SRichard Henderson }
4089b1e2af57SRichard Henderson 
4090b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4091b1e2af57SRichard Henderson {
4092b1e2af57SRichard Henderson     nullify_over(ctx);
4093b1e2af57SRichard Henderson 
4094b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4095b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4096b1e2af57SRichard Henderson                 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4097b1e2af57SRichard Henderson 
4098b1e2af57SRichard Henderson     return nullify_end(ctx);
4099b1e2af57SRichard Henderson }
4100b1e2af57SRichard Henderson 
4101b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4102b1e2af57SRichard Henderson {
4103b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, false);
4104b1e2af57SRichard Henderson }
4105b1e2af57SRichard Henderson 
4106b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4107b1e2af57SRichard Henderson {
4108b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, true);
4109b1e2af57SRichard Henderson }
4110b1e2af57SRichard Henderson 
4111c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a)
4112ebe9383cSRichard Henderson {
4113c3bad4f8SRichard Henderson     TCGv_i32 x, y, z;
4114ebe9383cSRichard Henderson 
4115ebe9383cSRichard Henderson     nullify_over(ctx);
4116c3bad4f8SRichard Henderson     x = load_frw0_i32(a->rm1);
4117c3bad4f8SRichard Henderson     y = load_frw0_i32(a->rm2);
4118c3bad4f8SRichard Henderson     z = load_frw0_i32(a->ra3);
4119ebe9383cSRichard Henderson 
4120c3bad4f8SRichard Henderson     if (a->neg) {
4121ad75a51eSRichard Henderson         gen_helper_fmpynfadd_s(x, tcg_env, x, y, z);
4122ebe9383cSRichard Henderson     } else {
4123ad75a51eSRichard Henderson         gen_helper_fmpyfadd_s(x, tcg_env, x, y, z);
4124ebe9383cSRichard Henderson     }
4125ebe9383cSRichard Henderson 
4126c3bad4f8SRichard Henderson     save_frw_i32(a->t, x);
412731234768SRichard Henderson     return nullify_end(ctx);
4128ebe9383cSRichard Henderson }
4129ebe9383cSRichard Henderson 
4130c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
4131ebe9383cSRichard Henderson {
4132c3bad4f8SRichard Henderson     TCGv_i64 x, y, z;
4133ebe9383cSRichard Henderson 
4134ebe9383cSRichard Henderson     nullify_over(ctx);
4135c3bad4f8SRichard Henderson     x = load_frd0(a->rm1);
4136c3bad4f8SRichard Henderson     y = load_frd0(a->rm2);
4137c3bad4f8SRichard Henderson     z = load_frd0(a->ra3);
4138ebe9383cSRichard Henderson 
4139c3bad4f8SRichard Henderson     if (a->neg) {
4140ad75a51eSRichard Henderson         gen_helper_fmpynfadd_d(x, tcg_env, x, y, z);
4141ebe9383cSRichard Henderson     } else {
4142ad75a51eSRichard Henderson         gen_helper_fmpyfadd_d(x, tcg_env, x, y, z);
4143ebe9383cSRichard Henderson     }
4144ebe9383cSRichard Henderson 
4145c3bad4f8SRichard Henderson     save_frd(a->t, x);
414631234768SRichard Henderson     return nullify_end(ctx);
4147ebe9383cSRichard Henderson }
4148ebe9383cSRichard Henderson 
414915da177bSSven Schnelle static bool trans_diag(DisasContext *ctx, arg_diag *a)
415015da177bSSven Schnelle {
4151cf6b28d4SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4152cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY
4153cf6b28d4SHelge Deller     if (a->i == 0x100) {
4154cf6b28d4SHelge Deller         /* emulate PDC BTLB, called by SeaBIOS-hppa */
4155ad75a51eSRichard Henderson         nullify_over(ctx);
4156ad75a51eSRichard Henderson         gen_helper_diag_btlb(tcg_env);
4157cf6b28d4SHelge Deller         return nullify_end(ctx);
415815da177bSSven Schnelle     }
4159ad75a51eSRichard Henderson #endif
4160ad75a51eSRichard Henderson     qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i);
4161ad75a51eSRichard Henderson     return true;
4162ad75a51eSRichard Henderson }
416315da177bSSven Schnelle 
4164b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
416561766fe9SRichard Henderson {
416651b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4167f764718dSRichard Henderson     int bound;
416861766fe9SRichard Henderson 
416951b061fbSRichard Henderson     ctx->cs = cs;
4170494737b7SRichard Henderson     ctx->tb_flags = ctx->base.tb->flags;
4171bd6243a3SRichard Henderson     ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
41723d68ee7bSRichard Henderson 
41733d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY
4174c01e5dfbSHelge Deller     ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX);
41753d68ee7bSRichard Henderson     ctx->mmu_idx = MMU_USER_IDX;
4176c01e5dfbSHelge Deller     ctx->iaoq_f = ctx->base.pc_first | ctx->privilege;
4177c01e5dfbSHelge Deller     ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege;
4178217d1a5eSRichard Henderson     ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
4179c301f34eSRichard Henderson #else
4180494737b7SRichard Henderson     ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
4181bb67ec32SRichard Henderson     ctx->mmu_idx = (ctx->tb_flags & PSW_D
4182bb67ec32SRichard Henderson                     ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
4183bb67ec32SRichard Henderson                     : MMU_PHYS_IDX);
41843d68ee7bSRichard Henderson 
4185c301f34eSRichard Henderson     /* Recover the IAOQ values from the GVA + PRIV.  */
4186c301f34eSRichard Henderson     uint64_t cs_base = ctx->base.tb->cs_base;
4187c301f34eSRichard Henderson     uint64_t iasq_f = cs_base & ~0xffffffffull;
4188c301f34eSRichard Henderson     int32_t diff = cs_base;
4189c301f34eSRichard Henderson 
4190c301f34eSRichard Henderson     ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
4191c301f34eSRichard Henderson     ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1);
4192c301f34eSRichard Henderson #endif
419351b061fbSRichard Henderson     ctx->iaoq_n = -1;
4194f764718dSRichard Henderson     ctx->iaoq_n_var = NULL;
419561766fe9SRichard Henderson 
41963d68ee7bSRichard Henderson     /* Bound the number of instructions by those left on the page.  */
41973d68ee7bSRichard Henderson     bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
4198b542683dSEmilio G. Cota     ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
419961766fe9SRichard Henderson }
420061766fe9SRichard Henderson 
420151b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
420251b061fbSRichard Henderson {
420351b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
420461766fe9SRichard Henderson 
42053d68ee7bSRichard Henderson     /* Seed the nullification status from PSW[N], as saved in TB->FLAGS.  */
420651b061fbSRichard Henderson     ctx->null_cond = cond_make_f();
420751b061fbSRichard Henderson     ctx->psw_n_nonzero = false;
4208494737b7SRichard Henderson     if (ctx->tb_flags & PSW_N) {
420951b061fbSRichard Henderson         ctx->null_cond.c = TCG_COND_ALWAYS;
421051b061fbSRichard Henderson         ctx->psw_n_nonzero = true;
4211129e9cc3SRichard Henderson     }
421251b061fbSRichard Henderson     ctx->null_lab = NULL;
421361766fe9SRichard Henderson }
421461766fe9SRichard Henderson 
421551b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
421651b061fbSRichard Henderson {
421751b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
421851b061fbSRichard Henderson 
421951b061fbSRichard Henderson     tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b);
422051b061fbSRichard Henderson }
422151b061fbSRichard Henderson 
422251b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
422351b061fbSRichard Henderson {
422451b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4225b77af26eSRichard Henderson     CPUHPPAState *env = cpu_env(cs);
422651b061fbSRichard Henderson     DisasJumpType ret;
422751b061fbSRichard Henderson 
422851b061fbSRichard Henderson     /* Execute one insn.  */
4229ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4230c301f34eSRichard Henderson     if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
423131234768SRichard Henderson         do_page_zero(ctx);
423231234768SRichard Henderson         ret = ctx->base.is_jmp;
4233869051eaSRichard Henderson         assert(ret != DISAS_NEXT);
4234ba1d0b44SRichard Henderson     } else
4235ba1d0b44SRichard Henderson #endif
4236ba1d0b44SRichard Henderson     {
423761766fe9SRichard Henderson         /* Always fetch the insn, even if nullified, so that we check
423861766fe9SRichard Henderson            the page permissions for execute.  */
42394e116893SIlya Leoshkevich         uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next);
424061766fe9SRichard Henderson 
424161766fe9SRichard Henderson         /* Set up the IA queue for the next insn.
424261766fe9SRichard Henderson            This will be overwritten by a branch.  */
424351b061fbSRichard Henderson         if (ctx->iaoq_b == -1) {
424451b061fbSRichard Henderson             ctx->iaoq_n = -1;
4245e12c6309SRichard Henderson             ctx->iaoq_n_var = tcg_temp_new();
4246*6fd0c7bcSRichard Henderson             tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
424761766fe9SRichard Henderson         } else {
424851b061fbSRichard Henderson             ctx->iaoq_n = ctx->iaoq_b + 4;
4249f764718dSRichard Henderson             ctx->iaoq_n_var = NULL;
425061766fe9SRichard Henderson         }
425161766fe9SRichard Henderson 
425251b061fbSRichard Henderson         if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
425351b061fbSRichard Henderson             ctx->null_cond.c = TCG_COND_NEVER;
4254869051eaSRichard Henderson             ret = DISAS_NEXT;
4255129e9cc3SRichard Henderson         } else {
42561a19da0dSRichard Henderson             ctx->insn = insn;
425731274b46SRichard Henderson             if (!decode(ctx, insn)) {
425831274b46SRichard Henderson                 gen_illegal(ctx);
425931274b46SRichard Henderson             }
426031234768SRichard Henderson             ret = ctx->base.is_jmp;
426151b061fbSRichard Henderson             assert(ctx->null_lab == NULL);
4262129e9cc3SRichard Henderson         }
426361766fe9SRichard Henderson     }
426461766fe9SRichard Henderson 
42653d68ee7bSRichard Henderson     /* Advance the insn queue.  Note that this check also detects
42663d68ee7bSRichard Henderson        a priority change within the instruction queue.  */
426751b061fbSRichard Henderson     if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
4268c301f34eSRichard Henderson         if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1
4269c301f34eSRichard Henderson             && use_goto_tb(ctx, ctx->iaoq_b)
4270c301f34eSRichard Henderson             && (ctx->null_cond.c == TCG_COND_NEVER
4271c301f34eSRichard Henderson                 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
427251b061fbSRichard Henderson             nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
427351b061fbSRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
427431234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_NORETURN;
4275129e9cc3SRichard Henderson         } else {
427631234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE;
427761766fe9SRichard Henderson         }
4278129e9cc3SRichard Henderson     }
427951b061fbSRichard Henderson     ctx->iaoq_f = ctx->iaoq_b;
428051b061fbSRichard Henderson     ctx->iaoq_b = ctx->iaoq_n;
4281c301f34eSRichard Henderson     ctx->base.pc_next += 4;
428261766fe9SRichard Henderson 
4283c5d0aec2SRichard Henderson     switch (ret) {
4284c5d0aec2SRichard Henderson     case DISAS_NORETURN:
4285c5d0aec2SRichard Henderson     case DISAS_IAQ_N_UPDATED:
4286c5d0aec2SRichard Henderson         break;
4287c5d0aec2SRichard Henderson 
4288c5d0aec2SRichard Henderson     case DISAS_NEXT:
4289c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE:
4290c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
429151b061fbSRichard Henderson         if (ctx->iaoq_f == -1) {
4292a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b);
4293741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
4294c301f34eSRichard Henderson #ifndef CONFIG_USER_ONLY
4295c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
4296c301f34eSRichard Henderson #endif
429751b061fbSRichard Henderson             nullify_save(ctx);
4298c5d0aec2SRichard Henderson             ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT
4299c5d0aec2SRichard Henderson                                 ? DISAS_EXIT
4300c5d0aec2SRichard Henderson                                 : DISAS_IAQ_N_UPDATED);
430151b061fbSRichard Henderson         } else if (ctx->iaoq_b == -1) {
4302a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var);
430361766fe9SRichard Henderson         }
4304c5d0aec2SRichard Henderson         break;
4305c5d0aec2SRichard Henderson 
4306c5d0aec2SRichard Henderson     default:
4307c5d0aec2SRichard Henderson         g_assert_not_reached();
4308c5d0aec2SRichard Henderson     }
430961766fe9SRichard Henderson }
431061766fe9SRichard Henderson 
431151b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
431251b061fbSRichard Henderson {
431351b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4314e1b5a5edSRichard Henderson     DisasJumpType is_jmp = ctx->base.is_jmp;
431551b061fbSRichard Henderson 
4316e1b5a5edSRichard Henderson     switch (is_jmp) {
4317869051eaSRichard Henderson     case DISAS_NORETURN:
431861766fe9SRichard Henderson         break;
431951b061fbSRichard Henderson     case DISAS_TOO_MANY:
4320869051eaSRichard Henderson     case DISAS_IAQ_N_STALE:
4321e1b5a5edSRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
4322741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
4323741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
432451b061fbSRichard Henderson         nullify_save(ctx);
432561766fe9SRichard Henderson         /* FALLTHRU */
4326869051eaSRichard Henderson     case DISAS_IAQ_N_UPDATED:
43278532a14eSRichard Henderson         if (is_jmp != DISAS_IAQ_N_STALE_EXIT) {
43287f11636dSEmilio G. Cota             tcg_gen_lookup_and_goto_ptr();
43298532a14eSRichard Henderson             break;
433061766fe9SRichard Henderson         }
4331c5d0aec2SRichard Henderson         /* FALLTHRU */
4332c5d0aec2SRichard Henderson     case DISAS_EXIT:
4333c5d0aec2SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
433461766fe9SRichard Henderson         break;
433561766fe9SRichard Henderson     default:
433651b061fbSRichard Henderson         g_assert_not_reached();
433761766fe9SRichard Henderson     }
433851b061fbSRichard Henderson }
433961766fe9SRichard Henderson 
43408eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase,
43418eb806a7SRichard Henderson                               CPUState *cs, FILE *logfile)
434251b061fbSRichard Henderson {
4343c301f34eSRichard Henderson     target_ulong pc = dcbase->pc_first;
434461766fe9SRichard Henderson 
4345ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4346ba1d0b44SRichard Henderson     switch (pc) {
43477ad439dfSRichard Henderson     case 0x00:
43488eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000000:  (null)\n");
4349ba1d0b44SRichard Henderson         return;
43507ad439dfSRichard Henderson     case 0xb0:
43518eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000b0:  light-weight-syscall\n");
4352ba1d0b44SRichard Henderson         return;
43537ad439dfSRichard Henderson     case 0xe0:
43548eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000e0:  set-thread-pointer-syscall\n");
4355ba1d0b44SRichard Henderson         return;
43567ad439dfSRichard Henderson     case 0x100:
43578eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000100:  syscall\n");
4358ba1d0b44SRichard Henderson         return;
43597ad439dfSRichard Henderson     }
4360ba1d0b44SRichard Henderson #endif
4361ba1d0b44SRichard Henderson 
43628eb806a7SRichard Henderson     fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
43638eb806a7SRichard Henderson     target_disas(logfile, cs, pc, dcbase->tb->size);
436461766fe9SRichard Henderson }
436551b061fbSRichard Henderson 
436651b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = {
436751b061fbSRichard Henderson     .init_disas_context = hppa_tr_init_disas_context,
436851b061fbSRichard Henderson     .tb_start           = hppa_tr_tb_start,
436951b061fbSRichard Henderson     .insn_start         = hppa_tr_insn_start,
437051b061fbSRichard Henderson     .translate_insn     = hppa_tr_translate_insn,
437151b061fbSRichard Henderson     .tb_stop            = hppa_tr_tb_stop,
437251b061fbSRichard Henderson     .disas_log          = hppa_tr_disas_log,
437351b061fbSRichard Henderson };
437451b061fbSRichard Henderson 
4375597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
4376306c8721SRichard Henderson                            target_ulong pc, void *host_pc)
437751b061fbSRichard Henderson {
437851b061fbSRichard Henderson     DisasContext ctx;
4379306c8721SRichard Henderson     translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
438061766fe9SRichard Henderson }
4381