xref: /openbmc/qemu/target/hppa/translate.c (revision e5d487c9724e0fc62b1afca9f8ea11fd072643a8)
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;
47f5b5c857SRichard Henderson     TCGOp *insn_start;
4861766fe9SRichard Henderson 
49c53e401eSRichard Henderson     uint64_t iaoq_f;
50c53e401eSRichard Henderson     uint64_t iaoq_b;
51c53e401eSRichard Henderson     uint64_t iaoq_n;
526fd0c7bcSRichard Henderson     TCGv_i64 iaoq_n_var;
5361766fe9SRichard Henderson 
5461766fe9SRichard Henderson     DisasCond null_cond;
5561766fe9SRichard Henderson     TCGLabel *null_lab;
5661766fe9SRichard Henderson 
57a4db4a78SRichard Henderson     TCGv_i64 zero;
58a4db4a78SRichard Henderson 
591a19da0dSRichard Henderson     uint32_t insn;
60494737b7SRichard Henderson     uint32_t tb_flags;
613d68ee7bSRichard Henderson     int mmu_idx;
623d68ee7bSRichard Henderson     int privilege;
6361766fe9SRichard Henderson     bool psw_n_nonzero;
64bd6243a3SRichard Henderson     bool is_pa20;
65217d1a5eSRichard Henderson 
66217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
67217d1a5eSRichard Henderson     MemOp unalign;
68217d1a5eSRichard Henderson #endif
6961766fe9SRichard Henderson } DisasContext;
7061766fe9SRichard Henderson 
71217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
72217d1a5eSRichard Henderson #define UNALIGN(C)  (C)->unalign
73217d1a5eSRichard Henderson #else
742d4afb03SRichard Henderson #define UNALIGN(C)  MO_ALIGN
75217d1a5eSRichard Henderson #endif
76217d1a5eSRichard Henderson 
77e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently.  */
78451e4ffdSRichard Henderson static int expand_sm_imm(DisasContext *ctx, int val)
79e36f27efSRichard Henderson {
80881d1073SHelge Deller     /* Keep unimplemented bits disabled -- see cpu_hppa_put_psw. */
81881d1073SHelge Deller     if (ctx->is_pa20) {
82e36f27efSRichard Henderson         if (val & PSW_SM_W) {
83881d1073SHelge Deller             val |= PSW_W;
84881d1073SHelge Deller         }
85881d1073SHelge Deller         val &= ~(PSW_SM_W | PSW_SM_E | PSW_G);
86881d1073SHelge Deller     } else {
87881d1073SHelge Deller         val &= ~(PSW_SM_W | PSW_SM_E | PSW_O);
88e36f27efSRichard Henderson     }
89e36f27efSRichard Henderson     return val;
90e36f27efSRichard Henderson }
91e36f27efSRichard Henderson 
92deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base.  */
93451e4ffdSRichard Henderson static int expand_sr3x(DisasContext *ctx, int val)
94deee69a1SRichard Henderson {
95deee69a1SRichard Henderson     return ~val;
96deee69a1SRichard Henderson }
97deee69a1SRichard Henderson 
981cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value
991cd012a5SRichard Henderson    we use for the final M.  */
100451e4ffdSRichard Henderson static int ma_to_m(DisasContext *ctx, int val)
1011cd012a5SRichard Henderson {
1021cd012a5SRichard Henderson     return val & 2 ? (val & 1 ? -1 : 1) : 0;
1031cd012a5SRichard Henderson }
1041cd012a5SRichard Henderson 
105740038d7SRichard Henderson /* Convert the sign of the displacement to a pre or post-modify.  */
106451e4ffdSRichard Henderson static int pos_to_m(DisasContext *ctx, int val)
107740038d7SRichard Henderson {
108740038d7SRichard Henderson     return val ? 1 : -1;
109740038d7SRichard Henderson }
110740038d7SRichard Henderson 
111451e4ffdSRichard Henderson static int neg_to_m(DisasContext *ctx, int val)
112740038d7SRichard Henderson {
113740038d7SRichard Henderson     return val ? -1 : 1;
114740038d7SRichard Henderson }
115740038d7SRichard Henderson 
116740038d7SRichard Henderson /* Used for branch targets and fp memory ops.  */
117451e4ffdSRichard Henderson static int expand_shl2(DisasContext *ctx, int val)
11801afb7beSRichard Henderson {
11901afb7beSRichard Henderson     return val << 2;
12001afb7beSRichard Henderson }
12101afb7beSRichard Henderson 
122740038d7SRichard Henderson /* Used for fp memory ops.  */
123451e4ffdSRichard Henderson static int expand_shl3(DisasContext *ctx, int val)
124740038d7SRichard Henderson {
125740038d7SRichard Henderson     return val << 3;
126740038d7SRichard Henderson }
127740038d7SRichard Henderson 
1280588e061SRichard Henderson /* Used for assemble_21.  */
129451e4ffdSRichard Henderson static int expand_shl11(DisasContext *ctx, int val)
1300588e061SRichard Henderson {
1310588e061SRichard Henderson     return val << 11;
1320588e061SRichard Henderson }
1330588e061SRichard Henderson 
13472ae4f2bSRichard Henderson static int assemble_6(DisasContext *ctx, int val)
13572ae4f2bSRichard Henderson {
13672ae4f2bSRichard Henderson     /*
13772ae4f2bSRichard Henderson      * Officially, 32 * x + 32 - y.
13872ae4f2bSRichard Henderson      * Here, x is already in bit 5, and y is [4:0].
13972ae4f2bSRichard Henderson      * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1,
14072ae4f2bSRichard Henderson      * with the overflow from bit 4 summing with x.
14172ae4f2bSRichard Henderson      */
14272ae4f2bSRichard Henderson     return (val ^ 31) + 1;
14372ae4f2bSRichard Henderson }
14472ae4f2bSRichard Henderson 
145c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */
146c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val)
147c65c3ee1SRichard Henderson {
148c65c3ee1SRichard Henderson     return val ? val : 4; /* 0 == "*<<" */
149c65c3ee1SRichard Henderson }
150c65c3ee1SRichard Henderson 
15101afb7beSRichard Henderson 
15240f9f908SRichard Henderson /* Include the auto-generated decoder.  */
153abff1abfSPaolo Bonzini #include "decode-insns.c.inc"
15440f9f908SRichard Henderson 
15561766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated
15661766fe9SRichard Henderson    the iaq (for whatever reason), so don't do it again on exit.  */
157869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED  DISAS_TARGET_0
15861766fe9SRichard Henderson 
15961766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor
16061766fe9SRichard Henderson    updated the iaq for the next instruction to be executed.  */
161869051eaSRichard Henderson #define DISAS_IAQ_N_STALE    DISAS_TARGET_1
16261766fe9SRichard Henderson 
163e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately
164e1b5a5edSRichard Henderson    to recognize unmasked interrupts.  */
165e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT      DISAS_TARGET_2
166c5d0aec2SRichard Henderson #define DISAS_EXIT                  DISAS_TARGET_3
167e1b5a5edSRichard Henderson 
16861766fe9SRichard Henderson /* global register indexes */
1696fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32];
17033423472SRichard Henderson static TCGv_i64 cpu_sr[4];
171494737b7SRichard Henderson static TCGv_i64 cpu_srH;
1726fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f;
1736fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b;
174c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f;
175c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b;
1766fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar;
1776fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n;
1786fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v;
1796fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb;
1806fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb;
18161766fe9SRichard Henderson 
18261766fe9SRichard Henderson void hppa_translate_init(void)
18361766fe9SRichard Henderson {
18461766fe9SRichard Henderson #define DEF_VAR(V)  { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
18561766fe9SRichard Henderson 
1866fd0c7bcSRichard Henderson     typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar;
18761766fe9SRichard Henderson     static const GlobalVar vars[] = {
18835136a77SRichard Henderson         { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) },
18961766fe9SRichard Henderson         DEF_VAR(psw_n),
19061766fe9SRichard Henderson         DEF_VAR(psw_v),
19161766fe9SRichard Henderson         DEF_VAR(psw_cb),
19261766fe9SRichard Henderson         DEF_VAR(psw_cb_msb),
19361766fe9SRichard Henderson         DEF_VAR(iaoq_f),
19461766fe9SRichard Henderson         DEF_VAR(iaoq_b),
19561766fe9SRichard Henderson     };
19661766fe9SRichard Henderson 
19761766fe9SRichard Henderson #undef DEF_VAR
19861766fe9SRichard Henderson 
19961766fe9SRichard Henderson     /* Use the symbolic register names that match the disassembler.  */
20061766fe9SRichard Henderson     static const char gr_names[32][4] = {
20161766fe9SRichard Henderson         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
20261766fe9SRichard Henderson         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
20361766fe9SRichard Henderson         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
20461766fe9SRichard Henderson         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
20561766fe9SRichard Henderson     };
20633423472SRichard Henderson     /* SR[4-7] are not global registers so that we can index them.  */
207494737b7SRichard Henderson     static const char sr_names[5][4] = {
208494737b7SRichard Henderson         "sr0", "sr1", "sr2", "sr3", "srH"
20933423472SRichard Henderson     };
21061766fe9SRichard Henderson 
21161766fe9SRichard Henderson     int i;
21261766fe9SRichard Henderson 
213f764718dSRichard Henderson     cpu_gr[0] = NULL;
21461766fe9SRichard Henderson     for (i = 1; i < 32; i++) {
215ad75a51eSRichard Henderson         cpu_gr[i] = tcg_global_mem_new(tcg_env,
21661766fe9SRichard Henderson                                        offsetof(CPUHPPAState, gr[i]),
21761766fe9SRichard Henderson                                        gr_names[i]);
21861766fe9SRichard Henderson     }
21933423472SRichard Henderson     for (i = 0; i < 4; i++) {
220ad75a51eSRichard Henderson         cpu_sr[i] = tcg_global_mem_new_i64(tcg_env,
22133423472SRichard Henderson                                            offsetof(CPUHPPAState, sr[i]),
22233423472SRichard Henderson                                            sr_names[i]);
22333423472SRichard Henderson     }
224ad75a51eSRichard Henderson     cpu_srH = tcg_global_mem_new_i64(tcg_env,
225494737b7SRichard Henderson                                      offsetof(CPUHPPAState, sr[4]),
226494737b7SRichard Henderson                                      sr_names[4]);
22761766fe9SRichard Henderson 
22861766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(vars); ++i) {
22961766fe9SRichard Henderson         const GlobalVar *v = &vars[i];
230ad75a51eSRichard Henderson         *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name);
23161766fe9SRichard Henderson     }
232c301f34eSRichard Henderson 
233ad75a51eSRichard Henderson     cpu_iasq_f = tcg_global_mem_new_i64(tcg_env,
234c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_f),
235c301f34eSRichard Henderson                                         "iasq_f");
236ad75a51eSRichard Henderson     cpu_iasq_b = tcg_global_mem_new_i64(tcg_env,
237c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_b),
238c301f34eSRichard Henderson                                         "iasq_b");
23961766fe9SRichard Henderson }
24061766fe9SRichard Henderson 
241f5b5c857SRichard Henderson static void set_insn_breg(DisasContext *ctx, int breg)
242f5b5c857SRichard Henderson {
243f5b5c857SRichard Henderson     assert(ctx->insn_start != NULL);
244f5b5c857SRichard Henderson     tcg_set_insn_start_param(ctx->insn_start, 2, breg);
245f5b5c857SRichard Henderson     ctx->insn_start = NULL;
246f5b5c857SRichard Henderson }
247f5b5c857SRichard Henderson 
248129e9cc3SRichard Henderson static DisasCond cond_make_f(void)
249129e9cc3SRichard Henderson {
250f764718dSRichard Henderson     return (DisasCond){
251f764718dSRichard Henderson         .c = TCG_COND_NEVER,
252f764718dSRichard Henderson         .a0 = NULL,
253f764718dSRichard Henderson         .a1 = NULL,
254f764718dSRichard Henderson     };
255129e9cc3SRichard Henderson }
256129e9cc3SRichard Henderson 
257df0232feSRichard Henderson static DisasCond cond_make_t(void)
258df0232feSRichard Henderson {
259df0232feSRichard Henderson     return (DisasCond){
260df0232feSRichard Henderson         .c = TCG_COND_ALWAYS,
261df0232feSRichard Henderson         .a0 = NULL,
262df0232feSRichard Henderson         .a1 = NULL,
263df0232feSRichard Henderson     };
264df0232feSRichard Henderson }
265df0232feSRichard Henderson 
266129e9cc3SRichard Henderson static DisasCond cond_make_n(void)
267129e9cc3SRichard Henderson {
268f764718dSRichard Henderson     return (DisasCond){
269f764718dSRichard Henderson         .c = TCG_COND_NE,
270f764718dSRichard Henderson         .a0 = cpu_psw_n,
2716fd0c7bcSRichard Henderson         .a1 = tcg_constant_i64(0)
272f764718dSRichard Henderson     };
273129e9cc3SRichard Henderson }
274129e9cc3SRichard Henderson 
2756fd0c7bcSRichard Henderson static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
276b47a4a02SSven Schnelle {
277b47a4a02SSven Schnelle     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
2784fe9533aSRichard Henderson     return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 };
2794fe9533aSRichard Henderson }
2804fe9533aSRichard Henderson 
2816fd0c7bcSRichard Henderson static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0)
2824fe9533aSRichard Henderson {
2836fd0c7bcSRichard Henderson     return cond_make_tmp(c, a0, tcg_constant_i64(0));
284b47a4a02SSven Schnelle }
285b47a4a02SSven Schnelle 
2866fd0c7bcSRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0)
287129e9cc3SRichard Henderson {
288aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2896fd0c7bcSRichard Henderson     tcg_gen_mov_i64(tmp, a0);
290b47a4a02SSven Schnelle     return cond_make_0_tmp(c, tmp);
291129e9cc3SRichard Henderson }
292129e9cc3SRichard Henderson 
2936fd0c7bcSRichard Henderson static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
294129e9cc3SRichard Henderson {
295aac0f603SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
296aac0f603SRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
297129e9cc3SRichard Henderson 
2986fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t0, a0);
2996fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t1, a1);
3004fe9533aSRichard Henderson     return cond_make_tmp(c, t0, t1);
301129e9cc3SRichard Henderson }
302129e9cc3SRichard Henderson 
303129e9cc3SRichard Henderson static void cond_free(DisasCond *cond)
304129e9cc3SRichard Henderson {
305129e9cc3SRichard Henderson     switch (cond->c) {
306129e9cc3SRichard Henderson     default:
307f764718dSRichard Henderson         cond->a0 = NULL;
308f764718dSRichard Henderson         cond->a1 = NULL;
309129e9cc3SRichard Henderson         /* fallthru */
310129e9cc3SRichard Henderson     case TCG_COND_ALWAYS:
311129e9cc3SRichard Henderson         cond->c = TCG_COND_NEVER;
312129e9cc3SRichard Henderson         break;
313129e9cc3SRichard Henderson     case TCG_COND_NEVER:
314129e9cc3SRichard Henderson         break;
315129e9cc3SRichard Henderson     }
316129e9cc3SRichard Henderson }
317129e9cc3SRichard Henderson 
3186fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg)
31961766fe9SRichard Henderson {
32061766fe9SRichard Henderson     if (reg == 0) {
321bc3da3cfSRichard Henderson         return ctx->zero;
32261766fe9SRichard Henderson     } else {
32361766fe9SRichard Henderson         return cpu_gr[reg];
32461766fe9SRichard Henderson     }
32561766fe9SRichard Henderson }
32661766fe9SRichard Henderson 
3276fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg)
32861766fe9SRichard Henderson {
329129e9cc3SRichard Henderson     if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
330aac0f603SRichard Henderson         return tcg_temp_new_i64();
33161766fe9SRichard Henderson     } else {
33261766fe9SRichard Henderson         return cpu_gr[reg];
33361766fe9SRichard Henderson     }
33461766fe9SRichard Henderson }
33561766fe9SRichard Henderson 
3366fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t)
337129e9cc3SRichard Henderson {
338129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
3396fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0,
340129e9cc3SRichard Henderson                             ctx->null_cond.a1, dest, t);
341129e9cc3SRichard Henderson     } else {
3426fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, t);
343129e9cc3SRichard Henderson     }
344129e9cc3SRichard Henderson }
345129e9cc3SRichard Henderson 
3466fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t)
347129e9cc3SRichard Henderson {
348129e9cc3SRichard Henderson     if (reg != 0) {
349129e9cc3SRichard Henderson         save_or_nullify(ctx, cpu_gr[reg], t);
350129e9cc3SRichard Henderson     }
351129e9cc3SRichard Henderson }
352129e9cc3SRichard Henderson 
353e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
35496d6407fSRichard Henderson # define HI_OFS  0
35596d6407fSRichard Henderson # define LO_OFS  4
35696d6407fSRichard Henderson #else
35796d6407fSRichard Henderson # define HI_OFS  4
35896d6407fSRichard Henderson # define LO_OFS  0
35996d6407fSRichard Henderson #endif
36096d6407fSRichard Henderson 
36196d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt)
36296d6407fSRichard Henderson {
36396d6407fSRichard Henderson     TCGv_i32 ret = tcg_temp_new_i32();
364ad75a51eSRichard Henderson     tcg_gen_ld_i32(ret, tcg_env,
36596d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
36696d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
36796d6407fSRichard Henderson     return ret;
36896d6407fSRichard Henderson }
36996d6407fSRichard Henderson 
370ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt)
371ebe9383cSRichard Henderson {
372ebe9383cSRichard Henderson     if (rt == 0) {
3730992a930SRichard Henderson         TCGv_i32 ret = tcg_temp_new_i32();
3740992a930SRichard Henderson         tcg_gen_movi_i32(ret, 0);
3750992a930SRichard Henderson         return ret;
376ebe9383cSRichard Henderson     } else {
377ebe9383cSRichard Henderson         return load_frw_i32(rt);
378ebe9383cSRichard Henderson     }
379ebe9383cSRichard Henderson }
380ebe9383cSRichard Henderson 
381ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt)
382ebe9383cSRichard Henderson {
383ebe9383cSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
3840992a930SRichard Henderson     if (rt == 0) {
3850992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
3860992a930SRichard Henderson     } else {
387ad75a51eSRichard Henderson         tcg_gen_ld32u_i64(ret, tcg_env,
388ebe9383cSRichard Henderson                           offsetof(CPUHPPAState, fr[rt & 31])
389ebe9383cSRichard Henderson                           + (rt & 32 ? LO_OFS : HI_OFS));
390ebe9383cSRichard Henderson     }
3910992a930SRichard Henderson     return ret;
392ebe9383cSRichard Henderson }
393ebe9383cSRichard Henderson 
39496d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val)
39596d6407fSRichard Henderson {
396ad75a51eSRichard Henderson     tcg_gen_st_i32(val, tcg_env,
39796d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
39896d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
39996d6407fSRichard Henderson }
40096d6407fSRichard Henderson 
40196d6407fSRichard Henderson #undef HI_OFS
40296d6407fSRichard Henderson #undef LO_OFS
40396d6407fSRichard Henderson 
40496d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt)
40596d6407fSRichard Henderson {
40696d6407fSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
407ad75a51eSRichard Henderson     tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt]));
40896d6407fSRichard Henderson     return ret;
40996d6407fSRichard Henderson }
41096d6407fSRichard Henderson 
411ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt)
412ebe9383cSRichard Henderson {
413ebe9383cSRichard Henderson     if (rt == 0) {
4140992a930SRichard Henderson         TCGv_i64 ret = tcg_temp_new_i64();
4150992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
4160992a930SRichard Henderson         return ret;
417ebe9383cSRichard Henderson     } else {
418ebe9383cSRichard Henderson         return load_frd(rt);
419ebe9383cSRichard Henderson     }
420ebe9383cSRichard Henderson }
421ebe9383cSRichard Henderson 
42296d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val)
42396d6407fSRichard Henderson {
424ad75a51eSRichard Henderson     tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt]));
42596d6407fSRichard Henderson }
42696d6407fSRichard Henderson 
42733423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg)
42833423472SRichard Henderson {
42933423472SRichard Henderson #ifdef CONFIG_USER_ONLY
43033423472SRichard Henderson     tcg_gen_movi_i64(dest, 0);
43133423472SRichard Henderson #else
43233423472SRichard Henderson     if (reg < 4) {
43333423472SRichard Henderson         tcg_gen_mov_i64(dest, cpu_sr[reg]);
434494737b7SRichard Henderson     } else if (ctx->tb_flags & TB_FLAG_SR_SAME) {
435494737b7SRichard Henderson         tcg_gen_mov_i64(dest, cpu_srH);
43633423472SRichard Henderson     } else {
437ad75a51eSRichard Henderson         tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg]));
43833423472SRichard Henderson     }
43933423472SRichard Henderson #endif
44033423472SRichard Henderson }
44133423472SRichard Henderson 
442129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified.
443129e9cc3SRichard Henderson    Use this when the insn is too complex for a conditional move.  */
444129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx)
445129e9cc3SRichard Henderson {
446129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
447129e9cc3SRichard Henderson         /* The always condition should have been handled in the main loop.  */
448129e9cc3SRichard Henderson         assert(ctx->null_cond.c != TCG_COND_ALWAYS);
449129e9cc3SRichard Henderson 
450129e9cc3SRichard Henderson         ctx->null_lab = gen_new_label();
451129e9cc3SRichard Henderson 
452129e9cc3SRichard Henderson         /* If we're using PSW[N], copy it to a temp because... */
4536e94937aSRichard Henderson         if (ctx->null_cond.a0 == cpu_psw_n) {
454aac0f603SRichard Henderson             ctx->null_cond.a0 = tcg_temp_new_i64();
4556fd0c7bcSRichard Henderson             tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n);
456129e9cc3SRichard Henderson         }
457129e9cc3SRichard Henderson         /* ... we clear it before branching over the implementation,
458129e9cc3SRichard Henderson            so that (1) it's clear after nullifying this insn and
459129e9cc3SRichard Henderson            (2) if this insn nullifies the next, PSW[N] is valid.  */
460129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
461129e9cc3SRichard Henderson             ctx->psw_n_nonzero = false;
4626fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
463129e9cc3SRichard Henderson         }
464129e9cc3SRichard Henderson 
4656fd0c7bcSRichard Henderson         tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0,
466129e9cc3SRichard Henderson                            ctx->null_cond.a1, ctx->null_lab);
467129e9cc3SRichard Henderson         cond_free(&ctx->null_cond);
468129e9cc3SRichard Henderson     }
469129e9cc3SRichard Henderson }
470129e9cc3SRichard Henderson 
471129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N].  */
472129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx)
473129e9cc3SRichard Henderson {
474129e9cc3SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
475129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
4766fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
477129e9cc3SRichard Henderson         }
478129e9cc3SRichard Henderson         return;
479129e9cc3SRichard Henderson     }
4806e94937aSRichard Henderson     if (ctx->null_cond.a0 != cpu_psw_n) {
4816fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n,
482129e9cc3SRichard Henderson                             ctx->null_cond.a0, ctx->null_cond.a1);
483129e9cc3SRichard Henderson         ctx->psw_n_nonzero = true;
484129e9cc3SRichard Henderson     }
485129e9cc3SRichard Henderson     cond_free(&ctx->null_cond);
486129e9cc3SRichard Henderson }
487129e9cc3SRichard Henderson 
488129e9cc3SRichard Henderson /* Set a PSW[N] to X.  The intention is that this is used immediately
489129e9cc3SRichard Henderson    before a goto_tb/exit_tb, so that there is no fallthru path to other
490129e9cc3SRichard Henderson    code within the TB.  Therefore we do not update psw_n_nonzero.  */
491129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x)
492129e9cc3SRichard Henderson {
493129e9cc3SRichard Henderson     if (ctx->psw_n_nonzero || x) {
4946fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, x);
495129e9cc3SRichard Henderson     }
496129e9cc3SRichard Henderson }
497129e9cc3SRichard Henderson 
498129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified.
49940f9f908SRichard Henderson    This is the pair to nullify_over.  Always returns true so that
50040f9f908SRichard Henderson    it may be tail-called from a translate function.  */
50131234768SRichard Henderson static bool nullify_end(DisasContext *ctx)
502129e9cc3SRichard Henderson {
503129e9cc3SRichard Henderson     TCGLabel *null_lab = ctx->null_lab;
50431234768SRichard Henderson     DisasJumpType status = ctx->base.is_jmp;
505129e9cc3SRichard Henderson 
506f49b3537SRichard Henderson     /* For NEXT, NORETURN, STALE, we can easily continue (or exit).
507f49b3537SRichard Henderson        For UPDATED, we cannot update on the nullified path.  */
508f49b3537SRichard Henderson     assert(status != DISAS_IAQ_N_UPDATED);
509f49b3537SRichard Henderson 
510129e9cc3SRichard Henderson     if (likely(null_lab == NULL)) {
511129e9cc3SRichard Henderson         /* The current insn wasn't conditional or handled the condition
512129e9cc3SRichard Henderson            applied to it without a branch, so the (new) setting of
513129e9cc3SRichard Henderson            NULL_COND can be applied directly to the next insn.  */
51431234768SRichard Henderson         return true;
515129e9cc3SRichard Henderson     }
516129e9cc3SRichard Henderson     ctx->null_lab = NULL;
517129e9cc3SRichard Henderson 
518129e9cc3SRichard Henderson     if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
519129e9cc3SRichard Henderson         /* The next instruction will be unconditional,
520129e9cc3SRichard Henderson            and NULL_COND already reflects that.  */
521129e9cc3SRichard Henderson         gen_set_label(null_lab);
522129e9cc3SRichard Henderson     } else {
523129e9cc3SRichard Henderson         /* The insn that we just executed is itself nullifying the next
524129e9cc3SRichard Henderson            instruction.  Store the condition in the PSW[N] global.
525129e9cc3SRichard Henderson            We asserted PSW[N] = 0 in nullify_over, so that after the
526129e9cc3SRichard Henderson            label we have the proper value in place.  */
527129e9cc3SRichard Henderson         nullify_save(ctx);
528129e9cc3SRichard Henderson         gen_set_label(null_lab);
529129e9cc3SRichard Henderson         ctx->null_cond = cond_make_n();
530129e9cc3SRichard Henderson     }
531869051eaSRichard Henderson     if (status == DISAS_NORETURN) {
53231234768SRichard Henderson         ctx->base.is_jmp = DISAS_NEXT;
533129e9cc3SRichard Henderson     }
53431234768SRichard Henderson     return true;
535129e9cc3SRichard Henderson }
536129e9cc3SRichard Henderson 
537c53e401eSRichard Henderson static uint64_t gva_offset_mask(DisasContext *ctx)
538698240d1SRichard Henderson {
539698240d1SRichard Henderson     return (ctx->tb_flags & PSW_W
540698240d1SRichard Henderson             ? MAKE_64BIT_MASK(0, 62)
541698240d1SRichard Henderson             : MAKE_64BIT_MASK(0, 32));
542698240d1SRichard Henderson }
543698240d1SRichard Henderson 
5446fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest,
5456fd0c7bcSRichard Henderson                             uint64_t ival, TCGv_i64 vval)
54661766fe9SRichard Henderson {
547c53e401eSRichard Henderson     uint64_t mask = gva_offset_mask(ctx);
548f13bf343SRichard Henderson 
549f13bf343SRichard Henderson     if (ival != -1) {
5506fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, ival & mask);
551f13bf343SRichard Henderson         return;
552f13bf343SRichard Henderson     }
553f13bf343SRichard Henderson     tcg_debug_assert(vval != NULL);
554f13bf343SRichard Henderson 
555f13bf343SRichard Henderson     /*
556f13bf343SRichard Henderson      * We know that the IAOQ is already properly masked.
557f13bf343SRichard Henderson      * This optimization is primarily for "iaoq_f = iaoq_b".
558f13bf343SRichard Henderson      */
559f13bf343SRichard Henderson     if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) {
5606fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, vval);
56161766fe9SRichard Henderson     } else {
5626fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, vval, mask);
56361766fe9SRichard Henderson     }
56461766fe9SRichard Henderson }
56561766fe9SRichard Henderson 
566c53e401eSRichard Henderson static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp)
56761766fe9SRichard Henderson {
56861766fe9SRichard Henderson     return ctx->iaoq_f + disp + 8;
56961766fe9SRichard Henderson }
57061766fe9SRichard Henderson 
57161766fe9SRichard Henderson static void gen_excp_1(int exception)
57261766fe9SRichard Henderson {
573ad75a51eSRichard Henderson     gen_helper_excp(tcg_env, tcg_constant_i32(exception));
57461766fe9SRichard Henderson }
57561766fe9SRichard Henderson 
57631234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception)
57761766fe9SRichard Henderson {
578741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
579741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
580129e9cc3SRichard Henderson     nullify_save(ctx);
58161766fe9SRichard Henderson     gen_excp_1(exception);
58231234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
58361766fe9SRichard Henderson }
58461766fe9SRichard Henderson 
58531234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc)
5861a19da0dSRichard Henderson {
58731234768SRichard Henderson     nullify_over(ctx);
5886fd0c7bcSRichard Henderson     tcg_gen_st_i64(tcg_constant_i64(ctx->insn),
589ad75a51eSRichard Henderson                    tcg_env, offsetof(CPUHPPAState, cr[CR_IIR]));
59031234768SRichard Henderson     gen_excp(ctx, exc);
59131234768SRichard Henderson     return nullify_end(ctx);
5921a19da0dSRichard Henderson }
5931a19da0dSRichard Henderson 
59431234768SRichard Henderson static bool gen_illegal(DisasContext *ctx)
59561766fe9SRichard Henderson {
59631234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_ILL);
59761766fe9SRichard Henderson }
59861766fe9SRichard Henderson 
59940f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY
60040f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
60140f9f908SRichard Henderson     return gen_excp_iir(ctx, EXCP)
60240f9f908SRichard Henderson #else
603e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
604e1b5a5edSRichard Henderson     do {                                     \
605e1b5a5edSRichard Henderson         if (ctx->privilege != 0) {           \
60631234768SRichard Henderson             return gen_excp_iir(ctx, EXCP);  \
607e1b5a5edSRichard Henderson         }                                    \
608e1b5a5edSRichard Henderson     } while (0)
60940f9f908SRichard Henderson #endif
610e1b5a5edSRichard Henderson 
611c53e401eSRichard Henderson static bool use_goto_tb(DisasContext *ctx, uint64_t dest)
61261766fe9SRichard Henderson {
61357f91498SRichard Henderson     return translator_use_goto_tb(&ctx->base, dest);
61461766fe9SRichard Henderson }
61561766fe9SRichard Henderson 
616129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page,
617129e9cc3SRichard Henderson    and we're not attempting to set a breakpoint on it, then we can
618129e9cc3SRichard Henderson    totally skip the nullified insn.  This avoids creating and
619129e9cc3SRichard Henderson    executing a TB that merely branches to the next TB.  */
620129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx)
621129e9cc3SRichard Henderson {
622129e9cc3SRichard Henderson     return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
623129e9cc3SRichard Henderson             && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
624129e9cc3SRichard Henderson }
625129e9cc3SRichard Henderson 
62661766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which,
627c53e401eSRichard Henderson                         uint64_t f, uint64_t b)
62861766fe9SRichard Henderson {
62961766fe9SRichard Henderson     if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
63061766fe9SRichard Henderson         tcg_gen_goto_tb(which);
631a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, f, NULL);
632a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, b, NULL);
63307ea28b4SRichard Henderson         tcg_gen_exit_tb(ctx->base.tb, which);
63461766fe9SRichard Henderson     } else {
635741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, f, cpu_iaoq_b);
636741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, b, ctx->iaoq_n_var);
6377f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
63861766fe9SRichard Henderson     }
63961766fe9SRichard Henderson }
64061766fe9SRichard Henderson 
641b47a4a02SSven Schnelle static bool cond_need_sv(int c)
642b47a4a02SSven Schnelle {
643b47a4a02SSven Schnelle     return c == 2 || c == 3 || c == 6;
644b47a4a02SSven Schnelle }
645b47a4a02SSven Schnelle 
646b47a4a02SSven Schnelle static bool cond_need_cb(int c)
647b47a4a02SSven Schnelle {
648b47a4a02SSven Schnelle     return c == 4 || c == 5;
649b47a4a02SSven Schnelle }
650b47a4a02SSven Schnelle 
6516fd0c7bcSRichard Henderson /* Need extensions from TCGv_i32 to TCGv_i64. */
65272ca8753SRichard Henderson static bool cond_need_ext(DisasContext *ctx, bool d)
65372ca8753SRichard Henderson {
654c53e401eSRichard Henderson     return !(ctx->is_pa20 && d);
65572ca8753SRichard Henderson }
65672ca8753SRichard Henderson 
657b47a4a02SSven Schnelle /*
658b47a4a02SSven Schnelle  * Compute conditional for arithmetic.  See Page 5-3, Table 5-1, of
659b47a4a02SSven Schnelle  * the Parisc 1.1 Architecture Reference Manual for details.
660b47a4a02SSven Schnelle  */
661b2167459SRichard Henderson 
662a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d,
6636fd0c7bcSRichard Henderson                          TCGv_i64 res, TCGv_i64 cb_msb, TCGv_i64 sv)
664b2167459SRichard Henderson {
665b2167459SRichard Henderson     DisasCond cond;
6666fd0c7bcSRichard Henderson     TCGv_i64 tmp;
667b2167459SRichard Henderson 
668b2167459SRichard Henderson     switch (cf >> 1) {
669b47a4a02SSven Schnelle     case 0: /* Never / TR    (0 / 1) */
670b2167459SRichard Henderson         cond = cond_make_f();
671b2167459SRichard Henderson         break;
672b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
673a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
674aac0f603SRichard Henderson             tmp = tcg_temp_new_i64();
6756fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
676a751eb31SRichard Henderson             res = tmp;
677a751eb31SRichard Henderson         }
678b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, res);
679b2167459SRichard Henderson         break;
680b47a4a02SSven Schnelle     case 2: /* < / >=        (N ^ V / !(N ^ V) */
681aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
6826fd0c7bcSRichard Henderson         tcg_gen_xor_i64(tmp, res, sv);
683a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
6846fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, tmp);
685a751eb31SRichard Henderson         }
686b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_LT, tmp);
687b2167459SRichard Henderson         break;
688b47a4a02SSven Schnelle     case 3: /* <= / >        (N ^ V) | Z / !((N ^ V) | Z) */
689b47a4a02SSven Schnelle         /*
690b47a4a02SSven Schnelle          * Simplify:
691b47a4a02SSven Schnelle          *   (N ^ V) | Z
692b47a4a02SSven Schnelle          *   ((res < 0) ^ (sv < 0)) | !res
693b47a4a02SSven Schnelle          *   ((res ^ sv) < 0) | !res
694b47a4a02SSven Schnelle          *   (~(res ^ sv) >= 0) | !res
695b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31) | !res
696b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31 & res)
697b47a4a02SSven Schnelle          */
698aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
6996fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(tmp, res, sv);
700a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
7016fd0c7bcSRichard Henderson             tcg_gen_sextract_i64(tmp, tmp, 31, 1);
7026fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
7036fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
704a751eb31SRichard Henderson         } else {
7056fd0c7bcSRichard Henderson             tcg_gen_sari_i64(tmp, tmp, 63);
7066fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
707a751eb31SRichard Henderson         }
708b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
709b2167459SRichard Henderson         break;
710b2167459SRichard Henderson     case 4: /* NUV / UV      (!C / C) */
711a751eb31SRichard Henderson         /* Only bit 0 of cb_msb is ever set. */
712b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, cb_msb);
713b2167459SRichard Henderson         break;
714b2167459SRichard Henderson     case 5: /* ZNV / VNZ     (!C | Z / C & !Z) */
715aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
7166fd0c7bcSRichard Henderson         tcg_gen_neg_i64(tmp, cb_msb);
7176fd0c7bcSRichard Henderson         tcg_gen_and_i64(tmp, tmp, res);
718a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
7196fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
720a751eb31SRichard Henderson         }
721b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
722b2167459SRichard Henderson         break;
723b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
724a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
725aac0f603SRichard Henderson             tmp = tcg_temp_new_i64();
7266fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, sv);
727a751eb31SRichard Henderson             sv = tmp;
728a751eb31SRichard Henderson         }
729b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, sv);
730b2167459SRichard Henderson         break;
731b2167459SRichard Henderson     case 7: /* OD / EV */
732aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
7336fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, res, 1);
734b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_NE, tmp);
735b2167459SRichard Henderson         break;
736b2167459SRichard Henderson     default:
737b2167459SRichard Henderson         g_assert_not_reached();
738b2167459SRichard Henderson     }
739b2167459SRichard Henderson     if (cf & 1) {
740b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
741b2167459SRichard Henderson     }
742b2167459SRichard Henderson 
743b2167459SRichard Henderson     return cond;
744b2167459SRichard Henderson }
745b2167459SRichard Henderson 
746b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
747b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
748b2167459SRichard Henderson    deleted as unused.  */
749b2167459SRichard Henderson 
7504fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d,
7516fd0c7bcSRichard Henderson                              TCGv_i64 res, TCGv_i64 in1,
7526fd0c7bcSRichard Henderson                              TCGv_i64 in2, TCGv_i64 sv)
753b2167459SRichard Henderson {
7544fe9533aSRichard Henderson     TCGCond tc;
7554fe9533aSRichard Henderson     bool ext_uns;
756b2167459SRichard Henderson 
757b2167459SRichard Henderson     switch (cf >> 1) {
758b2167459SRichard Henderson     case 1: /* = / <> */
7594fe9533aSRichard Henderson         tc = TCG_COND_EQ;
7604fe9533aSRichard Henderson         ext_uns = true;
761b2167459SRichard Henderson         break;
762b2167459SRichard Henderson     case 2: /* < / >= */
7634fe9533aSRichard Henderson         tc = TCG_COND_LT;
7644fe9533aSRichard Henderson         ext_uns = false;
765b2167459SRichard Henderson         break;
766b2167459SRichard Henderson     case 3: /* <= / > */
7674fe9533aSRichard Henderson         tc = TCG_COND_LE;
7684fe9533aSRichard Henderson         ext_uns = false;
769b2167459SRichard Henderson         break;
770b2167459SRichard Henderson     case 4: /* << / >>= */
7714fe9533aSRichard Henderson         tc = TCG_COND_LTU;
7724fe9533aSRichard Henderson         ext_uns = true;
773b2167459SRichard Henderson         break;
774b2167459SRichard Henderson     case 5: /* <<= / >> */
7754fe9533aSRichard Henderson         tc = TCG_COND_LEU;
7764fe9533aSRichard Henderson         ext_uns = true;
777b2167459SRichard Henderson         break;
778b2167459SRichard Henderson     default:
779a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, sv);
780b2167459SRichard Henderson     }
781b2167459SRichard Henderson 
7824fe9533aSRichard Henderson     if (cf & 1) {
7834fe9533aSRichard Henderson         tc = tcg_invert_cond(tc);
7844fe9533aSRichard Henderson     }
7854fe9533aSRichard Henderson     if (cond_need_ext(ctx, d)) {
786aac0f603SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
787aac0f603SRichard Henderson         TCGv_i64 t2 = tcg_temp_new_i64();
7884fe9533aSRichard Henderson 
7894fe9533aSRichard Henderson         if (ext_uns) {
7906fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t1, in1);
7916fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t2, in2);
7924fe9533aSRichard Henderson         } else {
7936fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t1, in1);
7946fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t2, in2);
7954fe9533aSRichard Henderson         }
7964fe9533aSRichard Henderson         return cond_make_tmp(tc, t1, t2);
7974fe9533aSRichard Henderson     }
7984fe9533aSRichard Henderson     return cond_make(tc, in1, in2);
799b2167459SRichard Henderson }
800b2167459SRichard Henderson 
801df0232feSRichard Henderson /*
802df0232feSRichard Henderson  * Similar, but for logicals, where the carry and overflow bits are not
803df0232feSRichard Henderson  * computed, and use of them is undefined.
804df0232feSRichard Henderson  *
805df0232feSRichard Henderson  * Undefined or not, hardware does not trap.  It seems reasonable to
806df0232feSRichard Henderson  * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's
807df0232feSRichard Henderson  * how cases c={2,3} are treated.
808df0232feSRichard Henderson  */
809b2167459SRichard Henderson 
810b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d,
8116fd0c7bcSRichard Henderson                              TCGv_i64 res)
812b2167459SRichard Henderson {
813b5af8423SRichard Henderson     TCGCond tc;
814b5af8423SRichard Henderson     bool ext_uns;
815a751eb31SRichard Henderson 
816df0232feSRichard Henderson     switch (cf) {
817df0232feSRichard Henderson     case 0:  /* never */
818df0232feSRichard Henderson     case 9:  /* undef, C */
819df0232feSRichard Henderson     case 11: /* undef, C & !Z */
820df0232feSRichard Henderson     case 12: /* undef, V */
821df0232feSRichard Henderson         return cond_make_f();
822df0232feSRichard Henderson 
823df0232feSRichard Henderson     case 1:  /* true */
824df0232feSRichard Henderson     case 8:  /* undef, !C */
825df0232feSRichard Henderson     case 10: /* undef, !C | Z */
826df0232feSRichard Henderson     case 13: /* undef, !V */
827df0232feSRichard Henderson         return cond_make_t();
828df0232feSRichard Henderson 
829df0232feSRichard Henderson     case 2:  /* == */
830b5af8423SRichard Henderson         tc = TCG_COND_EQ;
831b5af8423SRichard Henderson         ext_uns = true;
832b5af8423SRichard Henderson         break;
833df0232feSRichard Henderson     case 3:  /* <> */
834b5af8423SRichard Henderson         tc = TCG_COND_NE;
835b5af8423SRichard Henderson         ext_uns = true;
836b5af8423SRichard Henderson         break;
837df0232feSRichard Henderson     case 4:  /* < */
838b5af8423SRichard Henderson         tc = TCG_COND_LT;
839b5af8423SRichard Henderson         ext_uns = false;
840b5af8423SRichard Henderson         break;
841df0232feSRichard Henderson     case 5:  /* >= */
842b5af8423SRichard Henderson         tc = TCG_COND_GE;
843b5af8423SRichard Henderson         ext_uns = false;
844b5af8423SRichard Henderson         break;
845df0232feSRichard Henderson     case 6:  /* <= */
846b5af8423SRichard Henderson         tc = TCG_COND_LE;
847b5af8423SRichard Henderson         ext_uns = false;
848b5af8423SRichard Henderson         break;
849df0232feSRichard Henderson     case 7:  /* > */
850b5af8423SRichard Henderson         tc = TCG_COND_GT;
851b5af8423SRichard Henderson         ext_uns = false;
852b5af8423SRichard Henderson         break;
853df0232feSRichard Henderson 
854df0232feSRichard Henderson     case 14: /* OD */
855df0232feSRichard Henderson     case 15: /* EV */
856a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, NULL);
857df0232feSRichard Henderson 
858df0232feSRichard Henderson     default:
859df0232feSRichard Henderson         g_assert_not_reached();
860b2167459SRichard Henderson     }
861b5af8423SRichard Henderson 
862b5af8423SRichard Henderson     if (cond_need_ext(ctx, d)) {
863aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
864b5af8423SRichard Henderson 
865b5af8423SRichard Henderson         if (ext_uns) {
8666fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
867b5af8423SRichard Henderson         } else {
8686fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, res);
869b5af8423SRichard Henderson         }
870b5af8423SRichard Henderson         return cond_make_0_tmp(tc, tmp);
871b5af8423SRichard Henderson     }
872b5af8423SRichard Henderson     return cond_make_0(tc, res);
873b2167459SRichard Henderson }
874b2167459SRichard Henderson 
87598cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
87698cd9ca7SRichard Henderson 
8774fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d,
8786fd0c7bcSRichard Henderson                              TCGv_i64 res)
87998cd9ca7SRichard Henderson {
88098cd9ca7SRichard Henderson     unsigned c, f;
88198cd9ca7SRichard Henderson 
88298cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
88398cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
88498cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
88598cd9ca7SRichard Henderson     c = orig & 3;
88698cd9ca7SRichard Henderson     if (c == 3) {
88798cd9ca7SRichard Henderson         c = 7;
88898cd9ca7SRichard Henderson     }
88998cd9ca7SRichard Henderson     f = (orig & 4) / 4;
89098cd9ca7SRichard Henderson 
891b5af8423SRichard Henderson     return do_log_cond(ctx, c * 2 + f, d, res);
89298cd9ca7SRichard Henderson }
89398cd9ca7SRichard Henderson 
894b2167459SRichard Henderson /* Similar, but for unit conditions.  */
895b2167459SRichard Henderson 
8966fd0c7bcSRichard Henderson static DisasCond do_unit_cond(unsigned cf, bool d, TCGv_i64 res,
8976fd0c7bcSRichard Henderson                               TCGv_i64 in1, TCGv_i64 in2)
898b2167459SRichard Henderson {
899b2167459SRichard Henderson     DisasCond cond;
9006fd0c7bcSRichard Henderson     TCGv_i64 tmp, cb = NULL;
901c53e401eSRichard Henderson     uint64_t d_repl = d ? 0x0000000100000001ull : 1;
902b2167459SRichard Henderson 
903b2167459SRichard Henderson     if (cf & 8) {
904b2167459SRichard Henderson         /* Since we want to test lots of carry-out bits all at once, do not
905b2167459SRichard Henderson          * do our normal thing and compute carry-in of bit B+1 since that
906b2167459SRichard Henderson          * leaves us with carry bits spread across two words.
907b2167459SRichard Henderson          */
908aac0f603SRichard Henderson         cb = tcg_temp_new_i64();
909aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
9106fd0c7bcSRichard Henderson         tcg_gen_or_i64(cb, in1, in2);
9116fd0c7bcSRichard Henderson         tcg_gen_and_i64(tmp, in1, in2);
9126fd0c7bcSRichard Henderson         tcg_gen_andc_i64(cb, cb, res);
9136fd0c7bcSRichard Henderson         tcg_gen_or_i64(cb, cb, tmp);
914b2167459SRichard Henderson     }
915b2167459SRichard Henderson 
916b2167459SRichard Henderson     switch (cf >> 1) {
917b2167459SRichard Henderson     case 0: /* never / TR */
918b2167459SRichard Henderson     case 1: /* undefined */
919b2167459SRichard Henderson     case 5: /* undefined */
920b2167459SRichard Henderson         cond = cond_make_f();
921b2167459SRichard Henderson         break;
922b2167459SRichard Henderson 
923b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
924b2167459SRichard Henderson         /* See hasless(v,1) from
925b2167459SRichard Henderson          * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
926b2167459SRichard Henderson          */
927aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
9286fd0c7bcSRichard Henderson         tcg_gen_subi_i64(tmp, res, d_repl * 0x01010101u);
9296fd0c7bcSRichard Henderson         tcg_gen_andc_i64(tmp, tmp, res);
9306fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80808080u);
931b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
932b2167459SRichard Henderson         break;
933b2167459SRichard Henderson 
934b2167459SRichard Henderson     case 3: /* SHZ / NHZ */
935aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
9366fd0c7bcSRichard Henderson         tcg_gen_subi_i64(tmp, res, d_repl * 0x00010001u);
9376fd0c7bcSRichard Henderson         tcg_gen_andc_i64(tmp, tmp, res);
9386fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80008000u);
939b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
940b2167459SRichard Henderson         break;
941b2167459SRichard Henderson 
942b2167459SRichard Henderson     case 4: /* SDC / NDC */
9436fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x88888888u);
944b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
945b2167459SRichard Henderson         break;
946b2167459SRichard Henderson 
947b2167459SRichard Henderson     case 6: /* SBC / NBC */
9486fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x80808080u);
949b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
950b2167459SRichard Henderson         break;
951b2167459SRichard Henderson 
952b2167459SRichard Henderson     case 7: /* SHC / NHC */
9536fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x80008000u);
954b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
955b2167459SRichard Henderson         break;
956b2167459SRichard Henderson 
957b2167459SRichard Henderson     default:
958b2167459SRichard Henderson         g_assert_not_reached();
959b2167459SRichard Henderson     }
960b2167459SRichard Henderson     if (cf & 1) {
961b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
962b2167459SRichard Henderson     }
963b2167459SRichard Henderson 
964b2167459SRichard Henderson     return cond;
965b2167459SRichard Henderson }
966b2167459SRichard Henderson 
9676fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d,
9686fd0c7bcSRichard Henderson                           TCGv_i64 cb, TCGv_i64 cb_msb)
96972ca8753SRichard Henderson {
97072ca8753SRichard Henderson     if (cond_need_ext(ctx, d)) {
971aac0f603SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
9726fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, cb, 32, 1);
97372ca8753SRichard Henderson         return t;
97472ca8753SRichard Henderson     }
97572ca8753SRichard Henderson     return cb_msb;
97672ca8753SRichard Henderson }
97772ca8753SRichard Henderson 
9786fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d)
97972ca8753SRichard Henderson {
98072ca8753SRichard Henderson     return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb);
98172ca8753SRichard Henderson }
98272ca8753SRichard Henderson 
983b2167459SRichard Henderson /* Compute signed overflow for addition.  */
9846fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res,
9856fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
986b2167459SRichard Henderson {
987aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
988aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
989b2167459SRichard Henderson 
9906fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
9916fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
9926fd0c7bcSRichard Henderson     tcg_gen_andc_i64(sv, sv, tmp);
993b2167459SRichard Henderson 
994b2167459SRichard Henderson     return sv;
995b2167459SRichard Henderson }
996b2167459SRichard Henderson 
997b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
9986fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res,
9996fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
1000b2167459SRichard Henderson {
1001aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
1002aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
1003b2167459SRichard Henderson 
10046fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
10056fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
10066fd0c7bcSRichard Henderson     tcg_gen_and_i64(sv, sv, tmp);
1007b2167459SRichard Henderson 
1008b2167459SRichard Henderson     return sv;
1009b2167459SRichard Henderson }
1010b2167459SRichard Henderson 
10116fd0c7bcSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
10126fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned shift, bool is_l,
1013faf97ba1SRichard Henderson                    bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d)
1014b2167459SRichard Henderson {
10156fd0c7bcSRichard Henderson     TCGv_i64 dest, cb, cb_msb, cb_cond, sv, tmp;
1016b2167459SRichard Henderson     unsigned c = cf >> 1;
1017b2167459SRichard Henderson     DisasCond cond;
1018b2167459SRichard Henderson 
1019aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1020f764718dSRichard Henderson     cb = NULL;
1021f764718dSRichard Henderson     cb_msb = NULL;
1022bdcccc17SRichard Henderson     cb_cond = NULL;
1023b2167459SRichard Henderson 
1024b2167459SRichard Henderson     if (shift) {
1025aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
10266fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, in1, shift);
1027b2167459SRichard Henderson         in1 = tmp;
1028b2167459SRichard Henderson     }
1029b2167459SRichard Henderson 
1030b47a4a02SSven Schnelle     if (!is_l || cond_need_cb(c)) {
1031aac0f603SRichard Henderson         cb_msb = tcg_temp_new_i64();
1032aac0f603SRichard Henderson         cb = tcg_temp_new_i64();
1033bdcccc17SRichard Henderson 
1034a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero);
1035b2167459SRichard Henderson         if (is_c) {
10366fd0c7bcSRichard Henderson             tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb,
1037a4db4a78SRichard Henderson                              get_psw_carry(ctx, d), ctx->zero);
1038b2167459SRichard Henderson         }
10396fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
10406fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1041bdcccc17SRichard Henderson         if (cond_need_cb(c)) {
1042bdcccc17SRichard Henderson             cb_cond = get_carry(ctx, d, cb, cb_msb);
1043b2167459SRichard Henderson         }
1044b2167459SRichard Henderson     } else {
10456fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
1046b2167459SRichard Henderson         if (is_c) {
10476fd0c7bcSRichard Henderson             tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d));
1048b2167459SRichard Henderson         }
1049b2167459SRichard Henderson     }
1050b2167459SRichard Henderson 
1051b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1052f764718dSRichard Henderson     sv = NULL;
1053b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1054b2167459SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
1055b2167459SRichard Henderson         if (is_tsv) {
1056b2167459SRichard Henderson             /* ??? Need to include overflow from shift.  */
1057ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1058b2167459SRichard Henderson         }
1059b2167459SRichard Henderson     }
1060b2167459SRichard Henderson 
1061b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1062a751eb31SRichard Henderson     cond = do_cond(ctx, cf, d, dest, cb_cond, sv);
1063b2167459SRichard Henderson     if (is_tc) {
1064aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
10656fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1066ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1067b2167459SRichard Henderson     }
1068b2167459SRichard Henderson 
1069b2167459SRichard Henderson     /* Write back the result.  */
1070b2167459SRichard Henderson     if (!is_l) {
1071b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
1072b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1073b2167459SRichard Henderson     }
1074b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1075b2167459SRichard Henderson 
1076b2167459SRichard Henderson     /* Install the new nullification.  */
1077b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1078b2167459SRichard Henderson     ctx->null_cond = cond;
1079b2167459SRichard Henderson }
1080b2167459SRichard Henderson 
1081faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a,
10820c982a28SRichard Henderson                        bool is_l, bool is_tsv, bool is_tc, bool is_c)
10830c982a28SRichard Henderson {
10846fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
10850c982a28SRichard Henderson 
10860c982a28SRichard Henderson     if (a->cf) {
10870c982a28SRichard Henderson         nullify_over(ctx);
10880c982a28SRichard Henderson     }
10890c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
10900c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1091faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l,
1092faf97ba1SRichard Henderson            is_tsv, is_tc, is_c, a->cf, a->d);
10930c982a28SRichard Henderson     return nullify_end(ctx);
10940c982a28SRichard Henderson }
10950c982a28SRichard Henderson 
10960588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a,
10970588e061SRichard Henderson                        bool is_tsv, bool is_tc)
10980588e061SRichard Henderson {
10996fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
11000588e061SRichard Henderson 
11010588e061SRichard Henderson     if (a->cf) {
11020588e061SRichard Henderson         nullify_over(ctx);
11030588e061SRichard Henderson     }
11046fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
11050588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
1106faf97ba1SRichard Henderson     /* All ADDI conditions are 32-bit. */
1107faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false);
11080588e061SRichard Henderson     return nullify_end(ctx);
11090588e061SRichard Henderson }
11100588e061SRichard Henderson 
11116fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
11126fd0c7bcSRichard Henderson                    TCGv_i64 in2, bool is_tsv, bool is_b,
111363c427c6SRichard Henderson                    bool is_tc, unsigned cf, bool d)
1114b2167459SRichard Henderson {
1115a4db4a78SRichard Henderson     TCGv_i64 dest, sv, cb, cb_msb, tmp;
1116b2167459SRichard Henderson     unsigned c = cf >> 1;
1117b2167459SRichard Henderson     DisasCond cond;
1118b2167459SRichard Henderson 
1119aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1120aac0f603SRichard Henderson     cb = tcg_temp_new_i64();
1121aac0f603SRichard Henderson     cb_msb = tcg_temp_new_i64();
1122b2167459SRichard Henderson 
1123b2167459SRichard Henderson     if (is_b) {
1124b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
11256fd0c7bcSRichard Henderson         tcg_gen_not_i64(cb, in2);
1126a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero,
1127a4db4a78SRichard Henderson                          get_psw_carry(ctx, d), ctx->zero);
1128a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero);
11296fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, in1);
11306fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1131b2167459SRichard Henderson     } else {
1132bdcccc17SRichard Henderson         /*
1133bdcccc17SRichard Henderson          * DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
1134bdcccc17SRichard Henderson          * operations by seeding the high word with 1 and subtracting.
1135bdcccc17SRichard Henderson          */
11366fd0c7bcSRichard Henderson         TCGv_i64 one = tcg_constant_i64(1);
1137a4db4a78SRichard Henderson         tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero);
11386fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(cb, in1, in2);
11396fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1140b2167459SRichard Henderson     }
1141b2167459SRichard Henderson 
1142b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1143f764718dSRichard Henderson     sv = NULL;
1144b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1145b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1146b2167459SRichard Henderson         if (is_tsv) {
1147ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1148b2167459SRichard Henderson         }
1149b2167459SRichard Henderson     }
1150b2167459SRichard Henderson 
1151b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
1152b2167459SRichard Henderson     if (!is_b) {
11534fe9533aSRichard Henderson         cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1154b2167459SRichard Henderson     } else {
1155a751eb31SRichard Henderson         cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv);
1156b2167459SRichard Henderson     }
1157b2167459SRichard Henderson 
1158b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1159b2167459SRichard Henderson     if (is_tc) {
1160aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
11616fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1162ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1163b2167459SRichard Henderson     }
1164b2167459SRichard Henderson 
1165b2167459SRichard Henderson     /* Write back the result.  */
1166b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
1167b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1168b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1169b2167459SRichard Henderson 
1170b2167459SRichard Henderson     /* Install the new nullification.  */
1171b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1172b2167459SRichard Henderson     ctx->null_cond = cond;
1173b2167459SRichard Henderson }
1174b2167459SRichard Henderson 
117563c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a,
11760c982a28SRichard Henderson                        bool is_tsv, bool is_b, bool is_tc)
11770c982a28SRichard Henderson {
11786fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
11790c982a28SRichard Henderson 
11800c982a28SRichard Henderson     if (a->cf) {
11810c982a28SRichard Henderson         nullify_over(ctx);
11820c982a28SRichard Henderson     }
11830c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
11840c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
118563c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d);
11860c982a28SRichard Henderson     return nullify_end(ctx);
11870c982a28SRichard Henderson }
11880c982a28SRichard Henderson 
11890588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv)
11900588e061SRichard Henderson {
11916fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
11920588e061SRichard Henderson 
11930588e061SRichard Henderson     if (a->cf) {
11940588e061SRichard Henderson         nullify_over(ctx);
11950588e061SRichard Henderson     }
11966fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
11970588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
119863c427c6SRichard Henderson     /* All SUBI conditions are 32-bit. */
119963c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false);
12000588e061SRichard Henderson     return nullify_end(ctx);
12010588e061SRichard Henderson }
12020588e061SRichard Henderson 
12036fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12046fd0c7bcSRichard Henderson                       TCGv_i64 in2, unsigned cf, bool d)
1205b2167459SRichard Henderson {
12066fd0c7bcSRichard Henderson     TCGv_i64 dest, sv;
1207b2167459SRichard Henderson     DisasCond cond;
1208b2167459SRichard Henderson 
1209aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
12106fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
1211b2167459SRichard Henderson 
1212b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1213f764718dSRichard Henderson     sv = NULL;
1214b47a4a02SSven Schnelle     if (cond_need_sv(cf >> 1)) {
1215b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1216b2167459SRichard Henderson     }
1217b2167459SRichard Henderson 
1218b2167459SRichard Henderson     /* Form the condition for the compare.  */
12194fe9533aSRichard Henderson     cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1220b2167459SRichard Henderson 
1221b2167459SRichard Henderson     /* Clear.  */
12226fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
1223b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1224b2167459SRichard Henderson 
1225b2167459SRichard Henderson     /* Install the new nullification.  */
1226b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1227b2167459SRichard Henderson     ctx->null_cond = cond;
1228b2167459SRichard Henderson }
1229b2167459SRichard Henderson 
12306fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12316fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned cf, bool d,
12326fd0c7bcSRichard Henderson                    void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1233b2167459SRichard Henderson {
12346fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, rt);
1235b2167459SRichard Henderson 
1236b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
1237b2167459SRichard Henderson     fn(dest, in1, in2);
1238b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1239b2167459SRichard Henderson 
1240b2167459SRichard Henderson     /* Install the new nullification.  */
1241b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1242b2167459SRichard Henderson     if (cf) {
1243b5af8423SRichard Henderson         ctx->null_cond = do_log_cond(ctx, cf, d, dest);
1244b2167459SRichard Henderson     }
1245b2167459SRichard Henderson }
1246b2167459SRichard Henderson 
1247fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a,
12486fd0c7bcSRichard Henderson                        void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
12490c982a28SRichard Henderson {
12506fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
12510c982a28SRichard Henderson 
12520c982a28SRichard Henderson     if (a->cf) {
12530c982a28SRichard Henderson         nullify_over(ctx);
12540c982a28SRichard Henderson     }
12550c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
12560c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1257fa8e3bedSRichard Henderson     do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn);
12580c982a28SRichard Henderson     return nullify_end(ctx);
12590c982a28SRichard Henderson }
12600c982a28SRichard Henderson 
12616fd0c7bcSRichard Henderson static void do_unit(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12626fd0c7bcSRichard Henderson                     TCGv_i64 in2, unsigned cf, bool d, bool is_tc,
12636fd0c7bcSRichard Henderson                     void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1264b2167459SRichard Henderson {
12656fd0c7bcSRichard Henderson     TCGv_i64 dest;
1266b2167459SRichard Henderson     DisasCond cond;
1267b2167459SRichard Henderson 
1268b2167459SRichard Henderson     if (cf == 0) {
1269b2167459SRichard Henderson         dest = dest_gpr(ctx, rt);
1270b2167459SRichard Henderson         fn(dest, in1, in2);
1271b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1272b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1273b2167459SRichard Henderson     } else {
1274aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
1275b2167459SRichard Henderson         fn(dest, in1, in2);
1276b2167459SRichard Henderson 
127759963d8fSRichard Henderson         cond = do_unit_cond(cf, d, dest, in1, in2);
1278b2167459SRichard Henderson 
1279b2167459SRichard Henderson         if (is_tc) {
1280aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
12816fd0c7bcSRichard Henderson             tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1282ad75a51eSRichard Henderson             gen_helper_tcond(tcg_env, tmp);
1283b2167459SRichard Henderson         }
1284b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1285b2167459SRichard Henderson 
1286b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1287b2167459SRichard Henderson         ctx->null_cond = cond;
1288b2167459SRichard Henderson     }
1289b2167459SRichard Henderson }
1290b2167459SRichard Henderson 
129186f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY
12928d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space
12938d6ae7fbSRichard Henderson    from the top 2 bits of the base register.  There are a few system
12948d6ae7fbSRichard Henderson    instructions that have a 3-bit space specifier, for which SR0 is
12958d6ae7fbSRichard Henderson    not special.  To handle this, pass ~SP.  */
12966fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base)
129786f8d05fSRichard Henderson {
129886f8d05fSRichard Henderson     TCGv_ptr ptr;
12996fd0c7bcSRichard Henderson     TCGv_i64 tmp;
130086f8d05fSRichard Henderson     TCGv_i64 spc;
130186f8d05fSRichard Henderson 
130286f8d05fSRichard Henderson     if (sp != 0) {
13038d6ae7fbSRichard Henderson         if (sp < 0) {
13048d6ae7fbSRichard Henderson             sp = ~sp;
13058d6ae7fbSRichard Henderson         }
13066fd0c7bcSRichard Henderson         spc = tcg_temp_new_i64();
13078d6ae7fbSRichard Henderson         load_spr(ctx, spc, sp);
13088d6ae7fbSRichard Henderson         return spc;
130986f8d05fSRichard Henderson     }
1310494737b7SRichard Henderson     if (ctx->tb_flags & TB_FLAG_SR_SAME) {
1311494737b7SRichard Henderson         return cpu_srH;
1312494737b7SRichard Henderson     }
131386f8d05fSRichard Henderson 
131486f8d05fSRichard Henderson     ptr = tcg_temp_new_ptr();
1315aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
13166fd0c7bcSRichard Henderson     spc = tcg_temp_new_i64();
131786f8d05fSRichard Henderson 
1318698240d1SRichard Henderson     /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */
13196fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5);
13206fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, 030);
13216fd0c7bcSRichard Henderson     tcg_gen_trunc_i64_ptr(ptr, tmp);
132286f8d05fSRichard Henderson 
1323ad75a51eSRichard Henderson     tcg_gen_add_ptr(ptr, ptr, tcg_env);
132486f8d05fSRichard Henderson     tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4]));
132586f8d05fSRichard Henderson 
132686f8d05fSRichard Henderson     return spc;
132786f8d05fSRichard Henderson }
132886f8d05fSRichard Henderson #endif
132986f8d05fSRichard Henderson 
13306fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
1331c53e401eSRichard Henderson                      unsigned rb, unsigned rx, int scale, int64_t disp,
133286f8d05fSRichard Henderson                      unsigned sp, int modify, bool is_phys)
133386f8d05fSRichard Henderson {
13346fd0c7bcSRichard Henderson     TCGv_i64 base = load_gpr(ctx, rb);
13356fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13366fd0c7bcSRichard Henderson     TCGv_i64 addr;
133786f8d05fSRichard Henderson 
1338f5b5c857SRichard Henderson     set_insn_breg(ctx, rb);
1339f5b5c857SRichard Henderson 
134086f8d05fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
134186f8d05fSRichard Henderson     if (rx) {
1342aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
13436fd0c7bcSRichard Henderson         tcg_gen_shli_i64(ofs, cpu_gr[rx], scale);
13446fd0c7bcSRichard Henderson         tcg_gen_add_i64(ofs, ofs, base);
134586f8d05fSRichard Henderson     } else if (disp || modify) {
1346aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
13476fd0c7bcSRichard Henderson         tcg_gen_addi_i64(ofs, base, disp);
134886f8d05fSRichard Henderson     } else {
134986f8d05fSRichard Henderson         ofs = base;
135086f8d05fSRichard Henderson     }
135186f8d05fSRichard Henderson 
135286f8d05fSRichard Henderson     *pofs = ofs;
13536fd0c7bcSRichard Henderson     *pgva = addr = tcg_temp_new_i64();
1354d265360fSRichard Henderson     tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base, gva_offset_mask(ctx));
1355698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY
135686f8d05fSRichard Henderson     if (!is_phys) {
1357d265360fSRichard Henderson         tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base));
135886f8d05fSRichard Henderson     }
135986f8d05fSRichard Henderson #endif
136086f8d05fSRichard Henderson }
136186f8d05fSRichard Henderson 
136296d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
136396d6407fSRichard Henderson  * < 0 for pre-modify,
136496d6407fSRichard Henderson  * > 0 for post-modify,
136596d6407fSRichard Henderson  * = 0 for no base register update.
136696d6407fSRichard Henderson  */
136796d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1368c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
136914776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
137096d6407fSRichard Henderson {
13716fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13726fd0c7bcSRichard Henderson     TCGv_i64 addr;
137396d6407fSRichard Henderson 
137496d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
137596d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
137696d6407fSRichard Henderson 
137786f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
137886f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1379c1f55d97SRichard Henderson     tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
138086f8d05fSRichard Henderson     if (modify) {
138186f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
138296d6407fSRichard Henderson     }
138396d6407fSRichard Henderson }
138496d6407fSRichard Henderson 
138596d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1386c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
138714776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
138896d6407fSRichard Henderson {
13896fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13906fd0c7bcSRichard Henderson     TCGv_i64 addr;
139196d6407fSRichard Henderson 
139296d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
139396d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
139496d6407fSRichard Henderson 
139586f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
139686f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1397217d1a5eSRichard Henderson     tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
139886f8d05fSRichard Henderson     if (modify) {
139986f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
140096d6407fSRichard Henderson     }
140196d6407fSRichard Henderson }
140296d6407fSRichard Henderson 
140396d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1404c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
140514776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
140696d6407fSRichard Henderson {
14076fd0c7bcSRichard Henderson     TCGv_i64 ofs;
14086fd0c7bcSRichard Henderson     TCGv_i64 addr;
140996d6407fSRichard Henderson 
141096d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
141196d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
141296d6407fSRichard Henderson 
141386f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
141486f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1415217d1a5eSRichard Henderson     tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
141686f8d05fSRichard Henderson     if (modify) {
141786f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
141896d6407fSRichard Henderson     }
141996d6407fSRichard Henderson }
142096d6407fSRichard Henderson 
142196d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1422c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
142314776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
142496d6407fSRichard Henderson {
14256fd0c7bcSRichard Henderson     TCGv_i64 ofs;
14266fd0c7bcSRichard Henderson     TCGv_i64 addr;
142796d6407fSRichard Henderson 
142896d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
142996d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
143096d6407fSRichard Henderson 
143186f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
143286f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1433217d1a5eSRichard Henderson     tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
143486f8d05fSRichard Henderson     if (modify) {
143586f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
143696d6407fSRichard Henderson     }
143796d6407fSRichard Henderson }
143896d6407fSRichard Henderson 
14391cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1440c53e401eSRichard Henderson                     unsigned rx, int scale, int64_t disp,
144114776ab5STony Nguyen                     unsigned sp, int modify, MemOp mop)
144296d6407fSRichard Henderson {
14436fd0c7bcSRichard Henderson     TCGv_i64 dest;
144496d6407fSRichard Henderson 
144596d6407fSRichard Henderson     nullify_over(ctx);
144696d6407fSRichard Henderson 
144796d6407fSRichard Henderson     if (modify == 0) {
144896d6407fSRichard Henderson         /* No base register update.  */
144996d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
145096d6407fSRichard Henderson     } else {
145196d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
1452aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
145396d6407fSRichard Henderson     }
14546fd0c7bcSRichard Henderson     do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
145596d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
145696d6407fSRichard Henderson 
14571cd012a5SRichard Henderson     return nullify_end(ctx);
145896d6407fSRichard Henderson }
145996d6407fSRichard Henderson 
1460740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
1461c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
146286f8d05fSRichard Henderson                       unsigned sp, int modify)
146396d6407fSRichard Henderson {
146496d6407fSRichard Henderson     TCGv_i32 tmp;
146596d6407fSRichard Henderson 
146696d6407fSRichard Henderson     nullify_over(ctx);
146796d6407fSRichard Henderson 
146896d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
146986f8d05fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
147096d6407fSRichard Henderson     save_frw_i32(rt, tmp);
147196d6407fSRichard Henderson 
147296d6407fSRichard Henderson     if (rt == 0) {
1473ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
147496d6407fSRichard Henderson     }
147596d6407fSRichard Henderson 
1476740038d7SRichard Henderson     return nullify_end(ctx);
147796d6407fSRichard Henderson }
147896d6407fSRichard Henderson 
1479740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a)
1480740038d7SRichard Henderson {
1481740038d7SRichard Henderson     return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1482740038d7SRichard Henderson                      a->disp, a->sp, a->m);
1483740038d7SRichard Henderson }
1484740038d7SRichard Henderson 
1485740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1486c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
148786f8d05fSRichard Henderson                       unsigned sp, int modify)
148896d6407fSRichard Henderson {
148996d6407fSRichard Henderson     TCGv_i64 tmp;
149096d6407fSRichard Henderson 
149196d6407fSRichard Henderson     nullify_over(ctx);
149296d6407fSRichard Henderson 
149396d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
1494fc313c64SFrédéric Pétrot     do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
149596d6407fSRichard Henderson     save_frd(rt, tmp);
149696d6407fSRichard Henderson 
149796d6407fSRichard Henderson     if (rt == 0) {
1498ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
149996d6407fSRichard Henderson     }
150096d6407fSRichard Henderson 
1501740038d7SRichard Henderson     return nullify_end(ctx);
1502740038d7SRichard Henderson }
1503740038d7SRichard Henderson 
1504740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a)
1505740038d7SRichard Henderson {
1506740038d7SRichard Henderson     return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1507740038d7SRichard Henderson                      a->disp, a->sp, a->m);
150896d6407fSRichard Henderson }
150996d6407fSRichard Henderson 
15101cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb,
1511c53e401eSRichard Henderson                      int64_t disp, unsigned sp,
151214776ab5STony Nguyen                      int modify, MemOp mop)
151396d6407fSRichard Henderson {
151496d6407fSRichard Henderson     nullify_over(ctx);
15156fd0c7bcSRichard Henderson     do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
15161cd012a5SRichard Henderson     return nullify_end(ctx);
151796d6407fSRichard Henderson }
151896d6407fSRichard Henderson 
1519740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1520c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
152186f8d05fSRichard Henderson                        unsigned sp, int modify)
152296d6407fSRichard Henderson {
152396d6407fSRichard Henderson     TCGv_i32 tmp;
152496d6407fSRichard Henderson 
152596d6407fSRichard Henderson     nullify_over(ctx);
152696d6407fSRichard Henderson 
152796d6407fSRichard Henderson     tmp = load_frw_i32(rt);
152886f8d05fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
152996d6407fSRichard Henderson 
1530740038d7SRichard Henderson     return nullify_end(ctx);
153196d6407fSRichard Henderson }
153296d6407fSRichard Henderson 
1533740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a)
1534740038d7SRichard Henderson {
1535740038d7SRichard Henderson     return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1536740038d7SRichard Henderson                       a->disp, a->sp, a->m);
1537740038d7SRichard Henderson }
1538740038d7SRichard Henderson 
1539740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1540c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
154186f8d05fSRichard Henderson                        unsigned sp, int modify)
154296d6407fSRichard Henderson {
154396d6407fSRichard Henderson     TCGv_i64 tmp;
154496d6407fSRichard Henderson 
154596d6407fSRichard Henderson     nullify_over(ctx);
154696d6407fSRichard Henderson 
154796d6407fSRichard Henderson     tmp = load_frd(rt);
1548fc313c64SFrédéric Pétrot     do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
154996d6407fSRichard Henderson 
1550740038d7SRichard Henderson     return nullify_end(ctx);
1551740038d7SRichard Henderson }
1552740038d7SRichard Henderson 
1553740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a)
1554740038d7SRichard Henderson {
1555740038d7SRichard Henderson     return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1556740038d7SRichard Henderson                       a->disp, a->sp, a->m);
155796d6407fSRichard Henderson }
155896d6407fSRichard Henderson 
15591ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1560ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1561ebe9383cSRichard Henderson {
1562ebe9383cSRichard Henderson     TCGv_i32 tmp;
1563ebe9383cSRichard Henderson 
1564ebe9383cSRichard Henderson     nullify_over(ctx);
1565ebe9383cSRichard Henderson     tmp = load_frw0_i32(ra);
1566ebe9383cSRichard Henderson 
1567ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1568ebe9383cSRichard Henderson 
1569ebe9383cSRichard Henderson     save_frw_i32(rt, tmp);
15701ca74648SRichard Henderson     return nullify_end(ctx);
1571ebe9383cSRichard Henderson }
1572ebe9383cSRichard Henderson 
15731ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1574ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1575ebe9383cSRichard Henderson {
1576ebe9383cSRichard Henderson     TCGv_i32 dst;
1577ebe9383cSRichard Henderson     TCGv_i64 src;
1578ebe9383cSRichard Henderson 
1579ebe9383cSRichard Henderson     nullify_over(ctx);
1580ebe9383cSRichard Henderson     src = load_frd(ra);
1581ebe9383cSRichard Henderson     dst = tcg_temp_new_i32();
1582ebe9383cSRichard Henderson 
1583ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1584ebe9383cSRichard Henderson 
1585ebe9383cSRichard Henderson     save_frw_i32(rt, dst);
15861ca74648SRichard Henderson     return nullify_end(ctx);
1587ebe9383cSRichard Henderson }
1588ebe9383cSRichard Henderson 
15891ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1590ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1591ebe9383cSRichard Henderson {
1592ebe9383cSRichard Henderson     TCGv_i64 tmp;
1593ebe9383cSRichard Henderson 
1594ebe9383cSRichard Henderson     nullify_over(ctx);
1595ebe9383cSRichard Henderson     tmp = load_frd0(ra);
1596ebe9383cSRichard Henderson 
1597ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1598ebe9383cSRichard Henderson 
1599ebe9383cSRichard Henderson     save_frd(rt, tmp);
16001ca74648SRichard Henderson     return nullify_end(ctx);
1601ebe9383cSRichard Henderson }
1602ebe9383cSRichard Henderson 
16031ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1604ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1605ebe9383cSRichard Henderson {
1606ebe9383cSRichard Henderson     TCGv_i32 src;
1607ebe9383cSRichard Henderson     TCGv_i64 dst;
1608ebe9383cSRichard Henderson 
1609ebe9383cSRichard Henderson     nullify_over(ctx);
1610ebe9383cSRichard Henderson     src = load_frw0_i32(ra);
1611ebe9383cSRichard Henderson     dst = tcg_temp_new_i64();
1612ebe9383cSRichard Henderson 
1613ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1614ebe9383cSRichard Henderson 
1615ebe9383cSRichard Henderson     save_frd(rt, dst);
16161ca74648SRichard Henderson     return nullify_end(ctx);
1617ebe9383cSRichard Henderson }
1618ebe9383cSRichard Henderson 
16191ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt,
1620ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
162131234768SRichard Henderson                         void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
1622ebe9383cSRichard Henderson {
1623ebe9383cSRichard Henderson     TCGv_i32 a, b;
1624ebe9383cSRichard Henderson 
1625ebe9383cSRichard Henderson     nullify_over(ctx);
1626ebe9383cSRichard Henderson     a = load_frw0_i32(ra);
1627ebe9383cSRichard Henderson     b = load_frw0_i32(rb);
1628ebe9383cSRichard Henderson 
1629ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1630ebe9383cSRichard Henderson 
1631ebe9383cSRichard Henderson     save_frw_i32(rt, a);
16321ca74648SRichard Henderson     return nullify_end(ctx);
1633ebe9383cSRichard Henderson }
1634ebe9383cSRichard Henderson 
16351ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt,
1636ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
163731234768SRichard Henderson                         void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
1638ebe9383cSRichard Henderson {
1639ebe9383cSRichard Henderson     TCGv_i64 a, b;
1640ebe9383cSRichard Henderson 
1641ebe9383cSRichard Henderson     nullify_over(ctx);
1642ebe9383cSRichard Henderson     a = load_frd0(ra);
1643ebe9383cSRichard Henderson     b = load_frd0(rb);
1644ebe9383cSRichard Henderson 
1645ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1646ebe9383cSRichard Henderson 
1647ebe9383cSRichard Henderson     save_frd(rt, a);
16481ca74648SRichard Henderson     return nullify_end(ctx);
1649ebe9383cSRichard Henderson }
1650ebe9383cSRichard Henderson 
165198cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
165298cd9ca7SRichard Henderson    have already had nullification handled.  */
1653c53e401eSRichard Henderson static bool do_dbranch(DisasContext *ctx, uint64_t dest,
165498cd9ca7SRichard Henderson                        unsigned link, bool is_n)
165598cd9ca7SRichard Henderson {
165698cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
165798cd9ca7SRichard Henderson         if (link != 0) {
1658741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
165998cd9ca7SRichard Henderson         }
166098cd9ca7SRichard Henderson         ctx->iaoq_n = dest;
166198cd9ca7SRichard Henderson         if (is_n) {
166298cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
166398cd9ca7SRichard Henderson         }
166498cd9ca7SRichard Henderson     } else {
166598cd9ca7SRichard Henderson         nullify_over(ctx);
166698cd9ca7SRichard Henderson 
166798cd9ca7SRichard Henderson         if (link != 0) {
1668741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
166998cd9ca7SRichard Henderson         }
167098cd9ca7SRichard Henderson 
167198cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
167298cd9ca7SRichard Henderson             nullify_set(ctx, 0);
167398cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, dest, dest + 4);
167498cd9ca7SRichard Henderson         } else {
167598cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
167698cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
167798cd9ca7SRichard Henderson         }
167898cd9ca7SRichard Henderson 
167931234768SRichard Henderson         nullify_end(ctx);
168098cd9ca7SRichard Henderson 
168198cd9ca7SRichard Henderson         nullify_set(ctx, 0);
168298cd9ca7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
168331234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
168498cd9ca7SRichard Henderson     }
168501afb7beSRichard Henderson     return true;
168698cd9ca7SRichard Henderson }
168798cd9ca7SRichard Henderson 
168898cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
168998cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
1690c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n,
169198cd9ca7SRichard Henderson                        DisasCond *cond)
169298cd9ca7SRichard Henderson {
1693c53e401eSRichard Henderson     uint64_t dest = iaoq_dest(ctx, disp);
169498cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
169598cd9ca7SRichard Henderson     TCGCond c = cond->c;
169698cd9ca7SRichard Henderson     bool n;
169798cd9ca7SRichard Henderson 
169898cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
169998cd9ca7SRichard Henderson 
170098cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
170198cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
170201afb7beSRichard Henderson         return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
170398cd9ca7SRichard Henderson     }
170498cd9ca7SRichard Henderson     if (c == TCG_COND_NEVER) {
170501afb7beSRichard Henderson         return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
170698cd9ca7SRichard Henderson     }
170798cd9ca7SRichard Henderson 
170898cd9ca7SRichard Henderson     taken = gen_new_label();
17096fd0c7bcSRichard Henderson     tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken);
171098cd9ca7SRichard Henderson     cond_free(cond);
171198cd9ca7SRichard Henderson 
171298cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
171398cd9ca7SRichard Henderson     n = is_n && disp < 0;
171498cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
171598cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1716a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
171798cd9ca7SRichard Henderson     } else {
171898cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
171998cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
172098cd9ca7SRichard Henderson             ctx->null_lab = NULL;
172198cd9ca7SRichard Henderson         }
172298cd9ca7SRichard Henderson         nullify_set(ctx, n);
1723c301f34eSRichard Henderson         if (ctx->iaoq_n == -1) {
1724c301f34eSRichard Henderson             /* The temporary iaoq_n_var died at the branch above.
1725c301f34eSRichard Henderson                Regenerate it here instead of saving it.  */
17266fd0c7bcSRichard Henderson             tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
1727c301f34eSRichard Henderson         }
1728a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
172998cd9ca7SRichard Henderson     }
173098cd9ca7SRichard Henderson 
173198cd9ca7SRichard Henderson     gen_set_label(taken);
173298cd9ca7SRichard Henderson 
173398cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
173498cd9ca7SRichard Henderson     n = is_n && disp >= 0;
173598cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
173698cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1737a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, dest, dest + 4);
173898cd9ca7SRichard Henderson     } else {
173998cd9ca7SRichard Henderson         nullify_set(ctx, n);
1740a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
174198cd9ca7SRichard Henderson     }
174298cd9ca7SRichard Henderson 
174398cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
174498cd9ca7SRichard Henderson     if (ctx->null_lab) {
174598cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
174698cd9ca7SRichard Henderson         ctx->null_lab = NULL;
174731234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
174898cd9ca7SRichard Henderson     } else {
174931234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
175098cd9ca7SRichard Henderson     }
175101afb7beSRichard Henderson     return true;
175298cd9ca7SRichard Henderson }
175398cd9ca7SRichard Henderson 
175498cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target.  This handles
175598cd9ca7SRichard Henderson    nullification of the branch itself.  */
17566fd0c7bcSRichard Henderson static bool do_ibranch(DisasContext *ctx, TCGv_i64 dest,
175798cd9ca7SRichard Henderson                        unsigned link, bool is_n)
175898cd9ca7SRichard Henderson {
17596fd0c7bcSRichard Henderson     TCGv_i64 a0, a1, next, tmp;
176098cd9ca7SRichard Henderson     TCGCond c;
176198cd9ca7SRichard Henderson 
176298cd9ca7SRichard Henderson     assert(ctx->null_lab == NULL);
176398cd9ca7SRichard Henderson 
176498cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
176598cd9ca7SRichard Henderson         if (link != 0) {
1766741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
176798cd9ca7SRichard Henderson         }
1768aac0f603SRichard Henderson         next = tcg_temp_new_i64();
17696fd0c7bcSRichard Henderson         tcg_gen_mov_i64(next, dest);
177098cd9ca7SRichard Henderson         if (is_n) {
1771c301f34eSRichard Henderson             if (use_nullify_skip(ctx)) {
1772a0180973SRichard Henderson                 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, next);
17736fd0c7bcSRichard Henderson                 tcg_gen_addi_i64(next, next, 4);
1774a0180973SRichard Henderson                 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
1775c301f34eSRichard Henderson                 nullify_set(ctx, 0);
177631234768SRichard Henderson                 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
177701afb7beSRichard Henderson                 return true;
1778c301f34eSRichard Henderson             }
177998cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
178098cd9ca7SRichard Henderson         }
1781c301f34eSRichard Henderson         ctx->iaoq_n = -1;
1782c301f34eSRichard Henderson         ctx->iaoq_n_var = next;
178398cd9ca7SRichard Henderson     } else if (is_n && use_nullify_skip(ctx)) {
178498cd9ca7SRichard Henderson         /* The (conditional) branch, B, nullifies the next insn, N,
178598cd9ca7SRichard Henderson            and we're allowed to skip execution N (no single-step or
17864137cb83SRichard Henderson            tracepoint in effect).  Since the goto_ptr that we must use
178798cd9ca7SRichard Henderson            for the indirect branch consumes no special resources, we
178898cd9ca7SRichard Henderson            can (conditionally) skip B and continue execution.  */
178998cd9ca7SRichard Henderson         /* The use_nullify_skip test implies we have a known control path.  */
179098cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_b != -1);
179198cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_n != -1);
179298cd9ca7SRichard Henderson 
179398cd9ca7SRichard Henderson         /* We do have to handle the non-local temporary, DEST, before
179498cd9ca7SRichard Henderson            branching.  Since IOAQ_F is not really live at this point, we
179598cd9ca7SRichard Henderson            can simply store DEST optimistically.  Similarly with IAOQ_B.  */
1796a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, dest);
1797aac0f603SRichard Henderson         next = tcg_temp_new_i64();
17986fd0c7bcSRichard Henderson         tcg_gen_addi_i64(next, dest, 4);
1799a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
180098cd9ca7SRichard Henderson 
180198cd9ca7SRichard Henderson         nullify_over(ctx);
180298cd9ca7SRichard Henderson         if (link != 0) {
18039a91dd84SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
180498cd9ca7SRichard Henderson         }
18057f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
180601afb7beSRichard Henderson         return nullify_end(ctx);
180798cd9ca7SRichard Henderson     } else {
180898cd9ca7SRichard Henderson         c = ctx->null_cond.c;
180998cd9ca7SRichard Henderson         a0 = ctx->null_cond.a0;
181098cd9ca7SRichard Henderson         a1 = ctx->null_cond.a1;
181198cd9ca7SRichard Henderson 
1812aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
1813aac0f603SRichard Henderson         next = tcg_temp_new_i64();
181498cd9ca7SRichard Henderson 
1815741322f4SRichard Henderson         copy_iaoq_entry(ctx, tmp, ctx->iaoq_n, ctx->iaoq_n_var);
18166fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(c, next, a0, a1, tmp, dest);
181798cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
181898cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
181998cd9ca7SRichard Henderson 
182098cd9ca7SRichard Henderson         if (link != 0) {
18216fd0c7bcSRichard Henderson             tcg_gen_movcond_i64(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
182298cd9ca7SRichard Henderson         }
182398cd9ca7SRichard Henderson 
182498cd9ca7SRichard Henderson         if (is_n) {
182598cd9ca7SRichard Henderson             /* The branch nullifies the next insn, which means the state of N
182698cd9ca7SRichard Henderson                after the branch is the inverse of the state of N that applied
182798cd9ca7SRichard Henderson                to the branch.  */
18286fd0c7bcSRichard Henderson             tcg_gen_setcond_i64(tcg_invert_cond(c), cpu_psw_n, a0, a1);
182998cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
183098cd9ca7SRichard Henderson             ctx->null_cond = cond_make_n();
183198cd9ca7SRichard Henderson             ctx->psw_n_nonzero = true;
183298cd9ca7SRichard Henderson         } else {
183398cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
183498cd9ca7SRichard Henderson         }
183598cd9ca7SRichard Henderson     }
183601afb7beSRichard Henderson     return true;
183798cd9ca7SRichard Henderson }
183898cd9ca7SRichard Henderson 
1839660eefe1SRichard Henderson /* Implement
1840660eefe1SRichard Henderson  *    if (IAOQ_Front{30..31} < GR[b]{30..31})
1841660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← GR[b]{30..31};
1842660eefe1SRichard Henderson  *    else
1843660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← IAOQ_Front{30..31};
1844660eefe1SRichard Henderson  * which keeps the privilege level from being increased.
1845660eefe1SRichard Henderson  */
18466fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset)
1847660eefe1SRichard Henderson {
18486fd0c7bcSRichard Henderson     TCGv_i64 dest;
1849660eefe1SRichard Henderson     switch (ctx->privilege) {
1850660eefe1SRichard Henderson     case 0:
1851660eefe1SRichard Henderson         /* Privilege 0 is maximum and is allowed to decrease.  */
1852660eefe1SRichard Henderson         return offset;
1853660eefe1SRichard Henderson     case 3:
1854993119feSRichard Henderson         /* Privilege 3 is minimum and is never allowed to increase.  */
1855aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
18566fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, offset, 3);
1857660eefe1SRichard Henderson         break;
1858660eefe1SRichard Henderson     default:
1859aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
18606fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, offset, -4);
18616fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, ctx->privilege);
18626fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(TCG_COND_GTU, dest, dest, offset, dest, offset);
1863660eefe1SRichard Henderson         break;
1864660eefe1SRichard Henderson     }
1865660eefe1SRichard Henderson     return dest;
1866660eefe1SRichard Henderson }
1867660eefe1SRichard Henderson 
1868ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
18697ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
18707ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
18717ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
18727ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
18737ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
18747ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
18757ad439dfSRichard Henderson    aforementioned BE.  */
187631234768SRichard Henderson static void do_page_zero(DisasContext *ctx)
18777ad439dfSRichard Henderson {
18786fd0c7bcSRichard Henderson     TCGv_i64 tmp;
1879a0180973SRichard Henderson 
18807ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
18817ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
18828b81968cSMichael Tokarev        next insn within the privileged page.  */
18837ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
18847ad439dfSRichard Henderson     case TCG_COND_NEVER:
18857ad439dfSRichard Henderson         break;
18867ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
18876fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, 0);
18887ad439dfSRichard Henderson         goto do_sigill;
18897ad439dfSRichard Henderson     default:
18907ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
18917ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
18927ad439dfSRichard Henderson         g_assert_not_reached();
18937ad439dfSRichard Henderson     }
18947ad439dfSRichard Henderson 
18957ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
18967ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
18977ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
18987ad439dfSRichard Henderson        under such conditions.  */
18997ad439dfSRichard Henderson     if (ctx->iaoq_b != ctx->iaoq_f + 4) {
19007ad439dfSRichard Henderson         goto do_sigill;
19017ad439dfSRichard Henderson     }
19027ad439dfSRichard Henderson 
1903ebd0e151SRichard Henderson     switch (ctx->iaoq_f & -4) {
19047ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
19052986721dSRichard Henderson         gen_excp_1(EXCP_IMP);
190631234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
190731234768SRichard Henderson         break;
19087ad439dfSRichard Henderson 
19097ad439dfSRichard Henderson     case 0xb0: /* LWS */
19107ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
191131234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
191231234768SRichard Henderson         break;
19137ad439dfSRichard Henderson 
19147ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
19156fd0c7bcSRichard Henderson         tcg_gen_st_i64(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27]));
1916aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
19176fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_gr[31], 3);
1918a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
19196fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, 4);
1920a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
192131234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
192231234768SRichard Henderson         break;
19237ad439dfSRichard Henderson 
19247ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
19257ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
192631234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
192731234768SRichard Henderson         break;
19287ad439dfSRichard Henderson 
19297ad439dfSRichard Henderson     default:
19307ad439dfSRichard Henderson     do_sigill:
19312986721dSRichard Henderson         gen_excp_1(EXCP_ILL);
193231234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
193331234768SRichard Henderson         break;
19347ad439dfSRichard Henderson     }
19357ad439dfSRichard Henderson }
1936ba1d0b44SRichard Henderson #endif
19377ad439dfSRichard Henderson 
1938deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a)
1939b2167459SRichard Henderson {
1940b2167459SRichard Henderson     cond_free(&ctx->null_cond);
194131234768SRichard Henderson     return true;
1942b2167459SRichard Henderson }
1943b2167459SRichard Henderson 
194440f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a)
194598a9cb79SRichard Henderson {
194631234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_BREAK);
194798a9cb79SRichard Henderson }
194898a9cb79SRichard Henderson 
1949e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a)
195098a9cb79SRichard Henderson {
195198a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
195298a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
195398a9cb79SRichard Henderson 
195498a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
195531234768SRichard Henderson     return true;
195698a9cb79SRichard Henderson }
195798a9cb79SRichard Henderson 
1958c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a)
195998a9cb79SRichard Henderson {
1960c603e14aSRichard Henderson     unsigned rt = a->t;
19616fd0c7bcSRichard Henderson     TCGv_i64 tmp = dest_gpr(ctx, rt);
19626fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tmp, ctx->iaoq_f);
196398a9cb79SRichard Henderson     save_gpr(ctx, rt, tmp);
196498a9cb79SRichard Henderson 
196598a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
196631234768SRichard Henderson     return true;
196798a9cb79SRichard Henderson }
196898a9cb79SRichard Henderson 
1969c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a)
197098a9cb79SRichard Henderson {
1971c603e14aSRichard Henderson     unsigned rt = a->t;
1972c603e14aSRichard Henderson     unsigned rs = a->sp;
197333423472SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
197498a9cb79SRichard Henderson 
197533423472SRichard Henderson     load_spr(ctx, t0, rs);
197633423472SRichard Henderson     tcg_gen_shri_i64(t0, t0, 32);
197733423472SRichard Henderson 
1978967662cdSRichard Henderson     save_gpr(ctx, rt, t0);
197998a9cb79SRichard Henderson 
198098a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
198131234768SRichard Henderson     return true;
198298a9cb79SRichard Henderson }
198398a9cb79SRichard Henderson 
1984c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a)
198598a9cb79SRichard Henderson {
1986c603e14aSRichard Henderson     unsigned rt = a->t;
1987c603e14aSRichard Henderson     unsigned ctl = a->r;
19886fd0c7bcSRichard Henderson     TCGv_i64 tmp;
198998a9cb79SRichard Henderson 
199098a9cb79SRichard Henderson     switch (ctl) {
199135136a77SRichard Henderson     case CR_SAR:
1992c603e14aSRichard Henderson         if (a->e == 0) {
199398a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
199498a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
19956fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
199698a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
199735136a77SRichard Henderson             goto done;
199898a9cb79SRichard Henderson         }
199998a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
200035136a77SRichard Henderson         goto done;
200135136a77SRichard Henderson     case CR_IT: /* Interval Timer */
200235136a77SRichard Henderson         /* FIXME: Respect PSW_S bit.  */
200335136a77SRichard Henderson         nullify_over(ctx);
200498a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
2005dfd1b812SRichard Henderson         if (translator_io_start(&ctx->base)) {
200649c29d6cSRichard Henderson             gen_helper_read_interval_timer(tmp);
200731234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
200849c29d6cSRichard Henderson         } else {
200949c29d6cSRichard Henderson             gen_helper_read_interval_timer(tmp);
201049c29d6cSRichard Henderson         }
201198a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
201231234768SRichard Henderson         return nullify_end(ctx);
201398a9cb79SRichard Henderson     case 26:
201498a9cb79SRichard Henderson     case 27:
201598a9cb79SRichard Henderson         break;
201698a9cb79SRichard Henderson     default:
201798a9cb79SRichard Henderson         /* All other control registers are privileged.  */
201835136a77SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
201935136a77SRichard Henderson         break;
202098a9cb79SRichard Henderson     }
202198a9cb79SRichard Henderson 
2022aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
20236fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
202435136a77SRichard Henderson     save_gpr(ctx, rt, tmp);
202535136a77SRichard Henderson 
202635136a77SRichard Henderson  done:
202798a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
202831234768SRichard Henderson     return true;
202998a9cb79SRichard Henderson }
203098a9cb79SRichard Henderson 
2031c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
203233423472SRichard Henderson {
2033c603e14aSRichard Henderson     unsigned rr = a->r;
2034c603e14aSRichard Henderson     unsigned rs = a->sp;
2035967662cdSRichard Henderson     TCGv_i64 tmp;
203633423472SRichard Henderson 
203733423472SRichard Henderson     if (rs >= 5) {
203833423472SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
203933423472SRichard Henderson     }
204033423472SRichard Henderson     nullify_over(ctx);
204133423472SRichard Henderson 
2042967662cdSRichard Henderson     tmp = tcg_temp_new_i64();
2043967662cdSRichard Henderson     tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32);
204433423472SRichard Henderson 
204533423472SRichard Henderson     if (rs >= 4) {
2046967662cdSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs]));
2047494737b7SRichard Henderson         ctx->tb_flags &= ~TB_FLAG_SR_SAME;
204833423472SRichard Henderson     } else {
2049967662cdSRichard Henderson         tcg_gen_mov_i64(cpu_sr[rs], tmp);
205033423472SRichard Henderson     }
205133423472SRichard Henderson 
205231234768SRichard Henderson     return nullify_end(ctx);
205333423472SRichard Henderson }
205433423472SRichard Henderson 
2055c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
205698a9cb79SRichard Henderson {
2057c603e14aSRichard Henderson     unsigned ctl = a->t;
20586fd0c7bcSRichard Henderson     TCGv_i64 reg;
20596fd0c7bcSRichard Henderson     TCGv_i64 tmp;
206098a9cb79SRichard Henderson 
206135136a77SRichard Henderson     if (ctl == CR_SAR) {
20624845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
2063aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
20646fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31);
206598a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
206698a9cb79SRichard Henderson 
206798a9cb79SRichard Henderson         cond_free(&ctx->null_cond);
206831234768SRichard Henderson         return true;
206998a9cb79SRichard Henderson     }
207098a9cb79SRichard Henderson 
207135136a77SRichard Henderson     /* All other control registers are privileged or read-only.  */
207235136a77SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
207335136a77SRichard Henderson 
2074c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
207535136a77SRichard Henderson     nullify_over(ctx);
20764c34bab0SHelge Deller 
20774c34bab0SHelge Deller     if (ctx->is_pa20) {
20784845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
20794c34bab0SHelge Deller     } else {
20804c34bab0SHelge Deller         reg = tcg_temp_new_i64();
20814c34bab0SHelge Deller         tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r));
20824c34bab0SHelge Deller     }
20834845f015SSven Schnelle 
208435136a77SRichard Henderson     switch (ctl) {
208535136a77SRichard Henderson     case CR_IT:
2086ad75a51eSRichard Henderson         gen_helper_write_interval_timer(tcg_env, reg);
208735136a77SRichard Henderson         break;
20884f5f2548SRichard Henderson     case CR_EIRR:
2089ad75a51eSRichard Henderson         gen_helper_write_eirr(tcg_env, reg);
20904f5f2548SRichard Henderson         break;
20914f5f2548SRichard Henderson     case CR_EIEM:
2092ad75a51eSRichard Henderson         gen_helper_write_eiem(tcg_env, reg);
209331234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
20944f5f2548SRichard Henderson         break;
20954f5f2548SRichard Henderson 
209635136a77SRichard Henderson     case CR_IIASQ:
209735136a77SRichard Henderson     case CR_IIAOQ:
209835136a77SRichard Henderson         /* FIXME: Respect PSW_Q bit */
209935136a77SRichard Henderson         /* The write advances the queue and stores to the back element.  */
2100aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
21016fd0c7bcSRichard Henderson         tcg_gen_ld_i64(tmp, tcg_env,
210235136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
21036fd0c7bcSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
21046fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env,
210535136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
210635136a77SRichard Henderson         break;
210735136a77SRichard Henderson 
2108d5de20bdSSven Schnelle     case CR_PID1:
2109d5de20bdSSven Schnelle     case CR_PID2:
2110d5de20bdSSven Schnelle     case CR_PID3:
2111d5de20bdSSven Schnelle     case CR_PID4:
21126fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
2113d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY
2114ad75a51eSRichard Henderson         gen_helper_change_prot_id(tcg_env);
2115d5de20bdSSven Schnelle #endif
2116d5de20bdSSven Schnelle         break;
2117d5de20bdSSven Schnelle 
211835136a77SRichard Henderson     default:
21196fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
212035136a77SRichard Henderson         break;
212135136a77SRichard Henderson     }
212231234768SRichard Henderson     return nullify_end(ctx);
21234f5f2548SRichard Henderson #endif
212435136a77SRichard Henderson }
212535136a77SRichard Henderson 
2126c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
212798a9cb79SRichard Henderson {
2128aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
212998a9cb79SRichard Henderson 
21306fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, load_gpr(ctx, a->r));
21316fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31);
213298a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
213398a9cb79SRichard Henderson 
213498a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
213531234768SRichard Henderson     return true;
213698a9cb79SRichard Henderson }
213798a9cb79SRichard Henderson 
2138e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a)
213998a9cb79SRichard Henderson {
21406fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
214198a9cb79SRichard Henderson 
21422330504cSHelge Deller #ifdef CONFIG_USER_ONLY
21432330504cSHelge Deller     /* We don't implement space registers in user mode. */
21446fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
21452330504cSHelge Deller #else
2146967662cdSRichard Henderson     tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
2147967662cdSRichard Henderson     tcg_gen_shri_i64(dest, dest, 32);
21482330504cSHelge Deller #endif
2149e36f27efSRichard Henderson     save_gpr(ctx, a->t, dest);
215098a9cb79SRichard Henderson 
215198a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
215231234768SRichard Henderson     return true;
215398a9cb79SRichard Henderson }
215498a9cb79SRichard Henderson 
2155e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a)
2156e36f27efSRichard Henderson {
2157e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2158e1b5a5edSRichard Henderson #ifndef CONFIG_USER_ONLY
21596fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2160e1b5a5edSRichard Henderson 
2161e1b5a5edSRichard Henderson     nullify_over(ctx);
2162e1b5a5edSRichard Henderson 
2163aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
21646fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
21656fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ~a->i);
2166ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2167e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2168e1b5a5edSRichard Henderson 
2169e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_M.  */
217031234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
217131234768SRichard Henderson     return nullify_end(ctx);
2172e36f27efSRichard Henderson #endif
2173e1b5a5edSRichard Henderson }
2174e1b5a5edSRichard Henderson 
2175e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
2176e1b5a5edSRichard Henderson {
2177e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2178e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
21796fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2180e1b5a5edSRichard Henderson 
2181e1b5a5edSRichard Henderson     nullify_over(ctx);
2182e1b5a5edSRichard Henderson 
2183aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
21846fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
21856fd0c7bcSRichard Henderson     tcg_gen_ori_i64(tmp, tmp, a->i);
2186ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2187e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2188e1b5a5edSRichard Henderson 
2189e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_I.  */
219031234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
219131234768SRichard Henderson     return nullify_end(ctx);
2192e36f27efSRichard Henderson #endif
2193e1b5a5edSRichard Henderson }
2194e1b5a5edSRichard Henderson 
2195c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
2196e1b5a5edSRichard Henderson {
2197e1b5a5edSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2198c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
21996fd0c7bcSRichard Henderson     TCGv_i64 tmp, reg;
2200e1b5a5edSRichard Henderson     nullify_over(ctx);
2201e1b5a5edSRichard Henderson 
2202c603e14aSRichard Henderson     reg = load_gpr(ctx, a->r);
2203aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2204ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, reg);
2205e1b5a5edSRichard Henderson 
2206e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts.  */
220731234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
220831234768SRichard Henderson     return nullify_end(ctx);
2209c603e14aSRichard Henderson #endif
2210e1b5a5edSRichard Henderson }
2211f49b3537SRichard Henderson 
2212e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r)
2213f49b3537SRichard Henderson {
2214f49b3537SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2215e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
2216f49b3537SRichard Henderson     nullify_over(ctx);
2217f49b3537SRichard Henderson 
2218e36f27efSRichard Henderson     if (rfi_r) {
2219ad75a51eSRichard Henderson         gen_helper_rfi_r(tcg_env);
2220f49b3537SRichard Henderson     } else {
2221ad75a51eSRichard Henderson         gen_helper_rfi(tcg_env);
2222f49b3537SRichard Henderson     }
222331234768SRichard Henderson     /* Exit the TB to recognize new interrupts.  */
222407ea28b4SRichard Henderson     tcg_gen_exit_tb(NULL, 0);
222531234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
2226f49b3537SRichard Henderson 
222731234768SRichard Henderson     return nullify_end(ctx);
2228e36f27efSRichard Henderson #endif
2229f49b3537SRichard Henderson }
22306210db05SHelge Deller 
2231e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a)
2232e36f27efSRichard Henderson {
2233e36f27efSRichard Henderson     return do_rfi(ctx, false);
2234e36f27efSRichard Henderson }
2235e36f27efSRichard Henderson 
2236e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a)
2237e36f27efSRichard Henderson {
2238e36f27efSRichard Henderson     return do_rfi(ctx, true);
2239e36f27efSRichard Henderson }
2240e36f27efSRichard Henderson 
224196927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a)
22426210db05SHelge Deller {
22436210db05SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
224496927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
22456210db05SHelge Deller     nullify_over(ctx);
2246ad75a51eSRichard Henderson     gen_helper_halt(tcg_env);
224731234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
224831234768SRichard Henderson     return nullify_end(ctx);
224996927adbSRichard Henderson #endif
22506210db05SHelge Deller }
225196927adbSRichard Henderson 
225296927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a)
225396927adbSRichard Henderson {
225496927adbSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
225596927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
225696927adbSRichard Henderson     nullify_over(ctx);
2257ad75a51eSRichard Henderson     gen_helper_reset(tcg_env);
225896927adbSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
225996927adbSRichard Henderson     return nullify_end(ctx);
226096927adbSRichard Henderson #endif
226196927adbSRichard Henderson }
2262e1b5a5edSRichard Henderson 
22634a4554c6SHelge Deller static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
22644a4554c6SHelge Deller {
22654a4554c6SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
22664a4554c6SHelge Deller #ifndef CONFIG_USER_ONLY
22674a4554c6SHelge Deller     nullify_over(ctx);
2268ad75a51eSRichard Henderson     gen_helper_getshadowregs(tcg_env);
22694a4554c6SHelge Deller     return nullify_end(ctx);
22704a4554c6SHelge Deller #endif
22714a4554c6SHelge Deller }
22724a4554c6SHelge Deller 
2273deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
227498a9cb79SRichard Henderson {
2275deee69a1SRichard Henderson     if (a->m) {
22766fd0c7bcSRichard Henderson         TCGv_i64 dest = dest_gpr(ctx, a->b);
22776fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->b);
22786fd0c7bcSRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->x);
227998a9cb79SRichard Henderson 
228098a9cb79SRichard Henderson         /* The only thing we need to do is the base register modification.  */
22816fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, src1, src2);
2282deee69a1SRichard Henderson         save_gpr(ctx, a->b, dest);
2283deee69a1SRichard Henderson     }
228498a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
228531234768SRichard Henderson     return true;
228698a9cb79SRichard Henderson }
228798a9cb79SRichard Henderson 
2288deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a)
228998a9cb79SRichard Henderson {
22906fd0c7bcSRichard Henderson     TCGv_i64 dest, ofs;
2291eed14219SRichard Henderson     TCGv_i32 level, want;
22926fd0c7bcSRichard Henderson     TCGv_i64 addr;
229398a9cb79SRichard Henderson 
229498a9cb79SRichard Henderson     nullify_over(ctx);
229598a9cb79SRichard Henderson 
2296deee69a1SRichard Henderson     dest = dest_gpr(ctx, a->t);
2297deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2298eed14219SRichard Henderson 
2299deee69a1SRichard Henderson     if (a->imm) {
2300*e5d487c9SRichard Henderson         level = tcg_constant_i32(a->ri & 3);
230198a9cb79SRichard Henderson     } else {
2302eed14219SRichard Henderson         level = tcg_temp_new_i32();
23036fd0c7bcSRichard Henderson         tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri));
2304eed14219SRichard Henderson         tcg_gen_andi_i32(level, level, 3);
230598a9cb79SRichard Henderson     }
230629dd6f64SRichard Henderson     want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ);
2307eed14219SRichard Henderson 
2308ad75a51eSRichard Henderson     gen_helper_probe(dest, tcg_env, addr, level, want);
2309eed14219SRichard Henderson 
2310deee69a1SRichard Henderson     save_gpr(ctx, a->t, dest);
231131234768SRichard Henderson     return nullify_end(ctx);
231298a9cb79SRichard Henderson }
231398a9cb79SRichard Henderson 
2314deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
23158d6ae7fbSRichard Henderson {
23168577f354SRichard Henderson     if (ctx->is_pa20) {
23178577f354SRichard Henderson         return false;
23188577f354SRichard Henderson     }
2319deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2320deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
23216fd0c7bcSRichard Henderson     TCGv_i64 addr;
23226fd0c7bcSRichard Henderson     TCGv_i64 ofs, reg;
23238d6ae7fbSRichard Henderson 
23248d6ae7fbSRichard Henderson     nullify_over(ctx);
23258d6ae7fbSRichard Henderson 
2326deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2327deee69a1SRichard Henderson     reg = load_gpr(ctx, a->r);
2328deee69a1SRichard Henderson     if (a->addr) {
23298577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
23308d6ae7fbSRichard Henderson     } else {
23318577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
23328d6ae7fbSRichard Henderson     }
23338d6ae7fbSRichard Henderson 
233432dc7569SSven Schnelle     /* Exit TB for TLB change if mmu is enabled.  */
233532dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
233631234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
233731234768SRichard Henderson     }
233831234768SRichard Henderson     return nullify_end(ctx);
2339deee69a1SRichard Henderson #endif
23408d6ae7fbSRichard Henderson }
234163300a00SRichard Henderson 
2342eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local)
234363300a00SRichard Henderson {
2344deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2345deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
23466fd0c7bcSRichard Henderson     TCGv_i64 addr;
23476fd0c7bcSRichard Henderson     TCGv_i64 ofs;
234863300a00SRichard Henderson 
234963300a00SRichard Henderson     nullify_over(ctx);
235063300a00SRichard Henderson 
2351deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2352eb25d10fSHelge Deller 
2353eb25d10fSHelge Deller     /*
2354eb25d10fSHelge Deller      * Page align now, rather than later, so that we can add in the
2355eb25d10fSHelge Deller      * page_size field from pa2.0 from the low 4 bits of GR[b].
2356eb25d10fSHelge Deller      */
2357eb25d10fSHelge Deller     tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK);
2358eb25d10fSHelge Deller     if (ctx->is_pa20) {
2359eb25d10fSHelge Deller         tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4);
236063300a00SRichard Henderson     }
2361eb25d10fSHelge Deller 
2362eb25d10fSHelge Deller     if (local) {
2363eb25d10fSHelge Deller         gen_helper_ptlb_l(tcg_env, addr);
236463300a00SRichard Henderson     } else {
2365ad75a51eSRichard Henderson         gen_helper_ptlb(tcg_env, addr);
236663300a00SRichard Henderson     }
236763300a00SRichard Henderson 
2368eb25d10fSHelge Deller     if (a->m) {
2369eb25d10fSHelge Deller         save_gpr(ctx, a->b, ofs);
2370eb25d10fSHelge Deller     }
2371eb25d10fSHelge Deller 
2372eb25d10fSHelge Deller     /* Exit TB for TLB change if mmu is enabled.  */
2373eb25d10fSHelge Deller     if (ctx->tb_flags & PSW_C) {
2374eb25d10fSHelge Deller         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2375eb25d10fSHelge Deller     }
2376eb25d10fSHelge Deller     return nullify_end(ctx);
2377eb25d10fSHelge Deller #endif
2378eb25d10fSHelge Deller }
2379eb25d10fSHelge Deller 
2380eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a)
2381eb25d10fSHelge Deller {
2382eb25d10fSHelge Deller     return do_pxtlb(ctx, a, false);
2383eb25d10fSHelge Deller }
2384eb25d10fSHelge Deller 
2385eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a)
2386eb25d10fSHelge Deller {
2387eb25d10fSHelge Deller     return ctx->is_pa20 && do_pxtlb(ctx, a, true);
2388eb25d10fSHelge Deller }
2389eb25d10fSHelge Deller 
2390eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a)
2391eb25d10fSHelge Deller {
2392eb25d10fSHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2393eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY
2394eb25d10fSHelge Deller     nullify_over(ctx);
2395eb25d10fSHelge Deller 
2396eb25d10fSHelge Deller     trans_nop_addrx(ctx, a);
2397eb25d10fSHelge Deller     gen_helper_ptlbe(tcg_env);
2398eb25d10fSHelge Deller 
239963300a00SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
240032dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
240131234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
240231234768SRichard Henderson     }
240331234768SRichard Henderson     return nullify_end(ctx);
2404deee69a1SRichard Henderson #endif
240563300a00SRichard Henderson }
24062dfcca9fSRichard Henderson 
24076797c315SNick Hudson /*
24086797c315SNick Hudson  * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
24096797c315SNick Hudson  * See
24106797c315SNick Hudson  *     https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
24116797c315SNick Hudson  *     page 13-9 (195/206)
24126797c315SNick Hudson  */
24136797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
24146797c315SNick Hudson {
24158577f354SRichard Henderson     if (ctx->is_pa20) {
24168577f354SRichard Henderson         return false;
24178577f354SRichard Henderson     }
24186797c315SNick Hudson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24196797c315SNick Hudson #ifndef CONFIG_USER_ONLY
24206fd0c7bcSRichard Henderson     TCGv_i64 addr, atl, stl;
24216fd0c7bcSRichard Henderson     TCGv_i64 reg;
24226797c315SNick Hudson 
24236797c315SNick Hudson     nullify_over(ctx);
24246797c315SNick Hudson 
24256797c315SNick Hudson     /*
24266797c315SNick Hudson      * FIXME:
24276797c315SNick Hudson      *  if (not (pcxl or pcxl2))
24286797c315SNick Hudson      *    return gen_illegal(ctx);
24296797c315SNick Hudson      */
24306797c315SNick Hudson 
24316fd0c7bcSRichard Henderson     atl = tcg_temp_new_i64();
24326fd0c7bcSRichard Henderson     stl = tcg_temp_new_i64();
24336fd0c7bcSRichard Henderson     addr = tcg_temp_new_i64();
24346797c315SNick Hudson 
2435ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(stl, tcg_env,
24366797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
24376797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIASQ]));
2438ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(atl, tcg_env,
24396797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
24406797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIAOQ]));
24416797c315SNick Hudson     tcg_gen_shli_i64(stl, stl, 32);
2442d265360fSRichard Henderson     tcg_gen_or_i64(addr, atl, stl);
24436797c315SNick Hudson 
24446797c315SNick Hudson     reg = load_gpr(ctx, a->r);
24456797c315SNick Hudson     if (a->addr) {
24468577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
24476797c315SNick Hudson     } else {
24488577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
24496797c315SNick Hudson     }
24506797c315SNick Hudson 
24516797c315SNick Hudson     /* Exit TB for TLB change if mmu is enabled.  */
24526797c315SNick Hudson     if (ctx->tb_flags & PSW_C) {
24536797c315SNick Hudson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
24546797c315SNick Hudson     }
24556797c315SNick Hudson     return nullify_end(ctx);
24566797c315SNick Hudson #endif
24576797c315SNick Hudson }
24586797c315SNick Hudson 
24598577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
24608577f354SRichard Henderson {
24618577f354SRichard Henderson     if (!ctx->is_pa20) {
24628577f354SRichard Henderson         return false;
24638577f354SRichard Henderson     }
24648577f354SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24658577f354SRichard Henderson #ifndef CONFIG_USER_ONLY
24668577f354SRichard Henderson     nullify_over(ctx);
24678577f354SRichard Henderson     {
24688577f354SRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
24698577f354SRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->r2);
24708577f354SRichard Henderson 
24718577f354SRichard Henderson         if (a->data) {
24728577f354SRichard Henderson             gen_helper_idtlbt_pa20(tcg_env, src1, src2);
24738577f354SRichard Henderson         } else {
24748577f354SRichard Henderson             gen_helper_iitlbt_pa20(tcg_env, src1, src2);
24758577f354SRichard Henderson         }
24768577f354SRichard Henderson     }
24778577f354SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
24788577f354SRichard Henderson     if (ctx->tb_flags & PSW_C) {
24798577f354SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
24808577f354SRichard Henderson     }
24818577f354SRichard Henderson     return nullify_end(ctx);
24828577f354SRichard Henderson #endif
24838577f354SRichard Henderson }
24848577f354SRichard Henderson 
2485deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
24862dfcca9fSRichard Henderson {
2487deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2488deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
24896fd0c7bcSRichard Henderson     TCGv_i64 vaddr;
24906fd0c7bcSRichard Henderson     TCGv_i64 ofs, paddr;
24912dfcca9fSRichard Henderson 
24922dfcca9fSRichard Henderson     nullify_over(ctx);
24932dfcca9fSRichard Henderson 
2494deee69a1SRichard Henderson     form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
24952dfcca9fSRichard Henderson 
2496aac0f603SRichard Henderson     paddr = tcg_temp_new_i64();
2497ad75a51eSRichard Henderson     gen_helper_lpa(paddr, tcg_env, vaddr);
24982dfcca9fSRichard Henderson 
24992dfcca9fSRichard Henderson     /* Note that physical address result overrides base modification.  */
2500deee69a1SRichard Henderson     if (a->m) {
2501deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
25022dfcca9fSRichard Henderson     }
2503deee69a1SRichard Henderson     save_gpr(ctx, a->t, paddr);
25042dfcca9fSRichard Henderson 
250531234768SRichard Henderson     return nullify_end(ctx);
2506deee69a1SRichard Henderson #endif
25072dfcca9fSRichard Henderson }
250843a97b81SRichard Henderson 
2509deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a)
251043a97b81SRichard Henderson {
251143a97b81SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
251243a97b81SRichard Henderson 
251343a97b81SRichard Henderson     /* The Coherence Index is an implementation-defined function of the
251443a97b81SRichard Henderson        physical address.  Two addresses with the same CI have a coherent
251543a97b81SRichard Henderson        view of the cache.  Our implementation is to return 0 for all,
251643a97b81SRichard Henderson        since the entire address space is coherent.  */
2517a4db4a78SRichard Henderson     save_gpr(ctx, a->t, ctx->zero);
251843a97b81SRichard Henderson 
251931234768SRichard Henderson     cond_free(&ctx->null_cond);
252031234768SRichard Henderson     return true;
252143a97b81SRichard Henderson }
252298a9cb79SRichard Henderson 
2523faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2524b2167459SRichard Henderson {
25250c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, false);
2526b2167459SRichard Henderson }
2527b2167459SRichard Henderson 
2528faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2529b2167459SRichard Henderson {
25300c982a28SRichard Henderson     return do_add_reg(ctx, a, true, false, false, false);
2531b2167459SRichard Henderson }
2532b2167459SRichard Henderson 
2533faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2534b2167459SRichard Henderson {
25350c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, false);
2536b2167459SRichard Henderson }
2537b2167459SRichard Henderson 
2538faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2539b2167459SRichard Henderson {
25400c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, true);
25410c982a28SRichard Henderson }
2542b2167459SRichard Henderson 
2543faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
25440c982a28SRichard Henderson {
25450c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, true);
25460c982a28SRichard Henderson }
25470c982a28SRichard Henderson 
254863c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
25490c982a28SRichard Henderson {
25500c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, false);
25510c982a28SRichard Henderson }
25520c982a28SRichard Henderson 
255363c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
25540c982a28SRichard Henderson {
25550c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, false);
25560c982a28SRichard Henderson }
25570c982a28SRichard Henderson 
255863c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
25590c982a28SRichard Henderson {
25600c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, true);
25610c982a28SRichard Henderson }
25620c982a28SRichard Henderson 
256363c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
25640c982a28SRichard Henderson {
25650c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, true);
25660c982a28SRichard Henderson }
25670c982a28SRichard Henderson 
256863c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
25690c982a28SRichard Henderson {
25700c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, true, false);
25710c982a28SRichard Henderson }
25720c982a28SRichard Henderson 
257363c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
25740c982a28SRichard Henderson {
25750c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, true, false);
25760c982a28SRichard Henderson }
25770c982a28SRichard Henderson 
2578fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
25790c982a28SRichard Henderson {
25806fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_andc_i64);
25810c982a28SRichard Henderson }
25820c982a28SRichard Henderson 
2583fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
25840c982a28SRichard Henderson {
25856fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_and_i64);
25860c982a28SRichard Henderson }
25870c982a28SRichard Henderson 
2588fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
25890c982a28SRichard Henderson {
25900c982a28SRichard Henderson     if (a->cf == 0) {
25910c982a28SRichard Henderson         unsigned r2 = a->r2;
25920c982a28SRichard Henderson         unsigned r1 = a->r1;
25930c982a28SRichard Henderson         unsigned rt = a->t;
25940c982a28SRichard Henderson 
25957aee8189SRichard Henderson         if (rt == 0) { /* NOP */
25967aee8189SRichard Henderson             cond_free(&ctx->null_cond);
25977aee8189SRichard Henderson             return true;
25987aee8189SRichard Henderson         }
25997aee8189SRichard Henderson         if (r2 == 0) { /* COPY */
2600b2167459SRichard Henderson             if (r1 == 0) {
26016fd0c7bcSRichard Henderson                 TCGv_i64 dest = dest_gpr(ctx, rt);
26026fd0c7bcSRichard Henderson                 tcg_gen_movi_i64(dest, 0);
2603b2167459SRichard Henderson                 save_gpr(ctx, rt, dest);
2604b2167459SRichard Henderson             } else {
2605b2167459SRichard Henderson                 save_gpr(ctx, rt, cpu_gr[r1]);
2606b2167459SRichard Henderson             }
2607b2167459SRichard Henderson             cond_free(&ctx->null_cond);
260831234768SRichard Henderson             return true;
2609b2167459SRichard Henderson         }
26107aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY
26117aee8189SRichard Henderson         /* These are QEMU extensions and are nops in the real architecture:
26127aee8189SRichard Henderson          *
26137aee8189SRichard Henderson          * or %r10,%r10,%r10 -- idle loop; wait for interrupt
26147aee8189SRichard Henderson          * or %r31,%r31,%r31 -- death loop; offline cpu
26157aee8189SRichard Henderson          *                      currently implemented as idle.
26167aee8189SRichard Henderson          */
26177aee8189SRichard Henderson         if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
26187aee8189SRichard Henderson             /* No need to check for supervisor, as userland can only pause
26197aee8189SRichard Henderson                until the next timer interrupt.  */
26207aee8189SRichard Henderson             nullify_over(ctx);
26217aee8189SRichard Henderson 
26227aee8189SRichard Henderson             /* Advance the instruction queue.  */
2623741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
2624741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
26257aee8189SRichard Henderson             nullify_set(ctx, 0);
26267aee8189SRichard Henderson 
26277aee8189SRichard Henderson             /* Tell the qemu main loop to halt until this cpu has work.  */
2628ad75a51eSRichard Henderson             tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
262929dd6f64SRichard Henderson                            offsetof(CPUState, halted) - offsetof(HPPACPU, env));
26307aee8189SRichard Henderson             gen_excp_1(EXCP_HALTED);
26317aee8189SRichard Henderson             ctx->base.is_jmp = DISAS_NORETURN;
26327aee8189SRichard Henderson 
26337aee8189SRichard Henderson             return nullify_end(ctx);
26347aee8189SRichard Henderson         }
26357aee8189SRichard Henderson #endif
26367aee8189SRichard Henderson     }
26376fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_or_i64);
26387aee8189SRichard Henderson }
2639b2167459SRichard Henderson 
2640fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
2641b2167459SRichard Henderson {
26426fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_xor_i64);
26430c982a28SRichard Henderson }
26440c982a28SRichard Henderson 
2645345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
26460c982a28SRichard 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);
2654345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
265531234768SRichard Henderson     return nullify_end(ctx);
2656b2167459SRichard Henderson }
2657b2167459SRichard Henderson 
2658af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
2659b2167459SRichard Henderson {
26606fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
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);
26676fd0c7bcSRichard Henderson     do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64);
266831234768SRichard Henderson     return nullify_end(ctx);
2669b2167459SRichard Henderson }
2670b2167459SRichard Henderson 
2671af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
2672b2167459SRichard Henderson {
26736fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, tmp;
2674b2167459SRichard Henderson 
26750c982a28SRichard Henderson     if (a->cf) {
2676b2167459SRichard Henderson         nullify_over(ctx);
2677b2167459SRichard Henderson     }
26780c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26790c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2680aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
26816fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, tcg_r2);
26826fd0c7bcSRichard Henderson     do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64);
268331234768SRichard Henderson     return nullify_end(ctx);
2684b2167459SRichard Henderson }
2685b2167459SRichard Henderson 
2686af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
2687b2167459SRichard Henderson {
26880c982a28SRichard Henderson     return do_uaddcm(ctx, a, false);
26890c982a28SRichard Henderson }
26900c982a28SRichard Henderson 
2691af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
26920c982a28SRichard Henderson {
26930c982a28SRichard Henderson     return do_uaddcm(ctx, a, true);
26940c982a28SRichard Henderson }
26950c982a28SRichard Henderson 
2696af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
26970c982a28SRichard Henderson {
26986fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2699b2167459SRichard Henderson 
2700b2167459SRichard Henderson     nullify_over(ctx);
2701b2167459SRichard Henderson 
2702aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
27036fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, cpu_psw_cb, 3);
2704b2167459SRichard Henderson     if (!is_i) {
27056fd0c7bcSRichard Henderson         tcg_gen_not_i64(tmp, tmp);
2706b2167459SRichard Henderson     }
27076fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
27086fd0c7bcSRichard Henderson     tcg_gen_muli_i64(tmp, tmp, 6);
2709af240753SRichard Henderson     do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false,
27106fd0c7bcSRichard Henderson             is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64);
271131234768SRichard Henderson     return nullify_end(ctx);
2712b2167459SRichard Henderson }
2713b2167459SRichard Henderson 
2714af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
2715b2167459SRichard Henderson {
27160c982a28SRichard Henderson     return do_dcor(ctx, a, false);
27170c982a28SRichard Henderson }
27180c982a28SRichard Henderson 
2719af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
27200c982a28SRichard Henderson {
27210c982a28SRichard Henderson     return do_dcor(ctx, a, true);
27220c982a28SRichard Henderson }
27230c982a28SRichard Henderson 
27240c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
27250c982a28SRichard Henderson {
2726a4db4a78SRichard Henderson     TCGv_i64 dest, add1, add2, addc, in1, in2;
27276fd0c7bcSRichard Henderson     TCGv_i64 cout;
2728b2167459SRichard Henderson 
2729b2167459SRichard Henderson     nullify_over(ctx);
2730b2167459SRichard Henderson 
27310c982a28SRichard Henderson     in1 = load_gpr(ctx, a->r1);
27320c982a28SRichard Henderson     in2 = load_gpr(ctx, a->r2);
2733b2167459SRichard Henderson 
2734aac0f603SRichard Henderson     add1 = tcg_temp_new_i64();
2735aac0f603SRichard Henderson     add2 = tcg_temp_new_i64();
2736aac0f603SRichard Henderson     addc = tcg_temp_new_i64();
2737aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
2738b2167459SRichard Henderson 
2739b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
27406fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, in1, in1);
27416fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
2742b2167459SRichard Henderson 
274372ca8753SRichard Henderson     /*
274472ca8753SRichard Henderson      * Add or subtract R2, depending on PSW[V].  Proper computation of
274572ca8753SRichard Henderson      * carry requires that we subtract via + ~R2 + 1, as described in
274672ca8753SRichard Henderson      * the manual.  By extracting and masking V, we can produce the
274772ca8753SRichard Henderson      * proper inputs to the addition without movcond.
274872ca8753SRichard Henderson      */
27496fd0c7bcSRichard Henderson     tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
27506fd0c7bcSRichard Henderson     tcg_gen_xor_i64(add2, in2, addc);
27516fd0c7bcSRichard Henderson     tcg_gen_andi_i64(addc, addc, 1);
275272ca8753SRichard Henderson 
2753a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero);
2754a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb,
2755a4db4a78SRichard Henderson                      addc, ctx->zero);
2756b2167459SRichard Henderson 
2757b2167459SRichard Henderson     /* Write back the result register.  */
27580c982a28SRichard Henderson     save_gpr(ctx, a->t, dest);
2759b2167459SRichard Henderson 
2760b2167459SRichard Henderson     /* Write back PSW[CB].  */
27616fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
27626fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
2763b2167459SRichard Henderson 
2764b2167459SRichard Henderson     /* Write back PSW[V] for the division step.  */
276572ca8753SRichard Henderson     cout = get_psw_carry(ctx, false);
27666fd0c7bcSRichard Henderson     tcg_gen_neg_i64(cpu_psw_v, cout);
27676fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
2768b2167459SRichard Henderson 
2769b2167459SRichard Henderson     /* Install the new nullification.  */
27700c982a28SRichard Henderson     if (a->cf) {
27716fd0c7bcSRichard Henderson         TCGv_i64 sv = NULL;
2772b47a4a02SSven Schnelle         if (cond_need_sv(a->cf >> 1)) {
2773b2167459SRichard Henderson             /* ??? The lshift is supposed to contribute to overflow.  */
2774b2167459SRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2);
2775b2167459SRichard Henderson         }
2776a751eb31SRichard Henderson         ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv);
2777b2167459SRichard Henderson     }
2778b2167459SRichard Henderson 
277931234768SRichard Henderson     return nullify_end(ctx);
2780b2167459SRichard Henderson }
2781b2167459SRichard Henderson 
27820588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a)
2783b2167459SRichard Henderson {
27840588e061SRichard Henderson     return do_add_imm(ctx, a, false, false);
27850588e061SRichard Henderson }
27860588e061SRichard Henderson 
27870588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a)
27880588e061SRichard Henderson {
27890588e061SRichard Henderson     return do_add_imm(ctx, a, true, false);
27900588e061SRichard Henderson }
27910588e061SRichard Henderson 
27920588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a)
27930588e061SRichard Henderson {
27940588e061SRichard Henderson     return do_add_imm(ctx, a, false, true);
27950588e061SRichard Henderson }
27960588e061SRichard Henderson 
27970588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a)
27980588e061SRichard Henderson {
27990588e061SRichard Henderson     return do_add_imm(ctx, a, true, true);
28000588e061SRichard Henderson }
28010588e061SRichard Henderson 
28020588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a)
28030588e061SRichard Henderson {
28040588e061SRichard Henderson     return do_sub_imm(ctx, a, false);
28050588e061SRichard Henderson }
28060588e061SRichard Henderson 
28070588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
28080588e061SRichard Henderson {
28090588e061SRichard Henderson     return do_sub_imm(ctx, a, true);
28100588e061SRichard Henderson }
28110588e061SRichard Henderson 
2812345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
28130588e061SRichard Henderson {
28146fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
2815b2167459SRichard Henderson 
28160588e061SRichard Henderson     if (a->cf) {
2817b2167459SRichard Henderson         nullify_over(ctx);
2818b2167459SRichard Henderson     }
2819b2167459SRichard Henderson 
28206fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
28210588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
2822345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
2823b2167459SRichard Henderson 
282431234768SRichard Henderson     return nullify_end(ctx);
2825b2167459SRichard Henderson }
2826b2167459SRichard Henderson 
28270843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a,
28280843563fSRichard Henderson                           void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
28290843563fSRichard Henderson {
28300843563fSRichard Henderson     TCGv_i64 r1, r2, dest;
28310843563fSRichard Henderson 
28320843563fSRichard Henderson     if (!ctx->is_pa20) {
28330843563fSRichard Henderson         return false;
28340843563fSRichard Henderson     }
28350843563fSRichard Henderson 
28360843563fSRichard Henderson     nullify_over(ctx);
28370843563fSRichard Henderson 
28380843563fSRichard Henderson     r1 = load_gpr(ctx, a->r1);
28390843563fSRichard Henderson     r2 = load_gpr(ctx, a->r2);
28400843563fSRichard Henderson     dest = dest_gpr(ctx, a->t);
28410843563fSRichard Henderson 
28420843563fSRichard Henderson     fn(dest, r1, r2);
28430843563fSRichard Henderson     save_gpr(ctx, a->t, dest);
28440843563fSRichard Henderson 
28450843563fSRichard Henderson     return nullify_end(ctx);
28460843563fSRichard Henderson }
28470843563fSRichard Henderson 
2848151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a,
2849151f309bSRichard Henderson                              void (*fn)(TCGv_i64, TCGv_i64, int64_t))
2850151f309bSRichard Henderson {
2851151f309bSRichard Henderson     TCGv_i64 r, dest;
2852151f309bSRichard Henderson 
2853151f309bSRichard Henderson     if (!ctx->is_pa20) {
2854151f309bSRichard Henderson         return false;
2855151f309bSRichard Henderson     }
2856151f309bSRichard Henderson 
2857151f309bSRichard Henderson     nullify_over(ctx);
2858151f309bSRichard Henderson 
2859151f309bSRichard Henderson     r = load_gpr(ctx, a->r);
2860151f309bSRichard Henderson     dest = dest_gpr(ctx, a->t);
2861151f309bSRichard Henderson 
2862151f309bSRichard Henderson     fn(dest, r, a->i);
2863151f309bSRichard Henderson     save_gpr(ctx, a->t, dest);
2864151f309bSRichard Henderson 
2865151f309bSRichard Henderson     return nullify_end(ctx);
2866151f309bSRichard Henderson }
2867151f309bSRichard Henderson 
28683bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a,
28693bbb8e48SRichard Henderson                                 void (*fn)(TCGv_i64, TCGv_i64,
28703bbb8e48SRichard Henderson                                            TCGv_i64, TCGv_i32))
28713bbb8e48SRichard Henderson {
28723bbb8e48SRichard Henderson     TCGv_i64 r1, r2, dest;
28733bbb8e48SRichard Henderson 
28743bbb8e48SRichard Henderson     if (!ctx->is_pa20) {
28753bbb8e48SRichard Henderson         return false;
28763bbb8e48SRichard Henderson     }
28773bbb8e48SRichard Henderson 
28783bbb8e48SRichard Henderson     nullify_over(ctx);
28793bbb8e48SRichard Henderson 
28803bbb8e48SRichard Henderson     r1 = load_gpr(ctx, a->r1);
28813bbb8e48SRichard Henderson     r2 = load_gpr(ctx, a->r2);
28823bbb8e48SRichard Henderson     dest = dest_gpr(ctx, a->t);
28833bbb8e48SRichard Henderson 
28843bbb8e48SRichard Henderson     fn(dest, r1, r2, tcg_constant_i32(a->sh));
28853bbb8e48SRichard Henderson     save_gpr(ctx, a->t, dest);
28863bbb8e48SRichard Henderson 
28873bbb8e48SRichard Henderson     return nullify_end(ctx);
28883bbb8e48SRichard Henderson }
28893bbb8e48SRichard Henderson 
28900843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a)
28910843563fSRichard Henderson {
28920843563fSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_add16_i64);
28930843563fSRichard Henderson }
28940843563fSRichard Henderson 
28950843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a)
28960843563fSRichard Henderson {
28970843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_ss);
28980843563fSRichard Henderson }
28990843563fSRichard Henderson 
29000843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a)
29010843563fSRichard Henderson {
29020843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_us);
29030843563fSRichard Henderson }
29040843563fSRichard Henderson 
29051b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a)
29061b3cb7c8SRichard Henderson {
29071b3cb7c8SRichard Henderson     return do_multimedia(ctx, a, gen_helper_havg);
29081b3cb7c8SRichard Henderson }
29091b3cb7c8SRichard Henderson 
2910151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a)
2911151f309bSRichard Henderson {
2912151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64);
2913151f309bSRichard Henderson }
2914151f309bSRichard Henderson 
2915151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a)
2916151f309bSRichard Henderson {
2917151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64);
2918151f309bSRichard Henderson }
2919151f309bSRichard Henderson 
2920151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a)
2921151f309bSRichard Henderson {
2922151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64);
2923151f309bSRichard Henderson }
2924151f309bSRichard Henderson 
29253bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a)
29263bbb8e48SRichard Henderson {
29273bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshladd);
29283bbb8e48SRichard Henderson }
29293bbb8e48SRichard Henderson 
29303bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a)
29313bbb8e48SRichard Henderson {
29323bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshradd);
29333bbb8e48SRichard Henderson }
29343bbb8e48SRichard Henderson 
293510c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a)
293610c9e58dSRichard Henderson {
293710c9e58dSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64);
293810c9e58dSRichard Henderson }
293910c9e58dSRichard Henderson 
294010c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a)
294110c9e58dSRichard Henderson {
294210c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_ss);
294310c9e58dSRichard Henderson }
294410c9e58dSRichard Henderson 
294510c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a)
294610c9e58dSRichard Henderson {
294710c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_us);
294810c9e58dSRichard Henderson }
294910c9e58dSRichard Henderson 
2950c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2951c2a7ee3fSRichard Henderson {
2952c2a7ee3fSRichard Henderson     uint64_t mask = 0xffff0000ffff0000ull;
2953c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2954c2a7ee3fSRichard Henderson 
2955c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r2, mask);
2956c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r1, mask);
2957c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, tmp, 16);
2958c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
2959c2a7ee3fSRichard Henderson }
2960c2a7ee3fSRichard Henderson 
2961c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a)
2962c2a7ee3fSRichard Henderson {
2963c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_l);
2964c2a7ee3fSRichard Henderson }
2965c2a7ee3fSRichard Henderson 
2966c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2967c2a7ee3fSRichard Henderson {
2968c2a7ee3fSRichard Henderson     uint64_t mask = 0x0000ffff0000ffffull;
2969c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2970c2a7ee3fSRichard Henderson 
2971c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r1, mask);
2972c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r2, mask);
2973c2a7ee3fSRichard Henderson     tcg_gen_shli_i64(tmp, tmp, 16);
2974c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
2975c2a7ee3fSRichard Henderson }
2976c2a7ee3fSRichard Henderson 
2977c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a)
2978c2a7ee3fSRichard Henderson {
2979c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_r);
2980c2a7ee3fSRichard Henderson }
2981c2a7ee3fSRichard Henderson 
2982c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2983c2a7ee3fSRichard Henderson {
2984c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2985c2a7ee3fSRichard Henderson 
2986c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, r2, 32);
2987c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r1, tmp, 0, 32);
2988c2a7ee3fSRichard Henderson }
2989c2a7ee3fSRichard Henderson 
2990c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a)
2991c2a7ee3fSRichard Henderson {
2992c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_l);
2993c2a7ee3fSRichard Henderson }
2994c2a7ee3fSRichard Henderson 
2995c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2996c2a7ee3fSRichard Henderson {
2997c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r2, r1, 32, 32);
2998c2a7ee3fSRichard Henderson }
2999c2a7ee3fSRichard Henderson 
3000c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a)
3001c2a7ee3fSRichard Henderson {
3002c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_r);
3003c2a7ee3fSRichard Henderson }
3004c2a7ee3fSRichard Henderson 
30054e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a)
30064e7abdb1SRichard Henderson {
30074e7abdb1SRichard Henderson     TCGv_i64 r, t0, t1, t2, t3;
30084e7abdb1SRichard Henderson 
30094e7abdb1SRichard Henderson     if (!ctx->is_pa20) {
30104e7abdb1SRichard Henderson         return false;
30114e7abdb1SRichard Henderson     }
30124e7abdb1SRichard Henderson 
30134e7abdb1SRichard Henderson     nullify_over(ctx);
30144e7abdb1SRichard Henderson 
30154e7abdb1SRichard Henderson     r = load_gpr(ctx, a->r1);
30164e7abdb1SRichard Henderson     t0 = tcg_temp_new_i64();
30174e7abdb1SRichard Henderson     t1 = tcg_temp_new_i64();
30184e7abdb1SRichard Henderson     t2 = tcg_temp_new_i64();
30194e7abdb1SRichard Henderson     t3 = tcg_temp_new_i64();
30204e7abdb1SRichard Henderson 
30214e7abdb1SRichard Henderson     tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16);
30224e7abdb1SRichard Henderson     tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16);
30234e7abdb1SRichard Henderson     tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16);
30244e7abdb1SRichard Henderson     tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16);
30254e7abdb1SRichard Henderson 
30264e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t1, t0, 16, 48);
30274e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t2, t3, t2, 16, 48);
30284e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t2, t0, 32, 32);
30294e7abdb1SRichard Henderson 
30304e7abdb1SRichard Henderson     save_gpr(ctx, a->t, t0);
30314e7abdb1SRichard Henderson     return nullify_end(ctx);
30324e7abdb1SRichard Henderson }
30334e7abdb1SRichard Henderson 
30341cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a)
303596d6407fSRichard Henderson {
3036b5caa17cSRichard Henderson     if (ctx->is_pa20) {
3037b5caa17cSRichard Henderson        /*
3038b5caa17cSRichard Henderson         * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches.
3039b5caa17cSRichard Henderson         * Any base modification still occurs.
3040b5caa17cSRichard Henderson         */
3041b5caa17cSRichard Henderson         if (a->t == 0) {
3042b5caa17cSRichard Henderson             return trans_nop_addrx(ctx, a);
3043b5caa17cSRichard Henderson         }
3044b5caa17cSRichard Henderson     } else if (a->size > MO_32) {
30450786a3b6SHelge Deller         return gen_illegal(ctx);
3046c53e401eSRichard Henderson     }
30471cd012a5SRichard Henderson     return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
30481cd012a5SRichard Henderson                    a->disp, a->sp, a->m, a->size | MO_TE);
304996d6407fSRichard Henderson }
305096d6407fSRichard Henderson 
30511cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a)
305296d6407fSRichard Henderson {
30531cd012a5SRichard Henderson     assert(a->x == 0 && a->scale == 0);
3054c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
30550786a3b6SHelge Deller         return gen_illegal(ctx);
305696d6407fSRichard Henderson     }
3057c53e401eSRichard Henderson     return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
30580786a3b6SHelge Deller }
305996d6407fSRichard Henderson 
30601cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
306196d6407fSRichard Henderson {
3062b1af755cSRichard Henderson     MemOp mop = MO_TE | MO_ALIGN | a->size;
3063a4db4a78SRichard Henderson     TCGv_i64 dest, ofs;
30646fd0c7bcSRichard Henderson     TCGv_i64 addr;
306596d6407fSRichard Henderson 
3066c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
306751416c4eSRichard Henderson         return gen_illegal(ctx);
306851416c4eSRichard Henderson     }
306951416c4eSRichard Henderson 
307096d6407fSRichard Henderson     nullify_over(ctx);
307196d6407fSRichard Henderson 
30721cd012a5SRichard Henderson     if (a->m) {
307386f8d05fSRichard Henderson         /* Base register modification.  Make sure if RT == RB,
307486f8d05fSRichard Henderson            we see the result of the load.  */
3075aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
307696d6407fSRichard Henderson     } else {
30771cd012a5SRichard Henderson         dest = dest_gpr(ctx, a->t);
307896d6407fSRichard Henderson     }
307996d6407fSRichard Henderson 
30801cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0,
30811cd012a5SRichard Henderson              a->disp, a->sp, a->m, ctx->mmu_idx == MMU_PHYS_IDX);
3082b1af755cSRichard Henderson 
3083b1af755cSRichard Henderson     /*
3084b1af755cSRichard Henderson      * For hppa1.1, LDCW is undefined unless aligned mod 16.
3085b1af755cSRichard Henderson      * However actual hardware succeeds with aligned mod 4.
3086b1af755cSRichard Henderson      * Detect this case and log a GUEST_ERROR.
3087b1af755cSRichard Henderson      *
3088b1af755cSRichard Henderson      * TODO: HPPA64 relaxes the over-alignment requirement
3089b1af755cSRichard Henderson      * with the ,co completer.
3090b1af755cSRichard Henderson      */
3091b1af755cSRichard Henderson     gen_helper_ldc_check(addr);
3092b1af755cSRichard Henderson 
3093a4db4a78SRichard Henderson     tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop);
3094b1af755cSRichard Henderson 
30951cd012a5SRichard Henderson     if (a->m) {
30961cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
309796d6407fSRichard Henderson     }
30981cd012a5SRichard Henderson     save_gpr(ctx, a->t, dest);
309996d6407fSRichard Henderson 
310031234768SRichard Henderson     return nullify_end(ctx);
310196d6407fSRichard Henderson }
310296d6407fSRichard Henderson 
31031cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a)
310496d6407fSRichard Henderson {
31056fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
31066fd0c7bcSRichard Henderson     TCGv_i64 addr;
310796d6407fSRichard Henderson 
310896d6407fSRichard Henderson     nullify_over(ctx);
310996d6407fSRichard Henderson 
31101cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
311186f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
31121cd012a5SRichard Henderson     val = load_gpr(ctx, a->r);
31131cd012a5SRichard Henderson     if (a->a) {
3114f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3115ad75a51eSRichard Henderson             gen_helper_stby_e_parallel(tcg_env, addr, val);
3116f9f46db4SEmilio G. Cota         } else {
3117ad75a51eSRichard Henderson             gen_helper_stby_e(tcg_env, addr, val);
3118f9f46db4SEmilio G. Cota         }
3119f9f46db4SEmilio G. Cota     } else {
3120f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3121ad75a51eSRichard Henderson             gen_helper_stby_b_parallel(tcg_env, addr, val);
312296d6407fSRichard Henderson         } else {
3123ad75a51eSRichard Henderson             gen_helper_stby_b(tcg_env, addr, val);
312496d6407fSRichard Henderson         }
3125f9f46db4SEmilio G. Cota     }
31261cd012a5SRichard Henderson     if (a->m) {
31276fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~3);
31281cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
312996d6407fSRichard Henderson     }
313096d6407fSRichard Henderson 
313131234768SRichard Henderson     return nullify_end(ctx);
313296d6407fSRichard Henderson }
313396d6407fSRichard Henderson 
313425460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a)
313525460fc5SRichard Henderson {
31366fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
31376fd0c7bcSRichard Henderson     TCGv_i64 addr;
313825460fc5SRichard Henderson 
313925460fc5SRichard Henderson     if (!ctx->is_pa20) {
314025460fc5SRichard Henderson         return false;
314125460fc5SRichard Henderson     }
314225460fc5SRichard Henderson     nullify_over(ctx);
314325460fc5SRichard Henderson 
314425460fc5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
314525460fc5SRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
314625460fc5SRichard Henderson     val = load_gpr(ctx, a->r);
314725460fc5SRichard Henderson     if (a->a) {
314825460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
314925460fc5SRichard Henderson             gen_helper_stdby_e_parallel(tcg_env, addr, val);
315025460fc5SRichard Henderson         } else {
315125460fc5SRichard Henderson             gen_helper_stdby_e(tcg_env, addr, val);
315225460fc5SRichard Henderson         }
315325460fc5SRichard Henderson     } else {
315425460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
315525460fc5SRichard Henderson             gen_helper_stdby_b_parallel(tcg_env, addr, val);
315625460fc5SRichard Henderson         } else {
315725460fc5SRichard Henderson             gen_helper_stdby_b(tcg_env, addr, val);
315825460fc5SRichard Henderson         }
315925460fc5SRichard Henderson     }
316025460fc5SRichard Henderson     if (a->m) {
31616fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~7);
316225460fc5SRichard Henderson         save_gpr(ctx, a->b, ofs);
316325460fc5SRichard Henderson     }
316425460fc5SRichard Henderson 
316525460fc5SRichard Henderson     return nullify_end(ctx);
316625460fc5SRichard Henderson }
316725460fc5SRichard Henderson 
31681cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a)
3169d0a851ccSRichard Henderson {
3170d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3171d0a851ccSRichard Henderson 
3172d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3173d0a851ccSRichard Henderson     ctx->mmu_idx = MMU_PHYS_IDX;
31741cd012a5SRichard Henderson     trans_ld(ctx, a);
3175d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
317631234768SRichard Henderson     return true;
3177d0a851ccSRichard Henderson }
3178d0a851ccSRichard Henderson 
31791cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a)
3180d0a851ccSRichard Henderson {
3181d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3182d0a851ccSRichard Henderson 
3183d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3184d0a851ccSRichard Henderson     ctx->mmu_idx = MMU_PHYS_IDX;
31851cd012a5SRichard Henderson     trans_st(ctx, a);
3186d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
318731234768SRichard Henderson     return true;
3188d0a851ccSRichard Henderson }
318995412a61SRichard Henderson 
31900588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
3191b2167459SRichard Henderson {
31926fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3193b2167459SRichard Henderson 
31946fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tcg_rt, a->i);
31950588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3196b2167459SRichard Henderson     cond_free(&ctx->null_cond);
319731234768SRichard Henderson     return true;
3198b2167459SRichard Henderson }
3199b2167459SRichard Henderson 
32000588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a)
3201b2167459SRichard Henderson {
32026fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
32036fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
3204b2167459SRichard Henderson 
32056fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
3206b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
3207b2167459SRichard Henderson     cond_free(&ctx->null_cond);
320831234768SRichard Henderson     return true;
3209b2167459SRichard Henderson }
3210b2167459SRichard Henderson 
32110588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
3212b2167459SRichard Henderson {
32136fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3214b2167459SRichard Henderson 
3215b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
3216d265360fSRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_i64.  */
32170588e061SRichard Henderson     if (a->b == 0) {
32186fd0c7bcSRichard Henderson         tcg_gen_movi_i64(tcg_rt, a->i);
3219b2167459SRichard Henderson     } else {
32206fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
3221b2167459SRichard Henderson     }
32220588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3223b2167459SRichard Henderson     cond_free(&ctx->null_cond);
322431234768SRichard Henderson     return true;
3225b2167459SRichard Henderson }
3226b2167459SRichard Henderson 
32276fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
3228e9efd4bcSRichard Henderson                     unsigned c, unsigned f, bool d, unsigned n, int disp)
322998cd9ca7SRichard Henderson {
32306fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv;
323198cd9ca7SRichard Henderson     DisasCond cond;
323298cd9ca7SRichard Henderson 
323398cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3234aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
323598cd9ca7SRichard Henderson 
32366fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
323798cd9ca7SRichard Henderson 
3238f764718dSRichard Henderson     sv = NULL;
3239b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
324098cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
324198cd9ca7SRichard Henderson     }
324298cd9ca7SRichard Henderson 
32434fe9533aSRichard Henderson     cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
324401afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
324598cd9ca7SRichard Henderson }
324698cd9ca7SRichard Henderson 
324701afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
324898cd9ca7SRichard Henderson {
3249e9efd4bcSRichard Henderson     if (!ctx->is_pa20 && a->d) {
3250e9efd4bcSRichard Henderson         return false;
3251e9efd4bcSRichard Henderson     }
325201afb7beSRichard Henderson     nullify_over(ctx);
3253e9efd4bcSRichard Henderson     return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
3254e9efd4bcSRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
325501afb7beSRichard Henderson }
325601afb7beSRichard Henderson 
325701afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
325801afb7beSRichard Henderson {
3259c65c3ee1SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3260c65c3ee1SRichard Henderson         return false;
3261c65c3ee1SRichard Henderson     }
326201afb7beSRichard Henderson     nullify_over(ctx);
32636fd0c7bcSRichard Henderson     return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
3264c65c3ee1SRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
326501afb7beSRichard Henderson }
326601afb7beSRichard Henderson 
32676fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
326801afb7beSRichard Henderson                     unsigned c, unsigned f, unsigned n, int disp)
326901afb7beSRichard Henderson {
32706fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv, cb_cond;
327198cd9ca7SRichard Henderson     DisasCond cond;
3272bdcccc17SRichard Henderson     bool d = false;
327398cd9ca7SRichard Henderson 
3274f25d3160SRichard Henderson     /*
3275f25d3160SRichard Henderson      * For hppa64, the ADDB conditions change with PSW.W,
3276f25d3160SRichard Henderson      * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3277f25d3160SRichard Henderson      */
3278f25d3160SRichard Henderson     if (ctx->tb_flags & PSW_W) {
3279f25d3160SRichard Henderson         d = c >= 5;
3280f25d3160SRichard Henderson         if (d) {
3281f25d3160SRichard Henderson             c &= 3;
3282f25d3160SRichard Henderson         }
3283f25d3160SRichard Henderson     }
3284f25d3160SRichard Henderson 
328598cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3286aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
3287f764718dSRichard Henderson     sv = NULL;
3288bdcccc17SRichard Henderson     cb_cond = NULL;
328998cd9ca7SRichard Henderson 
3290b47a4a02SSven Schnelle     if (cond_need_cb(c)) {
3291aac0f603SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
3292aac0f603SRichard Henderson         TCGv_i64 cb_msb = tcg_temp_new_i64();
3293bdcccc17SRichard Henderson 
32946fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cb_msb, 0);
32956fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
32966fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
32976fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
3298bdcccc17SRichard Henderson         cb_cond = get_carry(ctx, d, cb, cb_msb);
3299b47a4a02SSven Schnelle     } else {
33006fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
3301b47a4a02SSven Schnelle     }
3302b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
330398cd9ca7SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
330498cd9ca7SRichard Henderson     }
330598cd9ca7SRichard Henderson 
3306a751eb31SRichard Henderson     cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
330743675d20SSven Schnelle     save_gpr(ctx, r, dest);
330801afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
330998cd9ca7SRichard Henderson }
331098cd9ca7SRichard Henderson 
331101afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a)
331298cd9ca7SRichard Henderson {
331301afb7beSRichard Henderson     nullify_over(ctx);
331401afb7beSRichard Henderson     return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
331501afb7beSRichard Henderson }
331601afb7beSRichard Henderson 
331701afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
331801afb7beSRichard Henderson {
331901afb7beSRichard Henderson     nullify_over(ctx);
33206fd0c7bcSRichard Henderson     return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
332101afb7beSRichard Henderson }
332201afb7beSRichard Henderson 
332301afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
332401afb7beSRichard Henderson {
33256fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
332698cd9ca7SRichard Henderson     DisasCond cond;
332798cd9ca7SRichard Henderson 
332898cd9ca7SRichard Henderson     nullify_over(ctx);
332998cd9ca7SRichard Henderson 
3330aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
333101afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
333284e224d4SRichard Henderson     if (cond_need_ext(ctx, a->d)) {
33331e9ab9fbSRichard Henderson         /* Force shift into [32,63] */
33346fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_sar, 32);
33356fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, tmp);
33361e9ab9fbSRichard Henderson     } else {
33376fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
33381e9ab9fbSRichard Henderson     }
333998cd9ca7SRichard Henderson 
33401e9ab9fbSRichard Henderson     cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
334101afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
334298cd9ca7SRichard Henderson }
334398cd9ca7SRichard Henderson 
334401afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
334598cd9ca7SRichard Henderson {
33466fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
334701afb7beSRichard Henderson     DisasCond cond;
33481e9ab9fbSRichard Henderson     int p;
334901afb7beSRichard Henderson 
335001afb7beSRichard Henderson     nullify_over(ctx);
335101afb7beSRichard Henderson 
3352aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
335301afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
335484e224d4SRichard Henderson     p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0);
33556fd0c7bcSRichard Henderson     tcg_gen_shli_i64(tmp, tcg_r, p);
335601afb7beSRichard Henderson 
335701afb7beSRichard Henderson     cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
335801afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
335901afb7beSRichard Henderson }
336001afb7beSRichard Henderson 
336101afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a)
336201afb7beSRichard Henderson {
33636fd0c7bcSRichard Henderson     TCGv_i64 dest;
336498cd9ca7SRichard Henderson     DisasCond cond;
336598cd9ca7SRichard Henderson 
336698cd9ca7SRichard Henderson     nullify_over(ctx);
336798cd9ca7SRichard Henderson 
336801afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r2);
336901afb7beSRichard Henderson     if (a->r1 == 0) {
33706fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, 0);
337198cd9ca7SRichard Henderson     } else {
33726fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
337398cd9ca7SRichard Henderson     }
337498cd9ca7SRichard Henderson 
33754fa52edfSRichard Henderson     /* All MOVB conditions are 32-bit. */
33764fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
337701afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
337801afb7beSRichard Henderson }
337901afb7beSRichard Henderson 
338001afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
338101afb7beSRichard Henderson {
33826fd0c7bcSRichard Henderson     TCGv_i64 dest;
338301afb7beSRichard Henderson     DisasCond cond;
338401afb7beSRichard Henderson 
338501afb7beSRichard Henderson     nullify_over(ctx);
338601afb7beSRichard Henderson 
338701afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r);
33886fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, a->i);
338901afb7beSRichard Henderson 
33904fa52edfSRichard Henderson     /* All MOVBI conditions are 32-bit. */
33914fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
339201afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
339398cd9ca7SRichard Henderson }
339498cd9ca7SRichard Henderson 
3395f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
33960b1347d2SRichard Henderson {
33976fd0c7bcSRichard Henderson     TCGv_i64 dest, src2;
33980b1347d2SRichard Henderson 
3399f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3400f7b775a9SRichard Henderson         return false;
3401f7b775a9SRichard Henderson     }
340230878590SRichard Henderson     if (a->c) {
34030b1347d2SRichard Henderson         nullify_over(ctx);
34040b1347d2SRichard Henderson     }
34050b1347d2SRichard Henderson 
340630878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
3407f7b775a9SRichard Henderson     src2 = load_gpr(ctx, a->r2);
340830878590SRichard Henderson     if (a->r1 == 0) {
3409f7b775a9SRichard Henderson         if (a->d) {
34106fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src2, cpu_sar);
3411f7b775a9SRichard Henderson         } else {
3412aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
3413f7b775a9SRichard Henderson 
34146fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src2);
34156fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
34166fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, dest, tmp);
3417f7b775a9SRichard Henderson         }
341830878590SRichard Henderson     } else if (a->r1 == a->r2) {
3419f7b775a9SRichard Henderson         if (a->d) {
34206fd0c7bcSRichard Henderson             tcg_gen_rotr_i64(dest, src2, cpu_sar);
3421f7b775a9SRichard Henderson         } else {
34220b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
3423e1d635e8SRichard Henderson             TCGv_i32 s32 = tcg_temp_new_i32();
3424e1d635e8SRichard Henderson 
34256fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, src2);
34266fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(s32, cpu_sar);
3427f7b775a9SRichard Henderson             tcg_gen_andi_i32(s32, s32, 31);
3428e1d635e8SRichard Henderson             tcg_gen_rotr_i32(t32, t32, s32);
34296fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
3430f7b775a9SRichard Henderson         }
3431f7b775a9SRichard Henderson     } else {
34326fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
3433f7b775a9SRichard Henderson 
3434f7b775a9SRichard Henderson         if (a->d) {
3435aac0f603SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
3436aac0f603SRichard Henderson             TCGv_i64 n = tcg_temp_new_i64();
3437f7b775a9SRichard Henderson 
34386fd0c7bcSRichard Henderson             tcg_gen_xori_i64(n, cpu_sar, 63);
34396fd0c7bcSRichard Henderson             tcg_gen_shl_i64(t, src2, n);
34406fd0c7bcSRichard Henderson             tcg_gen_shli_i64(t, t, 1);
34416fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src1, cpu_sar);
34426fd0c7bcSRichard Henderson             tcg_gen_or_i64(dest, dest, t);
34430b1347d2SRichard Henderson         } else {
34440b1347d2SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
34450b1347d2SRichard Henderson             TCGv_i64 s = tcg_temp_new_i64();
34460b1347d2SRichard Henderson 
34476fd0c7bcSRichard Henderson             tcg_gen_concat32_i64(t, src2, src1);
3448967662cdSRichard Henderson             tcg_gen_andi_i64(s, cpu_sar, 31);
3449967662cdSRichard Henderson             tcg_gen_shr_i64(dest, t, s);
34500b1347d2SRichard Henderson         }
3451f7b775a9SRichard Henderson     }
345230878590SRichard Henderson     save_gpr(ctx, a->t, dest);
34530b1347d2SRichard Henderson 
34540b1347d2SRichard Henderson     /* Install the new nullification.  */
34550b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
345630878590SRichard Henderson     if (a->c) {
34574fa52edfSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
34580b1347d2SRichard Henderson     }
345931234768SRichard Henderson     return nullify_end(ctx);
34600b1347d2SRichard Henderson }
34610b1347d2SRichard Henderson 
3462f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
34630b1347d2SRichard Henderson {
3464f7b775a9SRichard Henderson     unsigned width, sa;
34656fd0c7bcSRichard Henderson     TCGv_i64 dest, t2;
34660b1347d2SRichard Henderson 
3467f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3468f7b775a9SRichard Henderson         return false;
3469f7b775a9SRichard Henderson     }
347030878590SRichard Henderson     if (a->c) {
34710b1347d2SRichard Henderson         nullify_over(ctx);
34720b1347d2SRichard Henderson     }
34730b1347d2SRichard Henderson 
3474f7b775a9SRichard Henderson     width = a->d ? 64 : 32;
3475f7b775a9SRichard Henderson     sa = width - 1 - a->cpos;
3476f7b775a9SRichard Henderson 
347730878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
347830878590SRichard Henderson     t2 = load_gpr(ctx, a->r2);
347905bfd4dbSRichard Henderson     if (a->r1 == 0) {
34806fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, t2, sa, width - sa);
3481c53e401eSRichard Henderson     } else if (width == TARGET_LONG_BITS) {
34826fd0c7bcSRichard Henderson         tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
3483f7b775a9SRichard Henderson     } else {
3484f7b775a9SRichard Henderson         assert(!a->d);
3485f7b775a9SRichard Henderson         if (a->r1 == a->r2) {
34860b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
34876fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, t2);
34880b1347d2SRichard Henderson             tcg_gen_rotri_i32(t32, t32, sa);
34896fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
34900b1347d2SRichard Henderson         } else {
3491967662cdSRichard Henderson             tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]);
3492967662cdSRichard Henderson             tcg_gen_extract_i64(dest, dest, sa, 32);
34930b1347d2SRichard Henderson         }
3494f7b775a9SRichard Henderson     }
349530878590SRichard Henderson     save_gpr(ctx, a->t, dest);
34960b1347d2SRichard Henderson 
34970b1347d2SRichard Henderson     /* Install the new nullification.  */
34980b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
349930878590SRichard Henderson     if (a->c) {
35004fa52edfSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
35010b1347d2SRichard Henderson     }
350231234768SRichard Henderson     return nullify_end(ctx);
35030b1347d2SRichard Henderson }
35040b1347d2SRichard Henderson 
3505bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
35060b1347d2SRichard Henderson {
3507bd792da3SRichard Henderson     unsigned widthm1 = a->d ? 63 : 31;
35086fd0c7bcSRichard Henderson     TCGv_i64 dest, src, tmp;
35090b1347d2SRichard Henderson 
3510bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3511bd792da3SRichard Henderson         return false;
3512bd792da3SRichard Henderson     }
351330878590SRichard Henderson     if (a->c) {
35140b1347d2SRichard Henderson         nullify_over(ctx);
35150b1347d2SRichard Henderson     }
35160b1347d2SRichard Henderson 
351730878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
351830878590SRichard Henderson     src = load_gpr(ctx, a->r);
3519aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
35200b1347d2SRichard Henderson 
35210b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
35226fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
35236fd0c7bcSRichard Henderson     tcg_gen_xori_i64(tmp, tmp, widthm1);
3524d781cb77SRichard Henderson 
352530878590SRichard Henderson     if (a->se) {
3526bd792da3SRichard Henderson         if (!a->d) {
35276fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(dest, src);
3528bd792da3SRichard Henderson             src = dest;
3529bd792da3SRichard Henderson         }
35306fd0c7bcSRichard Henderson         tcg_gen_sar_i64(dest, src, tmp);
35316fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, dest, 0, a->len);
35320b1347d2SRichard Henderson     } else {
3533bd792da3SRichard Henderson         if (!a->d) {
35346fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src);
3535bd792da3SRichard Henderson             src = dest;
3536bd792da3SRichard Henderson         }
35376fd0c7bcSRichard Henderson         tcg_gen_shr_i64(dest, src, tmp);
35386fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, dest, 0, a->len);
35390b1347d2SRichard Henderson     }
354030878590SRichard Henderson     save_gpr(ctx, a->t, dest);
35410b1347d2SRichard Henderson 
35420b1347d2SRichard Henderson     /* Install the new nullification.  */
35430b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
354430878590SRichard Henderson     if (a->c) {
3545bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
35460b1347d2SRichard Henderson     }
354731234768SRichard Henderson     return nullify_end(ctx);
35480b1347d2SRichard Henderson }
35490b1347d2SRichard Henderson 
3550bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
35510b1347d2SRichard Henderson {
3552bd792da3SRichard Henderson     unsigned len, cpos, width;
35536fd0c7bcSRichard Henderson     TCGv_i64 dest, src;
35540b1347d2SRichard Henderson 
3555bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3556bd792da3SRichard Henderson         return false;
3557bd792da3SRichard Henderson     }
355830878590SRichard Henderson     if (a->c) {
35590b1347d2SRichard Henderson         nullify_over(ctx);
35600b1347d2SRichard Henderson     }
35610b1347d2SRichard Henderson 
3562bd792da3SRichard Henderson     len = a->len;
3563bd792da3SRichard Henderson     width = a->d ? 64 : 32;
3564bd792da3SRichard Henderson     cpos = width - 1 - a->pos;
3565bd792da3SRichard Henderson     if (cpos + len > width) {
3566bd792da3SRichard Henderson         len = width - cpos;
3567bd792da3SRichard Henderson     }
3568bd792da3SRichard Henderson 
356930878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
357030878590SRichard Henderson     src = load_gpr(ctx, a->r);
357130878590SRichard Henderson     if (a->se) {
35726fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, src, cpos, len);
35730b1347d2SRichard Henderson     } else {
35746fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, src, cpos, len);
35750b1347d2SRichard Henderson     }
357630878590SRichard Henderson     save_gpr(ctx, a->t, dest);
35770b1347d2SRichard Henderson 
35780b1347d2SRichard Henderson     /* Install the new nullification.  */
35790b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
358030878590SRichard Henderson     if (a->c) {
3581bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
35820b1347d2SRichard Henderson     }
358331234768SRichard Henderson     return nullify_end(ctx);
35840b1347d2SRichard Henderson }
35850b1347d2SRichard Henderson 
358672ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
35870b1347d2SRichard Henderson {
358872ae4f2bSRichard Henderson     unsigned len, width;
3589c53e401eSRichard Henderson     uint64_t mask0, mask1;
35906fd0c7bcSRichard Henderson     TCGv_i64 dest;
35910b1347d2SRichard Henderson 
359272ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
359372ae4f2bSRichard Henderson         return false;
359472ae4f2bSRichard Henderson     }
359530878590SRichard Henderson     if (a->c) {
35960b1347d2SRichard Henderson         nullify_over(ctx);
35970b1347d2SRichard Henderson     }
359872ae4f2bSRichard Henderson 
359972ae4f2bSRichard Henderson     len = a->len;
360072ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
360172ae4f2bSRichard Henderson     if (a->cpos + len > width) {
360272ae4f2bSRichard Henderson         len = width - a->cpos;
36030b1347d2SRichard Henderson     }
36040b1347d2SRichard Henderson 
360530878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
360630878590SRichard Henderson     mask0 = deposit64(0, a->cpos, len, a->i);
360730878590SRichard Henderson     mask1 = deposit64(-1, a->cpos, len, a->i);
36080b1347d2SRichard Henderson 
360930878590SRichard Henderson     if (a->nz) {
36106fd0c7bcSRichard Henderson         TCGv_i64 src = load_gpr(ctx, a->t);
36116fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, src, mask1);
36126fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, mask0);
36130b1347d2SRichard Henderson     } else {
36146fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, mask0);
36150b1347d2SRichard Henderson     }
361630878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36170b1347d2SRichard Henderson 
36180b1347d2SRichard Henderson     /* Install the new nullification.  */
36190b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
362030878590SRichard Henderson     if (a->c) {
362172ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
36220b1347d2SRichard Henderson     }
362331234768SRichard Henderson     return nullify_end(ctx);
36240b1347d2SRichard Henderson }
36250b1347d2SRichard Henderson 
362672ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
36270b1347d2SRichard Henderson {
362830878590SRichard Henderson     unsigned rs = a->nz ? a->t : 0;
362972ae4f2bSRichard Henderson     unsigned len, width;
36306fd0c7bcSRichard Henderson     TCGv_i64 dest, val;
36310b1347d2SRichard Henderson 
363272ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
363372ae4f2bSRichard Henderson         return false;
363472ae4f2bSRichard Henderson     }
363530878590SRichard Henderson     if (a->c) {
36360b1347d2SRichard Henderson         nullify_over(ctx);
36370b1347d2SRichard Henderson     }
363872ae4f2bSRichard Henderson 
363972ae4f2bSRichard Henderson     len = a->len;
364072ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
364172ae4f2bSRichard Henderson     if (a->cpos + len > width) {
364272ae4f2bSRichard Henderson         len = width - a->cpos;
36430b1347d2SRichard Henderson     }
36440b1347d2SRichard Henderson 
364530878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
364630878590SRichard Henderson     val = load_gpr(ctx, a->r);
36470b1347d2SRichard Henderson     if (rs == 0) {
36486fd0c7bcSRichard Henderson         tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
36490b1347d2SRichard Henderson     } else {
36506fd0c7bcSRichard Henderson         tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
36510b1347d2SRichard Henderson     }
365230878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36530b1347d2SRichard Henderson 
36540b1347d2SRichard Henderson     /* Install the new nullification.  */
36550b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
365630878590SRichard Henderson     if (a->c) {
365772ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
36580b1347d2SRichard Henderson     }
365931234768SRichard Henderson     return nullify_end(ctx);
36600b1347d2SRichard Henderson }
36610b1347d2SRichard Henderson 
366272ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
36636fd0c7bcSRichard Henderson                        bool d, bool nz, unsigned len, TCGv_i64 val)
36640b1347d2SRichard Henderson {
36650b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
366672ae4f2bSRichard Henderson     unsigned widthm1 = d ? 63 : 31;
36676fd0c7bcSRichard Henderson     TCGv_i64 mask, tmp, shift, dest;
3668c53e401eSRichard Henderson     uint64_t msb = 1ULL << (len - 1);
36690b1347d2SRichard Henderson 
36700b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
3671aac0f603SRichard Henderson     shift = tcg_temp_new_i64();
3672aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
36730b1347d2SRichard Henderson 
36740b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
36756fd0c7bcSRichard Henderson     tcg_gen_andi_i64(shift, cpu_sar, widthm1);
36766fd0c7bcSRichard Henderson     tcg_gen_xori_i64(shift, shift, widthm1);
36770b1347d2SRichard Henderson 
3678aac0f603SRichard Henderson     mask = tcg_temp_new_i64();
36796fd0c7bcSRichard Henderson     tcg_gen_movi_i64(mask, msb + (msb - 1));
36806fd0c7bcSRichard Henderson     tcg_gen_and_i64(tmp, val, mask);
36810b1347d2SRichard Henderson     if (rs) {
36826fd0c7bcSRichard Henderson         tcg_gen_shl_i64(mask, mask, shift);
36836fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tmp, shift);
36846fd0c7bcSRichard Henderson         tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
36856fd0c7bcSRichard Henderson         tcg_gen_or_i64(dest, dest, tmp);
36860b1347d2SRichard Henderson     } else {
36876fd0c7bcSRichard Henderson         tcg_gen_shl_i64(dest, tmp, shift);
36880b1347d2SRichard Henderson     }
36890b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
36900b1347d2SRichard Henderson 
36910b1347d2SRichard Henderson     /* Install the new nullification.  */
36920b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
36930b1347d2SRichard Henderson     if (c) {
369472ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, c, d, dest);
36950b1347d2SRichard Henderson     }
369631234768SRichard Henderson     return nullify_end(ctx);
36970b1347d2SRichard Henderson }
36980b1347d2SRichard Henderson 
369972ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
370030878590SRichard Henderson {
370172ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
370272ae4f2bSRichard Henderson         return false;
370372ae4f2bSRichard Henderson     }
3704a6deecceSSven Schnelle     if (a->c) {
3705a6deecceSSven Schnelle         nullify_over(ctx);
3706a6deecceSSven Schnelle     }
370772ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
370872ae4f2bSRichard Henderson                       load_gpr(ctx, a->r));
370930878590SRichard Henderson }
371030878590SRichard Henderson 
371172ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
371230878590SRichard Henderson {
371372ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
371472ae4f2bSRichard Henderson         return false;
371572ae4f2bSRichard Henderson     }
3716a6deecceSSven Schnelle     if (a->c) {
3717a6deecceSSven Schnelle         nullify_over(ctx);
3718a6deecceSSven Schnelle     }
371972ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
37206fd0c7bcSRichard Henderson                       tcg_constant_i64(a->i));
372130878590SRichard Henderson }
37220b1347d2SRichard Henderson 
37238340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a)
372498cd9ca7SRichard Henderson {
37256fd0c7bcSRichard Henderson     TCGv_i64 tmp;
372698cd9ca7SRichard Henderson 
3727c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
372898cd9ca7SRichard Henderson     /* ??? It seems like there should be a good way of using
372998cd9ca7SRichard Henderson        "be disp(sr2, r0)", the canonical gateway entry mechanism
373098cd9ca7SRichard Henderson        to our advantage.  But that appears to be inconvenient to
373198cd9ca7SRichard Henderson        manage along side branch delay slots.  Therefore we handle
373298cd9ca7SRichard Henderson        entry into the gateway page via absolute address.  */
373398cd9ca7SRichard Henderson     /* Since we don't implement spaces, just branch.  Do notice the special
373498cd9ca7SRichard Henderson        case of "be disp(*,r0)" using a direct branch to disp, so that we can
373598cd9ca7SRichard Henderson        goto_tb to the TB containing the syscall.  */
37368340f534SRichard Henderson     if (a->b == 0) {
37378340f534SRichard Henderson         return do_dbranch(ctx, a->disp, a->l, a->n);
373898cd9ca7SRichard Henderson     }
3739c301f34eSRichard Henderson #else
3740c301f34eSRichard Henderson     nullify_over(ctx);
3741660eefe1SRichard Henderson #endif
3742660eefe1SRichard Henderson 
3743aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
37446fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp);
3745660eefe1SRichard Henderson     tmp = do_ibranch_priv(ctx, tmp);
3746c301f34eSRichard Henderson 
3747c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
37488340f534SRichard Henderson     return do_ibranch(ctx, tmp, a->l, a->n);
3749c301f34eSRichard Henderson #else
3750c301f34eSRichard Henderson     TCGv_i64 new_spc = tcg_temp_new_i64();
3751c301f34eSRichard Henderson 
37528340f534SRichard Henderson     load_spr(ctx, new_spc, a->sp);
37538340f534SRichard Henderson     if (a->l) {
3754741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
3755c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f);
3756c301f34eSRichard Henderson     }
37578340f534SRichard Henderson     if (a->n && use_nullify_skip(ctx)) {
3758a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
37596fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, 4);
3760a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3761c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, new_spc);
3762c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f);
3763c301f34eSRichard Henderson     } else {
3764741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3765c301f34eSRichard Henderson         if (ctx->iaoq_b == -1) {
3766c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3767c301f34eSRichard Henderson         }
3768a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3769c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, new_spc);
37708340f534SRichard Henderson         nullify_set(ctx, a->n);
3771c301f34eSRichard Henderson     }
3772c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
377331234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
377431234768SRichard Henderson     return nullify_end(ctx);
3775c301f34eSRichard Henderson #endif
377698cd9ca7SRichard Henderson }
377798cd9ca7SRichard Henderson 
37788340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a)
377998cd9ca7SRichard Henderson {
37808340f534SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n);
378198cd9ca7SRichard Henderson }
378298cd9ca7SRichard Henderson 
37838340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
378443e05652SRichard Henderson {
3785c53e401eSRichard Henderson     uint64_t dest = iaoq_dest(ctx, a->disp);
378643e05652SRichard Henderson 
37876e5f5300SSven Schnelle     nullify_over(ctx);
37886e5f5300SSven Schnelle 
378943e05652SRichard Henderson     /* Make sure the caller hasn't done something weird with the queue.
379043e05652SRichard Henderson      * ??? This is not quite the same as the PSW[B] bit, which would be
379143e05652SRichard Henderson      * expensive to track.  Real hardware will trap for
379243e05652SRichard Henderson      *    b  gateway
379343e05652SRichard Henderson      *    b  gateway+4  (in delay slot of first branch)
379443e05652SRichard Henderson      * However, checking for a non-sequential instruction queue *will*
379543e05652SRichard Henderson      * diagnose the security hole
379643e05652SRichard Henderson      *    b  gateway
379743e05652SRichard Henderson      *    b  evil
379843e05652SRichard Henderson      * in which instructions at evil would run with increased privs.
379943e05652SRichard Henderson      */
380043e05652SRichard Henderson     if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) {
380143e05652SRichard Henderson         return gen_illegal(ctx);
380243e05652SRichard Henderson     }
380343e05652SRichard Henderson 
380443e05652SRichard Henderson #ifndef CONFIG_USER_ONLY
380543e05652SRichard Henderson     if (ctx->tb_flags & PSW_C) {
3806b77af26eSRichard Henderson         CPUHPPAState *env = cpu_env(ctx->cs);
380743e05652SRichard Henderson         int type = hppa_artype_for_page(env, ctx->base.pc_next);
380843e05652SRichard Henderson         /* If we could not find a TLB entry, then we need to generate an
380943e05652SRichard Henderson            ITLB miss exception so the kernel will provide it.
381043e05652SRichard Henderson            The resulting TLB fill operation will invalidate this TB and
381143e05652SRichard Henderson            we will re-translate, at which point we *will* be able to find
381243e05652SRichard Henderson            the TLB entry and determine if this is in fact a gateway page.  */
381343e05652SRichard Henderson         if (type < 0) {
381431234768SRichard Henderson             gen_excp(ctx, EXCP_ITLB_MISS);
381531234768SRichard Henderson             return true;
381643e05652SRichard Henderson         }
381743e05652SRichard Henderson         /* No change for non-gateway pages or for priv decrease.  */
381843e05652SRichard Henderson         if (type >= 4 && type - 4 < ctx->privilege) {
381943e05652SRichard Henderson             dest = deposit32(dest, 0, 2, type - 4);
382043e05652SRichard Henderson         }
382143e05652SRichard Henderson     } else {
382243e05652SRichard Henderson         dest &= -4;  /* priv = 0 */
382343e05652SRichard Henderson     }
382443e05652SRichard Henderson #endif
382543e05652SRichard Henderson 
38266e5f5300SSven Schnelle     if (a->l) {
38276fd0c7bcSRichard Henderson         TCGv_i64 tmp = dest_gpr(ctx, a->l);
38286e5f5300SSven Schnelle         if (ctx->privilege < 3) {
38296fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, tmp, -4);
38306e5f5300SSven Schnelle         }
38316fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
38326e5f5300SSven Schnelle         save_gpr(ctx, a->l, tmp);
38336e5f5300SSven Schnelle     }
38346e5f5300SSven Schnelle 
38356e5f5300SSven Schnelle     return do_dbranch(ctx, dest, 0, a->n);
383643e05652SRichard Henderson }
383743e05652SRichard Henderson 
38388340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a)
383998cd9ca7SRichard Henderson {
3840b35aec85SRichard Henderson     if (a->x) {
3841aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
38426fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3);
38436fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8);
3844660eefe1SRichard Henderson         /* The computation here never changes privilege level.  */
38458340f534SRichard Henderson         return do_ibranch(ctx, tmp, a->l, a->n);
3846b35aec85SRichard Henderson     } else {
3847b35aec85SRichard Henderson         /* BLR R0,RX is a good way to load PC+8 into RX.  */
3848b35aec85SRichard Henderson         return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n);
3849b35aec85SRichard Henderson     }
385098cd9ca7SRichard Henderson }
385198cd9ca7SRichard Henderson 
38528340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a)
385398cd9ca7SRichard Henderson {
38546fd0c7bcSRichard Henderson     TCGv_i64 dest;
385598cd9ca7SRichard Henderson 
38568340f534SRichard Henderson     if (a->x == 0) {
38578340f534SRichard Henderson         dest = load_gpr(ctx, a->b);
385898cd9ca7SRichard Henderson     } else {
3859aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
38606fd0c7bcSRichard Henderson         tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
38616fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
386298cd9ca7SRichard Henderson     }
3863660eefe1SRichard Henderson     dest = do_ibranch_priv(ctx, dest);
38648340f534SRichard Henderson     return do_ibranch(ctx, dest, 0, a->n);
386598cd9ca7SRichard Henderson }
386698cd9ca7SRichard Henderson 
38678340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a)
386898cd9ca7SRichard Henderson {
38696fd0c7bcSRichard Henderson     TCGv_i64 dest;
387098cd9ca7SRichard Henderson 
3871c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
38728340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
38738340f534SRichard Henderson     return do_ibranch(ctx, dest, a->l, a->n);
3874c301f34eSRichard Henderson #else
3875c301f34eSRichard Henderson     nullify_over(ctx);
38768340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
3877c301f34eSRichard Henderson 
3878741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3879c301f34eSRichard Henderson     if (ctx->iaoq_b == -1) {
3880c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3881c301f34eSRichard Henderson     }
3882741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest);
3883c301f34eSRichard Henderson     tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
38848340f534SRichard Henderson     if (a->l) {
3885741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var);
3886c301f34eSRichard Henderson     }
38878340f534SRichard Henderson     nullify_set(ctx, a->n);
3888c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
388931234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
389031234768SRichard Henderson     return nullify_end(ctx);
3891c301f34eSRichard Henderson #endif
389298cd9ca7SRichard Henderson }
389398cd9ca7SRichard Henderson 
3894a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
3895a8966ba7SRichard Henderson {
3896a8966ba7SRichard Henderson     /* All branch target stack instructions implement as nop. */
3897a8966ba7SRichard Henderson     return ctx->is_pa20;
3898a8966ba7SRichard Henderson }
3899a8966ba7SRichard Henderson 
39001ca74648SRichard Henderson /*
39011ca74648SRichard Henderson  * Float class 0
39021ca74648SRichard Henderson  */
3903ebe9383cSRichard Henderson 
39041ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3905ebe9383cSRichard Henderson {
3906ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
3907ebe9383cSRichard Henderson }
3908ebe9383cSRichard Henderson 
390959f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
391059f8c04bSHelge Deller {
3911a300dad3SRichard Henderson     uint64_t ret;
3912a300dad3SRichard Henderson 
3913c53e401eSRichard Henderson     if (ctx->is_pa20) {
3914a300dad3SRichard Henderson         ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
3915a300dad3SRichard Henderson     } else {
3916a300dad3SRichard Henderson         ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
3917a300dad3SRichard Henderson     }
3918a300dad3SRichard Henderson 
391959f8c04bSHelge Deller     nullify_over(ctx);
3920a300dad3SRichard Henderson     save_frd(0, tcg_constant_i64(ret));
392159f8c04bSHelge Deller     return nullify_end(ctx);
392259f8c04bSHelge Deller }
392359f8c04bSHelge Deller 
39241ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a)
39251ca74648SRichard Henderson {
39261ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f);
39271ca74648SRichard Henderson }
39281ca74648SRichard Henderson 
3929ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3930ebe9383cSRichard Henderson {
3931ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
3932ebe9383cSRichard Henderson }
3933ebe9383cSRichard Henderson 
39341ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a)
39351ca74648SRichard Henderson {
39361ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d);
39371ca74648SRichard Henderson }
39381ca74648SRichard Henderson 
39391ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3940ebe9383cSRichard Henderson {
3941ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
3942ebe9383cSRichard Henderson }
3943ebe9383cSRichard Henderson 
39441ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a)
39451ca74648SRichard Henderson {
39461ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fabs_f);
39471ca74648SRichard Henderson }
39481ca74648SRichard Henderson 
3949ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3950ebe9383cSRichard Henderson {
3951ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
3952ebe9383cSRichard Henderson }
3953ebe9383cSRichard Henderson 
39541ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a)
39551ca74648SRichard Henderson {
39561ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fabs_d);
39571ca74648SRichard Henderson }
39581ca74648SRichard Henderson 
39591ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a)
39601ca74648SRichard Henderson {
39611ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s);
39621ca74648SRichard Henderson }
39631ca74648SRichard Henderson 
39641ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a)
39651ca74648SRichard Henderson {
39661ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d);
39671ca74648SRichard Henderson }
39681ca74648SRichard Henderson 
39691ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a)
39701ca74648SRichard Henderson {
39711ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s);
39721ca74648SRichard Henderson }
39731ca74648SRichard Henderson 
39741ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a)
39751ca74648SRichard Henderson {
39761ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d);
39771ca74648SRichard Henderson }
39781ca74648SRichard Henderson 
39791ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3980ebe9383cSRichard Henderson {
3981ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
3982ebe9383cSRichard Henderson }
3983ebe9383cSRichard Henderson 
39841ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a)
39851ca74648SRichard Henderson {
39861ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fneg_f);
39871ca74648SRichard Henderson }
39881ca74648SRichard Henderson 
3989ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3990ebe9383cSRichard Henderson {
3991ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
3992ebe9383cSRichard Henderson }
3993ebe9383cSRichard Henderson 
39941ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a)
39951ca74648SRichard Henderson {
39961ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fneg_d);
39971ca74648SRichard Henderson }
39981ca74648SRichard Henderson 
39991ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4000ebe9383cSRichard Henderson {
4001ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
4002ebe9383cSRichard Henderson }
4003ebe9383cSRichard Henderson 
40041ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a)
40051ca74648SRichard Henderson {
40061ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f);
40071ca74648SRichard Henderson }
40081ca74648SRichard Henderson 
4009ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4010ebe9383cSRichard Henderson {
4011ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
4012ebe9383cSRichard Henderson }
4013ebe9383cSRichard Henderson 
40141ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a)
40151ca74648SRichard Henderson {
40161ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d);
40171ca74648SRichard Henderson }
40181ca74648SRichard Henderson 
40191ca74648SRichard Henderson /*
40201ca74648SRichard Henderson  * Float class 1
40211ca74648SRichard Henderson  */
40221ca74648SRichard Henderson 
40231ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a)
40241ca74648SRichard Henderson {
40251ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s);
40261ca74648SRichard Henderson }
40271ca74648SRichard Henderson 
40281ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a)
40291ca74648SRichard Henderson {
40301ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d);
40311ca74648SRichard Henderson }
40321ca74648SRichard Henderson 
40331ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a)
40341ca74648SRichard Henderson {
40351ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s);
40361ca74648SRichard Henderson }
40371ca74648SRichard Henderson 
40381ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a)
40391ca74648SRichard Henderson {
40401ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s);
40411ca74648SRichard Henderson }
40421ca74648SRichard Henderson 
40431ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a)
40441ca74648SRichard Henderson {
40451ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d);
40461ca74648SRichard Henderson }
40471ca74648SRichard Henderson 
40481ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a)
40491ca74648SRichard Henderson {
40501ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d);
40511ca74648SRichard Henderson }
40521ca74648SRichard Henderson 
40531ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a)
40541ca74648SRichard Henderson {
40551ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w);
40561ca74648SRichard Henderson }
40571ca74648SRichard Henderson 
40581ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a)
40591ca74648SRichard Henderson {
40601ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w);
40611ca74648SRichard Henderson }
40621ca74648SRichard Henderson 
40631ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a)
40641ca74648SRichard Henderson {
40651ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw);
40661ca74648SRichard Henderson }
40671ca74648SRichard Henderson 
40681ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a)
40691ca74648SRichard Henderson {
40701ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw);
40711ca74648SRichard Henderson }
40721ca74648SRichard Henderson 
40731ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a)
40741ca74648SRichard Henderson {
40751ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w);
40761ca74648SRichard Henderson }
40771ca74648SRichard Henderson 
40781ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a)
40791ca74648SRichard Henderson {
40801ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w);
40811ca74648SRichard Henderson }
40821ca74648SRichard Henderson 
40831ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a)
40841ca74648SRichard Henderson {
40851ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw);
40861ca74648SRichard Henderson }
40871ca74648SRichard Henderson 
40881ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a)
40891ca74648SRichard Henderson {
40901ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw);
40911ca74648SRichard Henderson }
40921ca74648SRichard Henderson 
40931ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a)
40941ca74648SRichard Henderson {
40951ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s);
40961ca74648SRichard Henderson }
40971ca74648SRichard Henderson 
40981ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a)
40991ca74648SRichard Henderson {
41001ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s);
41011ca74648SRichard Henderson }
41021ca74648SRichard Henderson 
41031ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a)
41041ca74648SRichard Henderson {
41051ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d);
41061ca74648SRichard Henderson }
41071ca74648SRichard Henderson 
41081ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a)
41091ca74648SRichard Henderson {
41101ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d);
41111ca74648SRichard Henderson }
41121ca74648SRichard Henderson 
41131ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a)
41141ca74648SRichard Henderson {
41151ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw);
41161ca74648SRichard Henderson }
41171ca74648SRichard Henderson 
41181ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a)
41191ca74648SRichard Henderson {
41201ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw);
41211ca74648SRichard Henderson }
41221ca74648SRichard Henderson 
41231ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a)
41241ca74648SRichard Henderson {
41251ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw);
41261ca74648SRichard Henderson }
41271ca74648SRichard Henderson 
41281ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a)
41291ca74648SRichard Henderson {
41301ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw);
41311ca74648SRichard Henderson }
41321ca74648SRichard Henderson 
41331ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a)
41341ca74648SRichard Henderson {
41351ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw);
41361ca74648SRichard Henderson }
41371ca74648SRichard Henderson 
41381ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a)
41391ca74648SRichard Henderson {
41401ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw);
41411ca74648SRichard Henderson }
41421ca74648SRichard Henderson 
41431ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a)
41441ca74648SRichard Henderson {
41451ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw);
41461ca74648SRichard Henderson }
41471ca74648SRichard Henderson 
41481ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a)
41491ca74648SRichard Henderson {
41501ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw);
41511ca74648SRichard Henderson }
41521ca74648SRichard Henderson 
41531ca74648SRichard Henderson /*
41541ca74648SRichard Henderson  * Float class 2
41551ca74648SRichard Henderson  */
41561ca74648SRichard Henderson 
41571ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a)
4158ebe9383cSRichard Henderson {
4159ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
4160ebe9383cSRichard Henderson 
4161ebe9383cSRichard Henderson     nullify_over(ctx);
4162ebe9383cSRichard Henderson 
41631ca74648SRichard Henderson     ta = load_frw0_i32(a->r1);
41641ca74648SRichard Henderson     tb = load_frw0_i32(a->r2);
416529dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
416629dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4167ebe9383cSRichard Henderson 
4168ad75a51eSRichard Henderson     gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc);
4169ebe9383cSRichard Henderson 
41701ca74648SRichard Henderson     return nullify_end(ctx);
4171ebe9383cSRichard Henderson }
4172ebe9383cSRichard Henderson 
41731ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
4174ebe9383cSRichard Henderson {
4175ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
4176ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
4177ebe9383cSRichard Henderson 
4178ebe9383cSRichard Henderson     nullify_over(ctx);
4179ebe9383cSRichard Henderson 
41801ca74648SRichard Henderson     ta = load_frd0(a->r1);
41811ca74648SRichard Henderson     tb = load_frd0(a->r2);
418229dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
418329dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4184ebe9383cSRichard Henderson 
4185ad75a51eSRichard Henderson     gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc);
4186ebe9383cSRichard Henderson 
418731234768SRichard Henderson     return nullify_end(ctx);
4188ebe9383cSRichard Henderson }
4189ebe9383cSRichard Henderson 
41901ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
4191ebe9383cSRichard Henderson {
41926fd0c7bcSRichard Henderson     TCGv_i64 t;
4193ebe9383cSRichard Henderson 
4194ebe9383cSRichard Henderson     nullify_over(ctx);
4195ebe9383cSRichard Henderson 
4196aac0f603SRichard Henderson     t = tcg_temp_new_i64();
41976fd0c7bcSRichard Henderson     tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
4198ebe9383cSRichard Henderson 
41991ca74648SRichard Henderson     if (a->y == 1) {
4200ebe9383cSRichard Henderson         int mask;
4201ebe9383cSRichard Henderson         bool inv = false;
4202ebe9383cSRichard Henderson 
42031ca74648SRichard Henderson         switch (a->c) {
4204ebe9383cSRichard Henderson         case 0: /* simple */
42056fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, 0x4000000);
4206ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_NE, t);
4207ebe9383cSRichard Henderson             goto done;
4208ebe9383cSRichard Henderson         case 2: /* rej */
4209ebe9383cSRichard Henderson             inv = true;
4210ebe9383cSRichard Henderson             /* fallthru */
4211ebe9383cSRichard Henderson         case 1: /* acc */
4212ebe9383cSRichard Henderson             mask = 0x43ff800;
4213ebe9383cSRichard Henderson             break;
4214ebe9383cSRichard Henderson         case 6: /* rej8 */
4215ebe9383cSRichard Henderson             inv = true;
4216ebe9383cSRichard Henderson             /* fallthru */
4217ebe9383cSRichard Henderson         case 5: /* acc8 */
4218ebe9383cSRichard Henderson             mask = 0x43f8000;
4219ebe9383cSRichard Henderson             break;
4220ebe9383cSRichard Henderson         case 9: /* acc6 */
4221ebe9383cSRichard Henderson             mask = 0x43e0000;
4222ebe9383cSRichard Henderson             break;
4223ebe9383cSRichard Henderson         case 13: /* acc4 */
4224ebe9383cSRichard Henderson             mask = 0x4380000;
4225ebe9383cSRichard Henderson             break;
4226ebe9383cSRichard Henderson         case 17: /* acc2 */
4227ebe9383cSRichard Henderson             mask = 0x4200000;
4228ebe9383cSRichard Henderson             break;
4229ebe9383cSRichard Henderson         default:
42301ca74648SRichard Henderson             gen_illegal(ctx);
42311ca74648SRichard Henderson             return true;
4232ebe9383cSRichard Henderson         }
4233ebe9383cSRichard Henderson         if (inv) {
42346fd0c7bcSRichard Henderson             TCGv_i64 c = tcg_constant_i64(mask);
42356fd0c7bcSRichard Henderson             tcg_gen_or_i64(t, t, c);
4236ebe9383cSRichard Henderson             ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
4237ebe9383cSRichard Henderson         } else {
42386fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, mask);
4239ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
4240ebe9383cSRichard Henderson         }
42411ca74648SRichard Henderson     } else {
42421ca74648SRichard Henderson         unsigned cbit = (a->y ^ 1) - 1;
42431ca74648SRichard Henderson 
42446fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, t, 21 - cbit, 1);
42451ca74648SRichard Henderson         ctx->null_cond = cond_make_0(TCG_COND_NE, t);
42461ca74648SRichard Henderson     }
42471ca74648SRichard Henderson 
4248ebe9383cSRichard Henderson  done:
424931234768SRichard Henderson     return nullify_end(ctx);
4250ebe9383cSRichard Henderson }
4251ebe9383cSRichard Henderson 
42521ca74648SRichard Henderson /*
42531ca74648SRichard Henderson  * Float class 2
42541ca74648SRichard Henderson  */
42551ca74648SRichard Henderson 
42561ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a)
4257ebe9383cSRichard Henderson {
42581ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s);
42591ca74648SRichard Henderson }
42601ca74648SRichard Henderson 
42611ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a)
42621ca74648SRichard Henderson {
42631ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d);
42641ca74648SRichard Henderson }
42651ca74648SRichard Henderson 
42661ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a)
42671ca74648SRichard Henderson {
42681ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s);
42691ca74648SRichard Henderson }
42701ca74648SRichard Henderson 
42711ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a)
42721ca74648SRichard Henderson {
42731ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d);
42741ca74648SRichard Henderson }
42751ca74648SRichard Henderson 
42761ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a)
42771ca74648SRichard Henderson {
42781ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s);
42791ca74648SRichard Henderson }
42801ca74648SRichard Henderson 
42811ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a)
42821ca74648SRichard Henderson {
42831ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d);
42841ca74648SRichard Henderson }
42851ca74648SRichard Henderson 
42861ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a)
42871ca74648SRichard Henderson {
42881ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s);
42891ca74648SRichard Henderson }
42901ca74648SRichard Henderson 
42911ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a)
42921ca74648SRichard Henderson {
42931ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d);
42941ca74648SRichard Henderson }
42951ca74648SRichard Henderson 
42961ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a)
42971ca74648SRichard Henderson {
42981ca74648SRichard Henderson     TCGv_i64 x, y;
4299ebe9383cSRichard Henderson 
4300ebe9383cSRichard Henderson     nullify_over(ctx);
4301ebe9383cSRichard Henderson 
43021ca74648SRichard Henderson     x = load_frw0_i64(a->r1);
43031ca74648SRichard Henderson     y = load_frw0_i64(a->r2);
43041ca74648SRichard Henderson     tcg_gen_mul_i64(x, x, y);
43051ca74648SRichard Henderson     save_frd(a->t, x);
4306ebe9383cSRichard Henderson 
430731234768SRichard Henderson     return nullify_end(ctx);
4308ebe9383cSRichard Henderson }
4309ebe9383cSRichard Henderson 
4310ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
4311ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
4312ebe9383cSRichard Henderson {
4313ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
4314ebe9383cSRichard Henderson }
4315ebe9383cSRichard Henderson 
4316b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4317ebe9383cSRichard Henderson {
4318b1e2af57SRichard Henderson     int tm = fmpyadd_s_reg(a->tm);
4319b1e2af57SRichard Henderson     int ra = fmpyadd_s_reg(a->ra);
4320b1e2af57SRichard Henderson     int ta = fmpyadd_s_reg(a->ta);
4321b1e2af57SRichard Henderson     int rm2 = fmpyadd_s_reg(a->rm2);
4322b1e2af57SRichard Henderson     int rm1 = fmpyadd_s_reg(a->rm1);
4323ebe9383cSRichard Henderson 
4324ebe9383cSRichard Henderson     nullify_over(ctx);
4325ebe9383cSRichard Henderson 
4326ebe9383cSRichard Henderson     do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4327ebe9383cSRichard Henderson     do_fop_weww(ctx, ta, ta, ra,
4328ebe9383cSRichard Henderson                 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
4329ebe9383cSRichard Henderson 
433031234768SRichard Henderson     return nullify_end(ctx);
4331ebe9383cSRichard Henderson }
4332ebe9383cSRichard Henderson 
4333b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4334b1e2af57SRichard Henderson {
4335b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, false);
4336b1e2af57SRichard Henderson }
4337b1e2af57SRichard Henderson 
4338b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4339b1e2af57SRichard Henderson {
4340b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, true);
4341b1e2af57SRichard Henderson }
4342b1e2af57SRichard Henderson 
4343b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4344b1e2af57SRichard Henderson {
4345b1e2af57SRichard Henderson     nullify_over(ctx);
4346b1e2af57SRichard Henderson 
4347b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4348b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4349b1e2af57SRichard Henderson                 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4350b1e2af57SRichard Henderson 
4351b1e2af57SRichard Henderson     return nullify_end(ctx);
4352b1e2af57SRichard Henderson }
4353b1e2af57SRichard Henderson 
4354b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4355b1e2af57SRichard Henderson {
4356b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, false);
4357b1e2af57SRichard Henderson }
4358b1e2af57SRichard Henderson 
4359b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4360b1e2af57SRichard Henderson {
4361b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, true);
4362b1e2af57SRichard Henderson }
4363b1e2af57SRichard Henderson 
4364c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a)
4365ebe9383cSRichard Henderson {
4366c3bad4f8SRichard Henderson     TCGv_i32 x, y, z;
4367ebe9383cSRichard Henderson 
4368ebe9383cSRichard Henderson     nullify_over(ctx);
4369c3bad4f8SRichard Henderson     x = load_frw0_i32(a->rm1);
4370c3bad4f8SRichard Henderson     y = load_frw0_i32(a->rm2);
4371c3bad4f8SRichard Henderson     z = load_frw0_i32(a->ra3);
4372ebe9383cSRichard Henderson 
4373c3bad4f8SRichard Henderson     if (a->neg) {
4374ad75a51eSRichard Henderson         gen_helper_fmpynfadd_s(x, tcg_env, x, y, z);
4375ebe9383cSRichard Henderson     } else {
4376ad75a51eSRichard Henderson         gen_helper_fmpyfadd_s(x, tcg_env, x, y, z);
4377ebe9383cSRichard Henderson     }
4378ebe9383cSRichard Henderson 
4379c3bad4f8SRichard Henderson     save_frw_i32(a->t, x);
438031234768SRichard Henderson     return nullify_end(ctx);
4381ebe9383cSRichard Henderson }
4382ebe9383cSRichard Henderson 
4383c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
4384ebe9383cSRichard Henderson {
4385c3bad4f8SRichard Henderson     TCGv_i64 x, y, z;
4386ebe9383cSRichard Henderson 
4387ebe9383cSRichard Henderson     nullify_over(ctx);
4388c3bad4f8SRichard Henderson     x = load_frd0(a->rm1);
4389c3bad4f8SRichard Henderson     y = load_frd0(a->rm2);
4390c3bad4f8SRichard Henderson     z = load_frd0(a->ra3);
4391ebe9383cSRichard Henderson 
4392c3bad4f8SRichard Henderson     if (a->neg) {
4393ad75a51eSRichard Henderson         gen_helper_fmpynfadd_d(x, tcg_env, x, y, z);
4394ebe9383cSRichard Henderson     } else {
4395ad75a51eSRichard Henderson         gen_helper_fmpyfadd_d(x, tcg_env, x, y, z);
4396ebe9383cSRichard Henderson     }
4397ebe9383cSRichard Henderson 
4398c3bad4f8SRichard Henderson     save_frd(a->t, x);
439931234768SRichard Henderson     return nullify_end(ctx);
4400ebe9383cSRichard Henderson }
4401ebe9383cSRichard Henderson 
440215da177bSSven Schnelle static bool trans_diag(DisasContext *ctx, arg_diag *a)
440315da177bSSven Schnelle {
4404cf6b28d4SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4405cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY
4406cf6b28d4SHelge Deller     if (a->i == 0x100) {
4407cf6b28d4SHelge Deller         /* emulate PDC BTLB, called by SeaBIOS-hppa */
4408ad75a51eSRichard Henderson         nullify_over(ctx);
4409ad75a51eSRichard Henderson         gen_helper_diag_btlb(tcg_env);
4410cf6b28d4SHelge Deller         return nullify_end(ctx);
441115da177bSSven Schnelle     }
4412ad75a51eSRichard Henderson #endif
4413ad75a51eSRichard Henderson     qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i);
4414ad75a51eSRichard Henderson     return true;
4415ad75a51eSRichard Henderson }
441615da177bSSven Schnelle 
4417b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
441861766fe9SRichard Henderson {
441951b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4420f764718dSRichard Henderson     int bound;
442161766fe9SRichard Henderson 
442251b061fbSRichard Henderson     ctx->cs = cs;
4423494737b7SRichard Henderson     ctx->tb_flags = ctx->base.tb->flags;
4424bd6243a3SRichard Henderson     ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
44253d68ee7bSRichard Henderson 
44263d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY
4427c01e5dfbSHelge Deller     ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX);
44283d68ee7bSRichard Henderson     ctx->mmu_idx = MMU_USER_IDX;
4429c01e5dfbSHelge Deller     ctx->iaoq_f = ctx->base.pc_first | ctx->privilege;
4430c01e5dfbSHelge Deller     ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege;
4431217d1a5eSRichard Henderson     ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
4432c301f34eSRichard Henderson #else
4433494737b7SRichard Henderson     ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
4434bb67ec32SRichard Henderson     ctx->mmu_idx = (ctx->tb_flags & PSW_D
4435bb67ec32SRichard Henderson                     ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
4436bb67ec32SRichard Henderson                     : MMU_PHYS_IDX);
44373d68ee7bSRichard Henderson 
4438c301f34eSRichard Henderson     /* Recover the IAOQ values from the GVA + PRIV.  */
4439c301f34eSRichard Henderson     uint64_t cs_base = ctx->base.tb->cs_base;
4440c301f34eSRichard Henderson     uint64_t iasq_f = cs_base & ~0xffffffffull;
4441c301f34eSRichard Henderson     int32_t diff = cs_base;
4442c301f34eSRichard Henderson 
4443c301f34eSRichard Henderson     ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
4444c301f34eSRichard Henderson     ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1);
4445c301f34eSRichard Henderson #endif
444651b061fbSRichard Henderson     ctx->iaoq_n = -1;
4447f764718dSRichard Henderson     ctx->iaoq_n_var = NULL;
444861766fe9SRichard Henderson 
4449a4db4a78SRichard Henderson     ctx->zero = tcg_constant_i64(0);
4450a4db4a78SRichard Henderson 
44513d68ee7bSRichard Henderson     /* Bound the number of instructions by those left on the page.  */
44523d68ee7bSRichard Henderson     bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
4453b542683dSEmilio G. Cota     ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
445461766fe9SRichard Henderson }
445561766fe9SRichard Henderson 
445651b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
445751b061fbSRichard Henderson {
445851b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
445961766fe9SRichard Henderson 
44603d68ee7bSRichard Henderson     /* Seed the nullification status from PSW[N], as saved in TB->FLAGS.  */
446151b061fbSRichard Henderson     ctx->null_cond = cond_make_f();
446251b061fbSRichard Henderson     ctx->psw_n_nonzero = false;
4463494737b7SRichard Henderson     if (ctx->tb_flags & PSW_N) {
446451b061fbSRichard Henderson         ctx->null_cond.c = TCG_COND_ALWAYS;
446551b061fbSRichard Henderson         ctx->psw_n_nonzero = true;
4466129e9cc3SRichard Henderson     }
446751b061fbSRichard Henderson     ctx->null_lab = NULL;
446861766fe9SRichard Henderson }
446961766fe9SRichard Henderson 
447051b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
447151b061fbSRichard Henderson {
447251b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
447351b061fbSRichard Henderson 
4474f5b5c857SRichard Henderson     tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b, 0);
4475f5b5c857SRichard Henderson     ctx->insn_start = tcg_last_op();
447651b061fbSRichard Henderson }
447751b061fbSRichard Henderson 
447851b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
447951b061fbSRichard Henderson {
448051b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4481b77af26eSRichard Henderson     CPUHPPAState *env = cpu_env(cs);
448251b061fbSRichard Henderson     DisasJumpType ret;
448351b061fbSRichard Henderson 
448451b061fbSRichard Henderson     /* Execute one insn.  */
4485ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4486c301f34eSRichard Henderson     if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
448731234768SRichard Henderson         do_page_zero(ctx);
448831234768SRichard Henderson         ret = ctx->base.is_jmp;
4489869051eaSRichard Henderson         assert(ret != DISAS_NEXT);
4490ba1d0b44SRichard Henderson     } else
4491ba1d0b44SRichard Henderson #endif
4492ba1d0b44SRichard Henderson     {
449361766fe9SRichard Henderson         /* Always fetch the insn, even if nullified, so that we check
449461766fe9SRichard Henderson            the page permissions for execute.  */
44954e116893SIlya Leoshkevich         uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next);
449661766fe9SRichard Henderson 
449761766fe9SRichard Henderson         /* Set up the IA queue for the next insn.
449861766fe9SRichard Henderson            This will be overwritten by a branch.  */
449951b061fbSRichard Henderson         if (ctx->iaoq_b == -1) {
450051b061fbSRichard Henderson             ctx->iaoq_n = -1;
4501aac0f603SRichard Henderson             ctx->iaoq_n_var = tcg_temp_new_i64();
45026fd0c7bcSRichard Henderson             tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
450361766fe9SRichard Henderson         } else {
450451b061fbSRichard Henderson             ctx->iaoq_n = ctx->iaoq_b + 4;
4505f764718dSRichard Henderson             ctx->iaoq_n_var = NULL;
450661766fe9SRichard Henderson         }
450761766fe9SRichard Henderson 
450851b061fbSRichard Henderson         if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
450951b061fbSRichard Henderson             ctx->null_cond.c = TCG_COND_NEVER;
4510869051eaSRichard Henderson             ret = DISAS_NEXT;
4511129e9cc3SRichard Henderson         } else {
45121a19da0dSRichard Henderson             ctx->insn = insn;
451331274b46SRichard Henderson             if (!decode(ctx, insn)) {
451431274b46SRichard Henderson                 gen_illegal(ctx);
451531274b46SRichard Henderson             }
451631234768SRichard Henderson             ret = ctx->base.is_jmp;
451751b061fbSRichard Henderson             assert(ctx->null_lab == NULL);
4518129e9cc3SRichard Henderson         }
451961766fe9SRichard Henderson     }
452061766fe9SRichard Henderson 
45213d68ee7bSRichard Henderson     /* Advance the insn queue.  Note that this check also detects
45223d68ee7bSRichard Henderson        a priority change within the instruction queue.  */
452351b061fbSRichard Henderson     if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
4524c301f34eSRichard Henderson         if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1
4525c301f34eSRichard Henderson             && use_goto_tb(ctx, ctx->iaoq_b)
4526c301f34eSRichard Henderson             && (ctx->null_cond.c == TCG_COND_NEVER
4527c301f34eSRichard Henderson                 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
452851b061fbSRichard Henderson             nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
452951b061fbSRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
453031234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_NORETURN;
4531129e9cc3SRichard Henderson         } else {
453231234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE;
453361766fe9SRichard Henderson         }
4534129e9cc3SRichard Henderson     }
453551b061fbSRichard Henderson     ctx->iaoq_f = ctx->iaoq_b;
453651b061fbSRichard Henderson     ctx->iaoq_b = ctx->iaoq_n;
4537c301f34eSRichard Henderson     ctx->base.pc_next += 4;
453861766fe9SRichard Henderson 
4539c5d0aec2SRichard Henderson     switch (ret) {
4540c5d0aec2SRichard Henderson     case DISAS_NORETURN:
4541c5d0aec2SRichard Henderson     case DISAS_IAQ_N_UPDATED:
4542c5d0aec2SRichard Henderson         break;
4543c5d0aec2SRichard Henderson 
4544c5d0aec2SRichard Henderson     case DISAS_NEXT:
4545c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE:
4546c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
454751b061fbSRichard Henderson         if (ctx->iaoq_f == -1) {
4548a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b);
4549741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
4550c301f34eSRichard Henderson #ifndef CONFIG_USER_ONLY
4551c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
4552c301f34eSRichard Henderson #endif
455351b061fbSRichard Henderson             nullify_save(ctx);
4554c5d0aec2SRichard Henderson             ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT
4555c5d0aec2SRichard Henderson                                 ? DISAS_EXIT
4556c5d0aec2SRichard Henderson                                 : DISAS_IAQ_N_UPDATED);
455751b061fbSRichard Henderson         } else if (ctx->iaoq_b == -1) {
4558a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var);
455961766fe9SRichard Henderson         }
4560c5d0aec2SRichard Henderson         break;
4561c5d0aec2SRichard Henderson 
4562c5d0aec2SRichard Henderson     default:
4563c5d0aec2SRichard Henderson         g_assert_not_reached();
4564c5d0aec2SRichard Henderson     }
456561766fe9SRichard Henderson }
456661766fe9SRichard Henderson 
456751b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
456851b061fbSRichard Henderson {
456951b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4570e1b5a5edSRichard Henderson     DisasJumpType is_jmp = ctx->base.is_jmp;
457151b061fbSRichard Henderson 
4572e1b5a5edSRichard Henderson     switch (is_jmp) {
4573869051eaSRichard Henderson     case DISAS_NORETURN:
457461766fe9SRichard Henderson         break;
457551b061fbSRichard Henderson     case DISAS_TOO_MANY:
4576869051eaSRichard Henderson     case DISAS_IAQ_N_STALE:
4577e1b5a5edSRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
4578741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
4579741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
458051b061fbSRichard Henderson         nullify_save(ctx);
458161766fe9SRichard Henderson         /* FALLTHRU */
4582869051eaSRichard Henderson     case DISAS_IAQ_N_UPDATED:
45838532a14eSRichard Henderson         if (is_jmp != DISAS_IAQ_N_STALE_EXIT) {
45847f11636dSEmilio G. Cota             tcg_gen_lookup_and_goto_ptr();
45858532a14eSRichard Henderson             break;
458661766fe9SRichard Henderson         }
4587c5d0aec2SRichard Henderson         /* FALLTHRU */
4588c5d0aec2SRichard Henderson     case DISAS_EXIT:
4589c5d0aec2SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
459061766fe9SRichard Henderson         break;
459161766fe9SRichard Henderson     default:
459251b061fbSRichard Henderson         g_assert_not_reached();
459361766fe9SRichard Henderson     }
459451b061fbSRichard Henderson }
459561766fe9SRichard Henderson 
45968eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase,
45978eb806a7SRichard Henderson                               CPUState *cs, FILE *logfile)
459851b061fbSRichard Henderson {
4599c301f34eSRichard Henderson     target_ulong pc = dcbase->pc_first;
460061766fe9SRichard Henderson 
4601ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4602ba1d0b44SRichard Henderson     switch (pc) {
46037ad439dfSRichard Henderson     case 0x00:
46048eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000000:  (null)\n");
4605ba1d0b44SRichard Henderson         return;
46067ad439dfSRichard Henderson     case 0xb0:
46078eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000b0:  light-weight-syscall\n");
4608ba1d0b44SRichard Henderson         return;
46097ad439dfSRichard Henderson     case 0xe0:
46108eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000e0:  set-thread-pointer-syscall\n");
4611ba1d0b44SRichard Henderson         return;
46127ad439dfSRichard Henderson     case 0x100:
46138eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000100:  syscall\n");
4614ba1d0b44SRichard Henderson         return;
46157ad439dfSRichard Henderson     }
4616ba1d0b44SRichard Henderson #endif
4617ba1d0b44SRichard Henderson 
46188eb806a7SRichard Henderson     fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
46198eb806a7SRichard Henderson     target_disas(logfile, cs, pc, dcbase->tb->size);
462061766fe9SRichard Henderson }
462151b061fbSRichard Henderson 
462251b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = {
462351b061fbSRichard Henderson     .init_disas_context = hppa_tr_init_disas_context,
462451b061fbSRichard Henderson     .tb_start           = hppa_tr_tb_start,
462551b061fbSRichard Henderson     .insn_start         = hppa_tr_insn_start,
462651b061fbSRichard Henderson     .translate_insn     = hppa_tr_translate_insn,
462751b061fbSRichard Henderson     .tb_stop            = hppa_tr_tb_stop,
462851b061fbSRichard Henderson     .disas_log          = hppa_tr_disas_log,
462951b061fbSRichard Henderson };
463051b061fbSRichard Henderson 
4631597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
4632306c8721SRichard Henderson                            target_ulong pc, void *host_pc)
463351b061fbSRichard Henderson {
463451b061fbSRichard Henderson     DisasContext ctx;
4635306c8721SRichard Henderson     translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
463661766fe9SRichard Henderson }
4637