xref: /openbmc/qemu/target/hppa/translate.c (revision 4c34bab0d3dc59fef4ebce831fbca784a1e3e06a)
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"
260843563fSRichard Henderson #include "tcg/tcg-op-gvec.h"
2761766fe9SRichard Henderson #include "exec/helper-proto.h"
2861766fe9SRichard Henderson #include "exec/helper-gen.h"
29869051eaSRichard Henderson #include "exec/translator.h"
3061766fe9SRichard Henderson #include "exec/log.h"
3161766fe9SRichard Henderson 
32d53106c9SRichard Henderson #define HELPER_H "helper.h"
33d53106c9SRichard Henderson #include "exec/helper-info.c.inc"
34d53106c9SRichard Henderson #undef  HELPER_H
35d53106c9SRichard Henderson 
36aac0f603SRichard Henderson /* Choose to use explicit sizes within this file. */
37aac0f603SRichard Henderson #undef tcg_temp_new
38d53106c9SRichard Henderson 
3961766fe9SRichard Henderson typedef struct DisasCond {
4061766fe9SRichard Henderson     TCGCond c;
416fd0c7bcSRichard Henderson     TCGv_i64 a0, a1;
4261766fe9SRichard Henderson } DisasCond;
4361766fe9SRichard Henderson 
4461766fe9SRichard Henderson typedef struct DisasContext {
45d01a3625SRichard Henderson     DisasContextBase base;
4661766fe9SRichard Henderson     CPUState *cs;
4761766fe9SRichard Henderson 
48c53e401eSRichard Henderson     uint64_t iaoq_f;
49c53e401eSRichard Henderson     uint64_t iaoq_b;
50c53e401eSRichard Henderson     uint64_t iaoq_n;
516fd0c7bcSRichard Henderson     TCGv_i64 iaoq_n_var;
5261766fe9SRichard Henderson 
5361766fe9SRichard Henderson     DisasCond null_cond;
5461766fe9SRichard Henderson     TCGLabel *null_lab;
5561766fe9SRichard Henderson 
56a4db4a78SRichard Henderson     TCGv_i64 zero;
57a4db4a78SRichard Henderson 
581a19da0dSRichard Henderson     uint32_t insn;
59494737b7SRichard Henderson     uint32_t tb_flags;
603d68ee7bSRichard Henderson     int mmu_idx;
613d68ee7bSRichard Henderson     int privilege;
6261766fe9SRichard Henderson     bool psw_n_nonzero;
63bd6243a3SRichard Henderson     bool is_pa20;
64217d1a5eSRichard Henderson 
65217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
66217d1a5eSRichard Henderson     MemOp unalign;
67217d1a5eSRichard Henderson #endif
6861766fe9SRichard Henderson } DisasContext;
6961766fe9SRichard Henderson 
70217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
71217d1a5eSRichard Henderson #define UNALIGN(C)  (C)->unalign
72217d1a5eSRichard Henderson #else
732d4afb03SRichard Henderson #define UNALIGN(C)  MO_ALIGN
74217d1a5eSRichard Henderson #endif
75217d1a5eSRichard Henderson 
76e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently.  */
77451e4ffdSRichard Henderson static int expand_sm_imm(DisasContext *ctx, int val)
78e36f27efSRichard Henderson {
79e36f27efSRichard Henderson     if (val & PSW_SM_E) {
80e36f27efSRichard Henderson         val = (val & ~PSW_SM_E) | PSW_E;
81e36f27efSRichard Henderson     }
82e36f27efSRichard Henderson     if (val & PSW_SM_W) {
83e36f27efSRichard Henderson         val = (val & ~PSW_SM_W) | PSW_W;
84e36f27efSRichard Henderson     }
85e36f27efSRichard Henderson     return val;
86e36f27efSRichard Henderson }
87e36f27efSRichard Henderson 
88deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base.  */
89451e4ffdSRichard Henderson static int expand_sr3x(DisasContext *ctx, int val)
90deee69a1SRichard Henderson {
91deee69a1SRichard Henderson     return ~val;
92deee69a1SRichard Henderson }
93deee69a1SRichard Henderson 
941cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value
951cd012a5SRichard Henderson    we use for the final M.  */
96451e4ffdSRichard Henderson static int ma_to_m(DisasContext *ctx, int val)
971cd012a5SRichard Henderson {
981cd012a5SRichard Henderson     return val & 2 ? (val & 1 ? -1 : 1) : 0;
991cd012a5SRichard Henderson }
1001cd012a5SRichard Henderson 
101740038d7SRichard Henderson /* Convert the sign of the displacement to a pre or post-modify.  */
102451e4ffdSRichard Henderson static int pos_to_m(DisasContext *ctx, int val)
103740038d7SRichard Henderson {
104740038d7SRichard Henderson     return val ? 1 : -1;
105740038d7SRichard Henderson }
106740038d7SRichard Henderson 
107451e4ffdSRichard Henderson static int neg_to_m(DisasContext *ctx, int val)
108740038d7SRichard Henderson {
109740038d7SRichard Henderson     return val ? -1 : 1;
110740038d7SRichard Henderson }
111740038d7SRichard Henderson 
112740038d7SRichard Henderson /* Used for branch targets and fp memory ops.  */
113451e4ffdSRichard Henderson static int expand_shl2(DisasContext *ctx, int val)
11401afb7beSRichard Henderson {
11501afb7beSRichard Henderson     return val << 2;
11601afb7beSRichard Henderson }
11701afb7beSRichard Henderson 
118740038d7SRichard Henderson /* Used for fp memory ops.  */
119451e4ffdSRichard Henderson static int expand_shl3(DisasContext *ctx, int val)
120740038d7SRichard Henderson {
121740038d7SRichard Henderson     return val << 3;
122740038d7SRichard Henderson }
123740038d7SRichard Henderson 
1240588e061SRichard Henderson /* Used for assemble_21.  */
125451e4ffdSRichard Henderson static int expand_shl11(DisasContext *ctx, int val)
1260588e061SRichard Henderson {
1270588e061SRichard Henderson     return val << 11;
1280588e061SRichard Henderson }
1290588e061SRichard Henderson 
13072ae4f2bSRichard Henderson static int assemble_6(DisasContext *ctx, int val)
13172ae4f2bSRichard Henderson {
13272ae4f2bSRichard Henderson     /*
13372ae4f2bSRichard Henderson      * Officially, 32 * x + 32 - y.
13472ae4f2bSRichard Henderson      * Here, x is already in bit 5, and y is [4:0].
13572ae4f2bSRichard Henderson      * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1,
13672ae4f2bSRichard Henderson      * with the overflow from bit 4 summing with x.
13772ae4f2bSRichard Henderson      */
13872ae4f2bSRichard Henderson     return (val ^ 31) + 1;
13972ae4f2bSRichard Henderson }
14072ae4f2bSRichard Henderson 
141c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */
142c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val)
143c65c3ee1SRichard Henderson {
144c65c3ee1SRichard Henderson     return val ? val : 4; /* 0 == "*<<" */
145c65c3ee1SRichard Henderson }
146c65c3ee1SRichard Henderson 
14701afb7beSRichard Henderson 
14840f9f908SRichard Henderson /* Include the auto-generated decoder.  */
149abff1abfSPaolo Bonzini #include "decode-insns.c.inc"
15040f9f908SRichard Henderson 
15161766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated
15261766fe9SRichard Henderson    the iaq (for whatever reason), so don't do it again on exit.  */
153869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED  DISAS_TARGET_0
15461766fe9SRichard Henderson 
15561766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor
15661766fe9SRichard Henderson    updated the iaq for the next instruction to be executed.  */
157869051eaSRichard Henderson #define DISAS_IAQ_N_STALE    DISAS_TARGET_1
15861766fe9SRichard Henderson 
159e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately
160e1b5a5edSRichard Henderson    to recognize unmasked interrupts.  */
161e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT      DISAS_TARGET_2
162c5d0aec2SRichard Henderson #define DISAS_EXIT                  DISAS_TARGET_3
163e1b5a5edSRichard Henderson 
16461766fe9SRichard Henderson /* global register indexes */
1656fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32];
16633423472SRichard Henderson static TCGv_i64 cpu_sr[4];
167494737b7SRichard Henderson static TCGv_i64 cpu_srH;
1686fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f;
1696fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b;
170c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f;
171c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b;
1726fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar;
1736fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n;
1746fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v;
1756fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb;
1766fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb;
17761766fe9SRichard Henderson 
17861766fe9SRichard Henderson void hppa_translate_init(void)
17961766fe9SRichard Henderson {
18061766fe9SRichard Henderson #define DEF_VAR(V)  { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
18161766fe9SRichard Henderson 
1826fd0c7bcSRichard Henderson     typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar;
18361766fe9SRichard Henderson     static const GlobalVar vars[] = {
18435136a77SRichard Henderson         { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) },
18561766fe9SRichard Henderson         DEF_VAR(psw_n),
18661766fe9SRichard Henderson         DEF_VAR(psw_v),
18761766fe9SRichard Henderson         DEF_VAR(psw_cb),
18861766fe9SRichard Henderson         DEF_VAR(psw_cb_msb),
18961766fe9SRichard Henderson         DEF_VAR(iaoq_f),
19061766fe9SRichard Henderson         DEF_VAR(iaoq_b),
19161766fe9SRichard Henderson     };
19261766fe9SRichard Henderson 
19361766fe9SRichard Henderson #undef DEF_VAR
19461766fe9SRichard Henderson 
19561766fe9SRichard Henderson     /* Use the symbolic register names that match the disassembler.  */
19661766fe9SRichard Henderson     static const char gr_names[32][4] = {
19761766fe9SRichard Henderson         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
19861766fe9SRichard Henderson         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
19961766fe9SRichard Henderson         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
20061766fe9SRichard Henderson         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
20161766fe9SRichard Henderson     };
20233423472SRichard Henderson     /* SR[4-7] are not global registers so that we can index them.  */
203494737b7SRichard Henderson     static const char sr_names[5][4] = {
204494737b7SRichard Henderson         "sr0", "sr1", "sr2", "sr3", "srH"
20533423472SRichard Henderson     };
20661766fe9SRichard Henderson 
20761766fe9SRichard Henderson     int i;
20861766fe9SRichard Henderson 
209f764718dSRichard Henderson     cpu_gr[0] = NULL;
21061766fe9SRichard Henderson     for (i = 1; i < 32; i++) {
211ad75a51eSRichard Henderson         cpu_gr[i] = tcg_global_mem_new(tcg_env,
21261766fe9SRichard Henderson                                        offsetof(CPUHPPAState, gr[i]),
21361766fe9SRichard Henderson                                        gr_names[i]);
21461766fe9SRichard Henderson     }
21533423472SRichard Henderson     for (i = 0; i < 4; i++) {
216ad75a51eSRichard Henderson         cpu_sr[i] = tcg_global_mem_new_i64(tcg_env,
21733423472SRichard Henderson                                            offsetof(CPUHPPAState, sr[i]),
21833423472SRichard Henderson                                            sr_names[i]);
21933423472SRichard Henderson     }
220ad75a51eSRichard Henderson     cpu_srH = tcg_global_mem_new_i64(tcg_env,
221494737b7SRichard Henderson                                      offsetof(CPUHPPAState, sr[4]),
222494737b7SRichard Henderson                                      sr_names[4]);
22361766fe9SRichard Henderson 
22461766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(vars); ++i) {
22561766fe9SRichard Henderson         const GlobalVar *v = &vars[i];
226ad75a51eSRichard Henderson         *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name);
22761766fe9SRichard Henderson     }
228c301f34eSRichard Henderson 
229ad75a51eSRichard Henderson     cpu_iasq_f = tcg_global_mem_new_i64(tcg_env,
230c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_f),
231c301f34eSRichard Henderson                                         "iasq_f");
232ad75a51eSRichard Henderson     cpu_iasq_b = tcg_global_mem_new_i64(tcg_env,
233c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_b),
234c301f34eSRichard Henderson                                         "iasq_b");
23561766fe9SRichard Henderson }
23661766fe9SRichard Henderson 
237129e9cc3SRichard Henderson static DisasCond cond_make_f(void)
238129e9cc3SRichard Henderson {
239f764718dSRichard Henderson     return (DisasCond){
240f764718dSRichard Henderson         .c = TCG_COND_NEVER,
241f764718dSRichard Henderson         .a0 = NULL,
242f764718dSRichard Henderson         .a1 = NULL,
243f764718dSRichard Henderson     };
244129e9cc3SRichard Henderson }
245129e9cc3SRichard Henderson 
246df0232feSRichard Henderson static DisasCond cond_make_t(void)
247df0232feSRichard Henderson {
248df0232feSRichard Henderson     return (DisasCond){
249df0232feSRichard Henderson         .c = TCG_COND_ALWAYS,
250df0232feSRichard Henderson         .a0 = NULL,
251df0232feSRichard Henderson         .a1 = NULL,
252df0232feSRichard Henderson     };
253df0232feSRichard Henderson }
254df0232feSRichard Henderson 
255129e9cc3SRichard Henderson static DisasCond cond_make_n(void)
256129e9cc3SRichard Henderson {
257f764718dSRichard Henderson     return (DisasCond){
258f764718dSRichard Henderson         .c = TCG_COND_NE,
259f764718dSRichard Henderson         .a0 = cpu_psw_n,
2606fd0c7bcSRichard Henderson         .a1 = tcg_constant_i64(0)
261f764718dSRichard Henderson     };
262129e9cc3SRichard Henderson }
263129e9cc3SRichard Henderson 
2646fd0c7bcSRichard Henderson static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
265b47a4a02SSven Schnelle {
266b47a4a02SSven Schnelle     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
2674fe9533aSRichard Henderson     return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 };
2684fe9533aSRichard Henderson }
2694fe9533aSRichard Henderson 
2706fd0c7bcSRichard Henderson static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0)
2714fe9533aSRichard Henderson {
2726fd0c7bcSRichard Henderson     return cond_make_tmp(c, a0, tcg_constant_i64(0));
273b47a4a02SSven Schnelle }
274b47a4a02SSven Schnelle 
2756fd0c7bcSRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0)
276129e9cc3SRichard Henderson {
277aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2786fd0c7bcSRichard Henderson     tcg_gen_mov_i64(tmp, a0);
279b47a4a02SSven Schnelle     return cond_make_0_tmp(c, tmp);
280129e9cc3SRichard Henderson }
281129e9cc3SRichard Henderson 
2826fd0c7bcSRichard Henderson static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
283129e9cc3SRichard Henderson {
284aac0f603SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
285aac0f603SRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
286129e9cc3SRichard Henderson 
2876fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t0, a0);
2886fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t1, a1);
2894fe9533aSRichard Henderson     return cond_make_tmp(c, t0, t1);
290129e9cc3SRichard Henderson }
291129e9cc3SRichard Henderson 
292129e9cc3SRichard Henderson static void cond_free(DisasCond *cond)
293129e9cc3SRichard Henderson {
294129e9cc3SRichard Henderson     switch (cond->c) {
295129e9cc3SRichard Henderson     default:
296f764718dSRichard Henderson         cond->a0 = NULL;
297f764718dSRichard Henderson         cond->a1 = NULL;
298129e9cc3SRichard Henderson         /* fallthru */
299129e9cc3SRichard Henderson     case TCG_COND_ALWAYS:
300129e9cc3SRichard Henderson         cond->c = TCG_COND_NEVER;
301129e9cc3SRichard Henderson         break;
302129e9cc3SRichard Henderson     case TCG_COND_NEVER:
303129e9cc3SRichard Henderson         break;
304129e9cc3SRichard Henderson     }
305129e9cc3SRichard Henderson }
306129e9cc3SRichard Henderson 
3076fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg)
30861766fe9SRichard Henderson {
30961766fe9SRichard Henderson     if (reg == 0) {
310bc3da3cfSRichard Henderson         return ctx->zero;
31161766fe9SRichard Henderson     } else {
31261766fe9SRichard Henderson         return cpu_gr[reg];
31361766fe9SRichard Henderson     }
31461766fe9SRichard Henderson }
31561766fe9SRichard Henderson 
3166fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg)
31761766fe9SRichard Henderson {
318129e9cc3SRichard Henderson     if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
319aac0f603SRichard Henderson         return tcg_temp_new_i64();
32061766fe9SRichard Henderson     } else {
32161766fe9SRichard Henderson         return cpu_gr[reg];
32261766fe9SRichard Henderson     }
32361766fe9SRichard Henderson }
32461766fe9SRichard Henderson 
3256fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t)
326129e9cc3SRichard Henderson {
327129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
3286fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0,
329129e9cc3SRichard Henderson                             ctx->null_cond.a1, dest, t);
330129e9cc3SRichard Henderson     } else {
3316fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, t);
332129e9cc3SRichard Henderson     }
333129e9cc3SRichard Henderson }
334129e9cc3SRichard Henderson 
3356fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t)
336129e9cc3SRichard Henderson {
337129e9cc3SRichard Henderson     if (reg != 0) {
338129e9cc3SRichard Henderson         save_or_nullify(ctx, cpu_gr[reg], t);
339129e9cc3SRichard Henderson     }
340129e9cc3SRichard Henderson }
341129e9cc3SRichard Henderson 
342e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
34396d6407fSRichard Henderson # define HI_OFS  0
34496d6407fSRichard Henderson # define LO_OFS  4
34596d6407fSRichard Henderson #else
34696d6407fSRichard Henderson # define HI_OFS  4
34796d6407fSRichard Henderson # define LO_OFS  0
34896d6407fSRichard Henderson #endif
34996d6407fSRichard Henderson 
35096d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt)
35196d6407fSRichard Henderson {
35296d6407fSRichard Henderson     TCGv_i32 ret = tcg_temp_new_i32();
353ad75a51eSRichard Henderson     tcg_gen_ld_i32(ret, tcg_env,
35496d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
35596d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
35696d6407fSRichard Henderson     return ret;
35796d6407fSRichard Henderson }
35896d6407fSRichard Henderson 
359ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt)
360ebe9383cSRichard Henderson {
361ebe9383cSRichard Henderson     if (rt == 0) {
3620992a930SRichard Henderson         TCGv_i32 ret = tcg_temp_new_i32();
3630992a930SRichard Henderson         tcg_gen_movi_i32(ret, 0);
3640992a930SRichard Henderson         return ret;
365ebe9383cSRichard Henderson     } else {
366ebe9383cSRichard Henderson         return load_frw_i32(rt);
367ebe9383cSRichard Henderson     }
368ebe9383cSRichard Henderson }
369ebe9383cSRichard Henderson 
370ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt)
371ebe9383cSRichard Henderson {
372ebe9383cSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
3730992a930SRichard Henderson     if (rt == 0) {
3740992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
3750992a930SRichard Henderson     } else {
376ad75a51eSRichard Henderson         tcg_gen_ld32u_i64(ret, tcg_env,
377ebe9383cSRichard Henderson                           offsetof(CPUHPPAState, fr[rt & 31])
378ebe9383cSRichard Henderson                           + (rt & 32 ? LO_OFS : HI_OFS));
379ebe9383cSRichard Henderson     }
3800992a930SRichard Henderson     return ret;
381ebe9383cSRichard Henderson }
382ebe9383cSRichard Henderson 
38396d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val)
38496d6407fSRichard Henderson {
385ad75a51eSRichard Henderson     tcg_gen_st_i32(val, tcg_env,
38696d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
38796d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
38896d6407fSRichard Henderson }
38996d6407fSRichard Henderson 
39096d6407fSRichard Henderson #undef HI_OFS
39196d6407fSRichard Henderson #undef LO_OFS
39296d6407fSRichard Henderson 
39396d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt)
39496d6407fSRichard Henderson {
39596d6407fSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
396ad75a51eSRichard Henderson     tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt]));
39796d6407fSRichard Henderson     return ret;
39896d6407fSRichard Henderson }
39996d6407fSRichard Henderson 
400ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt)
401ebe9383cSRichard Henderson {
402ebe9383cSRichard Henderson     if (rt == 0) {
4030992a930SRichard Henderson         TCGv_i64 ret = tcg_temp_new_i64();
4040992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
4050992a930SRichard Henderson         return ret;
406ebe9383cSRichard Henderson     } else {
407ebe9383cSRichard Henderson         return load_frd(rt);
408ebe9383cSRichard Henderson     }
409ebe9383cSRichard Henderson }
410ebe9383cSRichard Henderson 
41196d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val)
41296d6407fSRichard Henderson {
413ad75a51eSRichard Henderson     tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt]));
41496d6407fSRichard Henderson }
41596d6407fSRichard Henderson 
41633423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg)
41733423472SRichard Henderson {
41833423472SRichard Henderson #ifdef CONFIG_USER_ONLY
41933423472SRichard Henderson     tcg_gen_movi_i64(dest, 0);
42033423472SRichard Henderson #else
42133423472SRichard Henderson     if (reg < 4) {
42233423472SRichard Henderson         tcg_gen_mov_i64(dest, cpu_sr[reg]);
423494737b7SRichard Henderson     } else if (ctx->tb_flags & TB_FLAG_SR_SAME) {
424494737b7SRichard Henderson         tcg_gen_mov_i64(dest, cpu_srH);
42533423472SRichard Henderson     } else {
426ad75a51eSRichard Henderson         tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg]));
42733423472SRichard Henderson     }
42833423472SRichard Henderson #endif
42933423472SRichard Henderson }
43033423472SRichard Henderson 
431129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified.
432129e9cc3SRichard Henderson    Use this when the insn is too complex for a conditional move.  */
433129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx)
434129e9cc3SRichard Henderson {
435129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
436129e9cc3SRichard Henderson         /* The always condition should have been handled in the main loop.  */
437129e9cc3SRichard Henderson         assert(ctx->null_cond.c != TCG_COND_ALWAYS);
438129e9cc3SRichard Henderson 
439129e9cc3SRichard Henderson         ctx->null_lab = gen_new_label();
440129e9cc3SRichard Henderson 
441129e9cc3SRichard Henderson         /* If we're using PSW[N], copy it to a temp because... */
4426e94937aSRichard Henderson         if (ctx->null_cond.a0 == cpu_psw_n) {
443aac0f603SRichard Henderson             ctx->null_cond.a0 = tcg_temp_new_i64();
4446fd0c7bcSRichard Henderson             tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n);
445129e9cc3SRichard Henderson         }
446129e9cc3SRichard Henderson         /* ... we clear it before branching over the implementation,
447129e9cc3SRichard Henderson            so that (1) it's clear after nullifying this insn and
448129e9cc3SRichard Henderson            (2) if this insn nullifies the next, PSW[N] is valid.  */
449129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
450129e9cc3SRichard Henderson             ctx->psw_n_nonzero = false;
4516fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
452129e9cc3SRichard Henderson         }
453129e9cc3SRichard Henderson 
4546fd0c7bcSRichard Henderson         tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0,
455129e9cc3SRichard Henderson                            ctx->null_cond.a1, ctx->null_lab);
456129e9cc3SRichard Henderson         cond_free(&ctx->null_cond);
457129e9cc3SRichard Henderson     }
458129e9cc3SRichard Henderson }
459129e9cc3SRichard Henderson 
460129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N].  */
461129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx)
462129e9cc3SRichard Henderson {
463129e9cc3SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
464129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
4656fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
466129e9cc3SRichard Henderson         }
467129e9cc3SRichard Henderson         return;
468129e9cc3SRichard Henderson     }
4696e94937aSRichard Henderson     if (ctx->null_cond.a0 != cpu_psw_n) {
4706fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n,
471129e9cc3SRichard Henderson                             ctx->null_cond.a0, ctx->null_cond.a1);
472129e9cc3SRichard Henderson         ctx->psw_n_nonzero = true;
473129e9cc3SRichard Henderson     }
474129e9cc3SRichard Henderson     cond_free(&ctx->null_cond);
475129e9cc3SRichard Henderson }
476129e9cc3SRichard Henderson 
477129e9cc3SRichard Henderson /* Set a PSW[N] to X.  The intention is that this is used immediately
478129e9cc3SRichard Henderson    before a goto_tb/exit_tb, so that there is no fallthru path to other
479129e9cc3SRichard Henderson    code within the TB.  Therefore we do not update psw_n_nonzero.  */
480129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x)
481129e9cc3SRichard Henderson {
482129e9cc3SRichard Henderson     if (ctx->psw_n_nonzero || x) {
4836fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, x);
484129e9cc3SRichard Henderson     }
485129e9cc3SRichard Henderson }
486129e9cc3SRichard Henderson 
487129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified.
48840f9f908SRichard Henderson    This is the pair to nullify_over.  Always returns true so that
48940f9f908SRichard Henderson    it may be tail-called from a translate function.  */
49031234768SRichard Henderson static bool nullify_end(DisasContext *ctx)
491129e9cc3SRichard Henderson {
492129e9cc3SRichard Henderson     TCGLabel *null_lab = ctx->null_lab;
49331234768SRichard Henderson     DisasJumpType status = ctx->base.is_jmp;
494129e9cc3SRichard Henderson 
495f49b3537SRichard Henderson     /* For NEXT, NORETURN, STALE, we can easily continue (or exit).
496f49b3537SRichard Henderson        For UPDATED, we cannot update on the nullified path.  */
497f49b3537SRichard Henderson     assert(status != DISAS_IAQ_N_UPDATED);
498f49b3537SRichard Henderson 
499129e9cc3SRichard Henderson     if (likely(null_lab == NULL)) {
500129e9cc3SRichard Henderson         /* The current insn wasn't conditional or handled the condition
501129e9cc3SRichard Henderson            applied to it without a branch, so the (new) setting of
502129e9cc3SRichard Henderson            NULL_COND can be applied directly to the next insn.  */
50331234768SRichard Henderson         return true;
504129e9cc3SRichard Henderson     }
505129e9cc3SRichard Henderson     ctx->null_lab = NULL;
506129e9cc3SRichard Henderson 
507129e9cc3SRichard Henderson     if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
508129e9cc3SRichard Henderson         /* The next instruction will be unconditional,
509129e9cc3SRichard Henderson            and NULL_COND already reflects that.  */
510129e9cc3SRichard Henderson         gen_set_label(null_lab);
511129e9cc3SRichard Henderson     } else {
512129e9cc3SRichard Henderson         /* The insn that we just executed is itself nullifying the next
513129e9cc3SRichard Henderson            instruction.  Store the condition in the PSW[N] global.
514129e9cc3SRichard Henderson            We asserted PSW[N] = 0 in nullify_over, so that after the
515129e9cc3SRichard Henderson            label we have the proper value in place.  */
516129e9cc3SRichard Henderson         nullify_save(ctx);
517129e9cc3SRichard Henderson         gen_set_label(null_lab);
518129e9cc3SRichard Henderson         ctx->null_cond = cond_make_n();
519129e9cc3SRichard Henderson     }
520869051eaSRichard Henderson     if (status == DISAS_NORETURN) {
52131234768SRichard Henderson         ctx->base.is_jmp = DISAS_NEXT;
522129e9cc3SRichard Henderson     }
52331234768SRichard Henderson     return true;
524129e9cc3SRichard Henderson }
525129e9cc3SRichard Henderson 
526c53e401eSRichard Henderson static uint64_t gva_offset_mask(DisasContext *ctx)
527698240d1SRichard Henderson {
528698240d1SRichard Henderson     return (ctx->tb_flags & PSW_W
529698240d1SRichard Henderson             ? MAKE_64BIT_MASK(0, 62)
530698240d1SRichard Henderson             : MAKE_64BIT_MASK(0, 32));
531698240d1SRichard Henderson }
532698240d1SRichard Henderson 
5336fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest,
5346fd0c7bcSRichard Henderson                             uint64_t ival, TCGv_i64 vval)
53561766fe9SRichard Henderson {
536c53e401eSRichard Henderson     uint64_t mask = gva_offset_mask(ctx);
537f13bf343SRichard Henderson 
538f13bf343SRichard Henderson     if (ival != -1) {
5396fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, ival & mask);
540f13bf343SRichard Henderson         return;
541f13bf343SRichard Henderson     }
542f13bf343SRichard Henderson     tcg_debug_assert(vval != NULL);
543f13bf343SRichard Henderson 
544f13bf343SRichard Henderson     /*
545f13bf343SRichard Henderson      * We know that the IAOQ is already properly masked.
546f13bf343SRichard Henderson      * This optimization is primarily for "iaoq_f = iaoq_b".
547f13bf343SRichard Henderson      */
548f13bf343SRichard Henderson     if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) {
5496fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, vval);
55061766fe9SRichard Henderson     } else {
5516fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, vval, mask);
55261766fe9SRichard Henderson     }
55361766fe9SRichard Henderson }
55461766fe9SRichard Henderson 
555c53e401eSRichard Henderson static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp)
55661766fe9SRichard Henderson {
55761766fe9SRichard Henderson     return ctx->iaoq_f + disp + 8;
55861766fe9SRichard Henderson }
55961766fe9SRichard Henderson 
56061766fe9SRichard Henderson static void gen_excp_1(int exception)
56161766fe9SRichard Henderson {
562ad75a51eSRichard Henderson     gen_helper_excp(tcg_env, tcg_constant_i32(exception));
56361766fe9SRichard Henderson }
56461766fe9SRichard Henderson 
56531234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception)
56661766fe9SRichard Henderson {
567741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
568741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
569129e9cc3SRichard Henderson     nullify_save(ctx);
57061766fe9SRichard Henderson     gen_excp_1(exception);
57131234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
57261766fe9SRichard Henderson }
57361766fe9SRichard Henderson 
57431234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc)
5751a19da0dSRichard Henderson {
57631234768SRichard Henderson     nullify_over(ctx);
5776fd0c7bcSRichard Henderson     tcg_gen_st_i64(tcg_constant_i64(ctx->insn),
578ad75a51eSRichard Henderson                    tcg_env, offsetof(CPUHPPAState, cr[CR_IIR]));
57931234768SRichard Henderson     gen_excp(ctx, exc);
58031234768SRichard Henderson     return nullify_end(ctx);
5811a19da0dSRichard Henderson }
5821a19da0dSRichard Henderson 
58331234768SRichard Henderson static bool gen_illegal(DisasContext *ctx)
58461766fe9SRichard Henderson {
58531234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_ILL);
58661766fe9SRichard Henderson }
58761766fe9SRichard Henderson 
58840f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY
58940f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
59040f9f908SRichard Henderson     return gen_excp_iir(ctx, EXCP)
59140f9f908SRichard Henderson #else
592e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
593e1b5a5edSRichard Henderson     do {                                     \
594e1b5a5edSRichard Henderson         if (ctx->privilege != 0) {           \
59531234768SRichard Henderson             return gen_excp_iir(ctx, EXCP);  \
596e1b5a5edSRichard Henderson         }                                    \
597e1b5a5edSRichard Henderson     } while (0)
59840f9f908SRichard Henderson #endif
599e1b5a5edSRichard Henderson 
600c53e401eSRichard Henderson static bool use_goto_tb(DisasContext *ctx, uint64_t dest)
60161766fe9SRichard Henderson {
60257f91498SRichard Henderson     return translator_use_goto_tb(&ctx->base, dest);
60361766fe9SRichard Henderson }
60461766fe9SRichard Henderson 
605129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page,
606129e9cc3SRichard Henderson    and we're not attempting to set a breakpoint on it, then we can
607129e9cc3SRichard Henderson    totally skip the nullified insn.  This avoids creating and
608129e9cc3SRichard Henderson    executing a TB that merely branches to the next TB.  */
609129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx)
610129e9cc3SRichard Henderson {
611129e9cc3SRichard Henderson     return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
612129e9cc3SRichard Henderson             && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
613129e9cc3SRichard Henderson }
614129e9cc3SRichard Henderson 
61561766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which,
616c53e401eSRichard Henderson                         uint64_t f, uint64_t b)
61761766fe9SRichard Henderson {
61861766fe9SRichard Henderson     if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
61961766fe9SRichard Henderson         tcg_gen_goto_tb(which);
620a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, f, NULL);
621a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, b, NULL);
62207ea28b4SRichard Henderson         tcg_gen_exit_tb(ctx->base.tb, which);
62361766fe9SRichard Henderson     } else {
624741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, f, cpu_iaoq_b);
625741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, b, ctx->iaoq_n_var);
6267f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
62761766fe9SRichard Henderson     }
62861766fe9SRichard Henderson }
62961766fe9SRichard Henderson 
630b47a4a02SSven Schnelle static bool cond_need_sv(int c)
631b47a4a02SSven Schnelle {
632b47a4a02SSven Schnelle     return c == 2 || c == 3 || c == 6;
633b47a4a02SSven Schnelle }
634b47a4a02SSven Schnelle 
635b47a4a02SSven Schnelle static bool cond_need_cb(int c)
636b47a4a02SSven Schnelle {
637b47a4a02SSven Schnelle     return c == 4 || c == 5;
638b47a4a02SSven Schnelle }
639b47a4a02SSven Schnelle 
6406fd0c7bcSRichard Henderson /* Need extensions from TCGv_i32 to TCGv_i64. */
64172ca8753SRichard Henderson static bool cond_need_ext(DisasContext *ctx, bool d)
64272ca8753SRichard Henderson {
643c53e401eSRichard Henderson     return !(ctx->is_pa20 && d);
64472ca8753SRichard Henderson }
64572ca8753SRichard Henderson 
646b47a4a02SSven Schnelle /*
647b47a4a02SSven Schnelle  * Compute conditional for arithmetic.  See Page 5-3, Table 5-1, of
648b47a4a02SSven Schnelle  * the Parisc 1.1 Architecture Reference Manual for details.
649b47a4a02SSven Schnelle  */
650b2167459SRichard Henderson 
651a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d,
6526fd0c7bcSRichard Henderson                          TCGv_i64 res, TCGv_i64 cb_msb, TCGv_i64 sv)
653b2167459SRichard Henderson {
654b2167459SRichard Henderson     DisasCond cond;
6556fd0c7bcSRichard Henderson     TCGv_i64 tmp;
656b2167459SRichard Henderson 
657b2167459SRichard Henderson     switch (cf >> 1) {
658b47a4a02SSven Schnelle     case 0: /* Never / TR    (0 / 1) */
659b2167459SRichard Henderson         cond = cond_make_f();
660b2167459SRichard Henderson         break;
661b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
662a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
663aac0f603SRichard Henderson             tmp = tcg_temp_new_i64();
6646fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
665a751eb31SRichard Henderson             res = tmp;
666a751eb31SRichard Henderson         }
667b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, res);
668b2167459SRichard Henderson         break;
669b47a4a02SSven Schnelle     case 2: /* < / >=        (N ^ V / !(N ^ V) */
670aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
6716fd0c7bcSRichard Henderson         tcg_gen_xor_i64(tmp, res, sv);
672a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
6736fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, tmp);
674a751eb31SRichard Henderson         }
675b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_LT, tmp);
676b2167459SRichard Henderson         break;
677b47a4a02SSven Schnelle     case 3: /* <= / >        (N ^ V) | Z / !((N ^ V) | Z) */
678b47a4a02SSven Schnelle         /*
679b47a4a02SSven Schnelle          * Simplify:
680b47a4a02SSven Schnelle          *   (N ^ V) | Z
681b47a4a02SSven Schnelle          *   ((res < 0) ^ (sv < 0)) | !res
682b47a4a02SSven Schnelle          *   ((res ^ sv) < 0) | !res
683b47a4a02SSven Schnelle          *   (~(res ^ sv) >= 0) | !res
684b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31) | !res
685b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31 & res)
686b47a4a02SSven Schnelle          */
687aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
6886fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(tmp, res, sv);
689a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
6906fd0c7bcSRichard Henderson             tcg_gen_sextract_i64(tmp, tmp, 31, 1);
6916fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
6926fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
693a751eb31SRichard Henderson         } else {
6946fd0c7bcSRichard Henderson             tcg_gen_sari_i64(tmp, tmp, 63);
6956fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
696a751eb31SRichard Henderson         }
697b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
698b2167459SRichard Henderson         break;
699b2167459SRichard Henderson     case 4: /* NUV / UV      (!C / C) */
700a751eb31SRichard Henderson         /* Only bit 0 of cb_msb is ever set. */
701b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, cb_msb);
702b2167459SRichard Henderson         break;
703b2167459SRichard Henderson     case 5: /* ZNV / VNZ     (!C | Z / C & !Z) */
704aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
7056fd0c7bcSRichard Henderson         tcg_gen_neg_i64(tmp, cb_msb);
7066fd0c7bcSRichard Henderson         tcg_gen_and_i64(tmp, tmp, res);
707a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
7086fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
709a751eb31SRichard Henderson         }
710b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
711b2167459SRichard Henderson         break;
712b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
713a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
714aac0f603SRichard Henderson             tmp = tcg_temp_new_i64();
7156fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, sv);
716a751eb31SRichard Henderson             sv = tmp;
717a751eb31SRichard Henderson         }
718b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, sv);
719b2167459SRichard Henderson         break;
720b2167459SRichard Henderson     case 7: /* OD / EV */
721aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
7226fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, res, 1);
723b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_NE, tmp);
724b2167459SRichard Henderson         break;
725b2167459SRichard Henderson     default:
726b2167459SRichard Henderson         g_assert_not_reached();
727b2167459SRichard Henderson     }
728b2167459SRichard Henderson     if (cf & 1) {
729b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
730b2167459SRichard Henderson     }
731b2167459SRichard Henderson 
732b2167459SRichard Henderson     return cond;
733b2167459SRichard Henderson }
734b2167459SRichard Henderson 
735b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
736b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
737b2167459SRichard Henderson    deleted as unused.  */
738b2167459SRichard Henderson 
7394fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d,
7406fd0c7bcSRichard Henderson                              TCGv_i64 res, TCGv_i64 in1,
7416fd0c7bcSRichard Henderson                              TCGv_i64 in2, TCGv_i64 sv)
742b2167459SRichard Henderson {
7434fe9533aSRichard Henderson     TCGCond tc;
7444fe9533aSRichard Henderson     bool ext_uns;
745b2167459SRichard Henderson 
746b2167459SRichard Henderson     switch (cf >> 1) {
747b2167459SRichard Henderson     case 1: /* = / <> */
7484fe9533aSRichard Henderson         tc = TCG_COND_EQ;
7494fe9533aSRichard Henderson         ext_uns = true;
750b2167459SRichard Henderson         break;
751b2167459SRichard Henderson     case 2: /* < / >= */
7524fe9533aSRichard Henderson         tc = TCG_COND_LT;
7534fe9533aSRichard Henderson         ext_uns = false;
754b2167459SRichard Henderson         break;
755b2167459SRichard Henderson     case 3: /* <= / > */
7564fe9533aSRichard Henderson         tc = TCG_COND_LE;
7574fe9533aSRichard Henderson         ext_uns = false;
758b2167459SRichard Henderson         break;
759b2167459SRichard Henderson     case 4: /* << / >>= */
7604fe9533aSRichard Henderson         tc = TCG_COND_LTU;
7614fe9533aSRichard Henderson         ext_uns = true;
762b2167459SRichard Henderson         break;
763b2167459SRichard Henderson     case 5: /* <<= / >> */
7644fe9533aSRichard Henderson         tc = TCG_COND_LEU;
7654fe9533aSRichard Henderson         ext_uns = true;
766b2167459SRichard Henderson         break;
767b2167459SRichard Henderson     default:
768a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, sv);
769b2167459SRichard Henderson     }
770b2167459SRichard Henderson 
7714fe9533aSRichard Henderson     if (cf & 1) {
7724fe9533aSRichard Henderson         tc = tcg_invert_cond(tc);
7734fe9533aSRichard Henderson     }
7744fe9533aSRichard Henderson     if (cond_need_ext(ctx, d)) {
775aac0f603SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
776aac0f603SRichard Henderson         TCGv_i64 t2 = tcg_temp_new_i64();
7774fe9533aSRichard Henderson 
7784fe9533aSRichard Henderson         if (ext_uns) {
7796fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t1, in1);
7806fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t2, in2);
7814fe9533aSRichard Henderson         } else {
7826fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t1, in1);
7836fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t2, in2);
7844fe9533aSRichard Henderson         }
7854fe9533aSRichard Henderson         return cond_make_tmp(tc, t1, t2);
7864fe9533aSRichard Henderson     }
7874fe9533aSRichard Henderson     return cond_make(tc, in1, in2);
788b2167459SRichard Henderson }
789b2167459SRichard Henderson 
790df0232feSRichard Henderson /*
791df0232feSRichard Henderson  * Similar, but for logicals, where the carry and overflow bits are not
792df0232feSRichard Henderson  * computed, and use of them is undefined.
793df0232feSRichard Henderson  *
794df0232feSRichard Henderson  * Undefined or not, hardware does not trap.  It seems reasonable to
795df0232feSRichard Henderson  * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's
796df0232feSRichard Henderson  * how cases c={2,3} are treated.
797df0232feSRichard Henderson  */
798b2167459SRichard Henderson 
799b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d,
8006fd0c7bcSRichard Henderson                              TCGv_i64 res)
801b2167459SRichard Henderson {
802b5af8423SRichard Henderson     TCGCond tc;
803b5af8423SRichard Henderson     bool ext_uns;
804a751eb31SRichard Henderson 
805df0232feSRichard Henderson     switch (cf) {
806df0232feSRichard Henderson     case 0:  /* never */
807df0232feSRichard Henderson     case 9:  /* undef, C */
808df0232feSRichard Henderson     case 11: /* undef, C & !Z */
809df0232feSRichard Henderson     case 12: /* undef, V */
810df0232feSRichard Henderson         return cond_make_f();
811df0232feSRichard Henderson 
812df0232feSRichard Henderson     case 1:  /* true */
813df0232feSRichard Henderson     case 8:  /* undef, !C */
814df0232feSRichard Henderson     case 10: /* undef, !C | Z */
815df0232feSRichard Henderson     case 13: /* undef, !V */
816df0232feSRichard Henderson         return cond_make_t();
817df0232feSRichard Henderson 
818df0232feSRichard Henderson     case 2:  /* == */
819b5af8423SRichard Henderson         tc = TCG_COND_EQ;
820b5af8423SRichard Henderson         ext_uns = true;
821b5af8423SRichard Henderson         break;
822df0232feSRichard Henderson     case 3:  /* <> */
823b5af8423SRichard Henderson         tc = TCG_COND_NE;
824b5af8423SRichard Henderson         ext_uns = true;
825b5af8423SRichard Henderson         break;
826df0232feSRichard Henderson     case 4:  /* < */
827b5af8423SRichard Henderson         tc = TCG_COND_LT;
828b5af8423SRichard Henderson         ext_uns = false;
829b5af8423SRichard Henderson         break;
830df0232feSRichard Henderson     case 5:  /* >= */
831b5af8423SRichard Henderson         tc = TCG_COND_GE;
832b5af8423SRichard Henderson         ext_uns = false;
833b5af8423SRichard Henderson         break;
834df0232feSRichard Henderson     case 6:  /* <= */
835b5af8423SRichard Henderson         tc = TCG_COND_LE;
836b5af8423SRichard Henderson         ext_uns = false;
837b5af8423SRichard Henderson         break;
838df0232feSRichard Henderson     case 7:  /* > */
839b5af8423SRichard Henderson         tc = TCG_COND_GT;
840b5af8423SRichard Henderson         ext_uns = false;
841b5af8423SRichard Henderson         break;
842df0232feSRichard Henderson 
843df0232feSRichard Henderson     case 14: /* OD */
844df0232feSRichard Henderson     case 15: /* EV */
845a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, NULL);
846df0232feSRichard Henderson 
847df0232feSRichard Henderson     default:
848df0232feSRichard Henderson         g_assert_not_reached();
849b2167459SRichard Henderson     }
850b5af8423SRichard Henderson 
851b5af8423SRichard Henderson     if (cond_need_ext(ctx, d)) {
852aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
853b5af8423SRichard Henderson 
854b5af8423SRichard Henderson         if (ext_uns) {
8556fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
856b5af8423SRichard Henderson         } else {
8576fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, res);
858b5af8423SRichard Henderson         }
859b5af8423SRichard Henderson         return cond_make_0_tmp(tc, tmp);
860b5af8423SRichard Henderson     }
861b5af8423SRichard Henderson     return cond_make_0(tc, res);
862b2167459SRichard Henderson }
863b2167459SRichard Henderson 
86498cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
86598cd9ca7SRichard Henderson 
8664fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d,
8676fd0c7bcSRichard Henderson                              TCGv_i64 res)
86898cd9ca7SRichard Henderson {
86998cd9ca7SRichard Henderson     unsigned c, f;
87098cd9ca7SRichard Henderson 
87198cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
87298cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
87398cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
87498cd9ca7SRichard Henderson     c = orig & 3;
87598cd9ca7SRichard Henderson     if (c == 3) {
87698cd9ca7SRichard Henderson         c = 7;
87798cd9ca7SRichard Henderson     }
87898cd9ca7SRichard Henderson     f = (orig & 4) / 4;
87998cd9ca7SRichard Henderson 
880b5af8423SRichard Henderson     return do_log_cond(ctx, c * 2 + f, d, res);
88198cd9ca7SRichard Henderson }
88298cd9ca7SRichard Henderson 
883b2167459SRichard Henderson /* Similar, but for unit conditions.  */
884b2167459SRichard Henderson 
8856fd0c7bcSRichard Henderson static DisasCond do_unit_cond(unsigned cf, bool d, TCGv_i64 res,
8866fd0c7bcSRichard Henderson                               TCGv_i64 in1, TCGv_i64 in2)
887b2167459SRichard Henderson {
888b2167459SRichard Henderson     DisasCond cond;
8896fd0c7bcSRichard Henderson     TCGv_i64 tmp, cb = NULL;
890c53e401eSRichard Henderson     uint64_t d_repl = d ? 0x0000000100000001ull : 1;
891b2167459SRichard Henderson 
892b2167459SRichard Henderson     if (cf & 8) {
893b2167459SRichard Henderson         /* Since we want to test lots of carry-out bits all at once, do not
894b2167459SRichard Henderson          * do our normal thing and compute carry-in of bit B+1 since that
895b2167459SRichard Henderson          * leaves us with carry bits spread across two words.
896b2167459SRichard Henderson          */
897aac0f603SRichard Henderson         cb = tcg_temp_new_i64();
898aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
8996fd0c7bcSRichard Henderson         tcg_gen_or_i64(cb, in1, in2);
9006fd0c7bcSRichard Henderson         tcg_gen_and_i64(tmp, in1, in2);
9016fd0c7bcSRichard Henderson         tcg_gen_andc_i64(cb, cb, res);
9026fd0c7bcSRichard Henderson         tcg_gen_or_i64(cb, cb, tmp);
903b2167459SRichard Henderson     }
904b2167459SRichard Henderson 
905b2167459SRichard Henderson     switch (cf >> 1) {
906b2167459SRichard Henderson     case 0: /* never / TR */
907b2167459SRichard Henderson     case 1: /* undefined */
908b2167459SRichard Henderson     case 5: /* undefined */
909b2167459SRichard Henderson         cond = cond_make_f();
910b2167459SRichard Henderson         break;
911b2167459SRichard Henderson 
912b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
913b2167459SRichard Henderson         /* See hasless(v,1) from
914b2167459SRichard Henderson          * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
915b2167459SRichard Henderson          */
916aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
9176fd0c7bcSRichard Henderson         tcg_gen_subi_i64(tmp, res, d_repl * 0x01010101u);
9186fd0c7bcSRichard Henderson         tcg_gen_andc_i64(tmp, tmp, res);
9196fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80808080u);
920b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
921b2167459SRichard Henderson         break;
922b2167459SRichard Henderson 
923b2167459SRichard Henderson     case 3: /* SHZ / NHZ */
924aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
9256fd0c7bcSRichard Henderson         tcg_gen_subi_i64(tmp, res, d_repl * 0x00010001u);
9266fd0c7bcSRichard Henderson         tcg_gen_andc_i64(tmp, tmp, res);
9276fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80008000u);
928b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
929b2167459SRichard Henderson         break;
930b2167459SRichard Henderson 
931b2167459SRichard Henderson     case 4: /* SDC / NDC */
9326fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x88888888u);
933b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
934b2167459SRichard Henderson         break;
935b2167459SRichard Henderson 
936b2167459SRichard Henderson     case 6: /* SBC / NBC */
9376fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x80808080u);
938b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
939b2167459SRichard Henderson         break;
940b2167459SRichard Henderson 
941b2167459SRichard Henderson     case 7: /* SHC / NHC */
9426fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x80008000u);
943b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
944b2167459SRichard Henderson         break;
945b2167459SRichard Henderson 
946b2167459SRichard Henderson     default:
947b2167459SRichard Henderson         g_assert_not_reached();
948b2167459SRichard Henderson     }
949b2167459SRichard Henderson     if (cf & 1) {
950b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
951b2167459SRichard Henderson     }
952b2167459SRichard Henderson 
953b2167459SRichard Henderson     return cond;
954b2167459SRichard Henderson }
955b2167459SRichard Henderson 
9566fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d,
9576fd0c7bcSRichard Henderson                           TCGv_i64 cb, TCGv_i64 cb_msb)
95872ca8753SRichard Henderson {
95972ca8753SRichard Henderson     if (cond_need_ext(ctx, d)) {
960aac0f603SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
9616fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, cb, 32, 1);
96272ca8753SRichard Henderson         return t;
96372ca8753SRichard Henderson     }
96472ca8753SRichard Henderson     return cb_msb;
96572ca8753SRichard Henderson }
96672ca8753SRichard Henderson 
9676fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d)
96872ca8753SRichard Henderson {
96972ca8753SRichard Henderson     return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb);
97072ca8753SRichard Henderson }
97172ca8753SRichard Henderson 
972b2167459SRichard Henderson /* Compute signed overflow for addition.  */
9736fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res,
9746fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
975b2167459SRichard Henderson {
976aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
977aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
978b2167459SRichard Henderson 
9796fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
9806fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
9816fd0c7bcSRichard Henderson     tcg_gen_andc_i64(sv, sv, tmp);
982b2167459SRichard Henderson 
983b2167459SRichard Henderson     return sv;
984b2167459SRichard Henderson }
985b2167459SRichard Henderson 
986b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
9876fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res,
9886fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
989b2167459SRichard Henderson {
990aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
991aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
992b2167459SRichard Henderson 
9936fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
9946fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
9956fd0c7bcSRichard Henderson     tcg_gen_and_i64(sv, sv, tmp);
996b2167459SRichard Henderson 
997b2167459SRichard Henderson     return sv;
998b2167459SRichard Henderson }
999b2167459SRichard Henderson 
10006fd0c7bcSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
10016fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned shift, bool is_l,
1002faf97ba1SRichard Henderson                    bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d)
1003b2167459SRichard Henderson {
10046fd0c7bcSRichard Henderson     TCGv_i64 dest, cb, cb_msb, cb_cond, sv, tmp;
1005b2167459SRichard Henderson     unsigned c = cf >> 1;
1006b2167459SRichard Henderson     DisasCond cond;
1007b2167459SRichard Henderson 
1008aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1009f764718dSRichard Henderson     cb = NULL;
1010f764718dSRichard Henderson     cb_msb = NULL;
1011bdcccc17SRichard Henderson     cb_cond = NULL;
1012b2167459SRichard Henderson 
1013b2167459SRichard Henderson     if (shift) {
1014aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
10156fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, in1, shift);
1016b2167459SRichard Henderson         in1 = tmp;
1017b2167459SRichard Henderson     }
1018b2167459SRichard Henderson 
1019b47a4a02SSven Schnelle     if (!is_l || cond_need_cb(c)) {
1020aac0f603SRichard Henderson         cb_msb = tcg_temp_new_i64();
1021aac0f603SRichard Henderson         cb = tcg_temp_new_i64();
1022bdcccc17SRichard Henderson 
1023a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero);
1024b2167459SRichard Henderson         if (is_c) {
10256fd0c7bcSRichard Henderson             tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb,
1026a4db4a78SRichard Henderson                              get_psw_carry(ctx, d), ctx->zero);
1027b2167459SRichard Henderson         }
10286fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
10296fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1030bdcccc17SRichard Henderson         if (cond_need_cb(c)) {
1031bdcccc17SRichard Henderson             cb_cond = get_carry(ctx, d, cb, cb_msb);
1032b2167459SRichard Henderson         }
1033b2167459SRichard Henderson     } else {
10346fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
1035b2167459SRichard Henderson         if (is_c) {
10366fd0c7bcSRichard Henderson             tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d));
1037b2167459SRichard Henderson         }
1038b2167459SRichard Henderson     }
1039b2167459SRichard Henderson 
1040b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1041f764718dSRichard Henderson     sv = NULL;
1042b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1043b2167459SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
1044b2167459SRichard Henderson         if (is_tsv) {
1045b2167459SRichard Henderson             /* ??? Need to include overflow from shift.  */
1046ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1047b2167459SRichard Henderson         }
1048b2167459SRichard Henderson     }
1049b2167459SRichard Henderson 
1050b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1051a751eb31SRichard Henderson     cond = do_cond(ctx, cf, d, dest, cb_cond, sv);
1052b2167459SRichard Henderson     if (is_tc) {
1053aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
10546fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1055ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1056b2167459SRichard Henderson     }
1057b2167459SRichard Henderson 
1058b2167459SRichard Henderson     /* Write back the result.  */
1059b2167459SRichard Henderson     if (!is_l) {
1060b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
1061b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1062b2167459SRichard Henderson     }
1063b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1064b2167459SRichard Henderson 
1065b2167459SRichard Henderson     /* Install the new nullification.  */
1066b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1067b2167459SRichard Henderson     ctx->null_cond = cond;
1068b2167459SRichard Henderson }
1069b2167459SRichard Henderson 
1070faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a,
10710c982a28SRichard Henderson                        bool is_l, bool is_tsv, bool is_tc, bool is_c)
10720c982a28SRichard Henderson {
10736fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
10740c982a28SRichard Henderson 
10750c982a28SRichard Henderson     if (a->cf) {
10760c982a28SRichard Henderson         nullify_over(ctx);
10770c982a28SRichard Henderson     }
10780c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
10790c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1080faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l,
1081faf97ba1SRichard Henderson            is_tsv, is_tc, is_c, a->cf, a->d);
10820c982a28SRichard Henderson     return nullify_end(ctx);
10830c982a28SRichard Henderson }
10840c982a28SRichard Henderson 
10850588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a,
10860588e061SRichard Henderson                        bool is_tsv, bool is_tc)
10870588e061SRichard Henderson {
10886fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
10890588e061SRichard Henderson 
10900588e061SRichard Henderson     if (a->cf) {
10910588e061SRichard Henderson         nullify_over(ctx);
10920588e061SRichard Henderson     }
10936fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
10940588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
1095faf97ba1SRichard Henderson     /* All ADDI conditions are 32-bit. */
1096faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false);
10970588e061SRichard Henderson     return nullify_end(ctx);
10980588e061SRichard Henderson }
10990588e061SRichard Henderson 
11006fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
11016fd0c7bcSRichard Henderson                    TCGv_i64 in2, bool is_tsv, bool is_b,
110263c427c6SRichard Henderson                    bool is_tc, unsigned cf, bool d)
1103b2167459SRichard Henderson {
1104a4db4a78SRichard Henderson     TCGv_i64 dest, sv, cb, cb_msb, tmp;
1105b2167459SRichard Henderson     unsigned c = cf >> 1;
1106b2167459SRichard Henderson     DisasCond cond;
1107b2167459SRichard Henderson 
1108aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1109aac0f603SRichard Henderson     cb = tcg_temp_new_i64();
1110aac0f603SRichard Henderson     cb_msb = tcg_temp_new_i64();
1111b2167459SRichard Henderson 
1112b2167459SRichard Henderson     if (is_b) {
1113b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
11146fd0c7bcSRichard Henderson         tcg_gen_not_i64(cb, in2);
1115a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero,
1116a4db4a78SRichard Henderson                          get_psw_carry(ctx, d), ctx->zero);
1117a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero);
11186fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, in1);
11196fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1120b2167459SRichard Henderson     } else {
1121bdcccc17SRichard Henderson         /*
1122bdcccc17SRichard Henderson          * DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
1123bdcccc17SRichard Henderson          * operations by seeding the high word with 1 and subtracting.
1124bdcccc17SRichard Henderson          */
11256fd0c7bcSRichard Henderson         TCGv_i64 one = tcg_constant_i64(1);
1126a4db4a78SRichard Henderson         tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero);
11276fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(cb, in1, in2);
11286fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1129b2167459SRichard Henderson     }
1130b2167459SRichard Henderson 
1131b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1132f764718dSRichard Henderson     sv = NULL;
1133b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1134b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1135b2167459SRichard Henderson         if (is_tsv) {
1136ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1137b2167459SRichard Henderson         }
1138b2167459SRichard Henderson     }
1139b2167459SRichard Henderson 
1140b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
1141b2167459SRichard Henderson     if (!is_b) {
11424fe9533aSRichard Henderson         cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1143b2167459SRichard Henderson     } else {
1144a751eb31SRichard Henderson         cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv);
1145b2167459SRichard Henderson     }
1146b2167459SRichard Henderson 
1147b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1148b2167459SRichard Henderson     if (is_tc) {
1149aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
11506fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1151ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1152b2167459SRichard Henderson     }
1153b2167459SRichard Henderson 
1154b2167459SRichard Henderson     /* Write back the result.  */
1155b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
1156b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1157b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1158b2167459SRichard Henderson 
1159b2167459SRichard Henderson     /* Install the new nullification.  */
1160b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1161b2167459SRichard Henderson     ctx->null_cond = cond;
1162b2167459SRichard Henderson }
1163b2167459SRichard Henderson 
116463c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a,
11650c982a28SRichard Henderson                        bool is_tsv, bool is_b, bool is_tc)
11660c982a28SRichard Henderson {
11676fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
11680c982a28SRichard Henderson 
11690c982a28SRichard Henderson     if (a->cf) {
11700c982a28SRichard Henderson         nullify_over(ctx);
11710c982a28SRichard Henderson     }
11720c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
11730c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
117463c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d);
11750c982a28SRichard Henderson     return nullify_end(ctx);
11760c982a28SRichard Henderson }
11770c982a28SRichard Henderson 
11780588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv)
11790588e061SRichard Henderson {
11806fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
11810588e061SRichard Henderson 
11820588e061SRichard Henderson     if (a->cf) {
11830588e061SRichard Henderson         nullify_over(ctx);
11840588e061SRichard Henderson     }
11856fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
11860588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
118763c427c6SRichard Henderson     /* All SUBI conditions are 32-bit. */
118863c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false);
11890588e061SRichard Henderson     return nullify_end(ctx);
11900588e061SRichard Henderson }
11910588e061SRichard Henderson 
11926fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
11936fd0c7bcSRichard Henderson                       TCGv_i64 in2, unsigned cf, bool d)
1194b2167459SRichard Henderson {
11956fd0c7bcSRichard Henderson     TCGv_i64 dest, sv;
1196b2167459SRichard Henderson     DisasCond cond;
1197b2167459SRichard Henderson 
1198aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
11996fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
1200b2167459SRichard Henderson 
1201b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1202f764718dSRichard Henderson     sv = NULL;
1203b47a4a02SSven Schnelle     if (cond_need_sv(cf >> 1)) {
1204b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1205b2167459SRichard Henderson     }
1206b2167459SRichard Henderson 
1207b2167459SRichard Henderson     /* Form the condition for the compare.  */
12084fe9533aSRichard Henderson     cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1209b2167459SRichard Henderson 
1210b2167459SRichard Henderson     /* Clear.  */
12116fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
1212b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1213b2167459SRichard Henderson 
1214b2167459SRichard Henderson     /* Install the new nullification.  */
1215b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1216b2167459SRichard Henderson     ctx->null_cond = cond;
1217b2167459SRichard Henderson }
1218b2167459SRichard Henderson 
12196fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12206fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned cf, bool d,
12216fd0c7bcSRichard Henderson                    void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1222b2167459SRichard Henderson {
12236fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, rt);
1224b2167459SRichard Henderson 
1225b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
1226b2167459SRichard Henderson     fn(dest, in1, in2);
1227b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1228b2167459SRichard Henderson 
1229b2167459SRichard Henderson     /* Install the new nullification.  */
1230b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1231b2167459SRichard Henderson     if (cf) {
1232b5af8423SRichard Henderson         ctx->null_cond = do_log_cond(ctx, cf, d, dest);
1233b2167459SRichard Henderson     }
1234b2167459SRichard Henderson }
1235b2167459SRichard Henderson 
1236fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a,
12376fd0c7bcSRichard Henderson                        void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
12380c982a28SRichard Henderson {
12396fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
12400c982a28SRichard Henderson 
12410c982a28SRichard Henderson     if (a->cf) {
12420c982a28SRichard Henderson         nullify_over(ctx);
12430c982a28SRichard Henderson     }
12440c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
12450c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1246fa8e3bedSRichard Henderson     do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn);
12470c982a28SRichard Henderson     return nullify_end(ctx);
12480c982a28SRichard Henderson }
12490c982a28SRichard Henderson 
12506fd0c7bcSRichard Henderson static void do_unit(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12516fd0c7bcSRichard Henderson                     TCGv_i64 in2, unsigned cf, bool d, bool is_tc,
12526fd0c7bcSRichard Henderson                     void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1253b2167459SRichard Henderson {
12546fd0c7bcSRichard Henderson     TCGv_i64 dest;
1255b2167459SRichard Henderson     DisasCond cond;
1256b2167459SRichard Henderson 
1257b2167459SRichard Henderson     if (cf == 0) {
1258b2167459SRichard Henderson         dest = dest_gpr(ctx, rt);
1259b2167459SRichard Henderson         fn(dest, in1, in2);
1260b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1261b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1262b2167459SRichard Henderson     } else {
1263aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
1264b2167459SRichard Henderson         fn(dest, in1, in2);
1265b2167459SRichard Henderson 
126659963d8fSRichard Henderson         cond = do_unit_cond(cf, d, dest, in1, in2);
1267b2167459SRichard Henderson 
1268b2167459SRichard Henderson         if (is_tc) {
1269aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
12706fd0c7bcSRichard Henderson             tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1271ad75a51eSRichard Henderson             gen_helper_tcond(tcg_env, tmp);
1272b2167459SRichard Henderson         }
1273b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1274b2167459SRichard Henderson 
1275b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1276b2167459SRichard Henderson         ctx->null_cond = cond;
1277b2167459SRichard Henderson     }
1278b2167459SRichard Henderson }
1279b2167459SRichard Henderson 
128086f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY
12818d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space
12828d6ae7fbSRichard Henderson    from the top 2 bits of the base register.  There are a few system
12838d6ae7fbSRichard Henderson    instructions that have a 3-bit space specifier, for which SR0 is
12848d6ae7fbSRichard Henderson    not special.  To handle this, pass ~SP.  */
12856fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base)
128686f8d05fSRichard Henderson {
128786f8d05fSRichard Henderson     TCGv_ptr ptr;
12886fd0c7bcSRichard Henderson     TCGv_i64 tmp;
128986f8d05fSRichard Henderson     TCGv_i64 spc;
129086f8d05fSRichard Henderson 
129186f8d05fSRichard Henderson     if (sp != 0) {
12928d6ae7fbSRichard Henderson         if (sp < 0) {
12938d6ae7fbSRichard Henderson             sp = ~sp;
12948d6ae7fbSRichard Henderson         }
12956fd0c7bcSRichard Henderson         spc = tcg_temp_new_i64();
12968d6ae7fbSRichard Henderson         load_spr(ctx, spc, sp);
12978d6ae7fbSRichard Henderson         return spc;
129886f8d05fSRichard Henderson     }
1299494737b7SRichard Henderson     if (ctx->tb_flags & TB_FLAG_SR_SAME) {
1300494737b7SRichard Henderson         return cpu_srH;
1301494737b7SRichard Henderson     }
130286f8d05fSRichard Henderson 
130386f8d05fSRichard Henderson     ptr = tcg_temp_new_ptr();
1304aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
13056fd0c7bcSRichard Henderson     spc = tcg_temp_new_i64();
130686f8d05fSRichard Henderson 
1307698240d1SRichard Henderson     /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */
13086fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5);
13096fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, 030);
13106fd0c7bcSRichard Henderson     tcg_gen_trunc_i64_ptr(ptr, tmp);
131186f8d05fSRichard Henderson 
1312ad75a51eSRichard Henderson     tcg_gen_add_ptr(ptr, ptr, tcg_env);
131386f8d05fSRichard Henderson     tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4]));
131486f8d05fSRichard Henderson 
131586f8d05fSRichard Henderson     return spc;
131686f8d05fSRichard Henderson }
131786f8d05fSRichard Henderson #endif
131886f8d05fSRichard Henderson 
13196fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
1320c53e401eSRichard Henderson                      unsigned rb, unsigned rx, int scale, int64_t disp,
132186f8d05fSRichard Henderson                      unsigned sp, int modify, bool is_phys)
132286f8d05fSRichard Henderson {
13236fd0c7bcSRichard Henderson     TCGv_i64 base = load_gpr(ctx, rb);
13246fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13256fd0c7bcSRichard Henderson     TCGv_i64 addr;
132686f8d05fSRichard Henderson 
132786f8d05fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
132886f8d05fSRichard Henderson     if (rx) {
1329aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
13306fd0c7bcSRichard Henderson         tcg_gen_shli_i64(ofs, cpu_gr[rx], scale);
13316fd0c7bcSRichard Henderson         tcg_gen_add_i64(ofs, ofs, base);
133286f8d05fSRichard Henderson     } else if (disp || modify) {
1333aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
13346fd0c7bcSRichard Henderson         tcg_gen_addi_i64(ofs, base, disp);
133586f8d05fSRichard Henderson     } else {
133686f8d05fSRichard Henderson         ofs = base;
133786f8d05fSRichard Henderson     }
133886f8d05fSRichard Henderson 
133986f8d05fSRichard Henderson     *pofs = ofs;
13406fd0c7bcSRichard Henderson     *pgva = addr = tcg_temp_new_i64();
1341d265360fSRichard Henderson     tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base, gva_offset_mask(ctx));
1342698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY
134386f8d05fSRichard Henderson     if (!is_phys) {
1344d265360fSRichard Henderson         tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base));
134586f8d05fSRichard Henderson     }
134686f8d05fSRichard Henderson #endif
134786f8d05fSRichard Henderson }
134886f8d05fSRichard Henderson 
134996d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
135096d6407fSRichard Henderson  * < 0 for pre-modify,
135196d6407fSRichard Henderson  * > 0 for post-modify,
135296d6407fSRichard Henderson  * = 0 for no base register update.
135396d6407fSRichard Henderson  */
135496d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1355c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
135614776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
135796d6407fSRichard Henderson {
13586fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13596fd0c7bcSRichard Henderson     TCGv_i64 addr;
136096d6407fSRichard Henderson 
136196d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
136296d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
136396d6407fSRichard Henderson 
136486f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
136586f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1366c1f55d97SRichard Henderson     tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
136786f8d05fSRichard Henderson     if (modify) {
136886f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
136996d6407fSRichard Henderson     }
137096d6407fSRichard Henderson }
137196d6407fSRichard Henderson 
137296d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1373c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
137414776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
137596d6407fSRichard Henderson {
13766fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13776fd0c7bcSRichard Henderson     TCGv_i64 addr;
137896d6407fSRichard Henderson 
137996d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
138096d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
138196d6407fSRichard Henderson 
138286f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
138386f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1384217d1a5eSRichard Henderson     tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
138586f8d05fSRichard Henderson     if (modify) {
138686f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
138796d6407fSRichard Henderson     }
138896d6407fSRichard Henderson }
138996d6407fSRichard Henderson 
139096d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1391c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
139214776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
139396d6407fSRichard Henderson {
13946fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13956fd0c7bcSRichard Henderson     TCGv_i64 addr;
139696d6407fSRichard Henderson 
139796d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
139896d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
139996d6407fSRichard Henderson 
140086f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
140186f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1402217d1a5eSRichard Henderson     tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
140386f8d05fSRichard Henderson     if (modify) {
140486f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
140596d6407fSRichard Henderson     }
140696d6407fSRichard Henderson }
140796d6407fSRichard Henderson 
140896d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1409c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
141014776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
141196d6407fSRichard Henderson {
14126fd0c7bcSRichard Henderson     TCGv_i64 ofs;
14136fd0c7bcSRichard Henderson     TCGv_i64 addr;
141496d6407fSRichard Henderson 
141596d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
141696d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
141796d6407fSRichard Henderson 
141886f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
141986f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1420217d1a5eSRichard Henderson     tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
142186f8d05fSRichard Henderson     if (modify) {
142286f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
142396d6407fSRichard Henderson     }
142496d6407fSRichard Henderson }
142596d6407fSRichard Henderson 
14261cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1427c53e401eSRichard Henderson                     unsigned rx, int scale, int64_t disp,
142814776ab5STony Nguyen                     unsigned sp, int modify, MemOp mop)
142996d6407fSRichard Henderson {
14306fd0c7bcSRichard Henderson     TCGv_i64 dest;
143196d6407fSRichard Henderson 
143296d6407fSRichard Henderson     nullify_over(ctx);
143396d6407fSRichard Henderson 
143496d6407fSRichard Henderson     if (modify == 0) {
143596d6407fSRichard Henderson         /* No base register update.  */
143696d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
143796d6407fSRichard Henderson     } else {
143896d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
1439aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
144096d6407fSRichard Henderson     }
14416fd0c7bcSRichard Henderson     do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
144296d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
144396d6407fSRichard Henderson 
14441cd012a5SRichard Henderson     return nullify_end(ctx);
144596d6407fSRichard Henderson }
144696d6407fSRichard Henderson 
1447740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
1448c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
144986f8d05fSRichard Henderson                       unsigned sp, int modify)
145096d6407fSRichard Henderson {
145196d6407fSRichard Henderson     TCGv_i32 tmp;
145296d6407fSRichard Henderson 
145396d6407fSRichard Henderson     nullify_over(ctx);
145496d6407fSRichard Henderson 
145596d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
145686f8d05fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
145796d6407fSRichard Henderson     save_frw_i32(rt, tmp);
145896d6407fSRichard Henderson 
145996d6407fSRichard Henderson     if (rt == 0) {
1460ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
146196d6407fSRichard Henderson     }
146296d6407fSRichard Henderson 
1463740038d7SRichard Henderson     return nullify_end(ctx);
146496d6407fSRichard Henderson }
146596d6407fSRichard Henderson 
1466740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a)
1467740038d7SRichard Henderson {
1468740038d7SRichard Henderson     return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1469740038d7SRichard Henderson                      a->disp, a->sp, a->m);
1470740038d7SRichard Henderson }
1471740038d7SRichard Henderson 
1472740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1473c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
147486f8d05fSRichard Henderson                       unsigned sp, int modify)
147596d6407fSRichard Henderson {
147696d6407fSRichard Henderson     TCGv_i64 tmp;
147796d6407fSRichard Henderson 
147896d6407fSRichard Henderson     nullify_over(ctx);
147996d6407fSRichard Henderson 
148096d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
1481fc313c64SFrédéric Pétrot     do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
148296d6407fSRichard Henderson     save_frd(rt, tmp);
148396d6407fSRichard Henderson 
148496d6407fSRichard Henderson     if (rt == 0) {
1485ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
148696d6407fSRichard Henderson     }
148796d6407fSRichard Henderson 
1488740038d7SRichard Henderson     return nullify_end(ctx);
1489740038d7SRichard Henderson }
1490740038d7SRichard Henderson 
1491740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a)
1492740038d7SRichard Henderson {
1493740038d7SRichard Henderson     return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1494740038d7SRichard Henderson                      a->disp, a->sp, a->m);
149596d6407fSRichard Henderson }
149696d6407fSRichard Henderson 
14971cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb,
1498c53e401eSRichard Henderson                      int64_t disp, unsigned sp,
149914776ab5STony Nguyen                      int modify, MemOp mop)
150096d6407fSRichard Henderson {
150196d6407fSRichard Henderson     nullify_over(ctx);
15026fd0c7bcSRichard Henderson     do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
15031cd012a5SRichard Henderson     return nullify_end(ctx);
150496d6407fSRichard Henderson }
150596d6407fSRichard Henderson 
1506740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1507c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
150886f8d05fSRichard Henderson                        unsigned sp, int modify)
150996d6407fSRichard Henderson {
151096d6407fSRichard Henderson     TCGv_i32 tmp;
151196d6407fSRichard Henderson 
151296d6407fSRichard Henderson     nullify_over(ctx);
151396d6407fSRichard Henderson 
151496d6407fSRichard Henderson     tmp = load_frw_i32(rt);
151586f8d05fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
151696d6407fSRichard Henderson 
1517740038d7SRichard Henderson     return nullify_end(ctx);
151896d6407fSRichard Henderson }
151996d6407fSRichard Henderson 
1520740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a)
1521740038d7SRichard Henderson {
1522740038d7SRichard Henderson     return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1523740038d7SRichard Henderson                       a->disp, a->sp, a->m);
1524740038d7SRichard Henderson }
1525740038d7SRichard Henderson 
1526740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1527c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
152886f8d05fSRichard Henderson                        unsigned sp, int modify)
152996d6407fSRichard Henderson {
153096d6407fSRichard Henderson     TCGv_i64 tmp;
153196d6407fSRichard Henderson 
153296d6407fSRichard Henderson     nullify_over(ctx);
153396d6407fSRichard Henderson 
153496d6407fSRichard Henderson     tmp = load_frd(rt);
1535fc313c64SFrédéric Pétrot     do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
153696d6407fSRichard Henderson 
1537740038d7SRichard Henderson     return nullify_end(ctx);
1538740038d7SRichard Henderson }
1539740038d7SRichard Henderson 
1540740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a)
1541740038d7SRichard Henderson {
1542740038d7SRichard Henderson     return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1543740038d7SRichard Henderson                       a->disp, a->sp, a->m);
154496d6407fSRichard Henderson }
154596d6407fSRichard Henderson 
15461ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1547ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1548ebe9383cSRichard Henderson {
1549ebe9383cSRichard Henderson     TCGv_i32 tmp;
1550ebe9383cSRichard Henderson 
1551ebe9383cSRichard Henderson     nullify_over(ctx);
1552ebe9383cSRichard Henderson     tmp = load_frw0_i32(ra);
1553ebe9383cSRichard Henderson 
1554ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1555ebe9383cSRichard Henderson 
1556ebe9383cSRichard Henderson     save_frw_i32(rt, tmp);
15571ca74648SRichard Henderson     return nullify_end(ctx);
1558ebe9383cSRichard Henderson }
1559ebe9383cSRichard Henderson 
15601ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1561ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1562ebe9383cSRichard Henderson {
1563ebe9383cSRichard Henderson     TCGv_i32 dst;
1564ebe9383cSRichard Henderson     TCGv_i64 src;
1565ebe9383cSRichard Henderson 
1566ebe9383cSRichard Henderson     nullify_over(ctx);
1567ebe9383cSRichard Henderson     src = load_frd(ra);
1568ebe9383cSRichard Henderson     dst = tcg_temp_new_i32();
1569ebe9383cSRichard Henderson 
1570ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1571ebe9383cSRichard Henderson 
1572ebe9383cSRichard Henderson     save_frw_i32(rt, dst);
15731ca74648SRichard Henderson     return nullify_end(ctx);
1574ebe9383cSRichard Henderson }
1575ebe9383cSRichard Henderson 
15761ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1577ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1578ebe9383cSRichard Henderson {
1579ebe9383cSRichard Henderson     TCGv_i64 tmp;
1580ebe9383cSRichard Henderson 
1581ebe9383cSRichard Henderson     nullify_over(ctx);
1582ebe9383cSRichard Henderson     tmp = load_frd0(ra);
1583ebe9383cSRichard Henderson 
1584ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1585ebe9383cSRichard Henderson 
1586ebe9383cSRichard Henderson     save_frd(rt, tmp);
15871ca74648SRichard Henderson     return nullify_end(ctx);
1588ebe9383cSRichard Henderson }
1589ebe9383cSRichard Henderson 
15901ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1591ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1592ebe9383cSRichard Henderson {
1593ebe9383cSRichard Henderson     TCGv_i32 src;
1594ebe9383cSRichard Henderson     TCGv_i64 dst;
1595ebe9383cSRichard Henderson 
1596ebe9383cSRichard Henderson     nullify_over(ctx);
1597ebe9383cSRichard Henderson     src = load_frw0_i32(ra);
1598ebe9383cSRichard Henderson     dst = tcg_temp_new_i64();
1599ebe9383cSRichard Henderson 
1600ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1601ebe9383cSRichard Henderson 
1602ebe9383cSRichard Henderson     save_frd(rt, dst);
16031ca74648SRichard Henderson     return nullify_end(ctx);
1604ebe9383cSRichard Henderson }
1605ebe9383cSRichard Henderson 
16061ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt,
1607ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
160831234768SRichard Henderson                         void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
1609ebe9383cSRichard Henderson {
1610ebe9383cSRichard Henderson     TCGv_i32 a, b;
1611ebe9383cSRichard Henderson 
1612ebe9383cSRichard Henderson     nullify_over(ctx);
1613ebe9383cSRichard Henderson     a = load_frw0_i32(ra);
1614ebe9383cSRichard Henderson     b = load_frw0_i32(rb);
1615ebe9383cSRichard Henderson 
1616ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1617ebe9383cSRichard Henderson 
1618ebe9383cSRichard Henderson     save_frw_i32(rt, a);
16191ca74648SRichard Henderson     return nullify_end(ctx);
1620ebe9383cSRichard Henderson }
1621ebe9383cSRichard Henderson 
16221ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt,
1623ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
162431234768SRichard Henderson                         void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
1625ebe9383cSRichard Henderson {
1626ebe9383cSRichard Henderson     TCGv_i64 a, b;
1627ebe9383cSRichard Henderson 
1628ebe9383cSRichard Henderson     nullify_over(ctx);
1629ebe9383cSRichard Henderson     a = load_frd0(ra);
1630ebe9383cSRichard Henderson     b = load_frd0(rb);
1631ebe9383cSRichard Henderson 
1632ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1633ebe9383cSRichard Henderson 
1634ebe9383cSRichard Henderson     save_frd(rt, a);
16351ca74648SRichard Henderson     return nullify_end(ctx);
1636ebe9383cSRichard Henderson }
1637ebe9383cSRichard Henderson 
163898cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
163998cd9ca7SRichard Henderson    have already had nullification handled.  */
1640c53e401eSRichard Henderson static bool do_dbranch(DisasContext *ctx, uint64_t dest,
164198cd9ca7SRichard Henderson                        unsigned link, bool is_n)
164298cd9ca7SRichard Henderson {
164398cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
164498cd9ca7SRichard Henderson         if (link != 0) {
1645741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
164698cd9ca7SRichard Henderson         }
164798cd9ca7SRichard Henderson         ctx->iaoq_n = dest;
164898cd9ca7SRichard Henderson         if (is_n) {
164998cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
165098cd9ca7SRichard Henderson         }
165198cd9ca7SRichard Henderson     } else {
165298cd9ca7SRichard Henderson         nullify_over(ctx);
165398cd9ca7SRichard Henderson 
165498cd9ca7SRichard Henderson         if (link != 0) {
1655741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
165698cd9ca7SRichard Henderson         }
165798cd9ca7SRichard Henderson 
165898cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
165998cd9ca7SRichard Henderson             nullify_set(ctx, 0);
166098cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, dest, dest + 4);
166198cd9ca7SRichard Henderson         } else {
166298cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
166398cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
166498cd9ca7SRichard Henderson         }
166598cd9ca7SRichard Henderson 
166631234768SRichard Henderson         nullify_end(ctx);
166798cd9ca7SRichard Henderson 
166898cd9ca7SRichard Henderson         nullify_set(ctx, 0);
166998cd9ca7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
167031234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
167198cd9ca7SRichard Henderson     }
167201afb7beSRichard Henderson     return true;
167398cd9ca7SRichard Henderson }
167498cd9ca7SRichard Henderson 
167598cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
167698cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
1677c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n,
167898cd9ca7SRichard Henderson                        DisasCond *cond)
167998cd9ca7SRichard Henderson {
1680c53e401eSRichard Henderson     uint64_t dest = iaoq_dest(ctx, disp);
168198cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
168298cd9ca7SRichard Henderson     TCGCond c = cond->c;
168398cd9ca7SRichard Henderson     bool n;
168498cd9ca7SRichard Henderson 
168598cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
168698cd9ca7SRichard Henderson 
168798cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
168898cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
168901afb7beSRichard Henderson         return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
169098cd9ca7SRichard Henderson     }
169198cd9ca7SRichard Henderson     if (c == TCG_COND_NEVER) {
169201afb7beSRichard Henderson         return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
169398cd9ca7SRichard Henderson     }
169498cd9ca7SRichard Henderson 
169598cd9ca7SRichard Henderson     taken = gen_new_label();
16966fd0c7bcSRichard Henderson     tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken);
169798cd9ca7SRichard Henderson     cond_free(cond);
169898cd9ca7SRichard Henderson 
169998cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
170098cd9ca7SRichard Henderson     n = is_n && disp < 0;
170198cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
170298cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1703a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
170498cd9ca7SRichard Henderson     } else {
170598cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
170698cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
170798cd9ca7SRichard Henderson             ctx->null_lab = NULL;
170898cd9ca7SRichard Henderson         }
170998cd9ca7SRichard Henderson         nullify_set(ctx, n);
1710c301f34eSRichard Henderson         if (ctx->iaoq_n == -1) {
1711c301f34eSRichard Henderson             /* The temporary iaoq_n_var died at the branch above.
1712c301f34eSRichard Henderson                Regenerate it here instead of saving it.  */
17136fd0c7bcSRichard Henderson             tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
1714c301f34eSRichard Henderson         }
1715a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
171698cd9ca7SRichard Henderson     }
171798cd9ca7SRichard Henderson 
171898cd9ca7SRichard Henderson     gen_set_label(taken);
171998cd9ca7SRichard Henderson 
172098cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
172198cd9ca7SRichard Henderson     n = is_n && disp >= 0;
172298cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
172398cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1724a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, dest, dest + 4);
172598cd9ca7SRichard Henderson     } else {
172698cd9ca7SRichard Henderson         nullify_set(ctx, n);
1727a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
172898cd9ca7SRichard Henderson     }
172998cd9ca7SRichard Henderson 
173098cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
173198cd9ca7SRichard Henderson     if (ctx->null_lab) {
173298cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
173398cd9ca7SRichard Henderson         ctx->null_lab = NULL;
173431234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
173598cd9ca7SRichard Henderson     } else {
173631234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
173798cd9ca7SRichard Henderson     }
173801afb7beSRichard Henderson     return true;
173998cd9ca7SRichard Henderson }
174098cd9ca7SRichard Henderson 
174198cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target.  This handles
174298cd9ca7SRichard Henderson    nullification of the branch itself.  */
17436fd0c7bcSRichard Henderson static bool do_ibranch(DisasContext *ctx, TCGv_i64 dest,
174498cd9ca7SRichard Henderson                        unsigned link, bool is_n)
174598cd9ca7SRichard Henderson {
17466fd0c7bcSRichard Henderson     TCGv_i64 a0, a1, next, tmp;
174798cd9ca7SRichard Henderson     TCGCond c;
174898cd9ca7SRichard Henderson 
174998cd9ca7SRichard Henderson     assert(ctx->null_lab == NULL);
175098cd9ca7SRichard Henderson 
175198cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
175298cd9ca7SRichard Henderson         if (link != 0) {
1753741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
175498cd9ca7SRichard Henderson         }
1755aac0f603SRichard Henderson         next = tcg_temp_new_i64();
17566fd0c7bcSRichard Henderson         tcg_gen_mov_i64(next, dest);
175798cd9ca7SRichard Henderson         if (is_n) {
1758c301f34eSRichard Henderson             if (use_nullify_skip(ctx)) {
1759a0180973SRichard Henderson                 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, next);
17606fd0c7bcSRichard Henderson                 tcg_gen_addi_i64(next, next, 4);
1761a0180973SRichard Henderson                 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
1762c301f34eSRichard Henderson                 nullify_set(ctx, 0);
176331234768SRichard Henderson                 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
176401afb7beSRichard Henderson                 return true;
1765c301f34eSRichard Henderson             }
176698cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
176798cd9ca7SRichard Henderson         }
1768c301f34eSRichard Henderson         ctx->iaoq_n = -1;
1769c301f34eSRichard Henderson         ctx->iaoq_n_var = next;
177098cd9ca7SRichard Henderson     } else if (is_n && use_nullify_skip(ctx)) {
177198cd9ca7SRichard Henderson         /* The (conditional) branch, B, nullifies the next insn, N,
177298cd9ca7SRichard Henderson            and we're allowed to skip execution N (no single-step or
17734137cb83SRichard Henderson            tracepoint in effect).  Since the goto_ptr that we must use
177498cd9ca7SRichard Henderson            for the indirect branch consumes no special resources, we
177598cd9ca7SRichard Henderson            can (conditionally) skip B and continue execution.  */
177698cd9ca7SRichard Henderson         /* The use_nullify_skip test implies we have a known control path.  */
177798cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_b != -1);
177898cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_n != -1);
177998cd9ca7SRichard Henderson 
178098cd9ca7SRichard Henderson         /* We do have to handle the non-local temporary, DEST, before
178198cd9ca7SRichard Henderson            branching.  Since IOAQ_F is not really live at this point, we
178298cd9ca7SRichard Henderson            can simply store DEST optimistically.  Similarly with IAOQ_B.  */
1783a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, dest);
1784aac0f603SRichard Henderson         next = tcg_temp_new_i64();
17856fd0c7bcSRichard Henderson         tcg_gen_addi_i64(next, dest, 4);
1786a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
178798cd9ca7SRichard Henderson 
178898cd9ca7SRichard Henderson         nullify_over(ctx);
178998cd9ca7SRichard Henderson         if (link != 0) {
17909a91dd84SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
179198cd9ca7SRichard Henderson         }
17927f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
179301afb7beSRichard Henderson         return nullify_end(ctx);
179498cd9ca7SRichard Henderson     } else {
179598cd9ca7SRichard Henderson         c = ctx->null_cond.c;
179698cd9ca7SRichard Henderson         a0 = ctx->null_cond.a0;
179798cd9ca7SRichard Henderson         a1 = ctx->null_cond.a1;
179898cd9ca7SRichard Henderson 
1799aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
1800aac0f603SRichard Henderson         next = tcg_temp_new_i64();
180198cd9ca7SRichard Henderson 
1802741322f4SRichard Henderson         copy_iaoq_entry(ctx, tmp, ctx->iaoq_n, ctx->iaoq_n_var);
18036fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(c, next, a0, a1, tmp, dest);
180498cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
180598cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
180698cd9ca7SRichard Henderson 
180798cd9ca7SRichard Henderson         if (link != 0) {
18086fd0c7bcSRichard Henderson             tcg_gen_movcond_i64(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
180998cd9ca7SRichard Henderson         }
181098cd9ca7SRichard Henderson 
181198cd9ca7SRichard Henderson         if (is_n) {
181298cd9ca7SRichard Henderson             /* The branch nullifies the next insn, which means the state of N
181398cd9ca7SRichard Henderson                after the branch is the inverse of the state of N that applied
181498cd9ca7SRichard Henderson                to the branch.  */
18156fd0c7bcSRichard Henderson             tcg_gen_setcond_i64(tcg_invert_cond(c), cpu_psw_n, a0, a1);
181698cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
181798cd9ca7SRichard Henderson             ctx->null_cond = cond_make_n();
181898cd9ca7SRichard Henderson             ctx->psw_n_nonzero = true;
181998cd9ca7SRichard Henderson         } else {
182098cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
182198cd9ca7SRichard Henderson         }
182298cd9ca7SRichard Henderson     }
182301afb7beSRichard Henderson     return true;
182498cd9ca7SRichard Henderson }
182598cd9ca7SRichard Henderson 
1826660eefe1SRichard Henderson /* Implement
1827660eefe1SRichard Henderson  *    if (IAOQ_Front{30..31} < GR[b]{30..31})
1828660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← GR[b]{30..31};
1829660eefe1SRichard Henderson  *    else
1830660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← IAOQ_Front{30..31};
1831660eefe1SRichard Henderson  * which keeps the privilege level from being increased.
1832660eefe1SRichard Henderson  */
18336fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset)
1834660eefe1SRichard Henderson {
18356fd0c7bcSRichard Henderson     TCGv_i64 dest;
1836660eefe1SRichard Henderson     switch (ctx->privilege) {
1837660eefe1SRichard Henderson     case 0:
1838660eefe1SRichard Henderson         /* Privilege 0 is maximum and is allowed to decrease.  */
1839660eefe1SRichard Henderson         return offset;
1840660eefe1SRichard Henderson     case 3:
1841993119feSRichard Henderson         /* Privilege 3 is minimum and is never allowed to increase.  */
1842aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
18436fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, offset, 3);
1844660eefe1SRichard Henderson         break;
1845660eefe1SRichard Henderson     default:
1846aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
18476fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, offset, -4);
18486fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, ctx->privilege);
18496fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(TCG_COND_GTU, dest, dest, offset, dest, offset);
1850660eefe1SRichard Henderson         break;
1851660eefe1SRichard Henderson     }
1852660eefe1SRichard Henderson     return dest;
1853660eefe1SRichard Henderson }
1854660eefe1SRichard Henderson 
1855ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
18567ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
18577ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
18587ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
18597ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
18607ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
18617ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
18627ad439dfSRichard Henderson    aforementioned BE.  */
186331234768SRichard Henderson static void do_page_zero(DisasContext *ctx)
18647ad439dfSRichard Henderson {
18656fd0c7bcSRichard Henderson     TCGv_i64 tmp;
1866a0180973SRichard Henderson 
18677ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
18687ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
18698b81968cSMichael Tokarev        next insn within the privileged page.  */
18707ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
18717ad439dfSRichard Henderson     case TCG_COND_NEVER:
18727ad439dfSRichard Henderson         break;
18737ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
18746fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, 0);
18757ad439dfSRichard Henderson         goto do_sigill;
18767ad439dfSRichard Henderson     default:
18777ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
18787ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
18797ad439dfSRichard Henderson         g_assert_not_reached();
18807ad439dfSRichard Henderson     }
18817ad439dfSRichard Henderson 
18827ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
18837ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
18847ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
18857ad439dfSRichard Henderson        under such conditions.  */
18867ad439dfSRichard Henderson     if (ctx->iaoq_b != ctx->iaoq_f + 4) {
18877ad439dfSRichard Henderson         goto do_sigill;
18887ad439dfSRichard Henderson     }
18897ad439dfSRichard Henderson 
1890ebd0e151SRichard Henderson     switch (ctx->iaoq_f & -4) {
18917ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
18922986721dSRichard Henderson         gen_excp_1(EXCP_IMP);
189331234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
189431234768SRichard Henderson         break;
18957ad439dfSRichard Henderson 
18967ad439dfSRichard Henderson     case 0xb0: /* LWS */
18977ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
189831234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
189931234768SRichard Henderson         break;
19007ad439dfSRichard Henderson 
19017ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
19026fd0c7bcSRichard Henderson         tcg_gen_st_i64(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27]));
1903aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
19046fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_gr[31], 3);
1905a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
19066fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, 4);
1907a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
190831234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
190931234768SRichard Henderson         break;
19107ad439dfSRichard Henderson 
19117ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
19127ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
191331234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
191431234768SRichard Henderson         break;
19157ad439dfSRichard Henderson 
19167ad439dfSRichard Henderson     default:
19177ad439dfSRichard Henderson     do_sigill:
19182986721dSRichard Henderson         gen_excp_1(EXCP_ILL);
191931234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
192031234768SRichard Henderson         break;
19217ad439dfSRichard Henderson     }
19227ad439dfSRichard Henderson }
1923ba1d0b44SRichard Henderson #endif
19247ad439dfSRichard Henderson 
1925deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a)
1926b2167459SRichard Henderson {
1927b2167459SRichard Henderson     cond_free(&ctx->null_cond);
192831234768SRichard Henderson     return true;
1929b2167459SRichard Henderson }
1930b2167459SRichard Henderson 
193140f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a)
193298a9cb79SRichard Henderson {
193331234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_BREAK);
193498a9cb79SRichard Henderson }
193598a9cb79SRichard Henderson 
1936e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a)
193798a9cb79SRichard Henderson {
193898a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
193998a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
194098a9cb79SRichard Henderson 
194198a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
194231234768SRichard Henderson     return true;
194398a9cb79SRichard Henderson }
194498a9cb79SRichard Henderson 
1945c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a)
194698a9cb79SRichard Henderson {
1947c603e14aSRichard Henderson     unsigned rt = a->t;
19486fd0c7bcSRichard Henderson     TCGv_i64 tmp = dest_gpr(ctx, rt);
19496fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tmp, ctx->iaoq_f);
195098a9cb79SRichard Henderson     save_gpr(ctx, rt, tmp);
195198a9cb79SRichard Henderson 
195298a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
195331234768SRichard Henderson     return true;
195498a9cb79SRichard Henderson }
195598a9cb79SRichard Henderson 
1956c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a)
195798a9cb79SRichard Henderson {
1958c603e14aSRichard Henderson     unsigned rt = a->t;
1959c603e14aSRichard Henderson     unsigned rs = a->sp;
196033423472SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
196198a9cb79SRichard Henderson 
196233423472SRichard Henderson     load_spr(ctx, t0, rs);
196333423472SRichard Henderson     tcg_gen_shri_i64(t0, t0, 32);
196433423472SRichard Henderson 
1965967662cdSRichard Henderson     save_gpr(ctx, rt, t0);
196698a9cb79SRichard Henderson 
196798a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
196831234768SRichard Henderson     return true;
196998a9cb79SRichard Henderson }
197098a9cb79SRichard Henderson 
1971c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a)
197298a9cb79SRichard Henderson {
1973c603e14aSRichard Henderson     unsigned rt = a->t;
1974c603e14aSRichard Henderson     unsigned ctl = a->r;
19756fd0c7bcSRichard Henderson     TCGv_i64 tmp;
197698a9cb79SRichard Henderson 
197798a9cb79SRichard Henderson     switch (ctl) {
197835136a77SRichard Henderson     case CR_SAR:
1979c603e14aSRichard Henderson         if (a->e == 0) {
198098a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
198198a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
19826fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
198398a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
198435136a77SRichard Henderson             goto done;
198598a9cb79SRichard Henderson         }
198698a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
198735136a77SRichard Henderson         goto done;
198835136a77SRichard Henderson     case CR_IT: /* Interval Timer */
198935136a77SRichard Henderson         /* FIXME: Respect PSW_S bit.  */
199035136a77SRichard Henderson         nullify_over(ctx);
199198a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
1992dfd1b812SRichard Henderson         if (translator_io_start(&ctx->base)) {
199349c29d6cSRichard Henderson             gen_helper_read_interval_timer(tmp);
199431234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
199549c29d6cSRichard Henderson         } else {
199649c29d6cSRichard Henderson             gen_helper_read_interval_timer(tmp);
199749c29d6cSRichard Henderson         }
199898a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
199931234768SRichard Henderson         return nullify_end(ctx);
200098a9cb79SRichard Henderson     case 26:
200198a9cb79SRichard Henderson     case 27:
200298a9cb79SRichard Henderson         break;
200398a9cb79SRichard Henderson     default:
200498a9cb79SRichard Henderson         /* All other control registers are privileged.  */
200535136a77SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
200635136a77SRichard Henderson         break;
200798a9cb79SRichard Henderson     }
200898a9cb79SRichard Henderson 
2009aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
20106fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
201135136a77SRichard Henderson     save_gpr(ctx, rt, tmp);
201235136a77SRichard Henderson 
201335136a77SRichard Henderson  done:
201498a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
201531234768SRichard Henderson     return true;
201698a9cb79SRichard Henderson }
201798a9cb79SRichard Henderson 
2018c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
201933423472SRichard Henderson {
2020c603e14aSRichard Henderson     unsigned rr = a->r;
2021c603e14aSRichard Henderson     unsigned rs = a->sp;
2022967662cdSRichard Henderson     TCGv_i64 tmp;
202333423472SRichard Henderson 
202433423472SRichard Henderson     if (rs >= 5) {
202533423472SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
202633423472SRichard Henderson     }
202733423472SRichard Henderson     nullify_over(ctx);
202833423472SRichard Henderson 
2029967662cdSRichard Henderson     tmp = tcg_temp_new_i64();
2030967662cdSRichard Henderson     tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32);
203133423472SRichard Henderson 
203233423472SRichard Henderson     if (rs >= 4) {
2033967662cdSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs]));
2034494737b7SRichard Henderson         ctx->tb_flags &= ~TB_FLAG_SR_SAME;
203533423472SRichard Henderson     } else {
2036967662cdSRichard Henderson         tcg_gen_mov_i64(cpu_sr[rs], tmp);
203733423472SRichard Henderson     }
203833423472SRichard Henderson 
203931234768SRichard Henderson     return nullify_end(ctx);
204033423472SRichard Henderson }
204133423472SRichard Henderson 
2042c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
204398a9cb79SRichard Henderson {
2044c603e14aSRichard Henderson     unsigned ctl = a->t;
20456fd0c7bcSRichard Henderson     TCGv_i64 reg;
20466fd0c7bcSRichard Henderson     TCGv_i64 tmp;
204798a9cb79SRichard Henderson 
204835136a77SRichard Henderson     if (ctl == CR_SAR) {
20494845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
2050aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
20516fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31);
205298a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
205398a9cb79SRichard Henderson 
205498a9cb79SRichard Henderson         cond_free(&ctx->null_cond);
205531234768SRichard Henderson         return true;
205698a9cb79SRichard Henderson     }
205798a9cb79SRichard Henderson 
205835136a77SRichard Henderson     /* All other control registers are privileged or read-only.  */
205935136a77SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
206035136a77SRichard Henderson 
2061c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
206235136a77SRichard Henderson     nullify_over(ctx);
2063*4c34bab0SHelge Deller 
2064*4c34bab0SHelge Deller     if (ctx->is_pa20) {
20654845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
2066*4c34bab0SHelge Deller     } else {
2067*4c34bab0SHelge Deller         reg = tcg_temp_new_i64();
2068*4c34bab0SHelge Deller         tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r));
2069*4c34bab0SHelge Deller     }
20704845f015SSven Schnelle 
207135136a77SRichard Henderson     switch (ctl) {
207235136a77SRichard Henderson     case CR_IT:
2073ad75a51eSRichard Henderson         gen_helper_write_interval_timer(tcg_env, reg);
207435136a77SRichard Henderson         break;
20754f5f2548SRichard Henderson     case CR_EIRR:
2076ad75a51eSRichard Henderson         gen_helper_write_eirr(tcg_env, reg);
20774f5f2548SRichard Henderson         break;
20784f5f2548SRichard Henderson     case CR_EIEM:
2079ad75a51eSRichard Henderson         gen_helper_write_eiem(tcg_env, reg);
208031234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
20814f5f2548SRichard Henderson         break;
20824f5f2548SRichard Henderson 
208335136a77SRichard Henderson     case CR_IIASQ:
208435136a77SRichard Henderson     case CR_IIAOQ:
208535136a77SRichard Henderson         /* FIXME: Respect PSW_Q bit */
208635136a77SRichard Henderson         /* The write advances the queue and stores to the back element.  */
2087aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
20886fd0c7bcSRichard Henderson         tcg_gen_ld_i64(tmp, tcg_env,
208935136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
20906fd0c7bcSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
20916fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env,
209235136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
209335136a77SRichard Henderson         break;
209435136a77SRichard Henderson 
2095d5de20bdSSven Schnelle     case CR_PID1:
2096d5de20bdSSven Schnelle     case CR_PID2:
2097d5de20bdSSven Schnelle     case CR_PID3:
2098d5de20bdSSven Schnelle     case CR_PID4:
20996fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
2100d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY
2101ad75a51eSRichard Henderson         gen_helper_change_prot_id(tcg_env);
2102d5de20bdSSven Schnelle #endif
2103d5de20bdSSven Schnelle         break;
2104d5de20bdSSven Schnelle 
210535136a77SRichard Henderson     default:
21066fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
210735136a77SRichard Henderson         break;
210835136a77SRichard Henderson     }
210931234768SRichard Henderson     return nullify_end(ctx);
21104f5f2548SRichard Henderson #endif
211135136a77SRichard Henderson }
211235136a77SRichard Henderson 
2113c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
211498a9cb79SRichard Henderson {
2115aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
211698a9cb79SRichard Henderson 
21176fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, load_gpr(ctx, a->r));
21186fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31);
211998a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
212098a9cb79SRichard Henderson 
212198a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
212231234768SRichard Henderson     return true;
212398a9cb79SRichard Henderson }
212498a9cb79SRichard Henderson 
2125e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a)
212698a9cb79SRichard Henderson {
21276fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
212898a9cb79SRichard Henderson 
21292330504cSHelge Deller #ifdef CONFIG_USER_ONLY
21302330504cSHelge Deller     /* We don't implement space registers in user mode. */
21316fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
21322330504cSHelge Deller #else
2133967662cdSRichard Henderson     tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
2134967662cdSRichard Henderson     tcg_gen_shri_i64(dest, dest, 32);
21352330504cSHelge Deller #endif
2136e36f27efSRichard Henderson     save_gpr(ctx, a->t, dest);
213798a9cb79SRichard Henderson 
213898a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
213931234768SRichard Henderson     return true;
214098a9cb79SRichard Henderson }
214198a9cb79SRichard Henderson 
2142e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a)
2143e36f27efSRichard Henderson {
2144e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2145e1b5a5edSRichard Henderson #ifndef CONFIG_USER_ONLY
21466fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2147e1b5a5edSRichard Henderson 
2148e1b5a5edSRichard Henderson     nullify_over(ctx);
2149e1b5a5edSRichard Henderson 
2150aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
21516fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
21526fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ~a->i);
2153ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2154e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2155e1b5a5edSRichard Henderson 
2156e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_M.  */
215731234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
215831234768SRichard Henderson     return nullify_end(ctx);
2159e36f27efSRichard Henderson #endif
2160e1b5a5edSRichard Henderson }
2161e1b5a5edSRichard Henderson 
2162e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
2163e1b5a5edSRichard Henderson {
2164e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2165e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
21666fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2167e1b5a5edSRichard Henderson 
2168e1b5a5edSRichard Henderson     nullify_over(ctx);
2169e1b5a5edSRichard Henderson 
2170aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
21716fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
21726fd0c7bcSRichard Henderson     tcg_gen_ori_i64(tmp, tmp, a->i);
2173ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2174e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2175e1b5a5edSRichard Henderson 
2176e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_I.  */
217731234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
217831234768SRichard Henderson     return nullify_end(ctx);
2179e36f27efSRichard Henderson #endif
2180e1b5a5edSRichard Henderson }
2181e1b5a5edSRichard Henderson 
2182c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
2183e1b5a5edSRichard Henderson {
2184e1b5a5edSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2185c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
21866fd0c7bcSRichard Henderson     TCGv_i64 tmp, reg;
2187e1b5a5edSRichard Henderson     nullify_over(ctx);
2188e1b5a5edSRichard Henderson 
2189c603e14aSRichard Henderson     reg = load_gpr(ctx, a->r);
2190aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2191ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, reg);
2192e1b5a5edSRichard Henderson 
2193e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts.  */
219431234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
219531234768SRichard Henderson     return nullify_end(ctx);
2196c603e14aSRichard Henderson #endif
2197e1b5a5edSRichard Henderson }
2198f49b3537SRichard Henderson 
2199e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r)
2200f49b3537SRichard Henderson {
2201f49b3537SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2202e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
2203f49b3537SRichard Henderson     nullify_over(ctx);
2204f49b3537SRichard Henderson 
2205e36f27efSRichard Henderson     if (rfi_r) {
2206ad75a51eSRichard Henderson         gen_helper_rfi_r(tcg_env);
2207f49b3537SRichard Henderson     } else {
2208ad75a51eSRichard Henderson         gen_helper_rfi(tcg_env);
2209f49b3537SRichard Henderson     }
221031234768SRichard Henderson     /* Exit the TB to recognize new interrupts.  */
221107ea28b4SRichard Henderson     tcg_gen_exit_tb(NULL, 0);
221231234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
2213f49b3537SRichard Henderson 
221431234768SRichard Henderson     return nullify_end(ctx);
2215e36f27efSRichard Henderson #endif
2216f49b3537SRichard Henderson }
22176210db05SHelge Deller 
2218e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a)
2219e36f27efSRichard Henderson {
2220e36f27efSRichard Henderson     return do_rfi(ctx, false);
2221e36f27efSRichard Henderson }
2222e36f27efSRichard Henderson 
2223e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a)
2224e36f27efSRichard Henderson {
2225e36f27efSRichard Henderson     return do_rfi(ctx, true);
2226e36f27efSRichard Henderson }
2227e36f27efSRichard Henderson 
222896927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a)
22296210db05SHelge Deller {
22306210db05SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
223196927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
22326210db05SHelge Deller     nullify_over(ctx);
2233ad75a51eSRichard Henderson     gen_helper_halt(tcg_env);
223431234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
223531234768SRichard Henderson     return nullify_end(ctx);
223696927adbSRichard Henderson #endif
22376210db05SHelge Deller }
223896927adbSRichard Henderson 
223996927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a)
224096927adbSRichard Henderson {
224196927adbSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
224296927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
224396927adbSRichard Henderson     nullify_over(ctx);
2244ad75a51eSRichard Henderson     gen_helper_reset(tcg_env);
224596927adbSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
224696927adbSRichard Henderson     return nullify_end(ctx);
224796927adbSRichard Henderson #endif
224896927adbSRichard Henderson }
2249e1b5a5edSRichard Henderson 
22504a4554c6SHelge Deller static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
22514a4554c6SHelge Deller {
22524a4554c6SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
22534a4554c6SHelge Deller #ifndef CONFIG_USER_ONLY
22544a4554c6SHelge Deller     nullify_over(ctx);
2255ad75a51eSRichard Henderson     gen_helper_getshadowregs(tcg_env);
22564a4554c6SHelge Deller     return nullify_end(ctx);
22574a4554c6SHelge Deller #endif
22584a4554c6SHelge Deller }
22594a4554c6SHelge Deller 
2260deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
226198a9cb79SRichard Henderson {
2262deee69a1SRichard Henderson     if (a->m) {
22636fd0c7bcSRichard Henderson         TCGv_i64 dest = dest_gpr(ctx, a->b);
22646fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->b);
22656fd0c7bcSRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->x);
226698a9cb79SRichard Henderson 
226798a9cb79SRichard Henderson         /* The only thing we need to do is the base register modification.  */
22686fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, src1, src2);
2269deee69a1SRichard Henderson         save_gpr(ctx, a->b, dest);
2270deee69a1SRichard Henderson     }
227198a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
227231234768SRichard Henderson     return true;
227398a9cb79SRichard Henderson }
227498a9cb79SRichard Henderson 
2275deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a)
227698a9cb79SRichard Henderson {
22776fd0c7bcSRichard Henderson     TCGv_i64 dest, ofs;
2278eed14219SRichard Henderson     TCGv_i32 level, want;
22796fd0c7bcSRichard Henderson     TCGv_i64 addr;
228098a9cb79SRichard Henderson 
228198a9cb79SRichard Henderson     nullify_over(ctx);
228298a9cb79SRichard Henderson 
2283deee69a1SRichard Henderson     dest = dest_gpr(ctx, a->t);
2284deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2285eed14219SRichard Henderson 
2286deee69a1SRichard Henderson     if (a->imm) {
228729dd6f64SRichard Henderson         level = tcg_constant_i32(a->ri);
228898a9cb79SRichard Henderson     } else {
2289eed14219SRichard Henderson         level = tcg_temp_new_i32();
22906fd0c7bcSRichard Henderson         tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri));
2291eed14219SRichard Henderson         tcg_gen_andi_i32(level, level, 3);
229298a9cb79SRichard Henderson     }
229329dd6f64SRichard Henderson     want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ);
2294eed14219SRichard Henderson 
2295ad75a51eSRichard Henderson     gen_helper_probe(dest, tcg_env, addr, level, want);
2296eed14219SRichard Henderson 
2297deee69a1SRichard Henderson     save_gpr(ctx, a->t, dest);
229831234768SRichard Henderson     return nullify_end(ctx);
229998a9cb79SRichard Henderson }
230098a9cb79SRichard Henderson 
2301deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
23028d6ae7fbSRichard Henderson {
23038577f354SRichard Henderson     if (ctx->is_pa20) {
23048577f354SRichard Henderson         return false;
23058577f354SRichard Henderson     }
2306deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2307deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
23086fd0c7bcSRichard Henderson     TCGv_i64 addr;
23096fd0c7bcSRichard Henderson     TCGv_i64 ofs, reg;
23108d6ae7fbSRichard Henderson 
23118d6ae7fbSRichard Henderson     nullify_over(ctx);
23128d6ae7fbSRichard Henderson 
2313deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2314deee69a1SRichard Henderson     reg = load_gpr(ctx, a->r);
2315deee69a1SRichard Henderson     if (a->addr) {
23168577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
23178d6ae7fbSRichard Henderson     } else {
23188577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
23198d6ae7fbSRichard Henderson     }
23208d6ae7fbSRichard Henderson 
232132dc7569SSven Schnelle     /* Exit TB for TLB change if mmu is enabled.  */
232232dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
232331234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
232431234768SRichard Henderson     }
232531234768SRichard Henderson     return nullify_end(ctx);
2326deee69a1SRichard Henderson #endif
23278d6ae7fbSRichard Henderson }
232863300a00SRichard Henderson 
2329eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local)
233063300a00SRichard Henderson {
2331deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2332deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
23336fd0c7bcSRichard Henderson     TCGv_i64 addr;
23346fd0c7bcSRichard Henderson     TCGv_i64 ofs;
233563300a00SRichard Henderson 
233663300a00SRichard Henderson     nullify_over(ctx);
233763300a00SRichard Henderson 
2338deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2339eb25d10fSHelge Deller 
2340eb25d10fSHelge Deller     /*
2341eb25d10fSHelge Deller      * Page align now, rather than later, so that we can add in the
2342eb25d10fSHelge Deller      * page_size field from pa2.0 from the low 4 bits of GR[b].
2343eb25d10fSHelge Deller      */
2344eb25d10fSHelge Deller     tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK);
2345eb25d10fSHelge Deller     if (ctx->is_pa20) {
2346eb25d10fSHelge Deller         tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4);
234763300a00SRichard Henderson     }
2348eb25d10fSHelge Deller 
2349eb25d10fSHelge Deller     if (local) {
2350eb25d10fSHelge Deller         gen_helper_ptlb_l(tcg_env, addr);
235163300a00SRichard Henderson     } else {
2352ad75a51eSRichard Henderson         gen_helper_ptlb(tcg_env, addr);
235363300a00SRichard Henderson     }
235463300a00SRichard Henderson 
2355eb25d10fSHelge Deller     if (a->m) {
2356eb25d10fSHelge Deller         save_gpr(ctx, a->b, ofs);
2357eb25d10fSHelge Deller     }
2358eb25d10fSHelge Deller 
2359eb25d10fSHelge Deller     /* Exit TB for TLB change if mmu is enabled.  */
2360eb25d10fSHelge Deller     if (ctx->tb_flags & PSW_C) {
2361eb25d10fSHelge Deller         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2362eb25d10fSHelge Deller     }
2363eb25d10fSHelge Deller     return nullify_end(ctx);
2364eb25d10fSHelge Deller #endif
2365eb25d10fSHelge Deller }
2366eb25d10fSHelge Deller 
2367eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a)
2368eb25d10fSHelge Deller {
2369eb25d10fSHelge Deller     return do_pxtlb(ctx, a, false);
2370eb25d10fSHelge Deller }
2371eb25d10fSHelge Deller 
2372eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a)
2373eb25d10fSHelge Deller {
2374eb25d10fSHelge Deller     return ctx->is_pa20 && do_pxtlb(ctx, a, true);
2375eb25d10fSHelge Deller }
2376eb25d10fSHelge Deller 
2377eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a)
2378eb25d10fSHelge Deller {
2379eb25d10fSHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2380eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY
2381eb25d10fSHelge Deller     nullify_over(ctx);
2382eb25d10fSHelge Deller 
2383eb25d10fSHelge Deller     trans_nop_addrx(ctx, a);
2384eb25d10fSHelge Deller     gen_helper_ptlbe(tcg_env);
2385eb25d10fSHelge Deller 
238663300a00SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
238732dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
238831234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
238931234768SRichard Henderson     }
239031234768SRichard Henderson     return nullify_end(ctx);
2391deee69a1SRichard Henderson #endif
239263300a00SRichard Henderson }
23932dfcca9fSRichard Henderson 
23946797c315SNick Hudson /*
23956797c315SNick Hudson  * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
23966797c315SNick Hudson  * See
23976797c315SNick Hudson  *     https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
23986797c315SNick Hudson  *     page 13-9 (195/206)
23996797c315SNick Hudson  */
24006797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
24016797c315SNick Hudson {
24028577f354SRichard Henderson     if (ctx->is_pa20) {
24038577f354SRichard Henderson         return false;
24048577f354SRichard Henderson     }
24056797c315SNick Hudson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24066797c315SNick Hudson #ifndef CONFIG_USER_ONLY
24076fd0c7bcSRichard Henderson     TCGv_i64 addr, atl, stl;
24086fd0c7bcSRichard Henderson     TCGv_i64 reg;
24096797c315SNick Hudson 
24106797c315SNick Hudson     nullify_over(ctx);
24116797c315SNick Hudson 
24126797c315SNick Hudson     /*
24136797c315SNick Hudson      * FIXME:
24146797c315SNick Hudson      *  if (not (pcxl or pcxl2))
24156797c315SNick Hudson      *    return gen_illegal(ctx);
24166797c315SNick Hudson      */
24176797c315SNick Hudson 
24186fd0c7bcSRichard Henderson     atl = tcg_temp_new_i64();
24196fd0c7bcSRichard Henderson     stl = tcg_temp_new_i64();
24206fd0c7bcSRichard Henderson     addr = tcg_temp_new_i64();
24216797c315SNick Hudson 
2422ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(stl, tcg_env,
24236797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
24246797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIASQ]));
2425ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(atl, tcg_env,
24266797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
24276797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIAOQ]));
24286797c315SNick Hudson     tcg_gen_shli_i64(stl, stl, 32);
2429d265360fSRichard Henderson     tcg_gen_or_i64(addr, atl, stl);
24306797c315SNick Hudson 
24316797c315SNick Hudson     reg = load_gpr(ctx, a->r);
24326797c315SNick Hudson     if (a->addr) {
24338577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
24346797c315SNick Hudson     } else {
24358577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
24366797c315SNick Hudson     }
24376797c315SNick Hudson 
24386797c315SNick Hudson     /* Exit TB for TLB change if mmu is enabled.  */
24396797c315SNick Hudson     if (ctx->tb_flags & PSW_C) {
24406797c315SNick Hudson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
24416797c315SNick Hudson     }
24426797c315SNick Hudson     return nullify_end(ctx);
24436797c315SNick Hudson #endif
24446797c315SNick Hudson }
24456797c315SNick Hudson 
24468577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
24478577f354SRichard Henderson {
24488577f354SRichard Henderson     if (!ctx->is_pa20) {
24498577f354SRichard Henderson         return false;
24508577f354SRichard Henderson     }
24518577f354SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24528577f354SRichard Henderson #ifndef CONFIG_USER_ONLY
24538577f354SRichard Henderson     nullify_over(ctx);
24548577f354SRichard Henderson     {
24558577f354SRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
24568577f354SRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->r2);
24578577f354SRichard Henderson 
24588577f354SRichard Henderson         if (a->data) {
24598577f354SRichard Henderson             gen_helper_idtlbt_pa20(tcg_env, src1, src2);
24608577f354SRichard Henderson         } else {
24618577f354SRichard Henderson             gen_helper_iitlbt_pa20(tcg_env, src1, src2);
24628577f354SRichard Henderson         }
24638577f354SRichard Henderson     }
24648577f354SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
24658577f354SRichard Henderson     if (ctx->tb_flags & PSW_C) {
24668577f354SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
24678577f354SRichard Henderson     }
24688577f354SRichard Henderson     return nullify_end(ctx);
24698577f354SRichard Henderson #endif
24708577f354SRichard Henderson }
24718577f354SRichard Henderson 
2472deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
24732dfcca9fSRichard Henderson {
2474deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2475deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
24766fd0c7bcSRichard Henderson     TCGv_i64 vaddr;
24776fd0c7bcSRichard Henderson     TCGv_i64 ofs, paddr;
24782dfcca9fSRichard Henderson 
24792dfcca9fSRichard Henderson     nullify_over(ctx);
24802dfcca9fSRichard Henderson 
2481deee69a1SRichard Henderson     form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
24822dfcca9fSRichard Henderson 
2483aac0f603SRichard Henderson     paddr = tcg_temp_new_i64();
2484ad75a51eSRichard Henderson     gen_helper_lpa(paddr, tcg_env, vaddr);
24852dfcca9fSRichard Henderson 
24862dfcca9fSRichard Henderson     /* Note that physical address result overrides base modification.  */
2487deee69a1SRichard Henderson     if (a->m) {
2488deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
24892dfcca9fSRichard Henderson     }
2490deee69a1SRichard Henderson     save_gpr(ctx, a->t, paddr);
24912dfcca9fSRichard Henderson 
249231234768SRichard Henderson     return nullify_end(ctx);
2493deee69a1SRichard Henderson #endif
24942dfcca9fSRichard Henderson }
249543a97b81SRichard Henderson 
2496deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a)
249743a97b81SRichard Henderson {
249843a97b81SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
249943a97b81SRichard Henderson 
250043a97b81SRichard Henderson     /* The Coherence Index is an implementation-defined function of the
250143a97b81SRichard Henderson        physical address.  Two addresses with the same CI have a coherent
250243a97b81SRichard Henderson        view of the cache.  Our implementation is to return 0 for all,
250343a97b81SRichard Henderson        since the entire address space is coherent.  */
2504a4db4a78SRichard Henderson     save_gpr(ctx, a->t, ctx->zero);
250543a97b81SRichard Henderson 
250631234768SRichard Henderson     cond_free(&ctx->null_cond);
250731234768SRichard Henderson     return true;
250843a97b81SRichard Henderson }
250998a9cb79SRichard Henderson 
2510faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2511b2167459SRichard Henderson {
25120c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, false);
2513b2167459SRichard Henderson }
2514b2167459SRichard Henderson 
2515faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2516b2167459SRichard Henderson {
25170c982a28SRichard Henderson     return do_add_reg(ctx, a, true, false, false, false);
2518b2167459SRichard Henderson }
2519b2167459SRichard Henderson 
2520faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2521b2167459SRichard Henderson {
25220c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, false);
2523b2167459SRichard Henderson }
2524b2167459SRichard Henderson 
2525faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2526b2167459SRichard Henderson {
25270c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, true);
25280c982a28SRichard Henderson }
2529b2167459SRichard Henderson 
2530faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
25310c982a28SRichard Henderson {
25320c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, true);
25330c982a28SRichard Henderson }
25340c982a28SRichard Henderson 
253563c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
25360c982a28SRichard Henderson {
25370c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, false);
25380c982a28SRichard Henderson }
25390c982a28SRichard Henderson 
254063c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
25410c982a28SRichard Henderson {
25420c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, false);
25430c982a28SRichard Henderson }
25440c982a28SRichard Henderson 
254563c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
25460c982a28SRichard Henderson {
25470c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, true);
25480c982a28SRichard Henderson }
25490c982a28SRichard Henderson 
255063c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
25510c982a28SRichard Henderson {
25520c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, true);
25530c982a28SRichard Henderson }
25540c982a28SRichard Henderson 
255563c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
25560c982a28SRichard Henderson {
25570c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, true, false);
25580c982a28SRichard Henderson }
25590c982a28SRichard Henderson 
256063c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
25610c982a28SRichard Henderson {
25620c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, true, false);
25630c982a28SRichard Henderson }
25640c982a28SRichard Henderson 
2565fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
25660c982a28SRichard Henderson {
25676fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_andc_i64);
25680c982a28SRichard Henderson }
25690c982a28SRichard Henderson 
2570fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
25710c982a28SRichard Henderson {
25726fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_and_i64);
25730c982a28SRichard Henderson }
25740c982a28SRichard Henderson 
2575fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
25760c982a28SRichard Henderson {
25770c982a28SRichard Henderson     if (a->cf == 0) {
25780c982a28SRichard Henderson         unsigned r2 = a->r2;
25790c982a28SRichard Henderson         unsigned r1 = a->r1;
25800c982a28SRichard Henderson         unsigned rt = a->t;
25810c982a28SRichard Henderson 
25827aee8189SRichard Henderson         if (rt == 0) { /* NOP */
25837aee8189SRichard Henderson             cond_free(&ctx->null_cond);
25847aee8189SRichard Henderson             return true;
25857aee8189SRichard Henderson         }
25867aee8189SRichard Henderson         if (r2 == 0) { /* COPY */
2587b2167459SRichard Henderson             if (r1 == 0) {
25886fd0c7bcSRichard Henderson                 TCGv_i64 dest = dest_gpr(ctx, rt);
25896fd0c7bcSRichard Henderson                 tcg_gen_movi_i64(dest, 0);
2590b2167459SRichard Henderson                 save_gpr(ctx, rt, dest);
2591b2167459SRichard Henderson             } else {
2592b2167459SRichard Henderson                 save_gpr(ctx, rt, cpu_gr[r1]);
2593b2167459SRichard Henderson             }
2594b2167459SRichard Henderson             cond_free(&ctx->null_cond);
259531234768SRichard Henderson             return true;
2596b2167459SRichard Henderson         }
25977aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY
25987aee8189SRichard Henderson         /* These are QEMU extensions and are nops in the real architecture:
25997aee8189SRichard Henderson          *
26007aee8189SRichard Henderson          * or %r10,%r10,%r10 -- idle loop; wait for interrupt
26017aee8189SRichard Henderson          * or %r31,%r31,%r31 -- death loop; offline cpu
26027aee8189SRichard Henderson          *                      currently implemented as idle.
26037aee8189SRichard Henderson          */
26047aee8189SRichard Henderson         if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
26057aee8189SRichard Henderson             /* No need to check for supervisor, as userland can only pause
26067aee8189SRichard Henderson                until the next timer interrupt.  */
26077aee8189SRichard Henderson             nullify_over(ctx);
26087aee8189SRichard Henderson 
26097aee8189SRichard Henderson             /* Advance the instruction queue.  */
2610741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
2611741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
26127aee8189SRichard Henderson             nullify_set(ctx, 0);
26137aee8189SRichard Henderson 
26147aee8189SRichard Henderson             /* Tell the qemu main loop to halt until this cpu has work.  */
2615ad75a51eSRichard Henderson             tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
261629dd6f64SRichard Henderson                            offsetof(CPUState, halted) - offsetof(HPPACPU, env));
26177aee8189SRichard Henderson             gen_excp_1(EXCP_HALTED);
26187aee8189SRichard Henderson             ctx->base.is_jmp = DISAS_NORETURN;
26197aee8189SRichard Henderson 
26207aee8189SRichard Henderson             return nullify_end(ctx);
26217aee8189SRichard Henderson         }
26227aee8189SRichard Henderson #endif
26237aee8189SRichard Henderson     }
26246fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_or_i64);
26257aee8189SRichard Henderson }
2626b2167459SRichard Henderson 
2627fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
2628b2167459SRichard Henderson {
26296fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_xor_i64);
26300c982a28SRichard Henderson }
26310c982a28SRichard Henderson 
2632345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
26330c982a28SRichard Henderson {
26346fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2635b2167459SRichard Henderson 
26360c982a28SRichard Henderson     if (a->cf) {
2637b2167459SRichard Henderson         nullify_over(ctx);
2638b2167459SRichard Henderson     }
26390c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26400c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2641345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
264231234768SRichard Henderson     return nullify_end(ctx);
2643b2167459SRichard Henderson }
2644b2167459SRichard Henderson 
2645af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
2646b2167459SRichard Henderson {
26476fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2648b2167459SRichard Henderson 
26490c982a28SRichard Henderson     if (a->cf) {
2650b2167459SRichard Henderson         nullify_over(ctx);
2651b2167459SRichard Henderson     }
26520c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26530c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
26546fd0c7bcSRichard Henderson     do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64);
265531234768SRichard Henderson     return nullify_end(ctx);
2656b2167459SRichard Henderson }
2657b2167459SRichard Henderson 
2658af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
2659b2167459SRichard Henderson {
26606fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, tmp;
2661b2167459SRichard Henderson 
26620c982a28SRichard Henderson     if (a->cf) {
2663b2167459SRichard Henderson         nullify_over(ctx);
2664b2167459SRichard Henderson     }
26650c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26660c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2667aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
26686fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, tcg_r2);
26696fd0c7bcSRichard Henderson     do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64);
267031234768SRichard Henderson     return nullify_end(ctx);
2671b2167459SRichard Henderson }
2672b2167459SRichard Henderson 
2673af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
2674b2167459SRichard Henderson {
26750c982a28SRichard Henderson     return do_uaddcm(ctx, a, false);
26760c982a28SRichard Henderson }
26770c982a28SRichard Henderson 
2678af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
26790c982a28SRichard Henderson {
26800c982a28SRichard Henderson     return do_uaddcm(ctx, a, true);
26810c982a28SRichard Henderson }
26820c982a28SRichard Henderson 
2683af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
26840c982a28SRichard Henderson {
26856fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2686b2167459SRichard Henderson 
2687b2167459SRichard Henderson     nullify_over(ctx);
2688b2167459SRichard Henderson 
2689aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
26906fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, cpu_psw_cb, 3);
2691b2167459SRichard Henderson     if (!is_i) {
26926fd0c7bcSRichard Henderson         tcg_gen_not_i64(tmp, tmp);
2693b2167459SRichard Henderson     }
26946fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
26956fd0c7bcSRichard Henderson     tcg_gen_muli_i64(tmp, tmp, 6);
2696af240753SRichard Henderson     do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false,
26976fd0c7bcSRichard Henderson             is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64);
269831234768SRichard Henderson     return nullify_end(ctx);
2699b2167459SRichard Henderson }
2700b2167459SRichard Henderson 
2701af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
2702b2167459SRichard Henderson {
27030c982a28SRichard Henderson     return do_dcor(ctx, a, false);
27040c982a28SRichard Henderson }
27050c982a28SRichard Henderson 
2706af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
27070c982a28SRichard Henderson {
27080c982a28SRichard Henderson     return do_dcor(ctx, a, true);
27090c982a28SRichard Henderson }
27100c982a28SRichard Henderson 
27110c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
27120c982a28SRichard Henderson {
2713a4db4a78SRichard Henderson     TCGv_i64 dest, add1, add2, addc, in1, in2;
27146fd0c7bcSRichard Henderson     TCGv_i64 cout;
2715b2167459SRichard Henderson 
2716b2167459SRichard Henderson     nullify_over(ctx);
2717b2167459SRichard Henderson 
27180c982a28SRichard Henderson     in1 = load_gpr(ctx, a->r1);
27190c982a28SRichard Henderson     in2 = load_gpr(ctx, a->r2);
2720b2167459SRichard Henderson 
2721aac0f603SRichard Henderson     add1 = tcg_temp_new_i64();
2722aac0f603SRichard Henderson     add2 = tcg_temp_new_i64();
2723aac0f603SRichard Henderson     addc = tcg_temp_new_i64();
2724aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
2725b2167459SRichard Henderson 
2726b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
27276fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, in1, in1);
27286fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
2729b2167459SRichard Henderson 
273072ca8753SRichard Henderson     /*
273172ca8753SRichard Henderson      * Add or subtract R2, depending on PSW[V].  Proper computation of
273272ca8753SRichard Henderson      * carry requires that we subtract via + ~R2 + 1, as described in
273372ca8753SRichard Henderson      * the manual.  By extracting and masking V, we can produce the
273472ca8753SRichard Henderson      * proper inputs to the addition without movcond.
273572ca8753SRichard Henderson      */
27366fd0c7bcSRichard Henderson     tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
27376fd0c7bcSRichard Henderson     tcg_gen_xor_i64(add2, in2, addc);
27386fd0c7bcSRichard Henderson     tcg_gen_andi_i64(addc, addc, 1);
273972ca8753SRichard Henderson 
2740a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero);
2741a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb,
2742a4db4a78SRichard Henderson                      addc, ctx->zero);
2743b2167459SRichard Henderson 
2744b2167459SRichard Henderson     /* Write back the result register.  */
27450c982a28SRichard Henderson     save_gpr(ctx, a->t, dest);
2746b2167459SRichard Henderson 
2747b2167459SRichard Henderson     /* Write back PSW[CB].  */
27486fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
27496fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
2750b2167459SRichard Henderson 
2751b2167459SRichard Henderson     /* Write back PSW[V] for the division step.  */
275272ca8753SRichard Henderson     cout = get_psw_carry(ctx, false);
27536fd0c7bcSRichard Henderson     tcg_gen_neg_i64(cpu_psw_v, cout);
27546fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
2755b2167459SRichard Henderson 
2756b2167459SRichard Henderson     /* Install the new nullification.  */
27570c982a28SRichard Henderson     if (a->cf) {
27586fd0c7bcSRichard Henderson         TCGv_i64 sv = NULL;
2759b47a4a02SSven Schnelle         if (cond_need_sv(a->cf >> 1)) {
2760b2167459SRichard Henderson             /* ??? The lshift is supposed to contribute to overflow.  */
2761b2167459SRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2);
2762b2167459SRichard Henderson         }
2763a751eb31SRichard Henderson         ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv);
2764b2167459SRichard Henderson     }
2765b2167459SRichard Henderson 
276631234768SRichard Henderson     return nullify_end(ctx);
2767b2167459SRichard Henderson }
2768b2167459SRichard Henderson 
27690588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a)
2770b2167459SRichard Henderson {
27710588e061SRichard Henderson     return do_add_imm(ctx, a, false, false);
27720588e061SRichard Henderson }
27730588e061SRichard Henderson 
27740588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a)
27750588e061SRichard Henderson {
27760588e061SRichard Henderson     return do_add_imm(ctx, a, true, false);
27770588e061SRichard Henderson }
27780588e061SRichard Henderson 
27790588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a)
27800588e061SRichard Henderson {
27810588e061SRichard Henderson     return do_add_imm(ctx, a, false, true);
27820588e061SRichard Henderson }
27830588e061SRichard Henderson 
27840588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a)
27850588e061SRichard Henderson {
27860588e061SRichard Henderson     return do_add_imm(ctx, a, true, true);
27870588e061SRichard Henderson }
27880588e061SRichard Henderson 
27890588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a)
27900588e061SRichard Henderson {
27910588e061SRichard Henderson     return do_sub_imm(ctx, a, false);
27920588e061SRichard Henderson }
27930588e061SRichard Henderson 
27940588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
27950588e061SRichard Henderson {
27960588e061SRichard Henderson     return do_sub_imm(ctx, a, true);
27970588e061SRichard Henderson }
27980588e061SRichard Henderson 
2799345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
28000588e061SRichard Henderson {
28016fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
2802b2167459SRichard Henderson 
28030588e061SRichard Henderson     if (a->cf) {
2804b2167459SRichard Henderson         nullify_over(ctx);
2805b2167459SRichard Henderson     }
2806b2167459SRichard Henderson 
28076fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
28080588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
2809345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
2810b2167459SRichard Henderson 
281131234768SRichard Henderson     return nullify_end(ctx);
2812b2167459SRichard Henderson }
2813b2167459SRichard Henderson 
28140843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a,
28150843563fSRichard Henderson                           void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
28160843563fSRichard Henderson {
28170843563fSRichard Henderson     TCGv_i64 r1, r2, dest;
28180843563fSRichard Henderson 
28190843563fSRichard Henderson     if (!ctx->is_pa20) {
28200843563fSRichard Henderson         return false;
28210843563fSRichard Henderson     }
28220843563fSRichard Henderson 
28230843563fSRichard Henderson     nullify_over(ctx);
28240843563fSRichard Henderson 
28250843563fSRichard Henderson     r1 = load_gpr(ctx, a->r1);
28260843563fSRichard Henderson     r2 = load_gpr(ctx, a->r2);
28270843563fSRichard Henderson     dest = dest_gpr(ctx, a->t);
28280843563fSRichard Henderson 
28290843563fSRichard Henderson     fn(dest, r1, r2);
28300843563fSRichard Henderson     save_gpr(ctx, a->t, dest);
28310843563fSRichard Henderson 
28320843563fSRichard Henderson     return nullify_end(ctx);
28330843563fSRichard Henderson }
28340843563fSRichard Henderson 
2835151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a,
2836151f309bSRichard Henderson                              void (*fn)(TCGv_i64, TCGv_i64, int64_t))
2837151f309bSRichard Henderson {
2838151f309bSRichard Henderson     TCGv_i64 r, dest;
2839151f309bSRichard Henderson 
2840151f309bSRichard Henderson     if (!ctx->is_pa20) {
2841151f309bSRichard Henderson         return false;
2842151f309bSRichard Henderson     }
2843151f309bSRichard Henderson 
2844151f309bSRichard Henderson     nullify_over(ctx);
2845151f309bSRichard Henderson 
2846151f309bSRichard Henderson     r = load_gpr(ctx, a->r);
2847151f309bSRichard Henderson     dest = dest_gpr(ctx, a->t);
2848151f309bSRichard Henderson 
2849151f309bSRichard Henderson     fn(dest, r, a->i);
2850151f309bSRichard Henderson     save_gpr(ctx, a->t, dest);
2851151f309bSRichard Henderson 
2852151f309bSRichard Henderson     return nullify_end(ctx);
2853151f309bSRichard Henderson }
2854151f309bSRichard Henderson 
28553bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a,
28563bbb8e48SRichard Henderson                                 void (*fn)(TCGv_i64, TCGv_i64,
28573bbb8e48SRichard Henderson                                            TCGv_i64, TCGv_i32))
28583bbb8e48SRichard Henderson {
28593bbb8e48SRichard Henderson     TCGv_i64 r1, r2, dest;
28603bbb8e48SRichard Henderson 
28613bbb8e48SRichard Henderson     if (!ctx->is_pa20) {
28623bbb8e48SRichard Henderson         return false;
28633bbb8e48SRichard Henderson     }
28643bbb8e48SRichard Henderson 
28653bbb8e48SRichard Henderson     nullify_over(ctx);
28663bbb8e48SRichard Henderson 
28673bbb8e48SRichard Henderson     r1 = load_gpr(ctx, a->r1);
28683bbb8e48SRichard Henderson     r2 = load_gpr(ctx, a->r2);
28693bbb8e48SRichard Henderson     dest = dest_gpr(ctx, a->t);
28703bbb8e48SRichard Henderson 
28713bbb8e48SRichard Henderson     fn(dest, r1, r2, tcg_constant_i32(a->sh));
28723bbb8e48SRichard Henderson     save_gpr(ctx, a->t, dest);
28733bbb8e48SRichard Henderson 
28743bbb8e48SRichard Henderson     return nullify_end(ctx);
28753bbb8e48SRichard Henderson }
28763bbb8e48SRichard Henderson 
28770843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a)
28780843563fSRichard Henderson {
28790843563fSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_add16_i64);
28800843563fSRichard Henderson }
28810843563fSRichard Henderson 
28820843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a)
28830843563fSRichard Henderson {
28840843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_ss);
28850843563fSRichard Henderson }
28860843563fSRichard Henderson 
28870843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a)
28880843563fSRichard Henderson {
28890843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_us);
28900843563fSRichard Henderson }
28910843563fSRichard Henderson 
28921b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a)
28931b3cb7c8SRichard Henderson {
28941b3cb7c8SRichard Henderson     return do_multimedia(ctx, a, gen_helper_havg);
28951b3cb7c8SRichard Henderson }
28961b3cb7c8SRichard Henderson 
2897151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a)
2898151f309bSRichard Henderson {
2899151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64);
2900151f309bSRichard Henderson }
2901151f309bSRichard Henderson 
2902151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a)
2903151f309bSRichard Henderson {
2904151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64);
2905151f309bSRichard Henderson }
2906151f309bSRichard Henderson 
2907151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a)
2908151f309bSRichard Henderson {
2909151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64);
2910151f309bSRichard Henderson }
2911151f309bSRichard Henderson 
29123bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a)
29133bbb8e48SRichard Henderson {
29143bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshladd);
29153bbb8e48SRichard Henderson }
29163bbb8e48SRichard Henderson 
29173bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a)
29183bbb8e48SRichard Henderson {
29193bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshradd);
29203bbb8e48SRichard Henderson }
29213bbb8e48SRichard Henderson 
292210c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a)
292310c9e58dSRichard Henderson {
292410c9e58dSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64);
292510c9e58dSRichard Henderson }
292610c9e58dSRichard Henderson 
292710c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a)
292810c9e58dSRichard Henderson {
292910c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_ss);
293010c9e58dSRichard Henderson }
293110c9e58dSRichard Henderson 
293210c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a)
293310c9e58dSRichard Henderson {
293410c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_us);
293510c9e58dSRichard Henderson }
293610c9e58dSRichard Henderson 
2937c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2938c2a7ee3fSRichard Henderson {
2939c2a7ee3fSRichard Henderson     uint64_t mask = 0xffff0000ffff0000ull;
2940c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2941c2a7ee3fSRichard Henderson 
2942c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r2, mask);
2943c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r1, mask);
2944c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, tmp, 16);
2945c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
2946c2a7ee3fSRichard Henderson }
2947c2a7ee3fSRichard Henderson 
2948c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a)
2949c2a7ee3fSRichard Henderson {
2950c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_l);
2951c2a7ee3fSRichard Henderson }
2952c2a7ee3fSRichard Henderson 
2953c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2954c2a7ee3fSRichard Henderson {
2955c2a7ee3fSRichard Henderson     uint64_t mask = 0x0000ffff0000ffffull;
2956c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2957c2a7ee3fSRichard Henderson 
2958c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r1, mask);
2959c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r2, mask);
2960c2a7ee3fSRichard Henderson     tcg_gen_shli_i64(tmp, tmp, 16);
2961c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
2962c2a7ee3fSRichard Henderson }
2963c2a7ee3fSRichard Henderson 
2964c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a)
2965c2a7ee3fSRichard Henderson {
2966c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_r);
2967c2a7ee3fSRichard Henderson }
2968c2a7ee3fSRichard Henderson 
2969c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2970c2a7ee3fSRichard Henderson {
2971c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2972c2a7ee3fSRichard Henderson 
2973c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, r2, 32);
2974c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r1, tmp, 0, 32);
2975c2a7ee3fSRichard Henderson }
2976c2a7ee3fSRichard Henderson 
2977c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a)
2978c2a7ee3fSRichard Henderson {
2979c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_l);
2980c2a7ee3fSRichard Henderson }
2981c2a7ee3fSRichard Henderson 
2982c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2983c2a7ee3fSRichard Henderson {
2984c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r2, r1, 32, 32);
2985c2a7ee3fSRichard Henderson }
2986c2a7ee3fSRichard Henderson 
2987c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a)
2988c2a7ee3fSRichard Henderson {
2989c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_r);
2990c2a7ee3fSRichard Henderson }
2991c2a7ee3fSRichard Henderson 
29924e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a)
29934e7abdb1SRichard Henderson {
29944e7abdb1SRichard Henderson     TCGv_i64 r, t0, t1, t2, t3;
29954e7abdb1SRichard Henderson 
29964e7abdb1SRichard Henderson     if (!ctx->is_pa20) {
29974e7abdb1SRichard Henderson         return false;
29984e7abdb1SRichard Henderson     }
29994e7abdb1SRichard Henderson 
30004e7abdb1SRichard Henderson     nullify_over(ctx);
30014e7abdb1SRichard Henderson 
30024e7abdb1SRichard Henderson     r = load_gpr(ctx, a->r1);
30034e7abdb1SRichard Henderson     t0 = tcg_temp_new_i64();
30044e7abdb1SRichard Henderson     t1 = tcg_temp_new_i64();
30054e7abdb1SRichard Henderson     t2 = tcg_temp_new_i64();
30064e7abdb1SRichard Henderson     t3 = tcg_temp_new_i64();
30074e7abdb1SRichard Henderson 
30084e7abdb1SRichard Henderson     tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16);
30094e7abdb1SRichard Henderson     tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16);
30104e7abdb1SRichard Henderson     tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16);
30114e7abdb1SRichard Henderson     tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16);
30124e7abdb1SRichard Henderson 
30134e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t1, t0, 16, 48);
30144e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t2, t3, t2, 16, 48);
30154e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t2, t0, 32, 32);
30164e7abdb1SRichard Henderson 
30174e7abdb1SRichard Henderson     save_gpr(ctx, a->t, t0);
30184e7abdb1SRichard Henderson     return nullify_end(ctx);
30194e7abdb1SRichard Henderson }
30204e7abdb1SRichard Henderson 
30211cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a)
302296d6407fSRichard Henderson {
3023b5caa17cSRichard Henderson     if (ctx->is_pa20) {
3024b5caa17cSRichard Henderson        /*
3025b5caa17cSRichard Henderson         * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches.
3026b5caa17cSRichard Henderson         * Any base modification still occurs.
3027b5caa17cSRichard Henderson         */
3028b5caa17cSRichard Henderson         if (a->t == 0) {
3029b5caa17cSRichard Henderson             return trans_nop_addrx(ctx, a);
3030b5caa17cSRichard Henderson         }
3031b5caa17cSRichard Henderson     } else if (a->size > MO_32) {
30320786a3b6SHelge Deller         return gen_illegal(ctx);
3033c53e401eSRichard Henderson     }
30341cd012a5SRichard Henderson     return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
30351cd012a5SRichard Henderson                    a->disp, a->sp, a->m, a->size | MO_TE);
303696d6407fSRichard Henderson }
303796d6407fSRichard Henderson 
30381cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a)
303996d6407fSRichard Henderson {
30401cd012a5SRichard Henderson     assert(a->x == 0 && a->scale == 0);
3041c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
30420786a3b6SHelge Deller         return gen_illegal(ctx);
304396d6407fSRichard Henderson     }
3044c53e401eSRichard Henderson     return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
30450786a3b6SHelge Deller }
304696d6407fSRichard Henderson 
30471cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
304896d6407fSRichard Henderson {
3049b1af755cSRichard Henderson     MemOp mop = MO_TE | MO_ALIGN | a->size;
3050a4db4a78SRichard Henderson     TCGv_i64 dest, ofs;
30516fd0c7bcSRichard Henderson     TCGv_i64 addr;
305296d6407fSRichard Henderson 
3053c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
305451416c4eSRichard Henderson         return gen_illegal(ctx);
305551416c4eSRichard Henderson     }
305651416c4eSRichard Henderson 
305796d6407fSRichard Henderson     nullify_over(ctx);
305896d6407fSRichard Henderson 
30591cd012a5SRichard Henderson     if (a->m) {
306086f8d05fSRichard Henderson         /* Base register modification.  Make sure if RT == RB,
306186f8d05fSRichard Henderson            we see the result of the load.  */
3062aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
306396d6407fSRichard Henderson     } else {
30641cd012a5SRichard Henderson         dest = dest_gpr(ctx, a->t);
306596d6407fSRichard Henderson     }
306696d6407fSRichard Henderson 
30671cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0,
30681cd012a5SRichard Henderson              a->disp, a->sp, a->m, ctx->mmu_idx == MMU_PHYS_IDX);
3069b1af755cSRichard Henderson 
3070b1af755cSRichard Henderson     /*
3071b1af755cSRichard Henderson      * For hppa1.1, LDCW is undefined unless aligned mod 16.
3072b1af755cSRichard Henderson      * However actual hardware succeeds with aligned mod 4.
3073b1af755cSRichard Henderson      * Detect this case and log a GUEST_ERROR.
3074b1af755cSRichard Henderson      *
3075b1af755cSRichard Henderson      * TODO: HPPA64 relaxes the over-alignment requirement
3076b1af755cSRichard Henderson      * with the ,co completer.
3077b1af755cSRichard Henderson      */
3078b1af755cSRichard Henderson     gen_helper_ldc_check(addr);
3079b1af755cSRichard Henderson 
3080a4db4a78SRichard Henderson     tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop);
3081b1af755cSRichard Henderson 
30821cd012a5SRichard Henderson     if (a->m) {
30831cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
308496d6407fSRichard Henderson     }
30851cd012a5SRichard Henderson     save_gpr(ctx, a->t, dest);
308696d6407fSRichard Henderson 
308731234768SRichard Henderson     return nullify_end(ctx);
308896d6407fSRichard Henderson }
308996d6407fSRichard Henderson 
30901cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a)
309196d6407fSRichard Henderson {
30926fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
30936fd0c7bcSRichard Henderson     TCGv_i64 addr;
309496d6407fSRichard Henderson 
309596d6407fSRichard Henderson     nullify_over(ctx);
309696d6407fSRichard Henderson 
30971cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
309886f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
30991cd012a5SRichard Henderson     val = load_gpr(ctx, a->r);
31001cd012a5SRichard Henderson     if (a->a) {
3101f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3102ad75a51eSRichard Henderson             gen_helper_stby_e_parallel(tcg_env, addr, val);
3103f9f46db4SEmilio G. Cota         } else {
3104ad75a51eSRichard Henderson             gen_helper_stby_e(tcg_env, addr, val);
3105f9f46db4SEmilio G. Cota         }
3106f9f46db4SEmilio G. Cota     } else {
3107f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3108ad75a51eSRichard Henderson             gen_helper_stby_b_parallel(tcg_env, addr, val);
310996d6407fSRichard Henderson         } else {
3110ad75a51eSRichard Henderson             gen_helper_stby_b(tcg_env, addr, val);
311196d6407fSRichard Henderson         }
3112f9f46db4SEmilio G. Cota     }
31131cd012a5SRichard Henderson     if (a->m) {
31146fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~3);
31151cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
311696d6407fSRichard Henderson     }
311796d6407fSRichard Henderson 
311831234768SRichard Henderson     return nullify_end(ctx);
311996d6407fSRichard Henderson }
312096d6407fSRichard Henderson 
312125460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a)
312225460fc5SRichard Henderson {
31236fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
31246fd0c7bcSRichard Henderson     TCGv_i64 addr;
312525460fc5SRichard Henderson 
312625460fc5SRichard Henderson     if (!ctx->is_pa20) {
312725460fc5SRichard Henderson         return false;
312825460fc5SRichard Henderson     }
312925460fc5SRichard Henderson     nullify_over(ctx);
313025460fc5SRichard Henderson 
313125460fc5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
313225460fc5SRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
313325460fc5SRichard Henderson     val = load_gpr(ctx, a->r);
313425460fc5SRichard Henderson     if (a->a) {
313525460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
313625460fc5SRichard Henderson             gen_helper_stdby_e_parallel(tcg_env, addr, val);
313725460fc5SRichard Henderson         } else {
313825460fc5SRichard Henderson             gen_helper_stdby_e(tcg_env, addr, val);
313925460fc5SRichard Henderson         }
314025460fc5SRichard Henderson     } else {
314125460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
314225460fc5SRichard Henderson             gen_helper_stdby_b_parallel(tcg_env, addr, val);
314325460fc5SRichard Henderson         } else {
314425460fc5SRichard Henderson             gen_helper_stdby_b(tcg_env, addr, val);
314525460fc5SRichard Henderson         }
314625460fc5SRichard Henderson     }
314725460fc5SRichard Henderson     if (a->m) {
31486fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~7);
314925460fc5SRichard Henderson         save_gpr(ctx, a->b, ofs);
315025460fc5SRichard Henderson     }
315125460fc5SRichard Henderson 
315225460fc5SRichard Henderson     return nullify_end(ctx);
315325460fc5SRichard Henderson }
315425460fc5SRichard Henderson 
31551cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a)
3156d0a851ccSRichard Henderson {
3157d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3158d0a851ccSRichard Henderson 
3159d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3160d0a851ccSRichard Henderson     ctx->mmu_idx = MMU_PHYS_IDX;
31611cd012a5SRichard Henderson     trans_ld(ctx, a);
3162d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
316331234768SRichard Henderson     return true;
3164d0a851ccSRichard Henderson }
3165d0a851ccSRichard Henderson 
31661cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a)
3167d0a851ccSRichard Henderson {
3168d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3169d0a851ccSRichard Henderson 
3170d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3171d0a851ccSRichard Henderson     ctx->mmu_idx = MMU_PHYS_IDX;
31721cd012a5SRichard Henderson     trans_st(ctx, a);
3173d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
317431234768SRichard Henderson     return true;
3175d0a851ccSRichard Henderson }
317695412a61SRichard Henderson 
31770588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
3178b2167459SRichard Henderson {
31796fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3180b2167459SRichard Henderson 
31816fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tcg_rt, a->i);
31820588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3183b2167459SRichard Henderson     cond_free(&ctx->null_cond);
318431234768SRichard Henderson     return true;
3185b2167459SRichard Henderson }
3186b2167459SRichard Henderson 
31870588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a)
3188b2167459SRichard Henderson {
31896fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
31906fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
3191b2167459SRichard Henderson 
31926fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
3193b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
3194b2167459SRichard Henderson     cond_free(&ctx->null_cond);
319531234768SRichard Henderson     return true;
3196b2167459SRichard Henderson }
3197b2167459SRichard Henderson 
31980588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
3199b2167459SRichard Henderson {
32006fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3201b2167459SRichard Henderson 
3202b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
3203d265360fSRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_i64.  */
32040588e061SRichard Henderson     if (a->b == 0) {
32056fd0c7bcSRichard Henderson         tcg_gen_movi_i64(tcg_rt, a->i);
3206b2167459SRichard Henderson     } else {
32076fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
3208b2167459SRichard Henderson     }
32090588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3210b2167459SRichard Henderson     cond_free(&ctx->null_cond);
321131234768SRichard Henderson     return true;
3212b2167459SRichard Henderson }
3213b2167459SRichard Henderson 
32146fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
3215e9efd4bcSRichard Henderson                     unsigned c, unsigned f, bool d, unsigned n, int disp)
321698cd9ca7SRichard Henderson {
32176fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv;
321898cd9ca7SRichard Henderson     DisasCond cond;
321998cd9ca7SRichard Henderson 
322098cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3221aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
322298cd9ca7SRichard Henderson 
32236fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
322498cd9ca7SRichard Henderson 
3225f764718dSRichard Henderson     sv = NULL;
3226b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
322798cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
322898cd9ca7SRichard Henderson     }
322998cd9ca7SRichard Henderson 
32304fe9533aSRichard Henderson     cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
323101afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
323298cd9ca7SRichard Henderson }
323398cd9ca7SRichard Henderson 
323401afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
323598cd9ca7SRichard Henderson {
3236e9efd4bcSRichard Henderson     if (!ctx->is_pa20 && a->d) {
3237e9efd4bcSRichard Henderson         return false;
3238e9efd4bcSRichard Henderson     }
323901afb7beSRichard Henderson     nullify_over(ctx);
3240e9efd4bcSRichard Henderson     return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
3241e9efd4bcSRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
324201afb7beSRichard Henderson }
324301afb7beSRichard Henderson 
324401afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
324501afb7beSRichard Henderson {
3246c65c3ee1SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3247c65c3ee1SRichard Henderson         return false;
3248c65c3ee1SRichard Henderson     }
324901afb7beSRichard Henderson     nullify_over(ctx);
32506fd0c7bcSRichard Henderson     return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
3251c65c3ee1SRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
325201afb7beSRichard Henderson }
325301afb7beSRichard Henderson 
32546fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
325501afb7beSRichard Henderson                     unsigned c, unsigned f, unsigned n, int disp)
325601afb7beSRichard Henderson {
32576fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv, cb_cond;
325898cd9ca7SRichard Henderson     DisasCond cond;
3259bdcccc17SRichard Henderson     bool d = false;
326098cd9ca7SRichard Henderson 
3261f25d3160SRichard Henderson     /*
3262f25d3160SRichard Henderson      * For hppa64, the ADDB conditions change with PSW.W,
3263f25d3160SRichard Henderson      * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3264f25d3160SRichard Henderson      */
3265f25d3160SRichard Henderson     if (ctx->tb_flags & PSW_W) {
3266f25d3160SRichard Henderson         d = c >= 5;
3267f25d3160SRichard Henderson         if (d) {
3268f25d3160SRichard Henderson             c &= 3;
3269f25d3160SRichard Henderson         }
3270f25d3160SRichard Henderson     }
3271f25d3160SRichard Henderson 
327298cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3273aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
3274f764718dSRichard Henderson     sv = NULL;
3275bdcccc17SRichard Henderson     cb_cond = NULL;
327698cd9ca7SRichard Henderson 
3277b47a4a02SSven Schnelle     if (cond_need_cb(c)) {
3278aac0f603SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
3279aac0f603SRichard Henderson         TCGv_i64 cb_msb = tcg_temp_new_i64();
3280bdcccc17SRichard Henderson 
32816fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cb_msb, 0);
32826fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
32836fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
32846fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
3285bdcccc17SRichard Henderson         cb_cond = get_carry(ctx, d, cb, cb_msb);
3286b47a4a02SSven Schnelle     } else {
32876fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
3288b47a4a02SSven Schnelle     }
3289b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
329098cd9ca7SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
329198cd9ca7SRichard Henderson     }
329298cd9ca7SRichard Henderson 
3293a751eb31SRichard Henderson     cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
329443675d20SSven Schnelle     save_gpr(ctx, r, dest);
329501afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
329698cd9ca7SRichard Henderson }
329798cd9ca7SRichard Henderson 
329801afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a)
329998cd9ca7SRichard Henderson {
330001afb7beSRichard Henderson     nullify_over(ctx);
330101afb7beSRichard Henderson     return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
330201afb7beSRichard Henderson }
330301afb7beSRichard Henderson 
330401afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
330501afb7beSRichard Henderson {
330601afb7beSRichard Henderson     nullify_over(ctx);
33076fd0c7bcSRichard Henderson     return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
330801afb7beSRichard Henderson }
330901afb7beSRichard Henderson 
331001afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
331101afb7beSRichard Henderson {
33126fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
331398cd9ca7SRichard Henderson     DisasCond cond;
331498cd9ca7SRichard Henderson 
331598cd9ca7SRichard Henderson     nullify_over(ctx);
331698cd9ca7SRichard Henderson 
3317aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
331801afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
331984e224d4SRichard Henderson     if (cond_need_ext(ctx, a->d)) {
33201e9ab9fbSRichard Henderson         /* Force shift into [32,63] */
33216fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_sar, 32);
33226fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, tmp);
33231e9ab9fbSRichard Henderson     } else {
33246fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
33251e9ab9fbSRichard Henderson     }
332698cd9ca7SRichard Henderson 
33271e9ab9fbSRichard Henderson     cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
332801afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
332998cd9ca7SRichard Henderson }
333098cd9ca7SRichard Henderson 
333101afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
333298cd9ca7SRichard Henderson {
33336fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
333401afb7beSRichard Henderson     DisasCond cond;
33351e9ab9fbSRichard Henderson     int p;
333601afb7beSRichard Henderson 
333701afb7beSRichard Henderson     nullify_over(ctx);
333801afb7beSRichard Henderson 
3339aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
334001afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
334184e224d4SRichard Henderson     p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0);
33426fd0c7bcSRichard Henderson     tcg_gen_shli_i64(tmp, tcg_r, p);
334301afb7beSRichard Henderson 
334401afb7beSRichard Henderson     cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
334501afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
334601afb7beSRichard Henderson }
334701afb7beSRichard Henderson 
334801afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a)
334901afb7beSRichard Henderson {
33506fd0c7bcSRichard Henderson     TCGv_i64 dest;
335198cd9ca7SRichard Henderson     DisasCond cond;
335298cd9ca7SRichard Henderson 
335398cd9ca7SRichard Henderson     nullify_over(ctx);
335498cd9ca7SRichard Henderson 
335501afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r2);
335601afb7beSRichard Henderson     if (a->r1 == 0) {
33576fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, 0);
335898cd9ca7SRichard Henderson     } else {
33596fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
336098cd9ca7SRichard Henderson     }
336198cd9ca7SRichard Henderson 
33624fa52edfSRichard Henderson     /* All MOVB conditions are 32-bit. */
33634fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
336401afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
336501afb7beSRichard Henderson }
336601afb7beSRichard Henderson 
336701afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
336801afb7beSRichard Henderson {
33696fd0c7bcSRichard Henderson     TCGv_i64 dest;
337001afb7beSRichard Henderson     DisasCond cond;
337101afb7beSRichard Henderson 
337201afb7beSRichard Henderson     nullify_over(ctx);
337301afb7beSRichard Henderson 
337401afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r);
33756fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, a->i);
337601afb7beSRichard Henderson 
33774fa52edfSRichard Henderson     /* All MOVBI conditions are 32-bit. */
33784fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
337901afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
338098cd9ca7SRichard Henderson }
338198cd9ca7SRichard Henderson 
3382f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
33830b1347d2SRichard Henderson {
33846fd0c7bcSRichard Henderson     TCGv_i64 dest, src2;
33850b1347d2SRichard Henderson 
3386f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3387f7b775a9SRichard Henderson         return false;
3388f7b775a9SRichard Henderson     }
338930878590SRichard Henderson     if (a->c) {
33900b1347d2SRichard Henderson         nullify_over(ctx);
33910b1347d2SRichard Henderson     }
33920b1347d2SRichard Henderson 
339330878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
3394f7b775a9SRichard Henderson     src2 = load_gpr(ctx, a->r2);
339530878590SRichard Henderson     if (a->r1 == 0) {
3396f7b775a9SRichard Henderson         if (a->d) {
33976fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src2, cpu_sar);
3398f7b775a9SRichard Henderson         } else {
3399aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
3400f7b775a9SRichard Henderson 
34016fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src2);
34026fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
34036fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, dest, tmp);
3404f7b775a9SRichard Henderson         }
340530878590SRichard Henderson     } else if (a->r1 == a->r2) {
3406f7b775a9SRichard Henderson         if (a->d) {
34076fd0c7bcSRichard Henderson             tcg_gen_rotr_i64(dest, src2, cpu_sar);
3408f7b775a9SRichard Henderson         } else {
34090b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
3410e1d635e8SRichard Henderson             TCGv_i32 s32 = tcg_temp_new_i32();
3411e1d635e8SRichard Henderson 
34126fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, src2);
34136fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(s32, cpu_sar);
3414f7b775a9SRichard Henderson             tcg_gen_andi_i32(s32, s32, 31);
3415e1d635e8SRichard Henderson             tcg_gen_rotr_i32(t32, t32, s32);
34166fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
3417f7b775a9SRichard Henderson         }
3418f7b775a9SRichard Henderson     } else {
34196fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
3420f7b775a9SRichard Henderson 
3421f7b775a9SRichard Henderson         if (a->d) {
3422aac0f603SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
3423aac0f603SRichard Henderson             TCGv_i64 n = tcg_temp_new_i64();
3424f7b775a9SRichard Henderson 
34256fd0c7bcSRichard Henderson             tcg_gen_xori_i64(n, cpu_sar, 63);
34266fd0c7bcSRichard Henderson             tcg_gen_shl_i64(t, src2, n);
34276fd0c7bcSRichard Henderson             tcg_gen_shli_i64(t, t, 1);
34286fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src1, cpu_sar);
34296fd0c7bcSRichard Henderson             tcg_gen_or_i64(dest, dest, t);
34300b1347d2SRichard Henderson         } else {
34310b1347d2SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
34320b1347d2SRichard Henderson             TCGv_i64 s = tcg_temp_new_i64();
34330b1347d2SRichard Henderson 
34346fd0c7bcSRichard Henderson             tcg_gen_concat32_i64(t, src2, src1);
3435967662cdSRichard Henderson             tcg_gen_andi_i64(s, cpu_sar, 31);
3436967662cdSRichard Henderson             tcg_gen_shr_i64(dest, t, s);
34370b1347d2SRichard Henderson         }
3438f7b775a9SRichard Henderson     }
343930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
34400b1347d2SRichard Henderson 
34410b1347d2SRichard Henderson     /* Install the new nullification.  */
34420b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
344330878590SRichard Henderson     if (a->c) {
34444fa52edfSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
34450b1347d2SRichard Henderson     }
344631234768SRichard Henderson     return nullify_end(ctx);
34470b1347d2SRichard Henderson }
34480b1347d2SRichard Henderson 
3449f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
34500b1347d2SRichard Henderson {
3451f7b775a9SRichard Henderson     unsigned width, sa;
34526fd0c7bcSRichard Henderson     TCGv_i64 dest, t2;
34530b1347d2SRichard Henderson 
3454f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3455f7b775a9SRichard Henderson         return false;
3456f7b775a9SRichard Henderson     }
345730878590SRichard Henderson     if (a->c) {
34580b1347d2SRichard Henderson         nullify_over(ctx);
34590b1347d2SRichard Henderson     }
34600b1347d2SRichard Henderson 
3461f7b775a9SRichard Henderson     width = a->d ? 64 : 32;
3462f7b775a9SRichard Henderson     sa = width - 1 - a->cpos;
3463f7b775a9SRichard Henderson 
346430878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
346530878590SRichard Henderson     t2 = load_gpr(ctx, a->r2);
346605bfd4dbSRichard Henderson     if (a->r1 == 0) {
34676fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, t2, sa, width - sa);
3468c53e401eSRichard Henderson     } else if (width == TARGET_LONG_BITS) {
34696fd0c7bcSRichard Henderson         tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
3470f7b775a9SRichard Henderson     } else {
3471f7b775a9SRichard Henderson         assert(!a->d);
3472f7b775a9SRichard Henderson         if (a->r1 == a->r2) {
34730b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
34746fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, t2);
34750b1347d2SRichard Henderson             tcg_gen_rotri_i32(t32, t32, sa);
34766fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
34770b1347d2SRichard Henderson         } else {
3478967662cdSRichard Henderson             tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]);
3479967662cdSRichard Henderson             tcg_gen_extract_i64(dest, dest, sa, 32);
34800b1347d2SRichard Henderson         }
3481f7b775a9SRichard Henderson     }
348230878590SRichard Henderson     save_gpr(ctx, a->t, dest);
34830b1347d2SRichard Henderson 
34840b1347d2SRichard Henderson     /* Install the new nullification.  */
34850b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
348630878590SRichard Henderson     if (a->c) {
34874fa52edfSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
34880b1347d2SRichard Henderson     }
348931234768SRichard Henderson     return nullify_end(ctx);
34900b1347d2SRichard Henderson }
34910b1347d2SRichard Henderson 
3492bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
34930b1347d2SRichard Henderson {
3494bd792da3SRichard Henderson     unsigned widthm1 = a->d ? 63 : 31;
34956fd0c7bcSRichard Henderson     TCGv_i64 dest, src, tmp;
34960b1347d2SRichard Henderson 
3497bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3498bd792da3SRichard Henderson         return false;
3499bd792da3SRichard Henderson     }
350030878590SRichard Henderson     if (a->c) {
35010b1347d2SRichard Henderson         nullify_over(ctx);
35020b1347d2SRichard Henderson     }
35030b1347d2SRichard Henderson 
350430878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
350530878590SRichard Henderson     src = load_gpr(ctx, a->r);
3506aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
35070b1347d2SRichard Henderson 
35080b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
35096fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
35106fd0c7bcSRichard Henderson     tcg_gen_xori_i64(tmp, tmp, widthm1);
3511d781cb77SRichard Henderson 
351230878590SRichard Henderson     if (a->se) {
3513bd792da3SRichard Henderson         if (!a->d) {
35146fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(dest, src);
3515bd792da3SRichard Henderson             src = dest;
3516bd792da3SRichard Henderson         }
35176fd0c7bcSRichard Henderson         tcg_gen_sar_i64(dest, src, tmp);
35186fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, dest, 0, a->len);
35190b1347d2SRichard Henderson     } else {
3520bd792da3SRichard Henderson         if (!a->d) {
35216fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src);
3522bd792da3SRichard Henderson             src = dest;
3523bd792da3SRichard Henderson         }
35246fd0c7bcSRichard Henderson         tcg_gen_shr_i64(dest, src, tmp);
35256fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, dest, 0, a->len);
35260b1347d2SRichard Henderson     }
352730878590SRichard Henderson     save_gpr(ctx, a->t, dest);
35280b1347d2SRichard Henderson 
35290b1347d2SRichard Henderson     /* Install the new nullification.  */
35300b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
353130878590SRichard Henderson     if (a->c) {
3532bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
35330b1347d2SRichard Henderson     }
353431234768SRichard Henderson     return nullify_end(ctx);
35350b1347d2SRichard Henderson }
35360b1347d2SRichard Henderson 
3537bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
35380b1347d2SRichard Henderson {
3539bd792da3SRichard Henderson     unsigned len, cpos, width;
35406fd0c7bcSRichard Henderson     TCGv_i64 dest, src;
35410b1347d2SRichard Henderson 
3542bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3543bd792da3SRichard Henderson         return false;
3544bd792da3SRichard Henderson     }
354530878590SRichard Henderson     if (a->c) {
35460b1347d2SRichard Henderson         nullify_over(ctx);
35470b1347d2SRichard Henderson     }
35480b1347d2SRichard Henderson 
3549bd792da3SRichard Henderson     len = a->len;
3550bd792da3SRichard Henderson     width = a->d ? 64 : 32;
3551bd792da3SRichard Henderson     cpos = width - 1 - a->pos;
3552bd792da3SRichard Henderson     if (cpos + len > width) {
3553bd792da3SRichard Henderson         len = width - cpos;
3554bd792da3SRichard Henderson     }
3555bd792da3SRichard Henderson 
355630878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
355730878590SRichard Henderson     src = load_gpr(ctx, a->r);
355830878590SRichard Henderson     if (a->se) {
35596fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, src, cpos, len);
35600b1347d2SRichard Henderson     } else {
35616fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, src, cpos, len);
35620b1347d2SRichard Henderson     }
356330878590SRichard Henderson     save_gpr(ctx, a->t, dest);
35640b1347d2SRichard Henderson 
35650b1347d2SRichard Henderson     /* Install the new nullification.  */
35660b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
356730878590SRichard Henderson     if (a->c) {
3568bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
35690b1347d2SRichard Henderson     }
357031234768SRichard Henderson     return nullify_end(ctx);
35710b1347d2SRichard Henderson }
35720b1347d2SRichard Henderson 
357372ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
35740b1347d2SRichard Henderson {
357572ae4f2bSRichard Henderson     unsigned len, width;
3576c53e401eSRichard Henderson     uint64_t mask0, mask1;
35776fd0c7bcSRichard Henderson     TCGv_i64 dest;
35780b1347d2SRichard Henderson 
357972ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
358072ae4f2bSRichard Henderson         return false;
358172ae4f2bSRichard Henderson     }
358230878590SRichard Henderson     if (a->c) {
35830b1347d2SRichard Henderson         nullify_over(ctx);
35840b1347d2SRichard Henderson     }
358572ae4f2bSRichard Henderson 
358672ae4f2bSRichard Henderson     len = a->len;
358772ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
358872ae4f2bSRichard Henderson     if (a->cpos + len > width) {
358972ae4f2bSRichard Henderson         len = width - a->cpos;
35900b1347d2SRichard Henderson     }
35910b1347d2SRichard Henderson 
359230878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
359330878590SRichard Henderson     mask0 = deposit64(0, a->cpos, len, a->i);
359430878590SRichard Henderson     mask1 = deposit64(-1, a->cpos, len, a->i);
35950b1347d2SRichard Henderson 
359630878590SRichard Henderson     if (a->nz) {
35976fd0c7bcSRichard Henderson         TCGv_i64 src = load_gpr(ctx, a->t);
35986fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, src, mask1);
35996fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, mask0);
36000b1347d2SRichard Henderson     } else {
36016fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, mask0);
36020b1347d2SRichard Henderson     }
360330878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36040b1347d2SRichard Henderson 
36050b1347d2SRichard Henderson     /* Install the new nullification.  */
36060b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
360730878590SRichard Henderson     if (a->c) {
360872ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
36090b1347d2SRichard Henderson     }
361031234768SRichard Henderson     return nullify_end(ctx);
36110b1347d2SRichard Henderson }
36120b1347d2SRichard Henderson 
361372ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
36140b1347d2SRichard Henderson {
361530878590SRichard Henderson     unsigned rs = a->nz ? a->t : 0;
361672ae4f2bSRichard Henderson     unsigned len, width;
36176fd0c7bcSRichard Henderson     TCGv_i64 dest, val;
36180b1347d2SRichard Henderson 
361972ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
362072ae4f2bSRichard Henderson         return false;
362172ae4f2bSRichard Henderson     }
362230878590SRichard Henderson     if (a->c) {
36230b1347d2SRichard Henderson         nullify_over(ctx);
36240b1347d2SRichard Henderson     }
362572ae4f2bSRichard Henderson 
362672ae4f2bSRichard Henderson     len = a->len;
362772ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
362872ae4f2bSRichard Henderson     if (a->cpos + len > width) {
362972ae4f2bSRichard Henderson         len = width - a->cpos;
36300b1347d2SRichard Henderson     }
36310b1347d2SRichard Henderson 
363230878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
363330878590SRichard Henderson     val = load_gpr(ctx, a->r);
36340b1347d2SRichard Henderson     if (rs == 0) {
36356fd0c7bcSRichard Henderson         tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
36360b1347d2SRichard Henderson     } else {
36376fd0c7bcSRichard Henderson         tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
36380b1347d2SRichard Henderson     }
363930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36400b1347d2SRichard Henderson 
36410b1347d2SRichard Henderson     /* Install the new nullification.  */
36420b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
364330878590SRichard Henderson     if (a->c) {
364472ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
36450b1347d2SRichard Henderson     }
364631234768SRichard Henderson     return nullify_end(ctx);
36470b1347d2SRichard Henderson }
36480b1347d2SRichard Henderson 
364972ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
36506fd0c7bcSRichard Henderson                        bool d, bool nz, unsigned len, TCGv_i64 val)
36510b1347d2SRichard Henderson {
36520b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
365372ae4f2bSRichard Henderson     unsigned widthm1 = d ? 63 : 31;
36546fd0c7bcSRichard Henderson     TCGv_i64 mask, tmp, shift, dest;
3655c53e401eSRichard Henderson     uint64_t msb = 1ULL << (len - 1);
36560b1347d2SRichard Henderson 
36570b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
3658aac0f603SRichard Henderson     shift = tcg_temp_new_i64();
3659aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
36600b1347d2SRichard Henderson 
36610b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
36626fd0c7bcSRichard Henderson     tcg_gen_andi_i64(shift, cpu_sar, widthm1);
36636fd0c7bcSRichard Henderson     tcg_gen_xori_i64(shift, shift, widthm1);
36640b1347d2SRichard Henderson 
3665aac0f603SRichard Henderson     mask = tcg_temp_new_i64();
36666fd0c7bcSRichard Henderson     tcg_gen_movi_i64(mask, msb + (msb - 1));
36676fd0c7bcSRichard Henderson     tcg_gen_and_i64(tmp, val, mask);
36680b1347d2SRichard Henderson     if (rs) {
36696fd0c7bcSRichard Henderson         tcg_gen_shl_i64(mask, mask, shift);
36706fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tmp, shift);
36716fd0c7bcSRichard Henderson         tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
36726fd0c7bcSRichard Henderson         tcg_gen_or_i64(dest, dest, tmp);
36730b1347d2SRichard Henderson     } else {
36746fd0c7bcSRichard Henderson         tcg_gen_shl_i64(dest, tmp, shift);
36750b1347d2SRichard Henderson     }
36760b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
36770b1347d2SRichard Henderson 
36780b1347d2SRichard Henderson     /* Install the new nullification.  */
36790b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
36800b1347d2SRichard Henderson     if (c) {
368172ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, c, d, dest);
36820b1347d2SRichard Henderson     }
368331234768SRichard Henderson     return nullify_end(ctx);
36840b1347d2SRichard Henderson }
36850b1347d2SRichard Henderson 
368672ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
368730878590SRichard Henderson {
368872ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
368972ae4f2bSRichard Henderson         return false;
369072ae4f2bSRichard Henderson     }
3691a6deecceSSven Schnelle     if (a->c) {
3692a6deecceSSven Schnelle         nullify_over(ctx);
3693a6deecceSSven Schnelle     }
369472ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
369572ae4f2bSRichard Henderson                       load_gpr(ctx, a->r));
369630878590SRichard Henderson }
369730878590SRichard Henderson 
369872ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
369930878590SRichard Henderson {
370072ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
370172ae4f2bSRichard Henderson         return false;
370272ae4f2bSRichard Henderson     }
3703a6deecceSSven Schnelle     if (a->c) {
3704a6deecceSSven Schnelle         nullify_over(ctx);
3705a6deecceSSven Schnelle     }
370672ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
37076fd0c7bcSRichard Henderson                       tcg_constant_i64(a->i));
370830878590SRichard Henderson }
37090b1347d2SRichard Henderson 
37108340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a)
371198cd9ca7SRichard Henderson {
37126fd0c7bcSRichard Henderson     TCGv_i64 tmp;
371398cd9ca7SRichard Henderson 
3714c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
371598cd9ca7SRichard Henderson     /* ??? It seems like there should be a good way of using
371698cd9ca7SRichard Henderson        "be disp(sr2, r0)", the canonical gateway entry mechanism
371798cd9ca7SRichard Henderson        to our advantage.  But that appears to be inconvenient to
371898cd9ca7SRichard Henderson        manage along side branch delay slots.  Therefore we handle
371998cd9ca7SRichard Henderson        entry into the gateway page via absolute address.  */
372098cd9ca7SRichard Henderson     /* Since we don't implement spaces, just branch.  Do notice the special
372198cd9ca7SRichard Henderson        case of "be disp(*,r0)" using a direct branch to disp, so that we can
372298cd9ca7SRichard Henderson        goto_tb to the TB containing the syscall.  */
37238340f534SRichard Henderson     if (a->b == 0) {
37248340f534SRichard Henderson         return do_dbranch(ctx, a->disp, a->l, a->n);
372598cd9ca7SRichard Henderson     }
3726c301f34eSRichard Henderson #else
3727c301f34eSRichard Henderson     nullify_over(ctx);
3728660eefe1SRichard Henderson #endif
3729660eefe1SRichard Henderson 
3730aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
37316fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp);
3732660eefe1SRichard Henderson     tmp = do_ibranch_priv(ctx, tmp);
3733c301f34eSRichard Henderson 
3734c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
37358340f534SRichard Henderson     return do_ibranch(ctx, tmp, a->l, a->n);
3736c301f34eSRichard Henderson #else
3737c301f34eSRichard Henderson     TCGv_i64 new_spc = tcg_temp_new_i64();
3738c301f34eSRichard Henderson 
37398340f534SRichard Henderson     load_spr(ctx, new_spc, a->sp);
37408340f534SRichard Henderson     if (a->l) {
3741741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
3742c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f);
3743c301f34eSRichard Henderson     }
37448340f534SRichard Henderson     if (a->n && use_nullify_skip(ctx)) {
3745a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
37466fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, 4);
3747a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3748c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, new_spc);
3749c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f);
3750c301f34eSRichard Henderson     } else {
3751741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3752c301f34eSRichard Henderson         if (ctx->iaoq_b == -1) {
3753c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3754c301f34eSRichard Henderson         }
3755a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3756c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, new_spc);
37578340f534SRichard Henderson         nullify_set(ctx, a->n);
3758c301f34eSRichard Henderson     }
3759c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
376031234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
376131234768SRichard Henderson     return nullify_end(ctx);
3762c301f34eSRichard Henderson #endif
376398cd9ca7SRichard Henderson }
376498cd9ca7SRichard Henderson 
37658340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a)
376698cd9ca7SRichard Henderson {
37678340f534SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n);
376898cd9ca7SRichard Henderson }
376998cd9ca7SRichard Henderson 
37708340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
377143e05652SRichard Henderson {
3772c53e401eSRichard Henderson     uint64_t dest = iaoq_dest(ctx, a->disp);
377343e05652SRichard Henderson 
37746e5f5300SSven Schnelle     nullify_over(ctx);
37756e5f5300SSven Schnelle 
377643e05652SRichard Henderson     /* Make sure the caller hasn't done something weird with the queue.
377743e05652SRichard Henderson      * ??? This is not quite the same as the PSW[B] bit, which would be
377843e05652SRichard Henderson      * expensive to track.  Real hardware will trap for
377943e05652SRichard Henderson      *    b  gateway
378043e05652SRichard Henderson      *    b  gateway+4  (in delay slot of first branch)
378143e05652SRichard Henderson      * However, checking for a non-sequential instruction queue *will*
378243e05652SRichard Henderson      * diagnose the security hole
378343e05652SRichard Henderson      *    b  gateway
378443e05652SRichard Henderson      *    b  evil
378543e05652SRichard Henderson      * in which instructions at evil would run with increased privs.
378643e05652SRichard Henderson      */
378743e05652SRichard Henderson     if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) {
378843e05652SRichard Henderson         return gen_illegal(ctx);
378943e05652SRichard Henderson     }
379043e05652SRichard Henderson 
379143e05652SRichard Henderson #ifndef CONFIG_USER_ONLY
379243e05652SRichard Henderson     if (ctx->tb_flags & PSW_C) {
3793b77af26eSRichard Henderson         CPUHPPAState *env = cpu_env(ctx->cs);
379443e05652SRichard Henderson         int type = hppa_artype_for_page(env, ctx->base.pc_next);
379543e05652SRichard Henderson         /* If we could not find a TLB entry, then we need to generate an
379643e05652SRichard Henderson            ITLB miss exception so the kernel will provide it.
379743e05652SRichard Henderson            The resulting TLB fill operation will invalidate this TB and
379843e05652SRichard Henderson            we will re-translate, at which point we *will* be able to find
379943e05652SRichard Henderson            the TLB entry and determine if this is in fact a gateway page.  */
380043e05652SRichard Henderson         if (type < 0) {
380131234768SRichard Henderson             gen_excp(ctx, EXCP_ITLB_MISS);
380231234768SRichard Henderson             return true;
380343e05652SRichard Henderson         }
380443e05652SRichard Henderson         /* No change for non-gateway pages or for priv decrease.  */
380543e05652SRichard Henderson         if (type >= 4 && type - 4 < ctx->privilege) {
380643e05652SRichard Henderson             dest = deposit32(dest, 0, 2, type - 4);
380743e05652SRichard Henderson         }
380843e05652SRichard Henderson     } else {
380943e05652SRichard Henderson         dest &= -4;  /* priv = 0 */
381043e05652SRichard Henderson     }
381143e05652SRichard Henderson #endif
381243e05652SRichard Henderson 
38136e5f5300SSven Schnelle     if (a->l) {
38146fd0c7bcSRichard Henderson         TCGv_i64 tmp = dest_gpr(ctx, a->l);
38156e5f5300SSven Schnelle         if (ctx->privilege < 3) {
38166fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, tmp, -4);
38176e5f5300SSven Schnelle         }
38186fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
38196e5f5300SSven Schnelle         save_gpr(ctx, a->l, tmp);
38206e5f5300SSven Schnelle     }
38216e5f5300SSven Schnelle 
38226e5f5300SSven Schnelle     return do_dbranch(ctx, dest, 0, a->n);
382343e05652SRichard Henderson }
382443e05652SRichard Henderson 
38258340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a)
382698cd9ca7SRichard Henderson {
3827b35aec85SRichard Henderson     if (a->x) {
3828aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
38296fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3);
38306fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8);
3831660eefe1SRichard Henderson         /* The computation here never changes privilege level.  */
38328340f534SRichard Henderson         return do_ibranch(ctx, tmp, a->l, a->n);
3833b35aec85SRichard Henderson     } else {
3834b35aec85SRichard Henderson         /* BLR R0,RX is a good way to load PC+8 into RX.  */
3835b35aec85SRichard Henderson         return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n);
3836b35aec85SRichard Henderson     }
383798cd9ca7SRichard Henderson }
383898cd9ca7SRichard Henderson 
38398340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a)
384098cd9ca7SRichard Henderson {
38416fd0c7bcSRichard Henderson     TCGv_i64 dest;
384298cd9ca7SRichard Henderson 
38438340f534SRichard Henderson     if (a->x == 0) {
38448340f534SRichard Henderson         dest = load_gpr(ctx, a->b);
384598cd9ca7SRichard Henderson     } else {
3846aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
38476fd0c7bcSRichard Henderson         tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
38486fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
384998cd9ca7SRichard Henderson     }
3850660eefe1SRichard Henderson     dest = do_ibranch_priv(ctx, dest);
38518340f534SRichard Henderson     return do_ibranch(ctx, dest, 0, a->n);
385298cd9ca7SRichard Henderson }
385398cd9ca7SRichard Henderson 
38548340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a)
385598cd9ca7SRichard Henderson {
38566fd0c7bcSRichard Henderson     TCGv_i64 dest;
385798cd9ca7SRichard Henderson 
3858c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
38598340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
38608340f534SRichard Henderson     return do_ibranch(ctx, dest, a->l, a->n);
3861c301f34eSRichard Henderson #else
3862c301f34eSRichard Henderson     nullify_over(ctx);
38638340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
3864c301f34eSRichard Henderson 
3865741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3866c301f34eSRichard Henderson     if (ctx->iaoq_b == -1) {
3867c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3868c301f34eSRichard Henderson     }
3869741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest);
3870c301f34eSRichard Henderson     tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
38718340f534SRichard Henderson     if (a->l) {
3872741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var);
3873c301f34eSRichard Henderson     }
38748340f534SRichard Henderson     nullify_set(ctx, a->n);
3875c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
387631234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
387731234768SRichard Henderson     return nullify_end(ctx);
3878c301f34eSRichard Henderson #endif
387998cd9ca7SRichard Henderson }
388098cd9ca7SRichard Henderson 
3881a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
3882a8966ba7SRichard Henderson {
3883a8966ba7SRichard Henderson     /* All branch target stack instructions implement as nop. */
3884a8966ba7SRichard Henderson     return ctx->is_pa20;
3885a8966ba7SRichard Henderson }
3886a8966ba7SRichard Henderson 
38871ca74648SRichard Henderson /*
38881ca74648SRichard Henderson  * Float class 0
38891ca74648SRichard Henderson  */
3890ebe9383cSRichard Henderson 
38911ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3892ebe9383cSRichard Henderson {
3893ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
3894ebe9383cSRichard Henderson }
3895ebe9383cSRichard Henderson 
389659f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
389759f8c04bSHelge Deller {
3898a300dad3SRichard Henderson     uint64_t ret;
3899a300dad3SRichard Henderson 
3900c53e401eSRichard Henderson     if (ctx->is_pa20) {
3901a300dad3SRichard Henderson         ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
3902a300dad3SRichard Henderson     } else {
3903a300dad3SRichard Henderson         ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
3904a300dad3SRichard Henderson     }
3905a300dad3SRichard Henderson 
390659f8c04bSHelge Deller     nullify_over(ctx);
3907a300dad3SRichard Henderson     save_frd(0, tcg_constant_i64(ret));
390859f8c04bSHelge Deller     return nullify_end(ctx);
390959f8c04bSHelge Deller }
391059f8c04bSHelge Deller 
39111ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a)
39121ca74648SRichard Henderson {
39131ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f);
39141ca74648SRichard Henderson }
39151ca74648SRichard Henderson 
3916ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3917ebe9383cSRichard Henderson {
3918ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
3919ebe9383cSRichard Henderson }
3920ebe9383cSRichard Henderson 
39211ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a)
39221ca74648SRichard Henderson {
39231ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d);
39241ca74648SRichard Henderson }
39251ca74648SRichard Henderson 
39261ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3927ebe9383cSRichard Henderson {
3928ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
3929ebe9383cSRichard Henderson }
3930ebe9383cSRichard Henderson 
39311ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a)
39321ca74648SRichard Henderson {
39331ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fabs_f);
39341ca74648SRichard Henderson }
39351ca74648SRichard Henderson 
3936ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3937ebe9383cSRichard Henderson {
3938ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
3939ebe9383cSRichard Henderson }
3940ebe9383cSRichard Henderson 
39411ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a)
39421ca74648SRichard Henderson {
39431ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fabs_d);
39441ca74648SRichard Henderson }
39451ca74648SRichard Henderson 
39461ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a)
39471ca74648SRichard Henderson {
39481ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s);
39491ca74648SRichard Henderson }
39501ca74648SRichard Henderson 
39511ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a)
39521ca74648SRichard Henderson {
39531ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d);
39541ca74648SRichard Henderson }
39551ca74648SRichard Henderson 
39561ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a)
39571ca74648SRichard Henderson {
39581ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s);
39591ca74648SRichard Henderson }
39601ca74648SRichard Henderson 
39611ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a)
39621ca74648SRichard Henderson {
39631ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d);
39641ca74648SRichard Henderson }
39651ca74648SRichard Henderson 
39661ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3967ebe9383cSRichard Henderson {
3968ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
3969ebe9383cSRichard Henderson }
3970ebe9383cSRichard Henderson 
39711ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a)
39721ca74648SRichard Henderson {
39731ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fneg_f);
39741ca74648SRichard Henderson }
39751ca74648SRichard Henderson 
3976ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3977ebe9383cSRichard Henderson {
3978ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
3979ebe9383cSRichard Henderson }
3980ebe9383cSRichard Henderson 
39811ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a)
39821ca74648SRichard Henderson {
39831ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fneg_d);
39841ca74648SRichard Henderson }
39851ca74648SRichard Henderson 
39861ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3987ebe9383cSRichard Henderson {
3988ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
3989ebe9383cSRichard Henderson }
3990ebe9383cSRichard Henderson 
39911ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a)
39921ca74648SRichard Henderson {
39931ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f);
39941ca74648SRichard Henderson }
39951ca74648SRichard Henderson 
3996ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3997ebe9383cSRichard Henderson {
3998ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
3999ebe9383cSRichard Henderson }
4000ebe9383cSRichard Henderson 
40011ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a)
40021ca74648SRichard Henderson {
40031ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d);
40041ca74648SRichard Henderson }
40051ca74648SRichard Henderson 
40061ca74648SRichard Henderson /*
40071ca74648SRichard Henderson  * Float class 1
40081ca74648SRichard Henderson  */
40091ca74648SRichard Henderson 
40101ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a)
40111ca74648SRichard Henderson {
40121ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s);
40131ca74648SRichard Henderson }
40141ca74648SRichard Henderson 
40151ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a)
40161ca74648SRichard Henderson {
40171ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d);
40181ca74648SRichard Henderson }
40191ca74648SRichard Henderson 
40201ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a)
40211ca74648SRichard Henderson {
40221ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s);
40231ca74648SRichard Henderson }
40241ca74648SRichard Henderson 
40251ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a)
40261ca74648SRichard Henderson {
40271ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s);
40281ca74648SRichard Henderson }
40291ca74648SRichard Henderson 
40301ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a)
40311ca74648SRichard Henderson {
40321ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d);
40331ca74648SRichard Henderson }
40341ca74648SRichard Henderson 
40351ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a)
40361ca74648SRichard Henderson {
40371ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d);
40381ca74648SRichard Henderson }
40391ca74648SRichard Henderson 
40401ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a)
40411ca74648SRichard Henderson {
40421ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w);
40431ca74648SRichard Henderson }
40441ca74648SRichard Henderson 
40451ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a)
40461ca74648SRichard Henderson {
40471ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w);
40481ca74648SRichard Henderson }
40491ca74648SRichard Henderson 
40501ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a)
40511ca74648SRichard Henderson {
40521ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw);
40531ca74648SRichard Henderson }
40541ca74648SRichard Henderson 
40551ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a)
40561ca74648SRichard Henderson {
40571ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw);
40581ca74648SRichard Henderson }
40591ca74648SRichard Henderson 
40601ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a)
40611ca74648SRichard Henderson {
40621ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w);
40631ca74648SRichard Henderson }
40641ca74648SRichard Henderson 
40651ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a)
40661ca74648SRichard Henderson {
40671ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w);
40681ca74648SRichard Henderson }
40691ca74648SRichard Henderson 
40701ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a)
40711ca74648SRichard Henderson {
40721ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw);
40731ca74648SRichard Henderson }
40741ca74648SRichard Henderson 
40751ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a)
40761ca74648SRichard Henderson {
40771ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw);
40781ca74648SRichard Henderson }
40791ca74648SRichard Henderson 
40801ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a)
40811ca74648SRichard Henderson {
40821ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s);
40831ca74648SRichard Henderson }
40841ca74648SRichard Henderson 
40851ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a)
40861ca74648SRichard Henderson {
40871ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s);
40881ca74648SRichard Henderson }
40891ca74648SRichard Henderson 
40901ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a)
40911ca74648SRichard Henderson {
40921ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d);
40931ca74648SRichard Henderson }
40941ca74648SRichard Henderson 
40951ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a)
40961ca74648SRichard Henderson {
40971ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d);
40981ca74648SRichard Henderson }
40991ca74648SRichard Henderson 
41001ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a)
41011ca74648SRichard Henderson {
41021ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw);
41031ca74648SRichard Henderson }
41041ca74648SRichard Henderson 
41051ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a)
41061ca74648SRichard Henderson {
41071ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw);
41081ca74648SRichard Henderson }
41091ca74648SRichard Henderson 
41101ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a)
41111ca74648SRichard Henderson {
41121ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw);
41131ca74648SRichard Henderson }
41141ca74648SRichard Henderson 
41151ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a)
41161ca74648SRichard Henderson {
41171ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw);
41181ca74648SRichard Henderson }
41191ca74648SRichard Henderson 
41201ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a)
41211ca74648SRichard Henderson {
41221ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw);
41231ca74648SRichard Henderson }
41241ca74648SRichard Henderson 
41251ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a)
41261ca74648SRichard Henderson {
41271ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw);
41281ca74648SRichard Henderson }
41291ca74648SRichard Henderson 
41301ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a)
41311ca74648SRichard Henderson {
41321ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw);
41331ca74648SRichard Henderson }
41341ca74648SRichard Henderson 
41351ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a)
41361ca74648SRichard Henderson {
41371ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw);
41381ca74648SRichard Henderson }
41391ca74648SRichard Henderson 
41401ca74648SRichard Henderson /*
41411ca74648SRichard Henderson  * Float class 2
41421ca74648SRichard Henderson  */
41431ca74648SRichard Henderson 
41441ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a)
4145ebe9383cSRichard Henderson {
4146ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
4147ebe9383cSRichard Henderson 
4148ebe9383cSRichard Henderson     nullify_over(ctx);
4149ebe9383cSRichard Henderson 
41501ca74648SRichard Henderson     ta = load_frw0_i32(a->r1);
41511ca74648SRichard Henderson     tb = load_frw0_i32(a->r2);
415229dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
415329dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4154ebe9383cSRichard Henderson 
4155ad75a51eSRichard Henderson     gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc);
4156ebe9383cSRichard Henderson 
41571ca74648SRichard Henderson     return nullify_end(ctx);
4158ebe9383cSRichard Henderson }
4159ebe9383cSRichard Henderson 
41601ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
4161ebe9383cSRichard Henderson {
4162ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
4163ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
4164ebe9383cSRichard Henderson 
4165ebe9383cSRichard Henderson     nullify_over(ctx);
4166ebe9383cSRichard Henderson 
41671ca74648SRichard Henderson     ta = load_frd0(a->r1);
41681ca74648SRichard Henderson     tb = load_frd0(a->r2);
416929dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
417029dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4171ebe9383cSRichard Henderson 
4172ad75a51eSRichard Henderson     gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc);
4173ebe9383cSRichard Henderson 
417431234768SRichard Henderson     return nullify_end(ctx);
4175ebe9383cSRichard Henderson }
4176ebe9383cSRichard Henderson 
41771ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
4178ebe9383cSRichard Henderson {
41796fd0c7bcSRichard Henderson     TCGv_i64 t;
4180ebe9383cSRichard Henderson 
4181ebe9383cSRichard Henderson     nullify_over(ctx);
4182ebe9383cSRichard Henderson 
4183aac0f603SRichard Henderson     t = tcg_temp_new_i64();
41846fd0c7bcSRichard Henderson     tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
4185ebe9383cSRichard Henderson 
41861ca74648SRichard Henderson     if (a->y == 1) {
4187ebe9383cSRichard Henderson         int mask;
4188ebe9383cSRichard Henderson         bool inv = false;
4189ebe9383cSRichard Henderson 
41901ca74648SRichard Henderson         switch (a->c) {
4191ebe9383cSRichard Henderson         case 0: /* simple */
41926fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, 0x4000000);
4193ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_NE, t);
4194ebe9383cSRichard Henderson             goto done;
4195ebe9383cSRichard Henderson         case 2: /* rej */
4196ebe9383cSRichard Henderson             inv = true;
4197ebe9383cSRichard Henderson             /* fallthru */
4198ebe9383cSRichard Henderson         case 1: /* acc */
4199ebe9383cSRichard Henderson             mask = 0x43ff800;
4200ebe9383cSRichard Henderson             break;
4201ebe9383cSRichard Henderson         case 6: /* rej8 */
4202ebe9383cSRichard Henderson             inv = true;
4203ebe9383cSRichard Henderson             /* fallthru */
4204ebe9383cSRichard Henderson         case 5: /* acc8 */
4205ebe9383cSRichard Henderson             mask = 0x43f8000;
4206ebe9383cSRichard Henderson             break;
4207ebe9383cSRichard Henderson         case 9: /* acc6 */
4208ebe9383cSRichard Henderson             mask = 0x43e0000;
4209ebe9383cSRichard Henderson             break;
4210ebe9383cSRichard Henderson         case 13: /* acc4 */
4211ebe9383cSRichard Henderson             mask = 0x4380000;
4212ebe9383cSRichard Henderson             break;
4213ebe9383cSRichard Henderson         case 17: /* acc2 */
4214ebe9383cSRichard Henderson             mask = 0x4200000;
4215ebe9383cSRichard Henderson             break;
4216ebe9383cSRichard Henderson         default:
42171ca74648SRichard Henderson             gen_illegal(ctx);
42181ca74648SRichard Henderson             return true;
4219ebe9383cSRichard Henderson         }
4220ebe9383cSRichard Henderson         if (inv) {
42216fd0c7bcSRichard Henderson             TCGv_i64 c = tcg_constant_i64(mask);
42226fd0c7bcSRichard Henderson             tcg_gen_or_i64(t, t, c);
4223ebe9383cSRichard Henderson             ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
4224ebe9383cSRichard Henderson         } else {
42256fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, mask);
4226ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
4227ebe9383cSRichard Henderson         }
42281ca74648SRichard Henderson     } else {
42291ca74648SRichard Henderson         unsigned cbit = (a->y ^ 1) - 1;
42301ca74648SRichard Henderson 
42316fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, t, 21 - cbit, 1);
42321ca74648SRichard Henderson         ctx->null_cond = cond_make_0(TCG_COND_NE, t);
42331ca74648SRichard Henderson     }
42341ca74648SRichard Henderson 
4235ebe9383cSRichard Henderson  done:
423631234768SRichard Henderson     return nullify_end(ctx);
4237ebe9383cSRichard Henderson }
4238ebe9383cSRichard Henderson 
42391ca74648SRichard Henderson /*
42401ca74648SRichard Henderson  * Float class 2
42411ca74648SRichard Henderson  */
42421ca74648SRichard Henderson 
42431ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a)
4244ebe9383cSRichard Henderson {
42451ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s);
42461ca74648SRichard Henderson }
42471ca74648SRichard Henderson 
42481ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a)
42491ca74648SRichard Henderson {
42501ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d);
42511ca74648SRichard Henderson }
42521ca74648SRichard Henderson 
42531ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a)
42541ca74648SRichard Henderson {
42551ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s);
42561ca74648SRichard Henderson }
42571ca74648SRichard Henderson 
42581ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a)
42591ca74648SRichard Henderson {
42601ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d);
42611ca74648SRichard Henderson }
42621ca74648SRichard Henderson 
42631ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a)
42641ca74648SRichard Henderson {
42651ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s);
42661ca74648SRichard Henderson }
42671ca74648SRichard Henderson 
42681ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a)
42691ca74648SRichard Henderson {
42701ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d);
42711ca74648SRichard Henderson }
42721ca74648SRichard Henderson 
42731ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a)
42741ca74648SRichard Henderson {
42751ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s);
42761ca74648SRichard Henderson }
42771ca74648SRichard Henderson 
42781ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a)
42791ca74648SRichard Henderson {
42801ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d);
42811ca74648SRichard Henderson }
42821ca74648SRichard Henderson 
42831ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a)
42841ca74648SRichard Henderson {
42851ca74648SRichard Henderson     TCGv_i64 x, y;
4286ebe9383cSRichard Henderson 
4287ebe9383cSRichard Henderson     nullify_over(ctx);
4288ebe9383cSRichard Henderson 
42891ca74648SRichard Henderson     x = load_frw0_i64(a->r1);
42901ca74648SRichard Henderson     y = load_frw0_i64(a->r2);
42911ca74648SRichard Henderson     tcg_gen_mul_i64(x, x, y);
42921ca74648SRichard Henderson     save_frd(a->t, x);
4293ebe9383cSRichard Henderson 
429431234768SRichard Henderson     return nullify_end(ctx);
4295ebe9383cSRichard Henderson }
4296ebe9383cSRichard Henderson 
4297ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
4298ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
4299ebe9383cSRichard Henderson {
4300ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
4301ebe9383cSRichard Henderson }
4302ebe9383cSRichard Henderson 
4303b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4304ebe9383cSRichard Henderson {
4305b1e2af57SRichard Henderson     int tm = fmpyadd_s_reg(a->tm);
4306b1e2af57SRichard Henderson     int ra = fmpyadd_s_reg(a->ra);
4307b1e2af57SRichard Henderson     int ta = fmpyadd_s_reg(a->ta);
4308b1e2af57SRichard Henderson     int rm2 = fmpyadd_s_reg(a->rm2);
4309b1e2af57SRichard Henderson     int rm1 = fmpyadd_s_reg(a->rm1);
4310ebe9383cSRichard Henderson 
4311ebe9383cSRichard Henderson     nullify_over(ctx);
4312ebe9383cSRichard Henderson 
4313ebe9383cSRichard Henderson     do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4314ebe9383cSRichard Henderson     do_fop_weww(ctx, ta, ta, ra,
4315ebe9383cSRichard Henderson                 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
4316ebe9383cSRichard Henderson 
431731234768SRichard Henderson     return nullify_end(ctx);
4318ebe9383cSRichard Henderson }
4319ebe9383cSRichard Henderson 
4320b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4321b1e2af57SRichard Henderson {
4322b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, false);
4323b1e2af57SRichard Henderson }
4324b1e2af57SRichard Henderson 
4325b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4326b1e2af57SRichard Henderson {
4327b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, true);
4328b1e2af57SRichard Henderson }
4329b1e2af57SRichard Henderson 
4330b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4331b1e2af57SRichard Henderson {
4332b1e2af57SRichard Henderson     nullify_over(ctx);
4333b1e2af57SRichard Henderson 
4334b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4335b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4336b1e2af57SRichard Henderson                 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4337b1e2af57SRichard Henderson 
4338b1e2af57SRichard Henderson     return nullify_end(ctx);
4339b1e2af57SRichard Henderson }
4340b1e2af57SRichard Henderson 
4341b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4342b1e2af57SRichard Henderson {
4343b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, false);
4344b1e2af57SRichard Henderson }
4345b1e2af57SRichard Henderson 
4346b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4347b1e2af57SRichard Henderson {
4348b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, true);
4349b1e2af57SRichard Henderson }
4350b1e2af57SRichard Henderson 
4351c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a)
4352ebe9383cSRichard Henderson {
4353c3bad4f8SRichard Henderson     TCGv_i32 x, y, z;
4354ebe9383cSRichard Henderson 
4355ebe9383cSRichard Henderson     nullify_over(ctx);
4356c3bad4f8SRichard Henderson     x = load_frw0_i32(a->rm1);
4357c3bad4f8SRichard Henderson     y = load_frw0_i32(a->rm2);
4358c3bad4f8SRichard Henderson     z = load_frw0_i32(a->ra3);
4359ebe9383cSRichard Henderson 
4360c3bad4f8SRichard Henderson     if (a->neg) {
4361ad75a51eSRichard Henderson         gen_helper_fmpynfadd_s(x, tcg_env, x, y, z);
4362ebe9383cSRichard Henderson     } else {
4363ad75a51eSRichard Henderson         gen_helper_fmpyfadd_s(x, tcg_env, x, y, z);
4364ebe9383cSRichard Henderson     }
4365ebe9383cSRichard Henderson 
4366c3bad4f8SRichard Henderson     save_frw_i32(a->t, x);
436731234768SRichard Henderson     return nullify_end(ctx);
4368ebe9383cSRichard Henderson }
4369ebe9383cSRichard Henderson 
4370c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
4371ebe9383cSRichard Henderson {
4372c3bad4f8SRichard Henderson     TCGv_i64 x, y, z;
4373ebe9383cSRichard Henderson 
4374ebe9383cSRichard Henderson     nullify_over(ctx);
4375c3bad4f8SRichard Henderson     x = load_frd0(a->rm1);
4376c3bad4f8SRichard Henderson     y = load_frd0(a->rm2);
4377c3bad4f8SRichard Henderson     z = load_frd0(a->ra3);
4378ebe9383cSRichard Henderson 
4379c3bad4f8SRichard Henderson     if (a->neg) {
4380ad75a51eSRichard Henderson         gen_helper_fmpynfadd_d(x, tcg_env, x, y, z);
4381ebe9383cSRichard Henderson     } else {
4382ad75a51eSRichard Henderson         gen_helper_fmpyfadd_d(x, tcg_env, x, y, z);
4383ebe9383cSRichard Henderson     }
4384ebe9383cSRichard Henderson 
4385c3bad4f8SRichard Henderson     save_frd(a->t, x);
438631234768SRichard Henderson     return nullify_end(ctx);
4387ebe9383cSRichard Henderson }
4388ebe9383cSRichard Henderson 
438915da177bSSven Schnelle static bool trans_diag(DisasContext *ctx, arg_diag *a)
439015da177bSSven Schnelle {
4391cf6b28d4SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4392cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY
4393cf6b28d4SHelge Deller     if (a->i == 0x100) {
4394cf6b28d4SHelge Deller         /* emulate PDC BTLB, called by SeaBIOS-hppa */
4395ad75a51eSRichard Henderson         nullify_over(ctx);
4396ad75a51eSRichard Henderson         gen_helper_diag_btlb(tcg_env);
4397cf6b28d4SHelge Deller         return nullify_end(ctx);
439815da177bSSven Schnelle     }
4399ad75a51eSRichard Henderson #endif
4400ad75a51eSRichard Henderson     qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i);
4401ad75a51eSRichard Henderson     return true;
4402ad75a51eSRichard Henderson }
440315da177bSSven Schnelle 
4404b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
440561766fe9SRichard Henderson {
440651b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4407f764718dSRichard Henderson     int bound;
440861766fe9SRichard Henderson 
440951b061fbSRichard Henderson     ctx->cs = cs;
4410494737b7SRichard Henderson     ctx->tb_flags = ctx->base.tb->flags;
4411bd6243a3SRichard Henderson     ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
44123d68ee7bSRichard Henderson 
44133d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY
4414c01e5dfbSHelge Deller     ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX);
44153d68ee7bSRichard Henderson     ctx->mmu_idx = MMU_USER_IDX;
4416c01e5dfbSHelge Deller     ctx->iaoq_f = ctx->base.pc_first | ctx->privilege;
4417c01e5dfbSHelge Deller     ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege;
4418217d1a5eSRichard Henderson     ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
4419c301f34eSRichard Henderson #else
4420494737b7SRichard Henderson     ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
4421bb67ec32SRichard Henderson     ctx->mmu_idx = (ctx->tb_flags & PSW_D
4422bb67ec32SRichard Henderson                     ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
4423bb67ec32SRichard Henderson                     : MMU_PHYS_IDX);
44243d68ee7bSRichard Henderson 
4425c301f34eSRichard Henderson     /* Recover the IAOQ values from the GVA + PRIV.  */
4426c301f34eSRichard Henderson     uint64_t cs_base = ctx->base.tb->cs_base;
4427c301f34eSRichard Henderson     uint64_t iasq_f = cs_base & ~0xffffffffull;
4428c301f34eSRichard Henderson     int32_t diff = cs_base;
4429c301f34eSRichard Henderson 
4430c301f34eSRichard Henderson     ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
4431c301f34eSRichard Henderson     ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1);
4432c301f34eSRichard Henderson #endif
443351b061fbSRichard Henderson     ctx->iaoq_n = -1;
4434f764718dSRichard Henderson     ctx->iaoq_n_var = NULL;
443561766fe9SRichard Henderson 
4436a4db4a78SRichard Henderson     ctx->zero = tcg_constant_i64(0);
4437a4db4a78SRichard Henderson 
44383d68ee7bSRichard Henderson     /* Bound the number of instructions by those left on the page.  */
44393d68ee7bSRichard Henderson     bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
4440b542683dSEmilio G. Cota     ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
444161766fe9SRichard Henderson }
444261766fe9SRichard Henderson 
444351b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
444451b061fbSRichard Henderson {
444551b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
444661766fe9SRichard Henderson 
44473d68ee7bSRichard Henderson     /* Seed the nullification status from PSW[N], as saved in TB->FLAGS.  */
444851b061fbSRichard Henderson     ctx->null_cond = cond_make_f();
444951b061fbSRichard Henderson     ctx->psw_n_nonzero = false;
4450494737b7SRichard Henderson     if (ctx->tb_flags & PSW_N) {
445151b061fbSRichard Henderson         ctx->null_cond.c = TCG_COND_ALWAYS;
445251b061fbSRichard Henderson         ctx->psw_n_nonzero = true;
4453129e9cc3SRichard Henderson     }
445451b061fbSRichard Henderson     ctx->null_lab = NULL;
445561766fe9SRichard Henderson }
445661766fe9SRichard Henderson 
445751b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
445851b061fbSRichard Henderson {
445951b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
446051b061fbSRichard Henderson 
446151b061fbSRichard Henderson     tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b);
446251b061fbSRichard Henderson }
446351b061fbSRichard Henderson 
446451b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
446551b061fbSRichard Henderson {
446651b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4467b77af26eSRichard Henderson     CPUHPPAState *env = cpu_env(cs);
446851b061fbSRichard Henderson     DisasJumpType ret;
446951b061fbSRichard Henderson 
447051b061fbSRichard Henderson     /* Execute one insn.  */
4471ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4472c301f34eSRichard Henderson     if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
447331234768SRichard Henderson         do_page_zero(ctx);
447431234768SRichard Henderson         ret = ctx->base.is_jmp;
4475869051eaSRichard Henderson         assert(ret != DISAS_NEXT);
4476ba1d0b44SRichard Henderson     } else
4477ba1d0b44SRichard Henderson #endif
4478ba1d0b44SRichard Henderson     {
447961766fe9SRichard Henderson         /* Always fetch the insn, even if nullified, so that we check
448061766fe9SRichard Henderson            the page permissions for execute.  */
44814e116893SIlya Leoshkevich         uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next);
448261766fe9SRichard Henderson 
448361766fe9SRichard Henderson         /* Set up the IA queue for the next insn.
448461766fe9SRichard Henderson            This will be overwritten by a branch.  */
448551b061fbSRichard Henderson         if (ctx->iaoq_b == -1) {
448651b061fbSRichard Henderson             ctx->iaoq_n = -1;
4487aac0f603SRichard Henderson             ctx->iaoq_n_var = tcg_temp_new_i64();
44886fd0c7bcSRichard Henderson             tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
448961766fe9SRichard Henderson         } else {
449051b061fbSRichard Henderson             ctx->iaoq_n = ctx->iaoq_b + 4;
4491f764718dSRichard Henderson             ctx->iaoq_n_var = NULL;
449261766fe9SRichard Henderson         }
449361766fe9SRichard Henderson 
449451b061fbSRichard Henderson         if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
449551b061fbSRichard Henderson             ctx->null_cond.c = TCG_COND_NEVER;
4496869051eaSRichard Henderson             ret = DISAS_NEXT;
4497129e9cc3SRichard Henderson         } else {
44981a19da0dSRichard Henderson             ctx->insn = insn;
449931274b46SRichard Henderson             if (!decode(ctx, insn)) {
450031274b46SRichard Henderson                 gen_illegal(ctx);
450131274b46SRichard Henderson             }
450231234768SRichard Henderson             ret = ctx->base.is_jmp;
450351b061fbSRichard Henderson             assert(ctx->null_lab == NULL);
4504129e9cc3SRichard Henderson         }
450561766fe9SRichard Henderson     }
450661766fe9SRichard Henderson 
45073d68ee7bSRichard Henderson     /* Advance the insn queue.  Note that this check also detects
45083d68ee7bSRichard Henderson        a priority change within the instruction queue.  */
450951b061fbSRichard Henderson     if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
4510c301f34eSRichard Henderson         if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1
4511c301f34eSRichard Henderson             && use_goto_tb(ctx, ctx->iaoq_b)
4512c301f34eSRichard Henderson             && (ctx->null_cond.c == TCG_COND_NEVER
4513c301f34eSRichard Henderson                 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
451451b061fbSRichard Henderson             nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
451551b061fbSRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
451631234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_NORETURN;
4517129e9cc3SRichard Henderson         } else {
451831234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE;
451961766fe9SRichard Henderson         }
4520129e9cc3SRichard Henderson     }
452151b061fbSRichard Henderson     ctx->iaoq_f = ctx->iaoq_b;
452251b061fbSRichard Henderson     ctx->iaoq_b = ctx->iaoq_n;
4523c301f34eSRichard Henderson     ctx->base.pc_next += 4;
452461766fe9SRichard Henderson 
4525c5d0aec2SRichard Henderson     switch (ret) {
4526c5d0aec2SRichard Henderson     case DISAS_NORETURN:
4527c5d0aec2SRichard Henderson     case DISAS_IAQ_N_UPDATED:
4528c5d0aec2SRichard Henderson         break;
4529c5d0aec2SRichard Henderson 
4530c5d0aec2SRichard Henderson     case DISAS_NEXT:
4531c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE:
4532c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
453351b061fbSRichard Henderson         if (ctx->iaoq_f == -1) {
4534a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b);
4535741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
4536c301f34eSRichard Henderson #ifndef CONFIG_USER_ONLY
4537c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
4538c301f34eSRichard Henderson #endif
453951b061fbSRichard Henderson             nullify_save(ctx);
4540c5d0aec2SRichard Henderson             ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT
4541c5d0aec2SRichard Henderson                                 ? DISAS_EXIT
4542c5d0aec2SRichard Henderson                                 : DISAS_IAQ_N_UPDATED);
454351b061fbSRichard Henderson         } else if (ctx->iaoq_b == -1) {
4544a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var);
454561766fe9SRichard Henderson         }
4546c5d0aec2SRichard Henderson         break;
4547c5d0aec2SRichard Henderson 
4548c5d0aec2SRichard Henderson     default:
4549c5d0aec2SRichard Henderson         g_assert_not_reached();
4550c5d0aec2SRichard Henderson     }
455161766fe9SRichard Henderson }
455261766fe9SRichard Henderson 
455351b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
455451b061fbSRichard Henderson {
455551b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4556e1b5a5edSRichard Henderson     DisasJumpType is_jmp = ctx->base.is_jmp;
455751b061fbSRichard Henderson 
4558e1b5a5edSRichard Henderson     switch (is_jmp) {
4559869051eaSRichard Henderson     case DISAS_NORETURN:
456061766fe9SRichard Henderson         break;
456151b061fbSRichard Henderson     case DISAS_TOO_MANY:
4562869051eaSRichard Henderson     case DISAS_IAQ_N_STALE:
4563e1b5a5edSRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
4564741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
4565741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
456651b061fbSRichard Henderson         nullify_save(ctx);
456761766fe9SRichard Henderson         /* FALLTHRU */
4568869051eaSRichard Henderson     case DISAS_IAQ_N_UPDATED:
45698532a14eSRichard Henderson         if (is_jmp != DISAS_IAQ_N_STALE_EXIT) {
45707f11636dSEmilio G. Cota             tcg_gen_lookup_and_goto_ptr();
45718532a14eSRichard Henderson             break;
457261766fe9SRichard Henderson         }
4573c5d0aec2SRichard Henderson         /* FALLTHRU */
4574c5d0aec2SRichard Henderson     case DISAS_EXIT:
4575c5d0aec2SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
457661766fe9SRichard Henderson         break;
457761766fe9SRichard Henderson     default:
457851b061fbSRichard Henderson         g_assert_not_reached();
457961766fe9SRichard Henderson     }
458051b061fbSRichard Henderson }
458161766fe9SRichard Henderson 
45828eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase,
45838eb806a7SRichard Henderson                               CPUState *cs, FILE *logfile)
458451b061fbSRichard Henderson {
4585c301f34eSRichard Henderson     target_ulong pc = dcbase->pc_first;
458661766fe9SRichard Henderson 
4587ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4588ba1d0b44SRichard Henderson     switch (pc) {
45897ad439dfSRichard Henderson     case 0x00:
45908eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000000:  (null)\n");
4591ba1d0b44SRichard Henderson         return;
45927ad439dfSRichard Henderson     case 0xb0:
45938eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000b0:  light-weight-syscall\n");
4594ba1d0b44SRichard Henderson         return;
45957ad439dfSRichard Henderson     case 0xe0:
45968eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000e0:  set-thread-pointer-syscall\n");
4597ba1d0b44SRichard Henderson         return;
45987ad439dfSRichard Henderson     case 0x100:
45998eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000100:  syscall\n");
4600ba1d0b44SRichard Henderson         return;
46017ad439dfSRichard Henderson     }
4602ba1d0b44SRichard Henderson #endif
4603ba1d0b44SRichard Henderson 
46048eb806a7SRichard Henderson     fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
46058eb806a7SRichard Henderson     target_disas(logfile, cs, pc, dcbase->tb->size);
460661766fe9SRichard Henderson }
460751b061fbSRichard Henderson 
460851b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = {
460951b061fbSRichard Henderson     .init_disas_context = hppa_tr_init_disas_context,
461051b061fbSRichard Henderson     .tb_start           = hppa_tr_tb_start,
461151b061fbSRichard Henderson     .insn_start         = hppa_tr_insn_start,
461251b061fbSRichard Henderson     .translate_insn     = hppa_tr_translate_insn,
461351b061fbSRichard Henderson     .tb_stop            = hppa_tr_tb_stop,
461451b061fbSRichard Henderson     .disas_log          = hppa_tr_disas_log,
461551b061fbSRichard Henderson };
461651b061fbSRichard Henderson 
4617597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
4618306c8721SRichard Henderson                            target_ulong pc, void *host_pc)
461951b061fbSRichard Henderson {
462051b061fbSRichard Henderson     DisasContext ctx;
4621306c8721SRichard Henderson     translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
462261766fe9SRichard Henderson }
4623