xref: /openbmc/qemu/target/hppa/translate.c (revision 94956d7b510d18f4449d1392b86e1a8f3e467612)
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
7317fe594cSRichard Henderson #define MMU_DISABLED(C)  false
74217d1a5eSRichard Henderson #else
752d4afb03SRichard Henderson #define UNALIGN(C)       MO_ALIGN
7617fe594cSRichard Henderson #define MMU_DISABLED(C)  MMU_IDX_MMU_DISABLED((C)->mmu_idx)
77217d1a5eSRichard Henderson #endif
78217d1a5eSRichard Henderson 
79e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently.  */
80451e4ffdSRichard Henderson static int expand_sm_imm(DisasContext *ctx, int val)
81e36f27efSRichard Henderson {
82881d1073SHelge Deller     /* Keep unimplemented bits disabled -- see cpu_hppa_put_psw. */
83881d1073SHelge Deller     if (ctx->is_pa20) {
84e36f27efSRichard Henderson         if (val & PSW_SM_W) {
85881d1073SHelge Deller             val |= PSW_W;
86881d1073SHelge Deller         }
87881d1073SHelge Deller         val &= ~(PSW_SM_W | PSW_SM_E | PSW_G);
88881d1073SHelge Deller     } else {
89881d1073SHelge Deller         val &= ~(PSW_SM_W | PSW_SM_E | PSW_O);
90e36f27efSRichard Henderson     }
91e36f27efSRichard Henderson     return val;
92e36f27efSRichard Henderson }
93e36f27efSRichard Henderson 
94deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base.  */
95451e4ffdSRichard Henderson static int expand_sr3x(DisasContext *ctx, int val)
96deee69a1SRichard Henderson {
97deee69a1SRichard Henderson     return ~val;
98deee69a1SRichard Henderson }
99deee69a1SRichard Henderson 
1001cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value
1011cd012a5SRichard Henderson    we use for the final M.  */
102451e4ffdSRichard Henderson static int ma_to_m(DisasContext *ctx, int val)
1031cd012a5SRichard Henderson {
1041cd012a5SRichard Henderson     return val & 2 ? (val & 1 ? -1 : 1) : 0;
1051cd012a5SRichard Henderson }
1061cd012a5SRichard Henderson 
107740038d7SRichard Henderson /* Convert the sign of the displacement to a pre or post-modify.  */
108451e4ffdSRichard Henderson static int pos_to_m(DisasContext *ctx, int val)
109740038d7SRichard Henderson {
110740038d7SRichard Henderson     return val ? 1 : -1;
111740038d7SRichard Henderson }
112740038d7SRichard Henderson 
113451e4ffdSRichard Henderson static int neg_to_m(DisasContext *ctx, int val)
114740038d7SRichard Henderson {
115740038d7SRichard Henderson     return val ? -1 : 1;
116740038d7SRichard Henderson }
117740038d7SRichard Henderson 
118740038d7SRichard Henderson /* Used for branch targets and fp memory ops.  */
119451e4ffdSRichard Henderson static int expand_shl2(DisasContext *ctx, int val)
12001afb7beSRichard Henderson {
12101afb7beSRichard Henderson     return val << 2;
12201afb7beSRichard Henderson }
12301afb7beSRichard Henderson 
124740038d7SRichard Henderson /* Used for fp memory ops.  */
125451e4ffdSRichard Henderson static int expand_shl3(DisasContext *ctx, int val)
126740038d7SRichard Henderson {
127740038d7SRichard Henderson     return val << 3;
128740038d7SRichard Henderson }
129740038d7SRichard Henderson 
1300588e061SRichard Henderson /* Used for assemble_21.  */
131451e4ffdSRichard Henderson static int expand_shl11(DisasContext *ctx, int val)
1320588e061SRichard Henderson {
1330588e061SRichard Henderson     return val << 11;
1340588e061SRichard Henderson }
1350588e061SRichard Henderson 
13672ae4f2bSRichard Henderson static int assemble_6(DisasContext *ctx, int val)
13772ae4f2bSRichard Henderson {
13872ae4f2bSRichard Henderson     /*
13972ae4f2bSRichard Henderson      * Officially, 32 * x + 32 - y.
14072ae4f2bSRichard Henderson      * Here, x is already in bit 5, and y is [4:0].
14172ae4f2bSRichard Henderson      * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1,
14272ae4f2bSRichard Henderson      * with the overflow from bit 4 summing with x.
14372ae4f2bSRichard Henderson      */
14472ae4f2bSRichard Henderson     return (val ^ 31) + 1;
14572ae4f2bSRichard Henderson }
14672ae4f2bSRichard Henderson 
147c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */
148c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val)
149c65c3ee1SRichard Henderson {
150c65c3ee1SRichard Henderson     return val ? val : 4; /* 0 == "*<<" */
151c65c3ee1SRichard Henderson }
152c65c3ee1SRichard Henderson 
15301afb7beSRichard Henderson 
15440f9f908SRichard Henderson /* Include the auto-generated decoder.  */
155abff1abfSPaolo Bonzini #include "decode-insns.c.inc"
15640f9f908SRichard Henderson 
15761766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated
15861766fe9SRichard Henderson    the iaq (for whatever reason), so don't do it again on exit.  */
159869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED  DISAS_TARGET_0
16061766fe9SRichard Henderson 
16161766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor
16261766fe9SRichard Henderson    updated the iaq for the next instruction to be executed.  */
163869051eaSRichard Henderson #define DISAS_IAQ_N_STALE    DISAS_TARGET_1
16461766fe9SRichard Henderson 
165e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately
166e1b5a5edSRichard Henderson    to recognize unmasked interrupts.  */
167e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT      DISAS_TARGET_2
168c5d0aec2SRichard Henderson #define DISAS_EXIT                  DISAS_TARGET_3
169e1b5a5edSRichard Henderson 
17061766fe9SRichard Henderson /* global register indexes */
1716fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32];
17233423472SRichard Henderson static TCGv_i64 cpu_sr[4];
173494737b7SRichard Henderson static TCGv_i64 cpu_srH;
1746fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f;
1756fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b;
176c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f;
177c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b;
1786fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar;
1796fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n;
1806fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v;
1816fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb;
1826fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb;
18361766fe9SRichard Henderson 
18461766fe9SRichard Henderson void hppa_translate_init(void)
18561766fe9SRichard Henderson {
18661766fe9SRichard Henderson #define DEF_VAR(V)  { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
18761766fe9SRichard Henderson 
1886fd0c7bcSRichard Henderson     typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar;
18961766fe9SRichard Henderson     static const GlobalVar vars[] = {
19035136a77SRichard Henderson         { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) },
19161766fe9SRichard Henderson         DEF_VAR(psw_n),
19261766fe9SRichard Henderson         DEF_VAR(psw_v),
19361766fe9SRichard Henderson         DEF_VAR(psw_cb),
19461766fe9SRichard Henderson         DEF_VAR(psw_cb_msb),
19561766fe9SRichard Henderson         DEF_VAR(iaoq_f),
19661766fe9SRichard Henderson         DEF_VAR(iaoq_b),
19761766fe9SRichard Henderson     };
19861766fe9SRichard Henderson 
19961766fe9SRichard Henderson #undef DEF_VAR
20061766fe9SRichard Henderson 
20161766fe9SRichard Henderson     /* Use the symbolic register names that match the disassembler.  */
20261766fe9SRichard Henderson     static const char gr_names[32][4] = {
20361766fe9SRichard Henderson         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
20461766fe9SRichard Henderson         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
20561766fe9SRichard Henderson         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
20661766fe9SRichard Henderson         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
20761766fe9SRichard Henderson     };
20833423472SRichard Henderson     /* SR[4-7] are not global registers so that we can index them.  */
209494737b7SRichard Henderson     static const char sr_names[5][4] = {
210494737b7SRichard Henderson         "sr0", "sr1", "sr2", "sr3", "srH"
21133423472SRichard Henderson     };
21261766fe9SRichard Henderson 
21361766fe9SRichard Henderson     int i;
21461766fe9SRichard Henderson 
215f764718dSRichard Henderson     cpu_gr[0] = NULL;
21661766fe9SRichard Henderson     for (i = 1; i < 32; i++) {
217ad75a51eSRichard Henderson         cpu_gr[i] = tcg_global_mem_new(tcg_env,
21861766fe9SRichard Henderson                                        offsetof(CPUHPPAState, gr[i]),
21961766fe9SRichard Henderson                                        gr_names[i]);
22061766fe9SRichard Henderson     }
22133423472SRichard Henderson     for (i = 0; i < 4; i++) {
222ad75a51eSRichard Henderson         cpu_sr[i] = tcg_global_mem_new_i64(tcg_env,
22333423472SRichard Henderson                                            offsetof(CPUHPPAState, sr[i]),
22433423472SRichard Henderson                                            sr_names[i]);
22533423472SRichard Henderson     }
226ad75a51eSRichard Henderson     cpu_srH = tcg_global_mem_new_i64(tcg_env,
227494737b7SRichard Henderson                                      offsetof(CPUHPPAState, sr[4]),
228494737b7SRichard Henderson                                      sr_names[4]);
22961766fe9SRichard Henderson 
23061766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(vars); ++i) {
23161766fe9SRichard Henderson         const GlobalVar *v = &vars[i];
232ad75a51eSRichard Henderson         *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name);
23361766fe9SRichard Henderson     }
234c301f34eSRichard Henderson 
235ad75a51eSRichard Henderson     cpu_iasq_f = tcg_global_mem_new_i64(tcg_env,
236c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_f),
237c301f34eSRichard Henderson                                         "iasq_f");
238ad75a51eSRichard Henderson     cpu_iasq_b = tcg_global_mem_new_i64(tcg_env,
239c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_b),
240c301f34eSRichard Henderson                                         "iasq_b");
24161766fe9SRichard Henderson }
24261766fe9SRichard Henderson 
243f5b5c857SRichard Henderson static void set_insn_breg(DisasContext *ctx, int breg)
244f5b5c857SRichard Henderson {
245f5b5c857SRichard Henderson     assert(ctx->insn_start != NULL);
246f5b5c857SRichard Henderson     tcg_set_insn_start_param(ctx->insn_start, 2, breg);
247f5b5c857SRichard Henderson     ctx->insn_start = NULL;
248f5b5c857SRichard Henderson }
249f5b5c857SRichard Henderson 
250129e9cc3SRichard Henderson static DisasCond cond_make_f(void)
251129e9cc3SRichard Henderson {
252f764718dSRichard Henderson     return (DisasCond){
253f764718dSRichard Henderson         .c = TCG_COND_NEVER,
254f764718dSRichard Henderson         .a0 = NULL,
255f764718dSRichard Henderson         .a1 = NULL,
256f764718dSRichard Henderson     };
257129e9cc3SRichard Henderson }
258129e9cc3SRichard Henderson 
259df0232feSRichard Henderson static DisasCond cond_make_t(void)
260df0232feSRichard Henderson {
261df0232feSRichard Henderson     return (DisasCond){
262df0232feSRichard Henderson         .c = TCG_COND_ALWAYS,
263df0232feSRichard Henderson         .a0 = NULL,
264df0232feSRichard Henderson         .a1 = NULL,
265df0232feSRichard Henderson     };
266df0232feSRichard Henderson }
267df0232feSRichard Henderson 
268129e9cc3SRichard Henderson static DisasCond cond_make_n(void)
269129e9cc3SRichard Henderson {
270f764718dSRichard Henderson     return (DisasCond){
271f764718dSRichard Henderson         .c = TCG_COND_NE,
272f764718dSRichard Henderson         .a0 = cpu_psw_n,
2736fd0c7bcSRichard Henderson         .a1 = tcg_constant_i64(0)
274f764718dSRichard Henderson     };
275129e9cc3SRichard Henderson }
276129e9cc3SRichard Henderson 
2776fd0c7bcSRichard Henderson static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
278b47a4a02SSven Schnelle {
279b47a4a02SSven Schnelle     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
2804fe9533aSRichard Henderson     return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 };
2814fe9533aSRichard Henderson }
2824fe9533aSRichard Henderson 
2836fd0c7bcSRichard Henderson static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0)
2844fe9533aSRichard Henderson {
2856fd0c7bcSRichard Henderson     return cond_make_tmp(c, a0, tcg_constant_i64(0));
286b47a4a02SSven Schnelle }
287b47a4a02SSven Schnelle 
2886fd0c7bcSRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0)
289129e9cc3SRichard Henderson {
290aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2916fd0c7bcSRichard Henderson     tcg_gen_mov_i64(tmp, a0);
292b47a4a02SSven Schnelle     return cond_make_0_tmp(c, tmp);
293129e9cc3SRichard Henderson }
294129e9cc3SRichard Henderson 
2956fd0c7bcSRichard Henderson static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
296129e9cc3SRichard Henderson {
297aac0f603SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
298aac0f603SRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
299129e9cc3SRichard Henderson 
3006fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t0, a0);
3016fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t1, a1);
3024fe9533aSRichard Henderson     return cond_make_tmp(c, t0, t1);
303129e9cc3SRichard Henderson }
304129e9cc3SRichard Henderson 
305129e9cc3SRichard Henderson static void cond_free(DisasCond *cond)
306129e9cc3SRichard Henderson {
307129e9cc3SRichard Henderson     switch (cond->c) {
308129e9cc3SRichard Henderson     default:
309f764718dSRichard Henderson         cond->a0 = NULL;
310f764718dSRichard Henderson         cond->a1 = NULL;
311129e9cc3SRichard Henderson         /* fallthru */
312129e9cc3SRichard Henderson     case TCG_COND_ALWAYS:
313129e9cc3SRichard Henderson         cond->c = TCG_COND_NEVER;
314129e9cc3SRichard Henderson         break;
315129e9cc3SRichard Henderson     case TCG_COND_NEVER:
316129e9cc3SRichard Henderson         break;
317129e9cc3SRichard Henderson     }
318129e9cc3SRichard Henderson }
319129e9cc3SRichard Henderson 
3206fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg)
32161766fe9SRichard Henderson {
32261766fe9SRichard Henderson     if (reg == 0) {
323bc3da3cfSRichard Henderson         return ctx->zero;
32461766fe9SRichard Henderson     } else {
32561766fe9SRichard Henderson         return cpu_gr[reg];
32661766fe9SRichard Henderson     }
32761766fe9SRichard Henderson }
32861766fe9SRichard Henderson 
3296fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg)
33061766fe9SRichard Henderson {
331129e9cc3SRichard Henderson     if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
332aac0f603SRichard Henderson         return tcg_temp_new_i64();
33361766fe9SRichard Henderson     } else {
33461766fe9SRichard Henderson         return cpu_gr[reg];
33561766fe9SRichard Henderson     }
33661766fe9SRichard Henderson }
33761766fe9SRichard Henderson 
3386fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t)
339129e9cc3SRichard Henderson {
340129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
3416fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0,
342129e9cc3SRichard Henderson                             ctx->null_cond.a1, dest, t);
343129e9cc3SRichard Henderson     } else {
3446fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, t);
345129e9cc3SRichard Henderson     }
346129e9cc3SRichard Henderson }
347129e9cc3SRichard Henderson 
3486fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t)
349129e9cc3SRichard Henderson {
350129e9cc3SRichard Henderson     if (reg != 0) {
351129e9cc3SRichard Henderson         save_or_nullify(ctx, cpu_gr[reg], t);
352129e9cc3SRichard Henderson     }
353129e9cc3SRichard Henderson }
354129e9cc3SRichard Henderson 
355e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
35696d6407fSRichard Henderson # define HI_OFS  0
35796d6407fSRichard Henderson # define LO_OFS  4
35896d6407fSRichard Henderson #else
35996d6407fSRichard Henderson # define HI_OFS  4
36096d6407fSRichard Henderson # define LO_OFS  0
36196d6407fSRichard Henderson #endif
36296d6407fSRichard Henderson 
36396d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt)
36496d6407fSRichard Henderson {
36596d6407fSRichard Henderson     TCGv_i32 ret = tcg_temp_new_i32();
366ad75a51eSRichard Henderson     tcg_gen_ld_i32(ret, tcg_env,
36796d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
36896d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
36996d6407fSRichard Henderson     return ret;
37096d6407fSRichard Henderson }
37196d6407fSRichard Henderson 
372ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt)
373ebe9383cSRichard Henderson {
374ebe9383cSRichard Henderson     if (rt == 0) {
3750992a930SRichard Henderson         TCGv_i32 ret = tcg_temp_new_i32();
3760992a930SRichard Henderson         tcg_gen_movi_i32(ret, 0);
3770992a930SRichard Henderson         return ret;
378ebe9383cSRichard Henderson     } else {
379ebe9383cSRichard Henderson         return load_frw_i32(rt);
380ebe9383cSRichard Henderson     }
381ebe9383cSRichard Henderson }
382ebe9383cSRichard Henderson 
383ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt)
384ebe9383cSRichard Henderson {
385ebe9383cSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
3860992a930SRichard Henderson     if (rt == 0) {
3870992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
3880992a930SRichard Henderson     } else {
389ad75a51eSRichard Henderson         tcg_gen_ld32u_i64(ret, tcg_env,
390ebe9383cSRichard Henderson                           offsetof(CPUHPPAState, fr[rt & 31])
391ebe9383cSRichard Henderson                           + (rt & 32 ? LO_OFS : HI_OFS));
392ebe9383cSRichard Henderson     }
3930992a930SRichard Henderson     return ret;
394ebe9383cSRichard Henderson }
395ebe9383cSRichard Henderson 
39696d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val)
39796d6407fSRichard Henderson {
398ad75a51eSRichard Henderson     tcg_gen_st_i32(val, tcg_env,
39996d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
40096d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
40196d6407fSRichard Henderson }
40296d6407fSRichard Henderson 
40396d6407fSRichard Henderson #undef HI_OFS
40496d6407fSRichard Henderson #undef LO_OFS
40596d6407fSRichard Henderson 
40696d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt)
40796d6407fSRichard Henderson {
40896d6407fSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
409ad75a51eSRichard Henderson     tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt]));
41096d6407fSRichard Henderson     return ret;
41196d6407fSRichard Henderson }
41296d6407fSRichard Henderson 
413ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt)
414ebe9383cSRichard Henderson {
415ebe9383cSRichard Henderson     if (rt == 0) {
4160992a930SRichard Henderson         TCGv_i64 ret = tcg_temp_new_i64();
4170992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
4180992a930SRichard Henderson         return ret;
419ebe9383cSRichard Henderson     } else {
420ebe9383cSRichard Henderson         return load_frd(rt);
421ebe9383cSRichard Henderson     }
422ebe9383cSRichard Henderson }
423ebe9383cSRichard Henderson 
42496d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val)
42596d6407fSRichard Henderson {
426ad75a51eSRichard Henderson     tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt]));
42796d6407fSRichard Henderson }
42896d6407fSRichard Henderson 
42933423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg)
43033423472SRichard Henderson {
43133423472SRichard Henderson #ifdef CONFIG_USER_ONLY
43233423472SRichard Henderson     tcg_gen_movi_i64(dest, 0);
43333423472SRichard Henderson #else
43433423472SRichard Henderson     if (reg < 4) {
43533423472SRichard Henderson         tcg_gen_mov_i64(dest, cpu_sr[reg]);
436494737b7SRichard Henderson     } else if (ctx->tb_flags & TB_FLAG_SR_SAME) {
437494737b7SRichard Henderson         tcg_gen_mov_i64(dest, cpu_srH);
43833423472SRichard Henderson     } else {
439ad75a51eSRichard Henderson         tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg]));
44033423472SRichard Henderson     }
44133423472SRichard Henderson #endif
44233423472SRichard Henderson }
44333423472SRichard Henderson 
444129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified.
445129e9cc3SRichard Henderson    Use this when the insn is too complex for a conditional move.  */
446129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx)
447129e9cc3SRichard Henderson {
448129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
449129e9cc3SRichard Henderson         /* The always condition should have been handled in the main loop.  */
450129e9cc3SRichard Henderson         assert(ctx->null_cond.c != TCG_COND_ALWAYS);
451129e9cc3SRichard Henderson 
452129e9cc3SRichard Henderson         ctx->null_lab = gen_new_label();
453129e9cc3SRichard Henderson 
454129e9cc3SRichard Henderson         /* If we're using PSW[N], copy it to a temp because... */
4556e94937aSRichard Henderson         if (ctx->null_cond.a0 == cpu_psw_n) {
456aac0f603SRichard Henderson             ctx->null_cond.a0 = tcg_temp_new_i64();
4576fd0c7bcSRichard Henderson             tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n);
458129e9cc3SRichard Henderson         }
459129e9cc3SRichard Henderson         /* ... we clear it before branching over the implementation,
460129e9cc3SRichard Henderson            so that (1) it's clear after nullifying this insn and
461129e9cc3SRichard Henderson            (2) if this insn nullifies the next, PSW[N] is valid.  */
462129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
463129e9cc3SRichard Henderson             ctx->psw_n_nonzero = false;
4646fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
465129e9cc3SRichard Henderson         }
466129e9cc3SRichard Henderson 
4676fd0c7bcSRichard Henderson         tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0,
468129e9cc3SRichard Henderson                            ctx->null_cond.a1, ctx->null_lab);
469129e9cc3SRichard Henderson         cond_free(&ctx->null_cond);
470129e9cc3SRichard Henderson     }
471129e9cc3SRichard Henderson }
472129e9cc3SRichard Henderson 
473129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N].  */
474129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx)
475129e9cc3SRichard Henderson {
476129e9cc3SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
477129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
4786fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
479129e9cc3SRichard Henderson         }
480129e9cc3SRichard Henderson         return;
481129e9cc3SRichard Henderson     }
4826e94937aSRichard Henderson     if (ctx->null_cond.a0 != cpu_psw_n) {
4836fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n,
484129e9cc3SRichard Henderson                             ctx->null_cond.a0, ctx->null_cond.a1);
485129e9cc3SRichard Henderson         ctx->psw_n_nonzero = true;
486129e9cc3SRichard Henderson     }
487129e9cc3SRichard Henderson     cond_free(&ctx->null_cond);
488129e9cc3SRichard Henderson }
489129e9cc3SRichard Henderson 
490129e9cc3SRichard Henderson /* Set a PSW[N] to X.  The intention is that this is used immediately
491129e9cc3SRichard Henderson    before a goto_tb/exit_tb, so that there is no fallthru path to other
492129e9cc3SRichard Henderson    code within the TB.  Therefore we do not update psw_n_nonzero.  */
493129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x)
494129e9cc3SRichard Henderson {
495129e9cc3SRichard Henderson     if (ctx->psw_n_nonzero || x) {
4966fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, x);
497129e9cc3SRichard Henderson     }
498129e9cc3SRichard Henderson }
499129e9cc3SRichard Henderson 
500129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified.
50140f9f908SRichard Henderson    This is the pair to nullify_over.  Always returns true so that
50240f9f908SRichard Henderson    it may be tail-called from a translate function.  */
50331234768SRichard Henderson static bool nullify_end(DisasContext *ctx)
504129e9cc3SRichard Henderson {
505129e9cc3SRichard Henderson     TCGLabel *null_lab = ctx->null_lab;
50631234768SRichard Henderson     DisasJumpType status = ctx->base.is_jmp;
507129e9cc3SRichard Henderson 
508f49b3537SRichard Henderson     /* For NEXT, NORETURN, STALE, we can easily continue (or exit).
509f49b3537SRichard Henderson        For UPDATED, we cannot update on the nullified path.  */
510f49b3537SRichard Henderson     assert(status != DISAS_IAQ_N_UPDATED);
511f49b3537SRichard Henderson 
512129e9cc3SRichard Henderson     if (likely(null_lab == NULL)) {
513129e9cc3SRichard Henderson         /* The current insn wasn't conditional or handled the condition
514129e9cc3SRichard Henderson            applied to it without a branch, so the (new) setting of
515129e9cc3SRichard Henderson            NULL_COND can be applied directly to the next insn.  */
51631234768SRichard Henderson         return true;
517129e9cc3SRichard Henderson     }
518129e9cc3SRichard Henderson     ctx->null_lab = NULL;
519129e9cc3SRichard Henderson 
520129e9cc3SRichard Henderson     if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
521129e9cc3SRichard Henderson         /* The next instruction will be unconditional,
522129e9cc3SRichard Henderson            and NULL_COND already reflects that.  */
523129e9cc3SRichard Henderson         gen_set_label(null_lab);
524129e9cc3SRichard Henderson     } else {
525129e9cc3SRichard Henderson         /* The insn that we just executed is itself nullifying the next
526129e9cc3SRichard Henderson            instruction.  Store the condition in the PSW[N] global.
527129e9cc3SRichard Henderson            We asserted PSW[N] = 0 in nullify_over, so that after the
528129e9cc3SRichard Henderson            label we have the proper value in place.  */
529129e9cc3SRichard Henderson         nullify_save(ctx);
530129e9cc3SRichard Henderson         gen_set_label(null_lab);
531129e9cc3SRichard Henderson         ctx->null_cond = cond_make_n();
532129e9cc3SRichard Henderson     }
533869051eaSRichard Henderson     if (status == DISAS_NORETURN) {
53431234768SRichard Henderson         ctx->base.is_jmp = DISAS_NEXT;
535129e9cc3SRichard Henderson     }
53631234768SRichard Henderson     return true;
537129e9cc3SRichard Henderson }
538129e9cc3SRichard Henderson 
539c53e401eSRichard Henderson static uint64_t gva_offset_mask(DisasContext *ctx)
540698240d1SRichard Henderson {
541698240d1SRichard Henderson     return (ctx->tb_flags & PSW_W
542698240d1SRichard Henderson             ? MAKE_64BIT_MASK(0, 62)
543698240d1SRichard Henderson             : MAKE_64BIT_MASK(0, 32));
544698240d1SRichard Henderson }
545698240d1SRichard Henderson 
5466fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest,
5476fd0c7bcSRichard Henderson                             uint64_t ival, TCGv_i64 vval)
54861766fe9SRichard Henderson {
549c53e401eSRichard Henderson     uint64_t mask = gva_offset_mask(ctx);
550f13bf343SRichard Henderson 
551f13bf343SRichard Henderson     if (ival != -1) {
5526fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, ival & mask);
553f13bf343SRichard Henderson         return;
554f13bf343SRichard Henderson     }
555f13bf343SRichard Henderson     tcg_debug_assert(vval != NULL);
556f13bf343SRichard Henderson 
557f13bf343SRichard Henderson     /*
558f13bf343SRichard Henderson      * We know that the IAOQ is already properly masked.
559f13bf343SRichard Henderson      * This optimization is primarily for "iaoq_f = iaoq_b".
560f13bf343SRichard Henderson      */
561f13bf343SRichard Henderson     if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) {
5626fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, vval);
56361766fe9SRichard Henderson     } else {
5646fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, vval, mask);
56561766fe9SRichard Henderson     }
56661766fe9SRichard Henderson }
56761766fe9SRichard Henderson 
568c53e401eSRichard Henderson static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp)
56961766fe9SRichard Henderson {
57061766fe9SRichard Henderson     return ctx->iaoq_f + disp + 8;
57161766fe9SRichard Henderson }
57261766fe9SRichard Henderson 
57361766fe9SRichard Henderson static void gen_excp_1(int exception)
57461766fe9SRichard Henderson {
575ad75a51eSRichard Henderson     gen_helper_excp(tcg_env, tcg_constant_i32(exception));
57661766fe9SRichard Henderson }
57761766fe9SRichard Henderson 
57831234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception)
57961766fe9SRichard Henderson {
580741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
581741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
582129e9cc3SRichard Henderson     nullify_save(ctx);
58361766fe9SRichard Henderson     gen_excp_1(exception);
58431234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
58561766fe9SRichard Henderson }
58661766fe9SRichard Henderson 
58731234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc)
5881a19da0dSRichard Henderson {
58931234768SRichard Henderson     nullify_over(ctx);
5906fd0c7bcSRichard Henderson     tcg_gen_st_i64(tcg_constant_i64(ctx->insn),
591ad75a51eSRichard Henderson                    tcg_env, offsetof(CPUHPPAState, cr[CR_IIR]));
59231234768SRichard Henderson     gen_excp(ctx, exc);
59331234768SRichard Henderson     return nullify_end(ctx);
5941a19da0dSRichard Henderson }
5951a19da0dSRichard Henderson 
59631234768SRichard Henderson static bool gen_illegal(DisasContext *ctx)
59761766fe9SRichard Henderson {
59831234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_ILL);
59961766fe9SRichard Henderson }
60061766fe9SRichard Henderson 
60140f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY
60240f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
60340f9f908SRichard Henderson     return gen_excp_iir(ctx, EXCP)
60440f9f908SRichard Henderson #else
605e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
606e1b5a5edSRichard Henderson     do {                                     \
607e1b5a5edSRichard Henderson         if (ctx->privilege != 0) {           \
60831234768SRichard Henderson             return gen_excp_iir(ctx, EXCP);  \
609e1b5a5edSRichard Henderson         }                                    \
610e1b5a5edSRichard Henderson     } while (0)
61140f9f908SRichard Henderson #endif
612e1b5a5edSRichard Henderson 
613c53e401eSRichard Henderson static bool use_goto_tb(DisasContext *ctx, uint64_t dest)
61461766fe9SRichard Henderson {
61557f91498SRichard Henderson     return translator_use_goto_tb(&ctx->base, dest);
61661766fe9SRichard Henderson }
61761766fe9SRichard Henderson 
618129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page,
619129e9cc3SRichard Henderson    and we're not attempting to set a breakpoint on it, then we can
620129e9cc3SRichard Henderson    totally skip the nullified insn.  This avoids creating and
621129e9cc3SRichard Henderson    executing a TB that merely branches to the next TB.  */
622129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx)
623129e9cc3SRichard Henderson {
624129e9cc3SRichard Henderson     return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
625129e9cc3SRichard Henderson             && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
626129e9cc3SRichard Henderson }
627129e9cc3SRichard Henderson 
62861766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which,
629c53e401eSRichard Henderson                         uint64_t f, uint64_t b)
63061766fe9SRichard Henderson {
63161766fe9SRichard Henderson     if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
63261766fe9SRichard Henderson         tcg_gen_goto_tb(which);
633a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, f, NULL);
634a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, b, NULL);
63507ea28b4SRichard Henderson         tcg_gen_exit_tb(ctx->base.tb, which);
63661766fe9SRichard Henderson     } else {
637741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, f, cpu_iaoq_b);
638741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, b, ctx->iaoq_n_var);
6397f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
64061766fe9SRichard Henderson     }
64161766fe9SRichard Henderson }
64261766fe9SRichard Henderson 
643b47a4a02SSven Schnelle static bool cond_need_sv(int c)
644b47a4a02SSven Schnelle {
645b47a4a02SSven Schnelle     return c == 2 || c == 3 || c == 6;
646b47a4a02SSven Schnelle }
647b47a4a02SSven Schnelle 
648b47a4a02SSven Schnelle static bool cond_need_cb(int c)
649b47a4a02SSven Schnelle {
650b47a4a02SSven Schnelle     return c == 4 || c == 5;
651b47a4a02SSven Schnelle }
652b47a4a02SSven Schnelle 
6536fd0c7bcSRichard Henderson /* Need extensions from TCGv_i32 to TCGv_i64. */
65472ca8753SRichard Henderson static bool cond_need_ext(DisasContext *ctx, bool d)
65572ca8753SRichard Henderson {
656c53e401eSRichard Henderson     return !(ctx->is_pa20 && d);
65772ca8753SRichard Henderson }
65872ca8753SRichard Henderson 
659b47a4a02SSven Schnelle /*
660b47a4a02SSven Schnelle  * Compute conditional for arithmetic.  See Page 5-3, Table 5-1, of
661b47a4a02SSven Schnelle  * the Parisc 1.1 Architecture Reference Manual for details.
662b47a4a02SSven Schnelle  */
663b2167459SRichard Henderson 
664a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d,
6656fd0c7bcSRichard Henderson                          TCGv_i64 res, TCGv_i64 cb_msb, TCGv_i64 sv)
666b2167459SRichard Henderson {
667b2167459SRichard Henderson     DisasCond cond;
6686fd0c7bcSRichard Henderson     TCGv_i64 tmp;
669b2167459SRichard Henderson 
670b2167459SRichard Henderson     switch (cf >> 1) {
671b47a4a02SSven Schnelle     case 0: /* Never / TR    (0 / 1) */
672b2167459SRichard Henderson         cond = cond_make_f();
673b2167459SRichard Henderson         break;
674b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
675a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
676aac0f603SRichard Henderson             tmp = tcg_temp_new_i64();
6776fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
678a751eb31SRichard Henderson             res = tmp;
679a751eb31SRichard Henderson         }
680b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, res);
681b2167459SRichard Henderson         break;
682b47a4a02SSven Schnelle     case 2: /* < / >=        (N ^ V / !(N ^ V) */
683aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
6846fd0c7bcSRichard Henderson         tcg_gen_xor_i64(tmp, res, sv);
685a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
6866fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, tmp);
687a751eb31SRichard Henderson         }
688b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_LT, tmp);
689b2167459SRichard Henderson         break;
690b47a4a02SSven Schnelle     case 3: /* <= / >        (N ^ V) | Z / !((N ^ V) | Z) */
691b47a4a02SSven Schnelle         /*
692b47a4a02SSven Schnelle          * Simplify:
693b47a4a02SSven Schnelle          *   (N ^ V) | Z
694b47a4a02SSven Schnelle          *   ((res < 0) ^ (sv < 0)) | !res
695b47a4a02SSven Schnelle          *   ((res ^ sv) < 0) | !res
696b47a4a02SSven Schnelle          *   (~(res ^ sv) >= 0) | !res
697b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31) | !res
698b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31 & res)
699b47a4a02SSven Schnelle          */
700aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
7016fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(tmp, res, sv);
702a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
7036fd0c7bcSRichard Henderson             tcg_gen_sextract_i64(tmp, tmp, 31, 1);
7046fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
7056fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
706a751eb31SRichard Henderson         } else {
7076fd0c7bcSRichard Henderson             tcg_gen_sari_i64(tmp, tmp, 63);
7086fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
709a751eb31SRichard Henderson         }
710b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
711b2167459SRichard Henderson         break;
712b2167459SRichard Henderson     case 4: /* NUV / UV      (!C / C) */
713a751eb31SRichard Henderson         /* Only bit 0 of cb_msb is ever set. */
714b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, cb_msb);
715b2167459SRichard Henderson         break;
716b2167459SRichard Henderson     case 5: /* ZNV / VNZ     (!C | Z / C & !Z) */
717aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
7186fd0c7bcSRichard Henderson         tcg_gen_neg_i64(tmp, cb_msb);
7196fd0c7bcSRichard Henderson         tcg_gen_and_i64(tmp, tmp, res);
720a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
7216fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
722a751eb31SRichard Henderson         }
723b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
724b2167459SRichard Henderson         break;
725b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
726a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
727aac0f603SRichard Henderson             tmp = tcg_temp_new_i64();
7286fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, sv);
729a751eb31SRichard Henderson             sv = tmp;
730a751eb31SRichard Henderson         }
731b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, sv);
732b2167459SRichard Henderson         break;
733b2167459SRichard Henderson     case 7: /* OD / EV */
734aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
7356fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, res, 1);
736b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_NE, tmp);
737b2167459SRichard Henderson         break;
738b2167459SRichard Henderson     default:
739b2167459SRichard Henderson         g_assert_not_reached();
740b2167459SRichard Henderson     }
741b2167459SRichard Henderson     if (cf & 1) {
742b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
743b2167459SRichard Henderson     }
744b2167459SRichard Henderson 
745b2167459SRichard Henderson     return cond;
746b2167459SRichard Henderson }
747b2167459SRichard Henderson 
748b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
749b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
750b2167459SRichard Henderson    deleted as unused.  */
751b2167459SRichard Henderson 
7524fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d,
7536fd0c7bcSRichard Henderson                              TCGv_i64 res, TCGv_i64 in1,
7546fd0c7bcSRichard Henderson                              TCGv_i64 in2, TCGv_i64 sv)
755b2167459SRichard Henderson {
7564fe9533aSRichard Henderson     TCGCond tc;
7574fe9533aSRichard Henderson     bool ext_uns;
758b2167459SRichard Henderson 
759b2167459SRichard Henderson     switch (cf >> 1) {
760b2167459SRichard Henderson     case 1: /* = / <> */
7614fe9533aSRichard Henderson         tc = TCG_COND_EQ;
7624fe9533aSRichard Henderson         ext_uns = true;
763b2167459SRichard Henderson         break;
764b2167459SRichard Henderson     case 2: /* < / >= */
7654fe9533aSRichard Henderson         tc = TCG_COND_LT;
7664fe9533aSRichard Henderson         ext_uns = false;
767b2167459SRichard Henderson         break;
768b2167459SRichard Henderson     case 3: /* <= / > */
7694fe9533aSRichard Henderson         tc = TCG_COND_LE;
7704fe9533aSRichard Henderson         ext_uns = false;
771b2167459SRichard Henderson         break;
772b2167459SRichard Henderson     case 4: /* << / >>= */
7734fe9533aSRichard Henderson         tc = TCG_COND_LTU;
7744fe9533aSRichard Henderson         ext_uns = true;
775b2167459SRichard Henderson         break;
776b2167459SRichard Henderson     case 5: /* <<= / >> */
7774fe9533aSRichard Henderson         tc = TCG_COND_LEU;
7784fe9533aSRichard Henderson         ext_uns = true;
779b2167459SRichard Henderson         break;
780b2167459SRichard Henderson     default:
781a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, sv);
782b2167459SRichard Henderson     }
783b2167459SRichard Henderson 
7844fe9533aSRichard Henderson     if (cf & 1) {
7854fe9533aSRichard Henderson         tc = tcg_invert_cond(tc);
7864fe9533aSRichard Henderson     }
7874fe9533aSRichard Henderson     if (cond_need_ext(ctx, d)) {
788aac0f603SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
789aac0f603SRichard Henderson         TCGv_i64 t2 = tcg_temp_new_i64();
7904fe9533aSRichard Henderson 
7914fe9533aSRichard Henderson         if (ext_uns) {
7926fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t1, in1);
7936fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t2, in2);
7944fe9533aSRichard Henderson         } else {
7956fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t1, in1);
7966fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t2, in2);
7974fe9533aSRichard Henderson         }
7984fe9533aSRichard Henderson         return cond_make_tmp(tc, t1, t2);
7994fe9533aSRichard Henderson     }
8004fe9533aSRichard Henderson     return cond_make(tc, in1, in2);
801b2167459SRichard Henderson }
802b2167459SRichard Henderson 
803df0232feSRichard Henderson /*
804df0232feSRichard Henderson  * Similar, but for logicals, where the carry and overflow bits are not
805df0232feSRichard Henderson  * computed, and use of them is undefined.
806df0232feSRichard Henderson  *
807df0232feSRichard Henderson  * Undefined or not, hardware does not trap.  It seems reasonable to
808df0232feSRichard Henderson  * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's
809df0232feSRichard Henderson  * how cases c={2,3} are treated.
810df0232feSRichard Henderson  */
811b2167459SRichard Henderson 
812b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d,
8136fd0c7bcSRichard Henderson                              TCGv_i64 res)
814b2167459SRichard Henderson {
815b5af8423SRichard Henderson     TCGCond tc;
816b5af8423SRichard Henderson     bool ext_uns;
817a751eb31SRichard Henderson 
818df0232feSRichard Henderson     switch (cf) {
819df0232feSRichard Henderson     case 0:  /* never */
820df0232feSRichard Henderson     case 9:  /* undef, C */
821df0232feSRichard Henderson     case 11: /* undef, C & !Z */
822df0232feSRichard Henderson     case 12: /* undef, V */
823df0232feSRichard Henderson         return cond_make_f();
824df0232feSRichard Henderson 
825df0232feSRichard Henderson     case 1:  /* true */
826df0232feSRichard Henderson     case 8:  /* undef, !C */
827df0232feSRichard Henderson     case 10: /* undef, !C | Z */
828df0232feSRichard Henderson     case 13: /* undef, !V */
829df0232feSRichard Henderson         return cond_make_t();
830df0232feSRichard Henderson 
831df0232feSRichard Henderson     case 2:  /* == */
832b5af8423SRichard Henderson         tc = TCG_COND_EQ;
833b5af8423SRichard Henderson         ext_uns = true;
834b5af8423SRichard Henderson         break;
835df0232feSRichard Henderson     case 3:  /* <> */
836b5af8423SRichard Henderson         tc = TCG_COND_NE;
837b5af8423SRichard Henderson         ext_uns = true;
838b5af8423SRichard Henderson         break;
839df0232feSRichard Henderson     case 4:  /* < */
840b5af8423SRichard Henderson         tc = TCG_COND_LT;
841b5af8423SRichard Henderson         ext_uns = false;
842b5af8423SRichard Henderson         break;
843df0232feSRichard Henderson     case 5:  /* >= */
844b5af8423SRichard Henderson         tc = TCG_COND_GE;
845b5af8423SRichard Henderson         ext_uns = false;
846b5af8423SRichard Henderson         break;
847df0232feSRichard Henderson     case 6:  /* <= */
848b5af8423SRichard Henderson         tc = TCG_COND_LE;
849b5af8423SRichard Henderson         ext_uns = false;
850b5af8423SRichard Henderson         break;
851df0232feSRichard Henderson     case 7:  /* > */
852b5af8423SRichard Henderson         tc = TCG_COND_GT;
853b5af8423SRichard Henderson         ext_uns = false;
854b5af8423SRichard Henderson         break;
855df0232feSRichard Henderson 
856df0232feSRichard Henderson     case 14: /* OD */
857df0232feSRichard Henderson     case 15: /* EV */
858a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, NULL);
859df0232feSRichard Henderson 
860df0232feSRichard Henderson     default:
861df0232feSRichard Henderson         g_assert_not_reached();
862b2167459SRichard Henderson     }
863b5af8423SRichard Henderson 
864b5af8423SRichard Henderson     if (cond_need_ext(ctx, d)) {
865aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
866b5af8423SRichard Henderson 
867b5af8423SRichard Henderson         if (ext_uns) {
8686fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
869b5af8423SRichard Henderson         } else {
8706fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, res);
871b5af8423SRichard Henderson         }
872b5af8423SRichard Henderson         return cond_make_0_tmp(tc, tmp);
873b5af8423SRichard Henderson     }
874b5af8423SRichard Henderson     return cond_make_0(tc, res);
875b2167459SRichard Henderson }
876b2167459SRichard Henderson 
87798cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
87898cd9ca7SRichard Henderson 
8794fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d,
8806fd0c7bcSRichard Henderson                              TCGv_i64 res)
88198cd9ca7SRichard Henderson {
88298cd9ca7SRichard Henderson     unsigned c, f;
88398cd9ca7SRichard Henderson 
88498cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
88598cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
88698cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
88798cd9ca7SRichard Henderson     c = orig & 3;
88898cd9ca7SRichard Henderson     if (c == 3) {
88998cd9ca7SRichard Henderson         c = 7;
89098cd9ca7SRichard Henderson     }
89198cd9ca7SRichard Henderson     f = (orig & 4) / 4;
89298cd9ca7SRichard Henderson 
893b5af8423SRichard Henderson     return do_log_cond(ctx, c * 2 + f, d, res);
89498cd9ca7SRichard Henderson }
89598cd9ca7SRichard Henderson 
896b2167459SRichard Henderson /* Similar, but for unit conditions.  */
897b2167459SRichard Henderson 
8986fd0c7bcSRichard Henderson static DisasCond do_unit_cond(unsigned cf, bool d, TCGv_i64 res,
8996fd0c7bcSRichard Henderson                               TCGv_i64 in1, TCGv_i64 in2)
900b2167459SRichard Henderson {
901b2167459SRichard Henderson     DisasCond cond;
9026fd0c7bcSRichard Henderson     TCGv_i64 tmp, cb = NULL;
903c53e401eSRichard Henderson     uint64_t d_repl = d ? 0x0000000100000001ull : 1;
904b2167459SRichard Henderson 
905b2167459SRichard Henderson     if (cf & 8) {
906b2167459SRichard Henderson         /* Since we want to test lots of carry-out bits all at once, do not
907b2167459SRichard Henderson          * do our normal thing and compute carry-in of bit B+1 since that
908b2167459SRichard Henderson          * leaves us with carry bits spread across two words.
909b2167459SRichard Henderson          */
910aac0f603SRichard Henderson         cb = tcg_temp_new_i64();
911aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
9126fd0c7bcSRichard Henderson         tcg_gen_or_i64(cb, in1, in2);
9136fd0c7bcSRichard Henderson         tcg_gen_and_i64(tmp, in1, in2);
9146fd0c7bcSRichard Henderson         tcg_gen_andc_i64(cb, cb, res);
9156fd0c7bcSRichard Henderson         tcg_gen_or_i64(cb, cb, tmp);
916b2167459SRichard Henderson     }
917b2167459SRichard Henderson 
918b2167459SRichard Henderson     switch (cf >> 1) {
919b2167459SRichard Henderson     case 0: /* never / TR */
920b2167459SRichard Henderson     case 1: /* undefined */
921b2167459SRichard Henderson     case 5: /* undefined */
922b2167459SRichard Henderson         cond = cond_make_f();
923b2167459SRichard Henderson         break;
924b2167459SRichard Henderson 
925b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
926b2167459SRichard Henderson         /* See hasless(v,1) from
927b2167459SRichard Henderson          * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
928b2167459SRichard Henderson          */
929aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
9306fd0c7bcSRichard Henderson         tcg_gen_subi_i64(tmp, res, d_repl * 0x01010101u);
9316fd0c7bcSRichard Henderson         tcg_gen_andc_i64(tmp, tmp, res);
9326fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80808080u);
933b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
934b2167459SRichard Henderson         break;
935b2167459SRichard Henderson 
936b2167459SRichard Henderson     case 3: /* SHZ / NHZ */
937aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
9386fd0c7bcSRichard Henderson         tcg_gen_subi_i64(tmp, res, d_repl * 0x00010001u);
9396fd0c7bcSRichard Henderson         tcg_gen_andc_i64(tmp, tmp, res);
9406fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80008000u);
941b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
942b2167459SRichard Henderson         break;
943b2167459SRichard Henderson 
944b2167459SRichard Henderson     case 4: /* SDC / NDC */
9456fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x88888888u);
946b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
947b2167459SRichard Henderson         break;
948b2167459SRichard Henderson 
949b2167459SRichard Henderson     case 6: /* SBC / NBC */
9506fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x80808080u);
951b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
952b2167459SRichard Henderson         break;
953b2167459SRichard Henderson 
954b2167459SRichard Henderson     case 7: /* SHC / NHC */
9556fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x80008000u);
956b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
957b2167459SRichard Henderson         break;
958b2167459SRichard Henderson 
959b2167459SRichard Henderson     default:
960b2167459SRichard Henderson         g_assert_not_reached();
961b2167459SRichard Henderson     }
962b2167459SRichard Henderson     if (cf & 1) {
963b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
964b2167459SRichard Henderson     }
965b2167459SRichard Henderson 
966b2167459SRichard Henderson     return cond;
967b2167459SRichard Henderson }
968b2167459SRichard Henderson 
9696fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d,
9706fd0c7bcSRichard Henderson                           TCGv_i64 cb, TCGv_i64 cb_msb)
97172ca8753SRichard Henderson {
97272ca8753SRichard Henderson     if (cond_need_ext(ctx, d)) {
973aac0f603SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
9746fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, cb, 32, 1);
97572ca8753SRichard Henderson         return t;
97672ca8753SRichard Henderson     }
97772ca8753SRichard Henderson     return cb_msb;
97872ca8753SRichard Henderson }
97972ca8753SRichard Henderson 
9806fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d)
98172ca8753SRichard Henderson {
98272ca8753SRichard Henderson     return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb);
98372ca8753SRichard Henderson }
98472ca8753SRichard Henderson 
985b2167459SRichard Henderson /* Compute signed overflow for addition.  */
9866fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res,
9876fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
988b2167459SRichard Henderson {
989aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
990aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
991b2167459SRichard Henderson 
9926fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
9936fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
9946fd0c7bcSRichard Henderson     tcg_gen_andc_i64(sv, sv, tmp);
995b2167459SRichard Henderson 
996b2167459SRichard Henderson     return sv;
997b2167459SRichard Henderson }
998b2167459SRichard Henderson 
999b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
10006fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res,
10016fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
1002b2167459SRichard Henderson {
1003aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
1004aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
1005b2167459SRichard Henderson 
10066fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
10076fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
10086fd0c7bcSRichard Henderson     tcg_gen_and_i64(sv, sv, tmp);
1009b2167459SRichard Henderson 
1010b2167459SRichard Henderson     return sv;
1011b2167459SRichard Henderson }
1012b2167459SRichard Henderson 
10136fd0c7bcSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
10146fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned shift, bool is_l,
1015faf97ba1SRichard Henderson                    bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d)
1016b2167459SRichard Henderson {
10176fd0c7bcSRichard Henderson     TCGv_i64 dest, cb, cb_msb, cb_cond, sv, tmp;
1018b2167459SRichard Henderson     unsigned c = cf >> 1;
1019b2167459SRichard Henderson     DisasCond cond;
1020b2167459SRichard Henderson 
1021aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1022f764718dSRichard Henderson     cb = NULL;
1023f764718dSRichard Henderson     cb_msb = NULL;
1024bdcccc17SRichard Henderson     cb_cond = NULL;
1025b2167459SRichard Henderson 
1026b2167459SRichard Henderson     if (shift) {
1027aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
10286fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, in1, shift);
1029b2167459SRichard Henderson         in1 = tmp;
1030b2167459SRichard Henderson     }
1031b2167459SRichard Henderson 
1032b47a4a02SSven Schnelle     if (!is_l || cond_need_cb(c)) {
1033aac0f603SRichard Henderson         cb_msb = tcg_temp_new_i64();
1034aac0f603SRichard Henderson         cb = tcg_temp_new_i64();
1035bdcccc17SRichard Henderson 
1036a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero);
1037b2167459SRichard Henderson         if (is_c) {
10386fd0c7bcSRichard Henderson             tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb,
1039a4db4a78SRichard Henderson                              get_psw_carry(ctx, d), ctx->zero);
1040b2167459SRichard Henderson         }
10416fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
10426fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1043bdcccc17SRichard Henderson         if (cond_need_cb(c)) {
1044bdcccc17SRichard Henderson             cb_cond = get_carry(ctx, d, cb, cb_msb);
1045b2167459SRichard Henderson         }
1046b2167459SRichard Henderson     } else {
10476fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
1048b2167459SRichard Henderson         if (is_c) {
10496fd0c7bcSRichard Henderson             tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d));
1050b2167459SRichard Henderson         }
1051b2167459SRichard Henderson     }
1052b2167459SRichard Henderson 
1053b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1054f764718dSRichard Henderson     sv = NULL;
1055b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1056b2167459SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
1057b2167459SRichard Henderson         if (is_tsv) {
1058b2167459SRichard Henderson             /* ??? Need to include overflow from shift.  */
1059ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1060b2167459SRichard Henderson         }
1061b2167459SRichard Henderson     }
1062b2167459SRichard Henderson 
1063b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1064a751eb31SRichard Henderson     cond = do_cond(ctx, cf, d, dest, cb_cond, sv);
1065b2167459SRichard Henderson     if (is_tc) {
1066aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
10676fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1068ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1069b2167459SRichard Henderson     }
1070b2167459SRichard Henderson 
1071b2167459SRichard Henderson     /* Write back the result.  */
1072b2167459SRichard Henderson     if (!is_l) {
1073b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
1074b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1075b2167459SRichard Henderson     }
1076b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1077b2167459SRichard Henderson 
1078b2167459SRichard Henderson     /* Install the new nullification.  */
1079b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1080b2167459SRichard Henderson     ctx->null_cond = cond;
1081b2167459SRichard Henderson }
1082b2167459SRichard Henderson 
1083faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a,
10840c982a28SRichard Henderson                        bool is_l, bool is_tsv, bool is_tc, bool is_c)
10850c982a28SRichard Henderson {
10866fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
10870c982a28SRichard Henderson 
10880c982a28SRichard Henderson     if (a->cf) {
10890c982a28SRichard Henderson         nullify_over(ctx);
10900c982a28SRichard Henderson     }
10910c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
10920c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1093faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l,
1094faf97ba1SRichard Henderson            is_tsv, is_tc, is_c, a->cf, a->d);
10950c982a28SRichard Henderson     return nullify_end(ctx);
10960c982a28SRichard Henderson }
10970c982a28SRichard Henderson 
10980588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a,
10990588e061SRichard Henderson                        bool is_tsv, bool is_tc)
11000588e061SRichard Henderson {
11016fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
11020588e061SRichard Henderson 
11030588e061SRichard Henderson     if (a->cf) {
11040588e061SRichard Henderson         nullify_over(ctx);
11050588e061SRichard Henderson     }
11066fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
11070588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
1108faf97ba1SRichard Henderson     /* All ADDI conditions are 32-bit. */
1109faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false);
11100588e061SRichard Henderson     return nullify_end(ctx);
11110588e061SRichard Henderson }
11120588e061SRichard Henderson 
11136fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
11146fd0c7bcSRichard Henderson                    TCGv_i64 in2, bool is_tsv, bool is_b,
111563c427c6SRichard Henderson                    bool is_tc, unsigned cf, bool d)
1116b2167459SRichard Henderson {
1117a4db4a78SRichard Henderson     TCGv_i64 dest, sv, cb, cb_msb, tmp;
1118b2167459SRichard Henderson     unsigned c = cf >> 1;
1119b2167459SRichard Henderson     DisasCond cond;
1120b2167459SRichard Henderson 
1121aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1122aac0f603SRichard Henderson     cb = tcg_temp_new_i64();
1123aac0f603SRichard Henderson     cb_msb = tcg_temp_new_i64();
1124b2167459SRichard Henderson 
1125b2167459SRichard Henderson     if (is_b) {
1126b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
11276fd0c7bcSRichard Henderson         tcg_gen_not_i64(cb, in2);
1128a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero,
1129a4db4a78SRichard Henderson                          get_psw_carry(ctx, d), ctx->zero);
1130a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero);
11316fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, in1);
11326fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1133b2167459SRichard Henderson     } else {
1134bdcccc17SRichard Henderson         /*
1135bdcccc17SRichard Henderson          * DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
1136bdcccc17SRichard Henderson          * operations by seeding the high word with 1 and subtracting.
1137bdcccc17SRichard Henderson          */
11386fd0c7bcSRichard Henderson         TCGv_i64 one = tcg_constant_i64(1);
1139a4db4a78SRichard Henderson         tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero);
11406fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(cb, in1, in2);
11416fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1142b2167459SRichard Henderson     }
1143b2167459SRichard Henderson 
1144b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1145f764718dSRichard Henderson     sv = NULL;
1146b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1147b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1148b2167459SRichard Henderson         if (is_tsv) {
1149ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1150b2167459SRichard Henderson         }
1151b2167459SRichard Henderson     }
1152b2167459SRichard Henderson 
1153b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
1154b2167459SRichard Henderson     if (!is_b) {
11554fe9533aSRichard Henderson         cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1156b2167459SRichard Henderson     } else {
1157a751eb31SRichard Henderson         cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv);
1158b2167459SRichard Henderson     }
1159b2167459SRichard Henderson 
1160b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1161b2167459SRichard Henderson     if (is_tc) {
1162aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
11636fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1164ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1165b2167459SRichard Henderson     }
1166b2167459SRichard Henderson 
1167b2167459SRichard Henderson     /* Write back the result.  */
1168b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
1169b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1170b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1171b2167459SRichard Henderson 
1172b2167459SRichard Henderson     /* Install the new nullification.  */
1173b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1174b2167459SRichard Henderson     ctx->null_cond = cond;
1175b2167459SRichard Henderson }
1176b2167459SRichard Henderson 
117763c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a,
11780c982a28SRichard Henderson                        bool is_tsv, bool is_b, bool is_tc)
11790c982a28SRichard Henderson {
11806fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
11810c982a28SRichard Henderson 
11820c982a28SRichard Henderson     if (a->cf) {
11830c982a28SRichard Henderson         nullify_over(ctx);
11840c982a28SRichard Henderson     }
11850c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
11860c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
118763c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d);
11880c982a28SRichard Henderson     return nullify_end(ctx);
11890c982a28SRichard Henderson }
11900c982a28SRichard Henderson 
11910588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv)
11920588e061SRichard Henderson {
11936fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
11940588e061SRichard Henderson 
11950588e061SRichard Henderson     if (a->cf) {
11960588e061SRichard Henderson         nullify_over(ctx);
11970588e061SRichard Henderson     }
11986fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
11990588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
120063c427c6SRichard Henderson     /* All SUBI conditions are 32-bit. */
120163c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false);
12020588e061SRichard Henderson     return nullify_end(ctx);
12030588e061SRichard Henderson }
12040588e061SRichard Henderson 
12056fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12066fd0c7bcSRichard Henderson                       TCGv_i64 in2, unsigned cf, bool d)
1207b2167459SRichard Henderson {
12086fd0c7bcSRichard Henderson     TCGv_i64 dest, sv;
1209b2167459SRichard Henderson     DisasCond cond;
1210b2167459SRichard Henderson 
1211aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
12126fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
1213b2167459SRichard Henderson 
1214b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1215f764718dSRichard Henderson     sv = NULL;
1216b47a4a02SSven Schnelle     if (cond_need_sv(cf >> 1)) {
1217b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1218b2167459SRichard Henderson     }
1219b2167459SRichard Henderson 
1220b2167459SRichard Henderson     /* Form the condition for the compare.  */
12214fe9533aSRichard Henderson     cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1222b2167459SRichard Henderson 
1223b2167459SRichard Henderson     /* Clear.  */
12246fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
1225b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1226b2167459SRichard Henderson 
1227b2167459SRichard Henderson     /* Install the new nullification.  */
1228b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1229b2167459SRichard Henderson     ctx->null_cond = cond;
1230b2167459SRichard Henderson }
1231b2167459SRichard Henderson 
12326fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12336fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned cf, bool d,
12346fd0c7bcSRichard Henderson                    void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1235b2167459SRichard Henderson {
12366fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, rt);
1237b2167459SRichard Henderson 
1238b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
1239b2167459SRichard Henderson     fn(dest, in1, in2);
1240b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1241b2167459SRichard Henderson 
1242b2167459SRichard Henderson     /* Install the new nullification.  */
1243b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1244b2167459SRichard Henderson     if (cf) {
1245b5af8423SRichard Henderson         ctx->null_cond = do_log_cond(ctx, cf, d, dest);
1246b2167459SRichard Henderson     }
1247b2167459SRichard Henderson }
1248b2167459SRichard Henderson 
1249fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a,
12506fd0c7bcSRichard Henderson                        void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
12510c982a28SRichard Henderson {
12526fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
12530c982a28SRichard Henderson 
12540c982a28SRichard Henderson     if (a->cf) {
12550c982a28SRichard Henderson         nullify_over(ctx);
12560c982a28SRichard Henderson     }
12570c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
12580c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1259fa8e3bedSRichard Henderson     do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn);
12600c982a28SRichard Henderson     return nullify_end(ctx);
12610c982a28SRichard Henderson }
12620c982a28SRichard Henderson 
12636fd0c7bcSRichard Henderson static void do_unit(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12646fd0c7bcSRichard Henderson                     TCGv_i64 in2, unsigned cf, bool d, bool is_tc,
12656fd0c7bcSRichard Henderson                     void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1266b2167459SRichard Henderson {
12676fd0c7bcSRichard Henderson     TCGv_i64 dest;
1268b2167459SRichard Henderson     DisasCond cond;
1269b2167459SRichard Henderson 
1270b2167459SRichard Henderson     if (cf == 0) {
1271b2167459SRichard Henderson         dest = dest_gpr(ctx, rt);
1272b2167459SRichard Henderson         fn(dest, in1, in2);
1273b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1274b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1275b2167459SRichard Henderson     } else {
1276aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
1277b2167459SRichard Henderson         fn(dest, in1, in2);
1278b2167459SRichard Henderson 
127959963d8fSRichard Henderson         cond = do_unit_cond(cf, d, dest, in1, in2);
1280b2167459SRichard Henderson 
1281b2167459SRichard Henderson         if (is_tc) {
1282aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
12836fd0c7bcSRichard Henderson             tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1284ad75a51eSRichard Henderson             gen_helper_tcond(tcg_env, tmp);
1285b2167459SRichard Henderson         }
1286b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1287b2167459SRichard Henderson 
1288b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1289b2167459SRichard Henderson         ctx->null_cond = cond;
1290b2167459SRichard Henderson     }
1291b2167459SRichard Henderson }
1292b2167459SRichard Henderson 
129386f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY
12948d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space
12958d6ae7fbSRichard Henderson    from the top 2 bits of the base register.  There are a few system
12968d6ae7fbSRichard Henderson    instructions that have a 3-bit space specifier, for which SR0 is
12978d6ae7fbSRichard Henderson    not special.  To handle this, pass ~SP.  */
12986fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base)
129986f8d05fSRichard Henderson {
130086f8d05fSRichard Henderson     TCGv_ptr ptr;
13016fd0c7bcSRichard Henderson     TCGv_i64 tmp;
130286f8d05fSRichard Henderson     TCGv_i64 spc;
130386f8d05fSRichard Henderson 
130486f8d05fSRichard Henderson     if (sp != 0) {
13058d6ae7fbSRichard Henderson         if (sp < 0) {
13068d6ae7fbSRichard Henderson             sp = ~sp;
13078d6ae7fbSRichard Henderson         }
13086fd0c7bcSRichard Henderson         spc = tcg_temp_new_i64();
13098d6ae7fbSRichard Henderson         load_spr(ctx, spc, sp);
13108d6ae7fbSRichard Henderson         return spc;
131186f8d05fSRichard Henderson     }
1312494737b7SRichard Henderson     if (ctx->tb_flags & TB_FLAG_SR_SAME) {
1313494737b7SRichard Henderson         return cpu_srH;
1314494737b7SRichard Henderson     }
131586f8d05fSRichard Henderson 
131686f8d05fSRichard Henderson     ptr = tcg_temp_new_ptr();
1317aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
13186fd0c7bcSRichard Henderson     spc = tcg_temp_new_i64();
131986f8d05fSRichard Henderson 
1320698240d1SRichard Henderson     /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */
13216fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5);
13226fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, 030);
13236fd0c7bcSRichard Henderson     tcg_gen_trunc_i64_ptr(ptr, tmp);
132486f8d05fSRichard Henderson 
1325ad75a51eSRichard Henderson     tcg_gen_add_ptr(ptr, ptr, tcg_env);
132686f8d05fSRichard Henderson     tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4]));
132786f8d05fSRichard Henderson 
132886f8d05fSRichard Henderson     return spc;
132986f8d05fSRichard Henderson }
133086f8d05fSRichard Henderson #endif
133186f8d05fSRichard Henderson 
13326fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
1333c53e401eSRichard Henderson                      unsigned rb, unsigned rx, int scale, int64_t disp,
133486f8d05fSRichard Henderson                      unsigned sp, int modify, bool is_phys)
133586f8d05fSRichard Henderson {
13366fd0c7bcSRichard Henderson     TCGv_i64 base = load_gpr(ctx, rb);
13376fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13386fd0c7bcSRichard Henderson     TCGv_i64 addr;
133986f8d05fSRichard Henderson 
1340f5b5c857SRichard Henderson     set_insn_breg(ctx, rb);
1341f5b5c857SRichard Henderson 
134286f8d05fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
134386f8d05fSRichard Henderson     if (rx) {
1344aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
13456fd0c7bcSRichard Henderson         tcg_gen_shli_i64(ofs, cpu_gr[rx], scale);
13466fd0c7bcSRichard Henderson         tcg_gen_add_i64(ofs, ofs, base);
134786f8d05fSRichard Henderson     } else if (disp || modify) {
1348aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
13496fd0c7bcSRichard Henderson         tcg_gen_addi_i64(ofs, base, disp);
135086f8d05fSRichard Henderson     } else {
135186f8d05fSRichard Henderson         ofs = base;
135286f8d05fSRichard Henderson     }
135386f8d05fSRichard Henderson 
135486f8d05fSRichard Henderson     *pofs = ofs;
13556fd0c7bcSRichard Henderson     *pgva = addr = tcg_temp_new_i64();
1356d265360fSRichard Henderson     tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base, gva_offset_mask(ctx));
1357698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY
135886f8d05fSRichard Henderson     if (!is_phys) {
1359d265360fSRichard Henderson         tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base));
136086f8d05fSRichard Henderson     }
136186f8d05fSRichard Henderson #endif
136286f8d05fSRichard Henderson }
136386f8d05fSRichard Henderson 
136496d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
136596d6407fSRichard Henderson  * < 0 for pre-modify,
136696d6407fSRichard Henderson  * > 0 for post-modify,
136796d6407fSRichard Henderson  * = 0 for no base register update.
136896d6407fSRichard Henderson  */
136996d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1370c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
137114776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
137296d6407fSRichard Henderson {
13736fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13746fd0c7bcSRichard Henderson     TCGv_i64 addr;
137596d6407fSRichard Henderson 
137696d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
137796d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
137896d6407fSRichard Henderson 
137986f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
138017fe594cSRichard Henderson              MMU_DISABLED(ctx));
1381c1f55d97SRichard Henderson     tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
138286f8d05fSRichard Henderson     if (modify) {
138386f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
138496d6407fSRichard Henderson     }
138596d6407fSRichard Henderson }
138696d6407fSRichard Henderson 
138796d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1388c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
138914776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
139096d6407fSRichard Henderson {
13916fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13926fd0c7bcSRichard Henderson     TCGv_i64 addr;
139396d6407fSRichard Henderson 
139496d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
139596d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
139696d6407fSRichard Henderson 
139786f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
139817fe594cSRichard Henderson              MMU_DISABLED(ctx));
1399217d1a5eSRichard Henderson     tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
140086f8d05fSRichard Henderson     if (modify) {
140186f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
140296d6407fSRichard Henderson     }
140396d6407fSRichard Henderson }
140496d6407fSRichard Henderson 
140596d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1406c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
140714776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
140896d6407fSRichard Henderson {
14096fd0c7bcSRichard Henderson     TCGv_i64 ofs;
14106fd0c7bcSRichard Henderson     TCGv_i64 addr;
141196d6407fSRichard Henderson 
141296d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
141396d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
141496d6407fSRichard Henderson 
141586f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
141617fe594cSRichard Henderson              MMU_DISABLED(ctx));
1417217d1a5eSRichard Henderson     tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
141886f8d05fSRichard Henderson     if (modify) {
141986f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
142096d6407fSRichard Henderson     }
142196d6407fSRichard Henderson }
142296d6407fSRichard Henderson 
142396d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1424c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
142514776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
142696d6407fSRichard Henderson {
14276fd0c7bcSRichard Henderson     TCGv_i64 ofs;
14286fd0c7bcSRichard Henderson     TCGv_i64 addr;
142996d6407fSRichard Henderson 
143096d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
143196d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
143296d6407fSRichard Henderson 
143386f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
143417fe594cSRichard Henderson              MMU_DISABLED(ctx));
1435217d1a5eSRichard Henderson     tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
143686f8d05fSRichard Henderson     if (modify) {
143786f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
143896d6407fSRichard Henderson     }
143996d6407fSRichard Henderson }
144096d6407fSRichard Henderson 
14411cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1442c53e401eSRichard Henderson                     unsigned rx, int scale, int64_t disp,
144314776ab5STony Nguyen                     unsigned sp, int modify, MemOp mop)
144496d6407fSRichard Henderson {
14456fd0c7bcSRichard Henderson     TCGv_i64 dest;
144696d6407fSRichard Henderson 
144796d6407fSRichard Henderson     nullify_over(ctx);
144896d6407fSRichard Henderson 
144996d6407fSRichard Henderson     if (modify == 0) {
145096d6407fSRichard Henderson         /* No base register update.  */
145196d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
145296d6407fSRichard Henderson     } else {
145396d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
1454aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
145596d6407fSRichard Henderson     }
14566fd0c7bcSRichard Henderson     do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
145796d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
145896d6407fSRichard Henderson 
14591cd012a5SRichard Henderson     return nullify_end(ctx);
146096d6407fSRichard Henderson }
146196d6407fSRichard Henderson 
1462740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
1463c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
146486f8d05fSRichard Henderson                       unsigned sp, int modify)
146596d6407fSRichard Henderson {
146696d6407fSRichard Henderson     TCGv_i32 tmp;
146796d6407fSRichard Henderson 
146896d6407fSRichard Henderson     nullify_over(ctx);
146996d6407fSRichard Henderson 
147096d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
147186f8d05fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
147296d6407fSRichard Henderson     save_frw_i32(rt, tmp);
147396d6407fSRichard Henderson 
147496d6407fSRichard Henderson     if (rt == 0) {
1475ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
147696d6407fSRichard Henderson     }
147796d6407fSRichard Henderson 
1478740038d7SRichard Henderson     return nullify_end(ctx);
147996d6407fSRichard Henderson }
148096d6407fSRichard Henderson 
1481740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a)
1482740038d7SRichard Henderson {
1483740038d7SRichard Henderson     return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1484740038d7SRichard Henderson                      a->disp, a->sp, a->m);
1485740038d7SRichard Henderson }
1486740038d7SRichard Henderson 
1487740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1488c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
148986f8d05fSRichard Henderson                       unsigned sp, int modify)
149096d6407fSRichard Henderson {
149196d6407fSRichard Henderson     TCGv_i64 tmp;
149296d6407fSRichard Henderson 
149396d6407fSRichard Henderson     nullify_over(ctx);
149496d6407fSRichard Henderson 
149596d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
1496fc313c64SFrédéric Pétrot     do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
149796d6407fSRichard Henderson     save_frd(rt, tmp);
149896d6407fSRichard Henderson 
149996d6407fSRichard Henderson     if (rt == 0) {
1500ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
150196d6407fSRichard Henderson     }
150296d6407fSRichard Henderson 
1503740038d7SRichard Henderson     return nullify_end(ctx);
1504740038d7SRichard Henderson }
1505740038d7SRichard Henderson 
1506740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a)
1507740038d7SRichard Henderson {
1508740038d7SRichard Henderson     return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1509740038d7SRichard Henderson                      a->disp, a->sp, a->m);
151096d6407fSRichard Henderson }
151196d6407fSRichard Henderson 
15121cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb,
1513c53e401eSRichard Henderson                      int64_t disp, unsigned sp,
151414776ab5STony Nguyen                      int modify, MemOp mop)
151596d6407fSRichard Henderson {
151696d6407fSRichard Henderson     nullify_over(ctx);
15176fd0c7bcSRichard Henderson     do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
15181cd012a5SRichard Henderson     return nullify_end(ctx);
151996d6407fSRichard Henderson }
152096d6407fSRichard Henderson 
1521740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1522c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
152386f8d05fSRichard Henderson                        unsigned sp, int modify)
152496d6407fSRichard Henderson {
152596d6407fSRichard Henderson     TCGv_i32 tmp;
152696d6407fSRichard Henderson 
152796d6407fSRichard Henderson     nullify_over(ctx);
152896d6407fSRichard Henderson 
152996d6407fSRichard Henderson     tmp = load_frw_i32(rt);
153086f8d05fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
153196d6407fSRichard Henderson 
1532740038d7SRichard Henderson     return nullify_end(ctx);
153396d6407fSRichard Henderson }
153496d6407fSRichard Henderson 
1535740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a)
1536740038d7SRichard Henderson {
1537740038d7SRichard Henderson     return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1538740038d7SRichard Henderson                       a->disp, a->sp, a->m);
1539740038d7SRichard Henderson }
1540740038d7SRichard Henderson 
1541740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1542c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
154386f8d05fSRichard Henderson                        unsigned sp, int modify)
154496d6407fSRichard Henderson {
154596d6407fSRichard Henderson     TCGv_i64 tmp;
154696d6407fSRichard Henderson 
154796d6407fSRichard Henderson     nullify_over(ctx);
154896d6407fSRichard Henderson 
154996d6407fSRichard Henderson     tmp = load_frd(rt);
1550fc313c64SFrédéric Pétrot     do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
155196d6407fSRichard Henderson 
1552740038d7SRichard Henderson     return nullify_end(ctx);
1553740038d7SRichard Henderson }
1554740038d7SRichard Henderson 
1555740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a)
1556740038d7SRichard Henderson {
1557740038d7SRichard Henderson     return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1558740038d7SRichard Henderson                       a->disp, a->sp, a->m);
155996d6407fSRichard Henderson }
156096d6407fSRichard Henderson 
15611ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1562ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1563ebe9383cSRichard Henderson {
1564ebe9383cSRichard Henderson     TCGv_i32 tmp;
1565ebe9383cSRichard Henderson 
1566ebe9383cSRichard Henderson     nullify_over(ctx);
1567ebe9383cSRichard Henderson     tmp = load_frw0_i32(ra);
1568ebe9383cSRichard Henderson 
1569ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1570ebe9383cSRichard Henderson 
1571ebe9383cSRichard Henderson     save_frw_i32(rt, tmp);
15721ca74648SRichard Henderson     return nullify_end(ctx);
1573ebe9383cSRichard Henderson }
1574ebe9383cSRichard Henderson 
15751ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1576ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1577ebe9383cSRichard Henderson {
1578ebe9383cSRichard Henderson     TCGv_i32 dst;
1579ebe9383cSRichard Henderson     TCGv_i64 src;
1580ebe9383cSRichard Henderson 
1581ebe9383cSRichard Henderson     nullify_over(ctx);
1582ebe9383cSRichard Henderson     src = load_frd(ra);
1583ebe9383cSRichard Henderson     dst = tcg_temp_new_i32();
1584ebe9383cSRichard Henderson 
1585ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1586ebe9383cSRichard Henderson 
1587ebe9383cSRichard Henderson     save_frw_i32(rt, dst);
15881ca74648SRichard Henderson     return nullify_end(ctx);
1589ebe9383cSRichard Henderson }
1590ebe9383cSRichard Henderson 
15911ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1592ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1593ebe9383cSRichard Henderson {
1594ebe9383cSRichard Henderson     TCGv_i64 tmp;
1595ebe9383cSRichard Henderson 
1596ebe9383cSRichard Henderson     nullify_over(ctx);
1597ebe9383cSRichard Henderson     tmp = load_frd0(ra);
1598ebe9383cSRichard Henderson 
1599ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1600ebe9383cSRichard Henderson 
1601ebe9383cSRichard Henderson     save_frd(rt, tmp);
16021ca74648SRichard Henderson     return nullify_end(ctx);
1603ebe9383cSRichard Henderson }
1604ebe9383cSRichard Henderson 
16051ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1606ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1607ebe9383cSRichard Henderson {
1608ebe9383cSRichard Henderson     TCGv_i32 src;
1609ebe9383cSRichard Henderson     TCGv_i64 dst;
1610ebe9383cSRichard Henderson 
1611ebe9383cSRichard Henderson     nullify_over(ctx);
1612ebe9383cSRichard Henderson     src = load_frw0_i32(ra);
1613ebe9383cSRichard Henderson     dst = tcg_temp_new_i64();
1614ebe9383cSRichard Henderson 
1615ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1616ebe9383cSRichard Henderson 
1617ebe9383cSRichard Henderson     save_frd(rt, dst);
16181ca74648SRichard Henderson     return nullify_end(ctx);
1619ebe9383cSRichard Henderson }
1620ebe9383cSRichard Henderson 
16211ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt,
1622ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
162331234768SRichard Henderson                         void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
1624ebe9383cSRichard Henderson {
1625ebe9383cSRichard Henderson     TCGv_i32 a, b;
1626ebe9383cSRichard Henderson 
1627ebe9383cSRichard Henderson     nullify_over(ctx);
1628ebe9383cSRichard Henderson     a = load_frw0_i32(ra);
1629ebe9383cSRichard Henderson     b = load_frw0_i32(rb);
1630ebe9383cSRichard Henderson 
1631ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1632ebe9383cSRichard Henderson 
1633ebe9383cSRichard Henderson     save_frw_i32(rt, a);
16341ca74648SRichard Henderson     return nullify_end(ctx);
1635ebe9383cSRichard Henderson }
1636ebe9383cSRichard Henderson 
16371ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt,
1638ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
163931234768SRichard Henderson                         void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
1640ebe9383cSRichard Henderson {
1641ebe9383cSRichard Henderson     TCGv_i64 a, b;
1642ebe9383cSRichard Henderson 
1643ebe9383cSRichard Henderson     nullify_over(ctx);
1644ebe9383cSRichard Henderson     a = load_frd0(ra);
1645ebe9383cSRichard Henderson     b = load_frd0(rb);
1646ebe9383cSRichard Henderson 
1647ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1648ebe9383cSRichard Henderson 
1649ebe9383cSRichard Henderson     save_frd(rt, a);
16501ca74648SRichard Henderson     return nullify_end(ctx);
1651ebe9383cSRichard Henderson }
1652ebe9383cSRichard Henderson 
165398cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
165498cd9ca7SRichard Henderson    have already had nullification handled.  */
1655c53e401eSRichard Henderson static bool do_dbranch(DisasContext *ctx, uint64_t dest,
165698cd9ca7SRichard Henderson                        unsigned link, bool is_n)
165798cd9ca7SRichard Henderson {
165898cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
165998cd9ca7SRichard Henderson         if (link != 0) {
1660741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
166198cd9ca7SRichard Henderson         }
166298cd9ca7SRichard Henderson         ctx->iaoq_n = dest;
166398cd9ca7SRichard Henderson         if (is_n) {
166498cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
166598cd9ca7SRichard Henderson         }
166698cd9ca7SRichard Henderson     } else {
166798cd9ca7SRichard Henderson         nullify_over(ctx);
166898cd9ca7SRichard Henderson 
166998cd9ca7SRichard Henderson         if (link != 0) {
1670741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
167198cd9ca7SRichard Henderson         }
167298cd9ca7SRichard Henderson 
167398cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
167498cd9ca7SRichard Henderson             nullify_set(ctx, 0);
167598cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, dest, dest + 4);
167698cd9ca7SRichard Henderson         } else {
167798cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
167898cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
167998cd9ca7SRichard Henderson         }
168098cd9ca7SRichard Henderson 
168131234768SRichard Henderson         nullify_end(ctx);
168298cd9ca7SRichard Henderson 
168398cd9ca7SRichard Henderson         nullify_set(ctx, 0);
168498cd9ca7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
168531234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
168698cd9ca7SRichard Henderson     }
168701afb7beSRichard Henderson     return true;
168898cd9ca7SRichard Henderson }
168998cd9ca7SRichard Henderson 
169098cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
169198cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
1692c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n,
169398cd9ca7SRichard Henderson                        DisasCond *cond)
169498cd9ca7SRichard Henderson {
1695c53e401eSRichard Henderson     uint64_t dest = iaoq_dest(ctx, disp);
169698cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
169798cd9ca7SRichard Henderson     TCGCond c = cond->c;
169898cd9ca7SRichard Henderson     bool n;
169998cd9ca7SRichard Henderson 
170098cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
170198cd9ca7SRichard Henderson 
170298cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
170398cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
170401afb7beSRichard Henderson         return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
170598cd9ca7SRichard Henderson     }
170698cd9ca7SRichard Henderson     if (c == TCG_COND_NEVER) {
170701afb7beSRichard Henderson         return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
170898cd9ca7SRichard Henderson     }
170998cd9ca7SRichard Henderson 
171098cd9ca7SRichard Henderson     taken = gen_new_label();
17116fd0c7bcSRichard Henderson     tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken);
171298cd9ca7SRichard Henderson     cond_free(cond);
171398cd9ca7SRichard Henderson 
171498cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
171598cd9ca7SRichard Henderson     n = is_n && disp < 0;
171698cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
171798cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1718a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
171998cd9ca7SRichard Henderson     } else {
172098cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
172198cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
172298cd9ca7SRichard Henderson             ctx->null_lab = NULL;
172398cd9ca7SRichard Henderson         }
172498cd9ca7SRichard Henderson         nullify_set(ctx, n);
1725c301f34eSRichard Henderson         if (ctx->iaoq_n == -1) {
1726c301f34eSRichard Henderson             /* The temporary iaoq_n_var died at the branch above.
1727c301f34eSRichard Henderson                Regenerate it here instead of saving it.  */
17286fd0c7bcSRichard Henderson             tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
1729c301f34eSRichard Henderson         }
1730a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
173198cd9ca7SRichard Henderson     }
173298cd9ca7SRichard Henderson 
173398cd9ca7SRichard Henderson     gen_set_label(taken);
173498cd9ca7SRichard Henderson 
173598cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
173698cd9ca7SRichard Henderson     n = is_n && disp >= 0;
173798cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
173898cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1739a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, dest, dest + 4);
174098cd9ca7SRichard Henderson     } else {
174198cd9ca7SRichard Henderson         nullify_set(ctx, n);
1742a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
174398cd9ca7SRichard Henderson     }
174498cd9ca7SRichard Henderson 
174598cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
174698cd9ca7SRichard Henderson     if (ctx->null_lab) {
174798cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
174898cd9ca7SRichard Henderson         ctx->null_lab = NULL;
174931234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
175098cd9ca7SRichard Henderson     } else {
175131234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
175298cd9ca7SRichard Henderson     }
175301afb7beSRichard Henderson     return true;
175498cd9ca7SRichard Henderson }
175598cd9ca7SRichard Henderson 
175698cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target.  This handles
175798cd9ca7SRichard Henderson    nullification of the branch itself.  */
17586fd0c7bcSRichard Henderson static bool do_ibranch(DisasContext *ctx, TCGv_i64 dest,
175998cd9ca7SRichard Henderson                        unsigned link, bool is_n)
176098cd9ca7SRichard Henderson {
17616fd0c7bcSRichard Henderson     TCGv_i64 a0, a1, next, tmp;
176298cd9ca7SRichard Henderson     TCGCond c;
176398cd9ca7SRichard Henderson 
176498cd9ca7SRichard Henderson     assert(ctx->null_lab == NULL);
176598cd9ca7SRichard Henderson 
176698cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
176798cd9ca7SRichard Henderson         if (link != 0) {
1768741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
176998cd9ca7SRichard Henderson         }
1770aac0f603SRichard Henderson         next = tcg_temp_new_i64();
17716fd0c7bcSRichard Henderson         tcg_gen_mov_i64(next, dest);
177298cd9ca7SRichard Henderson         if (is_n) {
1773c301f34eSRichard Henderson             if (use_nullify_skip(ctx)) {
1774a0180973SRichard Henderson                 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, next);
17756fd0c7bcSRichard Henderson                 tcg_gen_addi_i64(next, next, 4);
1776a0180973SRichard Henderson                 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
1777c301f34eSRichard Henderson                 nullify_set(ctx, 0);
177831234768SRichard Henderson                 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
177901afb7beSRichard Henderson                 return true;
1780c301f34eSRichard Henderson             }
178198cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
178298cd9ca7SRichard Henderson         }
1783c301f34eSRichard Henderson         ctx->iaoq_n = -1;
1784c301f34eSRichard Henderson         ctx->iaoq_n_var = next;
178598cd9ca7SRichard Henderson     } else if (is_n && use_nullify_skip(ctx)) {
178698cd9ca7SRichard Henderson         /* The (conditional) branch, B, nullifies the next insn, N,
178798cd9ca7SRichard Henderson            and we're allowed to skip execution N (no single-step or
17884137cb83SRichard Henderson            tracepoint in effect).  Since the goto_ptr that we must use
178998cd9ca7SRichard Henderson            for the indirect branch consumes no special resources, we
179098cd9ca7SRichard Henderson            can (conditionally) skip B and continue execution.  */
179198cd9ca7SRichard Henderson         /* The use_nullify_skip test implies we have a known control path.  */
179298cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_b != -1);
179398cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_n != -1);
179498cd9ca7SRichard Henderson 
179598cd9ca7SRichard Henderson         /* We do have to handle the non-local temporary, DEST, before
179698cd9ca7SRichard Henderson            branching.  Since IOAQ_F is not really live at this point, we
179798cd9ca7SRichard Henderson            can simply store DEST optimistically.  Similarly with IAOQ_B.  */
1798a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, dest);
1799aac0f603SRichard Henderson         next = tcg_temp_new_i64();
18006fd0c7bcSRichard Henderson         tcg_gen_addi_i64(next, dest, 4);
1801a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
180298cd9ca7SRichard Henderson 
180398cd9ca7SRichard Henderson         nullify_over(ctx);
180498cd9ca7SRichard Henderson         if (link != 0) {
18059a91dd84SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
180698cd9ca7SRichard Henderson         }
18077f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
180801afb7beSRichard Henderson         return nullify_end(ctx);
180998cd9ca7SRichard Henderson     } else {
181098cd9ca7SRichard Henderson         c = ctx->null_cond.c;
181198cd9ca7SRichard Henderson         a0 = ctx->null_cond.a0;
181298cd9ca7SRichard Henderson         a1 = ctx->null_cond.a1;
181398cd9ca7SRichard Henderson 
1814aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
1815aac0f603SRichard Henderson         next = tcg_temp_new_i64();
181698cd9ca7SRichard Henderson 
1817741322f4SRichard Henderson         copy_iaoq_entry(ctx, tmp, ctx->iaoq_n, ctx->iaoq_n_var);
18186fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(c, next, a0, a1, tmp, dest);
181998cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
182098cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
182198cd9ca7SRichard Henderson 
182298cd9ca7SRichard Henderson         if (link != 0) {
18236fd0c7bcSRichard Henderson             tcg_gen_movcond_i64(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
182498cd9ca7SRichard Henderson         }
182598cd9ca7SRichard Henderson 
182698cd9ca7SRichard Henderson         if (is_n) {
182798cd9ca7SRichard Henderson             /* The branch nullifies the next insn, which means the state of N
182898cd9ca7SRichard Henderson                after the branch is the inverse of the state of N that applied
182998cd9ca7SRichard Henderson                to the branch.  */
18306fd0c7bcSRichard Henderson             tcg_gen_setcond_i64(tcg_invert_cond(c), cpu_psw_n, a0, a1);
183198cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
183298cd9ca7SRichard Henderson             ctx->null_cond = cond_make_n();
183398cd9ca7SRichard Henderson             ctx->psw_n_nonzero = true;
183498cd9ca7SRichard Henderson         } else {
183598cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
183698cd9ca7SRichard Henderson         }
183798cd9ca7SRichard Henderson     }
183801afb7beSRichard Henderson     return true;
183998cd9ca7SRichard Henderson }
184098cd9ca7SRichard Henderson 
1841660eefe1SRichard Henderson /* Implement
1842660eefe1SRichard Henderson  *    if (IAOQ_Front{30..31} < GR[b]{30..31})
1843660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← GR[b]{30..31};
1844660eefe1SRichard Henderson  *    else
1845660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← IAOQ_Front{30..31};
1846660eefe1SRichard Henderson  * which keeps the privilege level from being increased.
1847660eefe1SRichard Henderson  */
18486fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset)
1849660eefe1SRichard Henderson {
18506fd0c7bcSRichard Henderson     TCGv_i64 dest;
1851660eefe1SRichard Henderson     switch (ctx->privilege) {
1852660eefe1SRichard Henderson     case 0:
1853660eefe1SRichard Henderson         /* Privilege 0 is maximum and is allowed to decrease.  */
1854660eefe1SRichard Henderson         return offset;
1855660eefe1SRichard Henderson     case 3:
1856993119feSRichard Henderson         /* Privilege 3 is minimum and is never allowed to increase.  */
1857aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
18586fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, offset, 3);
1859660eefe1SRichard Henderson         break;
1860660eefe1SRichard Henderson     default:
1861aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
18626fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, offset, -4);
18636fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, ctx->privilege);
18646fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(TCG_COND_GTU, dest, dest, offset, dest, offset);
1865660eefe1SRichard Henderson         break;
1866660eefe1SRichard Henderson     }
1867660eefe1SRichard Henderson     return dest;
1868660eefe1SRichard Henderson }
1869660eefe1SRichard Henderson 
1870ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
18717ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
18727ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
18737ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
18747ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
18757ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
18767ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
18777ad439dfSRichard Henderson    aforementioned BE.  */
187831234768SRichard Henderson static void do_page_zero(DisasContext *ctx)
18797ad439dfSRichard Henderson {
18806fd0c7bcSRichard Henderson     TCGv_i64 tmp;
1881a0180973SRichard Henderson 
18827ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
18837ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
18848b81968cSMichael Tokarev        next insn within the privileged page.  */
18857ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
18867ad439dfSRichard Henderson     case TCG_COND_NEVER:
18877ad439dfSRichard Henderson         break;
18887ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
18896fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, 0);
18907ad439dfSRichard Henderson         goto do_sigill;
18917ad439dfSRichard Henderson     default:
18927ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
18937ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
18947ad439dfSRichard Henderson         g_assert_not_reached();
18957ad439dfSRichard Henderson     }
18967ad439dfSRichard Henderson 
18977ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
18987ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
18997ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
19007ad439dfSRichard Henderson        under such conditions.  */
19017ad439dfSRichard Henderson     if (ctx->iaoq_b != ctx->iaoq_f + 4) {
19027ad439dfSRichard Henderson         goto do_sigill;
19037ad439dfSRichard Henderson     }
19047ad439dfSRichard Henderson 
1905ebd0e151SRichard Henderson     switch (ctx->iaoq_f & -4) {
19067ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
19072986721dSRichard Henderson         gen_excp_1(EXCP_IMP);
190831234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
190931234768SRichard Henderson         break;
19107ad439dfSRichard Henderson 
19117ad439dfSRichard Henderson     case 0xb0: /* LWS */
19127ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
191331234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
191431234768SRichard Henderson         break;
19157ad439dfSRichard Henderson 
19167ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
19176fd0c7bcSRichard Henderson         tcg_gen_st_i64(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27]));
1918aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
19196fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_gr[31], 3);
1920a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
19216fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, 4);
1922a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
192331234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
192431234768SRichard Henderson         break;
19257ad439dfSRichard Henderson 
19267ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
19277ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
192831234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
192931234768SRichard Henderson         break;
19307ad439dfSRichard Henderson 
19317ad439dfSRichard Henderson     default:
19327ad439dfSRichard Henderson     do_sigill:
19332986721dSRichard Henderson         gen_excp_1(EXCP_ILL);
193431234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
193531234768SRichard Henderson         break;
19367ad439dfSRichard Henderson     }
19377ad439dfSRichard Henderson }
1938ba1d0b44SRichard Henderson #endif
19397ad439dfSRichard Henderson 
1940deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a)
1941b2167459SRichard Henderson {
1942b2167459SRichard Henderson     cond_free(&ctx->null_cond);
194331234768SRichard Henderson     return true;
1944b2167459SRichard Henderson }
1945b2167459SRichard Henderson 
194640f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a)
194798a9cb79SRichard Henderson {
194831234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_BREAK);
194998a9cb79SRichard Henderson }
195098a9cb79SRichard Henderson 
1951e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a)
195298a9cb79SRichard Henderson {
195398a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
195498a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
195598a9cb79SRichard Henderson 
195698a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
195731234768SRichard Henderson     return true;
195898a9cb79SRichard Henderson }
195998a9cb79SRichard Henderson 
1960c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a)
196198a9cb79SRichard Henderson {
1962c603e14aSRichard Henderson     unsigned rt = a->t;
19636fd0c7bcSRichard Henderson     TCGv_i64 tmp = dest_gpr(ctx, rt);
19646fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tmp, ctx->iaoq_f);
196598a9cb79SRichard Henderson     save_gpr(ctx, rt, tmp);
196698a9cb79SRichard Henderson 
196798a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
196831234768SRichard Henderson     return true;
196998a9cb79SRichard Henderson }
197098a9cb79SRichard Henderson 
1971c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a)
197298a9cb79SRichard Henderson {
1973c603e14aSRichard Henderson     unsigned rt = a->t;
1974c603e14aSRichard Henderson     unsigned rs = a->sp;
197533423472SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
197698a9cb79SRichard Henderson 
197733423472SRichard Henderson     load_spr(ctx, t0, rs);
197833423472SRichard Henderson     tcg_gen_shri_i64(t0, t0, 32);
197933423472SRichard Henderson 
1980967662cdSRichard Henderson     save_gpr(ctx, rt, t0);
198198a9cb79SRichard Henderson 
198298a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
198331234768SRichard Henderson     return true;
198498a9cb79SRichard Henderson }
198598a9cb79SRichard Henderson 
1986c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a)
198798a9cb79SRichard Henderson {
1988c603e14aSRichard Henderson     unsigned rt = a->t;
1989c603e14aSRichard Henderson     unsigned ctl = a->r;
19906fd0c7bcSRichard Henderson     TCGv_i64 tmp;
199198a9cb79SRichard Henderson 
199298a9cb79SRichard Henderson     switch (ctl) {
199335136a77SRichard Henderson     case CR_SAR:
1994c603e14aSRichard Henderson         if (a->e == 0) {
199598a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
199698a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
19976fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
199898a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
199935136a77SRichard Henderson             goto done;
200098a9cb79SRichard Henderson         }
200198a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
200235136a77SRichard Henderson         goto done;
200335136a77SRichard Henderson     case CR_IT: /* Interval Timer */
200435136a77SRichard Henderson         /* FIXME: Respect PSW_S bit.  */
200535136a77SRichard Henderson         nullify_over(ctx);
200698a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
2007dfd1b812SRichard Henderson         if (translator_io_start(&ctx->base)) {
200849c29d6cSRichard Henderson             gen_helper_read_interval_timer(tmp);
200931234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
201049c29d6cSRichard Henderson         } else {
201149c29d6cSRichard Henderson             gen_helper_read_interval_timer(tmp);
201249c29d6cSRichard Henderson         }
201398a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
201431234768SRichard Henderson         return nullify_end(ctx);
201598a9cb79SRichard Henderson     case 26:
201698a9cb79SRichard Henderson     case 27:
201798a9cb79SRichard Henderson         break;
201898a9cb79SRichard Henderson     default:
201998a9cb79SRichard Henderson         /* All other control registers are privileged.  */
202035136a77SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
202135136a77SRichard Henderson         break;
202298a9cb79SRichard Henderson     }
202398a9cb79SRichard Henderson 
2024aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
20256fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
202635136a77SRichard Henderson     save_gpr(ctx, rt, tmp);
202735136a77SRichard Henderson 
202835136a77SRichard Henderson  done:
202998a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
203031234768SRichard Henderson     return true;
203198a9cb79SRichard Henderson }
203298a9cb79SRichard Henderson 
2033c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
203433423472SRichard Henderson {
2035c603e14aSRichard Henderson     unsigned rr = a->r;
2036c603e14aSRichard Henderson     unsigned rs = a->sp;
2037967662cdSRichard Henderson     TCGv_i64 tmp;
203833423472SRichard Henderson 
203933423472SRichard Henderson     if (rs >= 5) {
204033423472SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
204133423472SRichard Henderson     }
204233423472SRichard Henderson     nullify_over(ctx);
204333423472SRichard Henderson 
2044967662cdSRichard Henderson     tmp = tcg_temp_new_i64();
2045967662cdSRichard Henderson     tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32);
204633423472SRichard Henderson 
204733423472SRichard Henderson     if (rs >= 4) {
2048967662cdSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs]));
2049494737b7SRichard Henderson         ctx->tb_flags &= ~TB_FLAG_SR_SAME;
205033423472SRichard Henderson     } else {
2051967662cdSRichard Henderson         tcg_gen_mov_i64(cpu_sr[rs], tmp);
205233423472SRichard Henderson     }
205333423472SRichard Henderson 
205431234768SRichard Henderson     return nullify_end(ctx);
205533423472SRichard Henderson }
205633423472SRichard Henderson 
2057c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
205898a9cb79SRichard Henderson {
2059c603e14aSRichard Henderson     unsigned ctl = a->t;
20606fd0c7bcSRichard Henderson     TCGv_i64 reg;
20616fd0c7bcSRichard Henderson     TCGv_i64 tmp;
206298a9cb79SRichard Henderson 
206335136a77SRichard Henderson     if (ctl == CR_SAR) {
20644845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
2065aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
20666fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31);
206798a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
206898a9cb79SRichard Henderson 
206998a9cb79SRichard Henderson         cond_free(&ctx->null_cond);
207031234768SRichard Henderson         return true;
207198a9cb79SRichard Henderson     }
207298a9cb79SRichard Henderson 
207335136a77SRichard Henderson     /* All other control registers are privileged or read-only.  */
207435136a77SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
207535136a77SRichard Henderson 
2076c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
207735136a77SRichard Henderson     nullify_over(ctx);
20784c34bab0SHelge Deller 
20794c34bab0SHelge Deller     if (ctx->is_pa20) {
20804845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
20814c34bab0SHelge Deller     } else {
20824c34bab0SHelge Deller         reg = tcg_temp_new_i64();
20834c34bab0SHelge Deller         tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r));
20844c34bab0SHelge Deller     }
20854845f015SSven Schnelle 
208635136a77SRichard Henderson     switch (ctl) {
208735136a77SRichard Henderson     case CR_IT:
2088ad75a51eSRichard Henderson         gen_helper_write_interval_timer(tcg_env, reg);
208935136a77SRichard Henderson         break;
20904f5f2548SRichard Henderson     case CR_EIRR:
2091ad75a51eSRichard Henderson         gen_helper_write_eirr(tcg_env, reg);
20924f5f2548SRichard Henderson         break;
20934f5f2548SRichard Henderson     case CR_EIEM:
2094ad75a51eSRichard Henderson         gen_helper_write_eiem(tcg_env, reg);
209531234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
20964f5f2548SRichard Henderson         break;
20974f5f2548SRichard Henderson 
209835136a77SRichard Henderson     case CR_IIASQ:
209935136a77SRichard Henderson     case CR_IIAOQ:
210035136a77SRichard Henderson         /* FIXME: Respect PSW_Q bit */
210135136a77SRichard Henderson         /* The write advances the queue and stores to the back element.  */
2102aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
21036fd0c7bcSRichard Henderson         tcg_gen_ld_i64(tmp, tcg_env,
210435136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
21056fd0c7bcSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
21066fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env,
210735136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
210835136a77SRichard Henderson         break;
210935136a77SRichard Henderson 
2110d5de20bdSSven Schnelle     case CR_PID1:
2111d5de20bdSSven Schnelle     case CR_PID2:
2112d5de20bdSSven Schnelle     case CR_PID3:
2113d5de20bdSSven Schnelle     case CR_PID4:
21146fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
2115d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY
2116ad75a51eSRichard Henderson         gen_helper_change_prot_id(tcg_env);
2117d5de20bdSSven Schnelle #endif
2118d5de20bdSSven Schnelle         break;
2119d5de20bdSSven Schnelle 
212035136a77SRichard Henderson     default:
21216fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
212235136a77SRichard Henderson         break;
212335136a77SRichard Henderson     }
212431234768SRichard Henderson     return nullify_end(ctx);
21254f5f2548SRichard Henderson #endif
212635136a77SRichard Henderson }
212735136a77SRichard Henderson 
2128c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
212998a9cb79SRichard Henderson {
2130aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
213198a9cb79SRichard Henderson 
21326fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, load_gpr(ctx, a->r));
21336fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31);
213498a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
213598a9cb79SRichard Henderson 
213698a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
213731234768SRichard Henderson     return true;
213898a9cb79SRichard Henderson }
213998a9cb79SRichard Henderson 
2140e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a)
214198a9cb79SRichard Henderson {
21426fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
214398a9cb79SRichard Henderson 
21442330504cSHelge Deller #ifdef CONFIG_USER_ONLY
21452330504cSHelge Deller     /* We don't implement space registers in user mode. */
21466fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
21472330504cSHelge Deller #else
2148967662cdSRichard Henderson     tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
2149967662cdSRichard Henderson     tcg_gen_shri_i64(dest, dest, 32);
21502330504cSHelge Deller #endif
2151e36f27efSRichard Henderson     save_gpr(ctx, a->t, dest);
215298a9cb79SRichard Henderson 
215398a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
215431234768SRichard Henderson     return true;
215598a9cb79SRichard Henderson }
215698a9cb79SRichard Henderson 
2157e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a)
2158e36f27efSRichard Henderson {
21597b2d70a1SHelge Deller #ifdef CONFIG_USER_ONLY
2160e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
21617b2d70a1SHelge Deller #else
21626fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2163e1b5a5edSRichard Henderson 
21647b2d70a1SHelge Deller     /* HP-UX 11i and HP ODE use rsm for read-access to PSW */
21657b2d70a1SHelge Deller     if (a->i) {
21667b2d70a1SHelge Deller         CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
21677b2d70a1SHelge Deller     }
21687b2d70a1SHelge Deller 
2169e1b5a5edSRichard Henderson     nullify_over(ctx);
2170e1b5a5edSRichard Henderson 
2171aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
21726fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
21736fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ~a->i);
2174ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2175e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2176e1b5a5edSRichard Henderson 
2177e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_M.  */
217831234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
217931234768SRichard Henderson     return nullify_end(ctx);
2180e36f27efSRichard Henderson #endif
2181e1b5a5edSRichard Henderson }
2182e1b5a5edSRichard Henderson 
2183e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
2184e1b5a5edSRichard Henderson {
2185e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2186e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
21876fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2188e1b5a5edSRichard Henderson 
2189e1b5a5edSRichard Henderson     nullify_over(ctx);
2190e1b5a5edSRichard Henderson 
2191aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
21926fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
21936fd0c7bcSRichard Henderson     tcg_gen_ori_i64(tmp, tmp, a->i);
2194ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2195e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2196e1b5a5edSRichard Henderson 
2197e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_I.  */
219831234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
219931234768SRichard Henderson     return nullify_end(ctx);
2200e36f27efSRichard Henderson #endif
2201e1b5a5edSRichard Henderson }
2202e1b5a5edSRichard Henderson 
2203c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
2204e1b5a5edSRichard Henderson {
2205e1b5a5edSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2206c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
22076fd0c7bcSRichard Henderson     TCGv_i64 tmp, reg;
2208e1b5a5edSRichard Henderson     nullify_over(ctx);
2209e1b5a5edSRichard Henderson 
2210c603e14aSRichard Henderson     reg = load_gpr(ctx, a->r);
2211aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2212ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, reg);
2213e1b5a5edSRichard Henderson 
2214e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts.  */
221531234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
221631234768SRichard Henderson     return nullify_end(ctx);
2217c603e14aSRichard Henderson #endif
2218e1b5a5edSRichard Henderson }
2219f49b3537SRichard Henderson 
2220e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r)
2221f49b3537SRichard Henderson {
2222f49b3537SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2223e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
2224f49b3537SRichard Henderson     nullify_over(ctx);
2225f49b3537SRichard Henderson 
2226e36f27efSRichard Henderson     if (rfi_r) {
2227ad75a51eSRichard Henderson         gen_helper_rfi_r(tcg_env);
2228f49b3537SRichard Henderson     } else {
2229ad75a51eSRichard Henderson         gen_helper_rfi(tcg_env);
2230f49b3537SRichard Henderson     }
223131234768SRichard Henderson     /* Exit the TB to recognize new interrupts.  */
223207ea28b4SRichard Henderson     tcg_gen_exit_tb(NULL, 0);
223331234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
2234f49b3537SRichard Henderson 
223531234768SRichard Henderson     return nullify_end(ctx);
2236e36f27efSRichard Henderson #endif
2237f49b3537SRichard Henderson }
22386210db05SHelge Deller 
2239e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a)
2240e36f27efSRichard Henderson {
2241e36f27efSRichard Henderson     return do_rfi(ctx, false);
2242e36f27efSRichard Henderson }
2243e36f27efSRichard Henderson 
2244e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a)
2245e36f27efSRichard Henderson {
2246e36f27efSRichard Henderson     return do_rfi(ctx, true);
2247e36f27efSRichard Henderson }
2248e36f27efSRichard Henderson 
224996927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a)
22506210db05SHelge Deller {
22516210db05SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
225296927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
22536210db05SHelge Deller     nullify_over(ctx);
2254ad75a51eSRichard Henderson     gen_helper_halt(tcg_env);
225531234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
225631234768SRichard Henderson     return nullify_end(ctx);
225796927adbSRichard Henderson #endif
22586210db05SHelge Deller }
225996927adbSRichard Henderson 
226096927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a)
226196927adbSRichard Henderson {
226296927adbSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
226396927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
226496927adbSRichard Henderson     nullify_over(ctx);
2265ad75a51eSRichard Henderson     gen_helper_reset(tcg_env);
226696927adbSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
226796927adbSRichard Henderson     return nullify_end(ctx);
226896927adbSRichard Henderson #endif
226996927adbSRichard Henderson }
2270e1b5a5edSRichard Henderson 
22714a4554c6SHelge Deller static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
22724a4554c6SHelge Deller {
22734a4554c6SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
22744a4554c6SHelge Deller #ifndef CONFIG_USER_ONLY
22754a4554c6SHelge Deller     nullify_over(ctx);
2276ad75a51eSRichard Henderson     gen_helper_getshadowregs(tcg_env);
22774a4554c6SHelge Deller     return nullify_end(ctx);
22784a4554c6SHelge Deller #endif
22794a4554c6SHelge Deller }
22804a4554c6SHelge Deller 
2281deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
228298a9cb79SRichard Henderson {
2283deee69a1SRichard Henderson     if (a->m) {
22846fd0c7bcSRichard Henderson         TCGv_i64 dest = dest_gpr(ctx, a->b);
22856fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->b);
22866fd0c7bcSRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->x);
228798a9cb79SRichard Henderson 
228898a9cb79SRichard Henderson         /* The only thing we need to do is the base register modification.  */
22896fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, src1, src2);
2290deee69a1SRichard Henderson         save_gpr(ctx, a->b, dest);
2291deee69a1SRichard Henderson     }
229298a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
229331234768SRichard Henderson     return true;
229498a9cb79SRichard Henderson }
229598a9cb79SRichard Henderson 
2296deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a)
229798a9cb79SRichard Henderson {
22986fd0c7bcSRichard Henderson     TCGv_i64 dest, ofs;
2299eed14219SRichard Henderson     TCGv_i32 level, want;
23006fd0c7bcSRichard Henderson     TCGv_i64 addr;
230198a9cb79SRichard Henderson 
230298a9cb79SRichard Henderson     nullify_over(ctx);
230398a9cb79SRichard Henderson 
2304deee69a1SRichard Henderson     dest = dest_gpr(ctx, a->t);
2305deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2306eed14219SRichard Henderson 
2307deee69a1SRichard Henderson     if (a->imm) {
2308e5d487c9SRichard Henderson         level = tcg_constant_i32(a->ri & 3);
230998a9cb79SRichard Henderson     } else {
2310eed14219SRichard Henderson         level = tcg_temp_new_i32();
23116fd0c7bcSRichard Henderson         tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri));
2312eed14219SRichard Henderson         tcg_gen_andi_i32(level, level, 3);
231398a9cb79SRichard Henderson     }
231429dd6f64SRichard Henderson     want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ);
2315eed14219SRichard Henderson 
2316ad75a51eSRichard Henderson     gen_helper_probe(dest, tcg_env, addr, level, want);
2317eed14219SRichard Henderson 
2318deee69a1SRichard Henderson     save_gpr(ctx, a->t, dest);
231931234768SRichard Henderson     return nullify_end(ctx);
232098a9cb79SRichard Henderson }
232198a9cb79SRichard Henderson 
2322deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
23238d6ae7fbSRichard Henderson {
23248577f354SRichard Henderson     if (ctx->is_pa20) {
23258577f354SRichard Henderson         return false;
23268577f354SRichard Henderson     }
2327deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2328deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
23296fd0c7bcSRichard Henderson     TCGv_i64 addr;
23306fd0c7bcSRichard Henderson     TCGv_i64 ofs, reg;
23318d6ae7fbSRichard Henderson 
23328d6ae7fbSRichard Henderson     nullify_over(ctx);
23338d6ae7fbSRichard Henderson 
2334deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2335deee69a1SRichard Henderson     reg = load_gpr(ctx, a->r);
2336deee69a1SRichard Henderson     if (a->addr) {
23378577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
23388d6ae7fbSRichard Henderson     } else {
23398577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
23408d6ae7fbSRichard Henderson     }
23418d6ae7fbSRichard Henderson 
234232dc7569SSven Schnelle     /* Exit TB for TLB change if mmu is enabled.  */
234332dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
234431234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
234531234768SRichard Henderson     }
234631234768SRichard Henderson     return nullify_end(ctx);
2347deee69a1SRichard Henderson #endif
23488d6ae7fbSRichard Henderson }
234963300a00SRichard Henderson 
2350eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local)
235163300a00SRichard Henderson {
2352deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2353deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
23546fd0c7bcSRichard Henderson     TCGv_i64 addr;
23556fd0c7bcSRichard Henderson     TCGv_i64 ofs;
235663300a00SRichard Henderson 
235763300a00SRichard Henderson     nullify_over(ctx);
235863300a00SRichard Henderson 
2359deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2360eb25d10fSHelge Deller 
2361eb25d10fSHelge Deller     /*
2362eb25d10fSHelge Deller      * Page align now, rather than later, so that we can add in the
2363eb25d10fSHelge Deller      * page_size field from pa2.0 from the low 4 bits of GR[b].
2364eb25d10fSHelge Deller      */
2365eb25d10fSHelge Deller     tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK);
2366eb25d10fSHelge Deller     if (ctx->is_pa20) {
2367eb25d10fSHelge Deller         tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4);
236863300a00SRichard Henderson     }
2369eb25d10fSHelge Deller 
2370eb25d10fSHelge Deller     if (local) {
2371eb25d10fSHelge Deller         gen_helper_ptlb_l(tcg_env, addr);
237263300a00SRichard Henderson     } else {
2373ad75a51eSRichard Henderson         gen_helper_ptlb(tcg_env, addr);
237463300a00SRichard Henderson     }
237563300a00SRichard Henderson 
2376eb25d10fSHelge Deller     if (a->m) {
2377eb25d10fSHelge Deller         save_gpr(ctx, a->b, ofs);
2378eb25d10fSHelge Deller     }
2379eb25d10fSHelge Deller 
2380eb25d10fSHelge Deller     /* Exit TB for TLB change if mmu is enabled.  */
2381eb25d10fSHelge Deller     if (ctx->tb_flags & PSW_C) {
2382eb25d10fSHelge Deller         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2383eb25d10fSHelge Deller     }
2384eb25d10fSHelge Deller     return nullify_end(ctx);
2385eb25d10fSHelge Deller #endif
2386eb25d10fSHelge Deller }
2387eb25d10fSHelge Deller 
2388eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a)
2389eb25d10fSHelge Deller {
2390eb25d10fSHelge Deller     return do_pxtlb(ctx, a, false);
2391eb25d10fSHelge Deller }
2392eb25d10fSHelge Deller 
2393eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a)
2394eb25d10fSHelge Deller {
2395eb25d10fSHelge Deller     return ctx->is_pa20 && do_pxtlb(ctx, a, true);
2396eb25d10fSHelge Deller }
2397eb25d10fSHelge Deller 
2398eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a)
2399eb25d10fSHelge Deller {
2400eb25d10fSHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2401eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY
2402eb25d10fSHelge Deller     nullify_over(ctx);
2403eb25d10fSHelge Deller 
2404eb25d10fSHelge Deller     trans_nop_addrx(ctx, a);
2405eb25d10fSHelge Deller     gen_helper_ptlbe(tcg_env);
2406eb25d10fSHelge Deller 
240763300a00SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
240832dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
240931234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
241031234768SRichard Henderson     }
241131234768SRichard Henderson     return nullify_end(ctx);
2412deee69a1SRichard Henderson #endif
241363300a00SRichard Henderson }
24142dfcca9fSRichard Henderson 
24156797c315SNick Hudson /*
24166797c315SNick Hudson  * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
24176797c315SNick Hudson  * See
24186797c315SNick Hudson  *     https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
24196797c315SNick Hudson  *     page 13-9 (195/206)
24206797c315SNick Hudson  */
24216797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
24226797c315SNick Hudson {
24238577f354SRichard Henderson     if (ctx->is_pa20) {
24248577f354SRichard Henderson         return false;
24258577f354SRichard Henderson     }
24266797c315SNick Hudson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24276797c315SNick Hudson #ifndef CONFIG_USER_ONLY
24286fd0c7bcSRichard Henderson     TCGv_i64 addr, atl, stl;
24296fd0c7bcSRichard Henderson     TCGv_i64 reg;
24306797c315SNick Hudson 
24316797c315SNick Hudson     nullify_over(ctx);
24326797c315SNick Hudson 
24336797c315SNick Hudson     /*
24346797c315SNick Hudson      * FIXME:
24356797c315SNick Hudson      *  if (not (pcxl or pcxl2))
24366797c315SNick Hudson      *    return gen_illegal(ctx);
24376797c315SNick Hudson      */
24386797c315SNick Hudson 
24396fd0c7bcSRichard Henderson     atl = tcg_temp_new_i64();
24406fd0c7bcSRichard Henderson     stl = tcg_temp_new_i64();
24416fd0c7bcSRichard Henderson     addr = tcg_temp_new_i64();
24426797c315SNick Hudson 
2443ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(stl, tcg_env,
24446797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
24456797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIASQ]));
2446ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(atl, tcg_env,
24476797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
24486797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIAOQ]));
24496797c315SNick Hudson     tcg_gen_shli_i64(stl, stl, 32);
2450d265360fSRichard Henderson     tcg_gen_or_i64(addr, atl, stl);
24516797c315SNick Hudson 
24526797c315SNick Hudson     reg = load_gpr(ctx, a->r);
24536797c315SNick Hudson     if (a->addr) {
24548577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
24556797c315SNick Hudson     } else {
24568577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
24576797c315SNick Hudson     }
24586797c315SNick Hudson 
24596797c315SNick Hudson     /* Exit TB for TLB change if mmu is enabled.  */
24606797c315SNick Hudson     if (ctx->tb_flags & PSW_C) {
24616797c315SNick Hudson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
24626797c315SNick Hudson     }
24636797c315SNick Hudson     return nullify_end(ctx);
24646797c315SNick Hudson #endif
24656797c315SNick Hudson }
24666797c315SNick Hudson 
24678577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
24688577f354SRichard Henderson {
24698577f354SRichard Henderson     if (!ctx->is_pa20) {
24708577f354SRichard Henderson         return false;
24718577f354SRichard Henderson     }
24728577f354SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24738577f354SRichard Henderson #ifndef CONFIG_USER_ONLY
24748577f354SRichard Henderson     nullify_over(ctx);
24758577f354SRichard Henderson     {
24768577f354SRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
24778577f354SRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->r2);
24788577f354SRichard Henderson 
24798577f354SRichard Henderson         if (a->data) {
24808577f354SRichard Henderson             gen_helper_idtlbt_pa20(tcg_env, src1, src2);
24818577f354SRichard Henderson         } else {
24828577f354SRichard Henderson             gen_helper_iitlbt_pa20(tcg_env, src1, src2);
24838577f354SRichard Henderson         }
24848577f354SRichard Henderson     }
24858577f354SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
24868577f354SRichard Henderson     if (ctx->tb_flags & PSW_C) {
24878577f354SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
24888577f354SRichard Henderson     }
24898577f354SRichard Henderson     return nullify_end(ctx);
24908577f354SRichard Henderson #endif
24918577f354SRichard Henderson }
24928577f354SRichard Henderson 
2493deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
24942dfcca9fSRichard Henderson {
2495deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2496deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
24976fd0c7bcSRichard Henderson     TCGv_i64 vaddr;
24986fd0c7bcSRichard Henderson     TCGv_i64 ofs, paddr;
24992dfcca9fSRichard Henderson 
25002dfcca9fSRichard Henderson     nullify_over(ctx);
25012dfcca9fSRichard Henderson 
2502deee69a1SRichard Henderson     form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
25032dfcca9fSRichard Henderson 
2504aac0f603SRichard Henderson     paddr = tcg_temp_new_i64();
2505ad75a51eSRichard Henderson     gen_helper_lpa(paddr, tcg_env, vaddr);
25062dfcca9fSRichard Henderson 
25072dfcca9fSRichard Henderson     /* Note that physical address result overrides base modification.  */
2508deee69a1SRichard Henderson     if (a->m) {
2509deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
25102dfcca9fSRichard Henderson     }
2511deee69a1SRichard Henderson     save_gpr(ctx, a->t, paddr);
25122dfcca9fSRichard Henderson 
251331234768SRichard Henderson     return nullify_end(ctx);
2514deee69a1SRichard Henderson #endif
25152dfcca9fSRichard Henderson }
251643a97b81SRichard Henderson 
2517deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a)
251843a97b81SRichard Henderson {
251943a97b81SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
252043a97b81SRichard Henderson 
252143a97b81SRichard Henderson     /* The Coherence Index is an implementation-defined function of the
252243a97b81SRichard Henderson        physical address.  Two addresses with the same CI have a coherent
252343a97b81SRichard Henderson        view of the cache.  Our implementation is to return 0 for all,
252443a97b81SRichard Henderson        since the entire address space is coherent.  */
2525a4db4a78SRichard Henderson     save_gpr(ctx, a->t, ctx->zero);
252643a97b81SRichard Henderson 
252731234768SRichard Henderson     cond_free(&ctx->null_cond);
252831234768SRichard Henderson     return true;
252943a97b81SRichard Henderson }
253098a9cb79SRichard Henderson 
2531faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2532b2167459SRichard Henderson {
25330c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, false);
2534b2167459SRichard Henderson }
2535b2167459SRichard Henderson 
2536faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2537b2167459SRichard Henderson {
25380c982a28SRichard Henderson     return do_add_reg(ctx, a, true, false, false, false);
2539b2167459SRichard Henderson }
2540b2167459SRichard Henderson 
2541faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2542b2167459SRichard Henderson {
25430c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, false);
2544b2167459SRichard Henderson }
2545b2167459SRichard Henderson 
2546faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2547b2167459SRichard Henderson {
25480c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, true);
25490c982a28SRichard Henderson }
2550b2167459SRichard Henderson 
2551faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
25520c982a28SRichard Henderson {
25530c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, true);
25540c982a28SRichard Henderson }
25550c982a28SRichard Henderson 
255663c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
25570c982a28SRichard Henderson {
25580c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, false);
25590c982a28SRichard Henderson }
25600c982a28SRichard Henderson 
256163c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
25620c982a28SRichard Henderson {
25630c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, false);
25640c982a28SRichard Henderson }
25650c982a28SRichard Henderson 
256663c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
25670c982a28SRichard Henderson {
25680c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, true);
25690c982a28SRichard Henderson }
25700c982a28SRichard Henderson 
257163c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
25720c982a28SRichard Henderson {
25730c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, true);
25740c982a28SRichard Henderson }
25750c982a28SRichard Henderson 
257663c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
25770c982a28SRichard Henderson {
25780c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, true, false);
25790c982a28SRichard Henderson }
25800c982a28SRichard Henderson 
258163c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
25820c982a28SRichard Henderson {
25830c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, true, false);
25840c982a28SRichard Henderson }
25850c982a28SRichard Henderson 
2586fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
25870c982a28SRichard Henderson {
25886fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_andc_i64);
25890c982a28SRichard Henderson }
25900c982a28SRichard Henderson 
2591fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
25920c982a28SRichard Henderson {
25936fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_and_i64);
25940c982a28SRichard Henderson }
25950c982a28SRichard Henderson 
2596fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
25970c982a28SRichard Henderson {
25980c982a28SRichard Henderson     if (a->cf == 0) {
25990c982a28SRichard Henderson         unsigned r2 = a->r2;
26000c982a28SRichard Henderson         unsigned r1 = a->r1;
26010c982a28SRichard Henderson         unsigned rt = a->t;
26020c982a28SRichard Henderson 
26037aee8189SRichard Henderson         if (rt == 0) { /* NOP */
26047aee8189SRichard Henderson             cond_free(&ctx->null_cond);
26057aee8189SRichard Henderson             return true;
26067aee8189SRichard Henderson         }
26077aee8189SRichard Henderson         if (r2 == 0) { /* COPY */
2608b2167459SRichard Henderson             if (r1 == 0) {
26096fd0c7bcSRichard Henderson                 TCGv_i64 dest = dest_gpr(ctx, rt);
26106fd0c7bcSRichard Henderson                 tcg_gen_movi_i64(dest, 0);
2611b2167459SRichard Henderson                 save_gpr(ctx, rt, dest);
2612b2167459SRichard Henderson             } else {
2613b2167459SRichard Henderson                 save_gpr(ctx, rt, cpu_gr[r1]);
2614b2167459SRichard Henderson             }
2615b2167459SRichard Henderson             cond_free(&ctx->null_cond);
261631234768SRichard Henderson             return true;
2617b2167459SRichard Henderson         }
26187aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY
26197aee8189SRichard Henderson         /* These are QEMU extensions and are nops in the real architecture:
26207aee8189SRichard Henderson          *
26217aee8189SRichard Henderson          * or %r10,%r10,%r10 -- idle loop; wait for interrupt
26227aee8189SRichard Henderson          * or %r31,%r31,%r31 -- death loop; offline cpu
26237aee8189SRichard Henderson          *                      currently implemented as idle.
26247aee8189SRichard Henderson          */
26257aee8189SRichard Henderson         if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
26267aee8189SRichard Henderson             /* No need to check for supervisor, as userland can only pause
26277aee8189SRichard Henderson                until the next timer interrupt.  */
26287aee8189SRichard Henderson             nullify_over(ctx);
26297aee8189SRichard Henderson 
26307aee8189SRichard Henderson             /* Advance the instruction queue.  */
2631741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
2632741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
26337aee8189SRichard Henderson             nullify_set(ctx, 0);
26347aee8189SRichard Henderson 
26357aee8189SRichard Henderson             /* Tell the qemu main loop to halt until this cpu has work.  */
2636ad75a51eSRichard Henderson             tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
263729dd6f64SRichard Henderson                            offsetof(CPUState, halted) - offsetof(HPPACPU, env));
26387aee8189SRichard Henderson             gen_excp_1(EXCP_HALTED);
26397aee8189SRichard Henderson             ctx->base.is_jmp = DISAS_NORETURN;
26407aee8189SRichard Henderson 
26417aee8189SRichard Henderson             return nullify_end(ctx);
26427aee8189SRichard Henderson         }
26437aee8189SRichard Henderson #endif
26447aee8189SRichard Henderson     }
26456fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_or_i64);
26467aee8189SRichard Henderson }
2647b2167459SRichard Henderson 
2648fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
2649b2167459SRichard Henderson {
26506fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_xor_i64);
26510c982a28SRichard Henderson }
26520c982a28SRichard Henderson 
2653345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
26540c982a28SRichard Henderson {
26556fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2656b2167459SRichard Henderson 
26570c982a28SRichard Henderson     if (a->cf) {
2658b2167459SRichard Henderson         nullify_over(ctx);
2659b2167459SRichard Henderson     }
26600c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26610c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2662345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
266331234768SRichard Henderson     return nullify_end(ctx);
2664b2167459SRichard Henderson }
2665b2167459SRichard Henderson 
2666af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
2667b2167459SRichard Henderson {
26686fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2669b2167459SRichard Henderson 
26700c982a28SRichard Henderson     if (a->cf) {
2671b2167459SRichard Henderson         nullify_over(ctx);
2672b2167459SRichard Henderson     }
26730c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26740c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
26756fd0c7bcSRichard Henderson     do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64);
267631234768SRichard Henderson     return nullify_end(ctx);
2677b2167459SRichard Henderson }
2678b2167459SRichard Henderson 
2679af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
2680b2167459SRichard Henderson {
26816fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, tmp;
2682b2167459SRichard Henderson 
26830c982a28SRichard Henderson     if (a->cf) {
2684b2167459SRichard Henderson         nullify_over(ctx);
2685b2167459SRichard Henderson     }
26860c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26870c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2688aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
26896fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, tcg_r2);
26906fd0c7bcSRichard Henderson     do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64);
269131234768SRichard Henderson     return nullify_end(ctx);
2692b2167459SRichard Henderson }
2693b2167459SRichard Henderson 
2694af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
2695b2167459SRichard Henderson {
26960c982a28SRichard Henderson     return do_uaddcm(ctx, a, false);
26970c982a28SRichard Henderson }
26980c982a28SRichard Henderson 
2699af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
27000c982a28SRichard Henderson {
27010c982a28SRichard Henderson     return do_uaddcm(ctx, a, true);
27020c982a28SRichard Henderson }
27030c982a28SRichard Henderson 
2704af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
27050c982a28SRichard Henderson {
27066fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2707b2167459SRichard Henderson 
2708b2167459SRichard Henderson     nullify_over(ctx);
2709b2167459SRichard Henderson 
2710aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
27116fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, cpu_psw_cb, 3);
2712b2167459SRichard Henderson     if (!is_i) {
27136fd0c7bcSRichard Henderson         tcg_gen_not_i64(tmp, tmp);
2714b2167459SRichard Henderson     }
27156fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
27166fd0c7bcSRichard Henderson     tcg_gen_muli_i64(tmp, tmp, 6);
2717af240753SRichard Henderson     do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false,
27186fd0c7bcSRichard Henderson             is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64);
271931234768SRichard Henderson     return nullify_end(ctx);
2720b2167459SRichard Henderson }
2721b2167459SRichard Henderson 
2722af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
2723b2167459SRichard Henderson {
27240c982a28SRichard Henderson     return do_dcor(ctx, a, false);
27250c982a28SRichard Henderson }
27260c982a28SRichard Henderson 
2727af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
27280c982a28SRichard Henderson {
27290c982a28SRichard Henderson     return do_dcor(ctx, a, true);
27300c982a28SRichard Henderson }
27310c982a28SRichard Henderson 
27320c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
27330c982a28SRichard Henderson {
2734a4db4a78SRichard Henderson     TCGv_i64 dest, add1, add2, addc, in1, in2;
27356fd0c7bcSRichard Henderson     TCGv_i64 cout;
2736b2167459SRichard Henderson 
2737b2167459SRichard Henderson     nullify_over(ctx);
2738b2167459SRichard Henderson 
27390c982a28SRichard Henderson     in1 = load_gpr(ctx, a->r1);
27400c982a28SRichard Henderson     in2 = load_gpr(ctx, a->r2);
2741b2167459SRichard Henderson 
2742aac0f603SRichard Henderson     add1 = tcg_temp_new_i64();
2743aac0f603SRichard Henderson     add2 = tcg_temp_new_i64();
2744aac0f603SRichard Henderson     addc = tcg_temp_new_i64();
2745aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
2746b2167459SRichard Henderson 
2747b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
27486fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, in1, in1);
27496fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
2750b2167459SRichard Henderson 
275172ca8753SRichard Henderson     /*
275272ca8753SRichard Henderson      * Add or subtract R2, depending on PSW[V].  Proper computation of
275372ca8753SRichard Henderson      * carry requires that we subtract via + ~R2 + 1, as described in
275472ca8753SRichard Henderson      * the manual.  By extracting and masking V, we can produce the
275572ca8753SRichard Henderson      * proper inputs to the addition without movcond.
275672ca8753SRichard Henderson      */
27576fd0c7bcSRichard Henderson     tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
27586fd0c7bcSRichard Henderson     tcg_gen_xor_i64(add2, in2, addc);
27596fd0c7bcSRichard Henderson     tcg_gen_andi_i64(addc, addc, 1);
276072ca8753SRichard Henderson 
2761a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero);
2762a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb,
2763a4db4a78SRichard Henderson                      addc, ctx->zero);
2764b2167459SRichard Henderson 
2765b2167459SRichard Henderson     /* Write back the result register.  */
27660c982a28SRichard Henderson     save_gpr(ctx, a->t, dest);
2767b2167459SRichard Henderson 
2768b2167459SRichard Henderson     /* Write back PSW[CB].  */
27696fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
27706fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
2771b2167459SRichard Henderson 
2772b2167459SRichard Henderson     /* Write back PSW[V] for the division step.  */
277372ca8753SRichard Henderson     cout = get_psw_carry(ctx, false);
27746fd0c7bcSRichard Henderson     tcg_gen_neg_i64(cpu_psw_v, cout);
27756fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
2776b2167459SRichard Henderson 
2777b2167459SRichard Henderson     /* Install the new nullification.  */
27780c982a28SRichard Henderson     if (a->cf) {
27796fd0c7bcSRichard Henderson         TCGv_i64 sv = NULL;
2780b47a4a02SSven Schnelle         if (cond_need_sv(a->cf >> 1)) {
2781b2167459SRichard Henderson             /* ??? The lshift is supposed to contribute to overflow.  */
2782b2167459SRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2);
2783b2167459SRichard Henderson         }
2784a751eb31SRichard Henderson         ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv);
2785b2167459SRichard Henderson     }
2786b2167459SRichard Henderson 
278731234768SRichard Henderson     return nullify_end(ctx);
2788b2167459SRichard Henderson }
2789b2167459SRichard Henderson 
27900588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a)
2791b2167459SRichard Henderson {
27920588e061SRichard Henderson     return do_add_imm(ctx, a, false, false);
27930588e061SRichard Henderson }
27940588e061SRichard Henderson 
27950588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a)
27960588e061SRichard Henderson {
27970588e061SRichard Henderson     return do_add_imm(ctx, a, true, false);
27980588e061SRichard Henderson }
27990588e061SRichard Henderson 
28000588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a)
28010588e061SRichard Henderson {
28020588e061SRichard Henderson     return do_add_imm(ctx, a, false, true);
28030588e061SRichard Henderson }
28040588e061SRichard Henderson 
28050588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a)
28060588e061SRichard Henderson {
28070588e061SRichard Henderson     return do_add_imm(ctx, a, true, true);
28080588e061SRichard Henderson }
28090588e061SRichard Henderson 
28100588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a)
28110588e061SRichard Henderson {
28120588e061SRichard Henderson     return do_sub_imm(ctx, a, false);
28130588e061SRichard Henderson }
28140588e061SRichard Henderson 
28150588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
28160588e061SRichard Henderson {
28170588e061SRichard Henderson     return do_sub_imm(ctx, a, true);
28180588e061SRichard Henderson }
28190588e061SRichard Henderson 
2820345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
28210588e061SRichard Henderson {
28226fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
2823b2167459SRichard Henderson 
28240588e061SRichard Henderson     if (a->cf) {
2825b2167459SRichard Henderson         nullify_over(ctx);
2826b2167459SRichard Henderson     }
2827b2167459SRichard Henderson 
28286fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
28290588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
2830345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
2831b2167459SRichard Henderson 
283231234768SRichard Henderson     return nullify_end(ctx);
2833b2167459SRichard Henderson }
2834b2167459SRichard Henderson 
28350843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a,
28360843563fSRichard Henderson                           void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
28370843563fSRichard Henderson {
28380843563fSRichard Henderson     TCGv_i64 r1, r2, dest;
28390843563fSRichard Henderson 
28400843563fSRichard Henderson     if (!ctx->is_pa20) {
28410843563fSRichard Henderson         return false;
28420843563fSRichard Henderson     }
28430843563fSRichard Henderson 
28440843563fSRichard Henderson     nullify_over(ctx);
28450843563fSRichard Henderson 
28460843563fSRichard Henderson     r1 = load_gpr(ctx, a->r1);
28470843563fSRichard Henderson     r2 = load_gpr(ctx, a->r2);
28480843563fSRichard Henderson     dest = dest_gpr(ctx, a->t);
28490843563fSRichard Henderson 
28500843563fSRichard Henderson     fn(dest, r1, r2);
28510843563fSRichard Henderson     save_gpr(ctx, a->t, dest);
28520843563fSRichard Henderson 
28530843563fSRichard Henderson     return nullify_end(ctx);
28540843563fSRichard Henderson }
28550843563fSRichard Henderson 
2856151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a,
2857151f309bSRichard Henderson                              void (*fn)(TCGv_i64, TCGv_i64, int64_t))
2858151f309bSRichard Henderson {
2859151f309bSRichard Henderson     TCGv_i64 r, dest;
2860151f309bSRichard Henderson 
2861151f309bSRichard Henderson     if (!ctx->is_pa20) {
2862151f309bSRichard Henderson         return false;
2863151f309bSRichard Henderson     }
2864151f309bSRichard Henderson 
2865151f309bSRichard Henderson     nullify_over(ctx);
2866151f309bSRichard Henderson 
2867151f309bSRichard Henderson     r = load_gpr(ctx, a->r);
2868151f309bSRichard Henderson     dest = dest_gpr(ctx, a->t);
2869151f309bSRichard Henderson 
2870151f309bSRichard Henderson     fn(dest, r, a->i);
2871151f309bSRichard Henderson     save_gpr(ctx, a->t, dest);
2872151f309bSRichard Henderson 
2873151f309bSRichard Henderson     return nullify_end(ctx);
2874151f309bSRichard Henderson }
2875151f309bSRichard Henderson 
28763bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a,
28773bbb8e48SRichard Henderson                                 void (*fn)(TCGv_i64, TCGv_i64,
28783bbb8e48SRichard Henderson                                            TCGv_i64, TCGv_i32))
28793bbb8e48SRichard Henderson {
28803bbb8e48SRichard Henderson     TCGv_i64 r1, r2, dest;
28813bbb8e48SRichard Henderson 
28823bbb8e48SRichard Henderson     if (!ctx->is_pa20) {
28833bbb8e48SRichard Henderson         return false;
28843bbb8e48SRichard Henderson     }
28853bbb8e48SRichard Henderson 
28863bbb8e48SRichard Henderson     nullify_over(ctx);
28873bbb8e48SRichard Henderson 
28883bbb8e48SRichard Henderson     r1 = load_gpr(ctx, a->r1);
28893bbb8e48SRichard Henderson     r2 = load_gpr(ctx, a->r2);
28903bbb8e48SRichard Henderson     dest = dest_gpr(ctx, a->t);
28913bbb8e48SRichard Henderson 
28923bbb8e48SRichard Henderson     fn(dest, r1, r2, tcg_constant_i32(a->sh));
28933bbb8e48SRichard Henderson     save_gpr(ctx, a->t, dest);
28943bbb8e48SRichard Henderson 
28953bbb8e48SRichard Henderson     return nullify_end(ctx);
28963bbb8e48SRichard Henderson }
28973bbb8e48SRichard Henderson 
28980843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a)
28990843563fSRichard Henderson {
29000843563fSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_add16_i64);
29010843563fSRichard Henderson }
29020843563fSRichard Henderson 
29030843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a)
29040843563fSRichard Henderson {
29050843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_ss);
29060843563fSRichard Henderson }
29070843563fSRichard Henderson 
29080843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a)
29090843563fSRichard Henderson {
29100843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_us);
29110843563fSRichard Henderson }
29120843563fSRichard Henderson 
29131b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a)
29141b3cb7c8SRichard Henderson {
29151b3cb7c8SRichard Henderson     return do_multimedia(ctx, a, gen_helper_havg);
29161b3cb7c8SRichard Henderson }
29171b3cb7c8SRichard Henderson 
2918151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a)
2919151f309bSRichard Henderson {
2920151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64);
2921151f309bSRichard Henderson }
2922151f309bSRichard Henderson 
2923151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a)
2924151f309bSRichard Henderson {
2925151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64);
2926151f309bSRichard Henderson }
2927151f309bSRichard Henderson 
2928151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a)
2929151f309bSRichard Henderson {
2930151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64);
2931151f309bSRichard Henderson }
2932151f309bSRichard Henderson 
29333bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a)
29343bbb8e48SRichard Henderson {
29353bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshladd);
29363bbb8e48SRichard Henderson }
29373bbb8e48SRichard Henderson 
29383bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a)
29393bbb8e48SRichard Henderson {
29403bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshradd);
29413bbb8e48SRichard Henderson }
29423bbb8e48SRichard Henderson 
294310c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a)
294410c9e58dSRichard Henderson {
294510c9e58dSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64);
294610c9e58dSRichard Henderson }
294710c9e58dSRichard Henderson 
294810c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a)
294910c9e58dSRichard Henderson {
295010c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_ss);
295110c9e58dSRichard Henderson }
295210c9e58dSRichard Henderson 
295310c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a)
295410c9e58dSRichard Henderson {
295510c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_us);
295610c9e58dSRichard Henderson }
295710c9e58dSRichard Henderson 
2958c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2959c2a7ee3fSRichard Henderson {
2960c2a7ee3fSRichard Henderson     uint64_t mask = 0xffff0000ffff0000ull;
2961c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2962c2a7ee3fSRichard Henderson 
2963c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r2, mask);
2964c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r1, mask);
2965c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, tmp, 16);
2966c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
2967c2a7ee3fSRichard Henderson }
2968c2a7ee3fSRichard Henderson 
2969c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a)
2970c2a7ee3fSRichard Henderson {
2971c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_l);
2972c2a7ee3fSRichard Henderson }
2973c2a7ee3fSRichard Henderson 
2974c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2975c2a7ee3fSRichard Henderson {
2976c2a7ee3fSRichard Henderson     uint64_t mask = 0x0000ffff0000ffffull;
2977c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2978c2a7ee3fSRichard Henderson 
2979c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r1, mask);
2980c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r2, mask);
2981c2a7ee3fSRichard Henderson     tcg_gen_shli_i64(tmp, tmp, 16);
2982c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
2983c2a7ee3fSRichard Henderson }
2984c2a7ee3fSRichard Henderson 
2985c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a)
2986c2a7ee3fSRichard Henderson {
2987c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_r);
2988c2a7ee3fSRichard Henderson }
2989c2a7ee3fSRichard Henderson 
2990c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2991c2a7ee3fSRichard Henderson {
2992c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2993c2a7ee3fSRichard Henderson 
2994c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, r2, 32);
2995c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r1, tmp, 0, 32);
2996c2a7ee3fSRichard Henderson }
2997c2a7ee3fSRichard Henderson 
2998c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a)
2999c2a7ee3fSRichard Henderson {
3000c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_l);
3001c2a7ee3fSRichard Henderson }
3002c2a7ee3fSRichard Henderson 
3003c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3004c2a7ee3fSRichard Henderson {
3005c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r2, r1, 32, 32);
3006c2a7ee3fSRichard Henderson }
3007c2a7ee3fSRichard Henderson 
3008c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a)
3009c2a7ee3fSRichard Henderson {
3010c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_r);
3011c2a7ee3fSRichard Henderson }
3012c2a7ee3fSRichard Henderson 
30134e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a)
30144e7abdb1SRichard Henderson {
30154e7abdb1SRichard Henderson     TCGv_i64 r, t0, t1, t2, t3;
30164e7abdb1SRichard Henderson 
30174e7abdb1SRichard Henderson     if (!ctx->is_pa20) {
30184e7abdb1SRichard Henderson         return false;
30194e7abdb1SRichard Henderson     }
30204e7abdb1SRichard Henderson 
30214e7abdb1SRichard Henderson     nullify_over(ctx);
30224e7abdb1SRichard Henderson 
30234e7abdb1SRichard Henderson     r = load_gpr(ctx, a->r1);
30244e7abdb1SRichard Henderson     t0 = tcg_temp_new_i64();
30254e7abdb1SRichard Henderson     t1 = tcg_temp_new_i64();
30264e7abdb1SRichard Henderson     t2 = tcg_temp_new_i64();
30274e7abdb1SRichard Henderson     t3 = tcg_temp_new_i64();
30284e7abdb1SRichard Henderson 
30294e7abdb1SRichard Henderson     tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16);
30304e7abdb1SRichard Henderson     tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16);
30314e7abdb1SRichard Henderson     tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16);
30324e7abdb1SRichard Henderson     tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16);
30334e7abdb1SRichard Henderson 
30344e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t1, t0, 16, 48);
30354e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t2, t3, t2, 16, 48);
30364e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t2, t0, 32, 32);
30374e7abdb1SRichard Henderson 
30384e7abdb1SRichard Henderson     save_gpr(ctx, a->t, t0);
30394e7abdb1SRichard Henderson     return nullify_end(ctx);
30404e7abdb1SRichard Henderson }
30414e7abdb1SRichard Henderson 
30421cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a)
304396d6407fSRichard Henderson {
3044b5caa17cSRichard Henderson     if (ctx->is_pa20) {
3045b5caa17cSRichard Henderson        /*
3046b5caa17cSRichard Henderson         * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches.
3047b5caa17cSRichard Henderson         * Any base modification still occurs.
3048b5caa17cSRichard Henderson         */
3049b5caa17cSRichard Henderson         if (a->t == 0) {
3050b5caa17cSRichard Henderson             return trans_nop_addrx(ctx, a);
3051b5caa17cSRichard Henderson         }
3052b5caa17cSRichard Henderson     } else if (a->size > MO_32) {
30530786a3b6SHelge Deller         return gen_illegal(ctx);
3054c53e401eSRichard Henderson     }
30551cd012a5SRichard Henderson     return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
30561cd012a5SRichard Henderson                    a->disp, a->sp, a->m, a->size | MO_TE);
305796d6407fSRichard Henderson }
305896d6407fSRichard Henderson 
30591cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a)
306096d6407fSRichard Henderson {
30611cd012a5SRichard Henderson     assert(a->x == 0 && a->scale == 0);
3062c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
30630786a3b6SHelge Deller         return gen_illegal(ctx);
306496d6407fSRichard Henderson     }
3065c53e401eSRichard Henderson     return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
30660786a3b6SHelge Deller }
306796d6407fSRichard Henderson 
30681cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
306996d6407fSRichard Henderson {
3070b1af755cSRichard Henderson     MemOp mop = MO_TE | MO_ALIGN | a->size;
3071a4db4a78SRichard Henderson     TCGv_i64 dest, ofs;
30726fd0c7bcSRichard Henderson     TCGv_i64 addr;
307396d6407fSRichard Henderson 
3074c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
307551416c4eSRichard Henderson         return gen_illegal(ctx);
307651416c4eSRichard Henderson     }
307751416c4eSRichard Henderson 
307896d6407fSRichard Henderson     nullify_over(ctx);
307996d6407fSRichard Henderson 
30801cd012a5SRichard Henderson     if (a->m) {
308186f8d05fSRichard Henderson         /* Base register modification.  Make sure if RT == RB,
308286f8d05fSRichard Henderson            we see the result of the load.  */
3083aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
308496d6407fSRichard Henderson     } else {
30851cd012a5SRichard Henderson         dest = dest_gpr(ctx, a->t);
308696d6407fSRichard Henderson     }
308796d6407fSRichard Henderson 
30881cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0,
308917fe594cSRichard Henderson              a->disp, a->sp, a->m, MMU_DISABLED(ctx));
3090b1af755cSRichard Henderson 
3091b1af755cSRichard Henderson     /*
3092b1af755cSRichard Henderson      * For hppa1.1, LDCW is undefined unless aligned mod 16.
3093b1af755cSRichard Henderson      * However actual hardware succeeds with aligned mod 4.
3094b1af755cSRichard Henderson      * Detect this case and log a GUEST_ERROR.
3095b1af755cSRichard Henderson      *
3096b1af755cSRichard Henderson      * TODO: HPPA64 relaxes the over-alignment requirement
3097b1af755cSRichard Henderson      * with the ,co completer.
3098b1af755cSRichard Henderson      */
3099b1af755cSRichard Henderson     gen_helper_ldc_check(addr);
3100b1af755cSRichard Henderson 
3101a4db4a78SRichard Henderson     tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop);
3102b1af755cSRichard Henderson 
31031cd012a5SRichard Henderson     if (a->m) {
31041cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
310596d6407fSRichard Henderson     }
31061cd012a5SRichard Henderson     save_gpr(ctx, a->t, dest);
310796d6407fSRichard Henderson 
310831234768SRichard Henderson     return nullify_end(ctx);
310996d6407fSRichard Henderson }
311096d6407fSRichard Henderson 
31111cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a)
311296d6407fSRichard Henderson {
31136fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
31146fd0c7bcSRichard Henderson     TCGv_i64 addr;
311596d6407fSRichard Henderson 
311696d6407fSRichard Henderson     nullify_over(ctx);
311796d6407fSRichard Henderson 
31181cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
311917fe594cSRichard Henderson              MMU_DISABLED(ctx));
31201cd012a5SRichard Henderson     val = load_gpr(ctx, a->r);
31211cd012a5SRichard Henderson     if (a->a) {
3122f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3123ad75a51eSRichard Henderson             gen_helper_stby_e_parallel(tcg_env, addr, val);
3124f9f46db4SEmilio G. Cota         } else {
3125ad75a51eSRichard Henderson             gen_helper_stby_e(tcg_env, addr, val);
3126f9f46db4SEmilio G. Cota         }
3127f9f46db4SEmilio G. Cota     } else {
3128f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3129ad75a51eSRichard Henderson             gen_helper_stby_b_parallel(tcg_env, addr, val);
313096d6407fSRichard Henderson         } else {
3131ad75a51eSRichard Henderson             gen_helper_stby_b(tcg_env, addr, val);
313296d6407fSRichard Henderson         }
3133f9f46db4SEmilio G. Cota     }
31341cd012a5SRichard Henderson     if (a->m) {
31356fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~3);
31361cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
313796d6407fSRichard Henderson     }
313896d6407fSRichard Henderson 
313931234768SRichard Henderson     return nullify_end(ctx);
314096d6407fSRichard Henderson }
314196d6407fSRichard Henderson 
314225460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a)
314325460fc5SRichard Henderson {
31446fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
31456fd0c7bcSRichard Henderson     TCGv_i64 addr;
314625460fc5SRichard Henderson 
314725460fc5SRichard Henderson     if (!ctx->is_pa20) {
314825460fc5SRichard Henderson         return false;
314925460fc5SRichard Henderson     }
315025460fc5SRichard Henderson     nullify_over(ctx);
315125460fc5SRichard Henderson 
315225460fc5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
315317fe594cSRichard Henderson              MMU_DISABLED(ctx));
315425460fc5SRichard Henderson     val = load_gpr(ctx, a->r);
315525460fc5SRichard Henderson     if (a->a) {
315625460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
315725460fc5SRichard Henderson             gen_helper_stdby_e_parallel(tcg_env, addr, val);
315825460fc5SRichard Henderson         } else {
315925460fc5SRichard Henderson             gen_helper_stdby_e(tcg_env, addr, val);
316025460fc5SRichard Henderson         }
316125460fc5SRichard Henderson     } else {
316225460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
316325460fc5SRichard Henderson             gen_helper_stdby_b_parallel(tcg_env, addr, val);
316425460fc5SRichard Henderson         } else {
316525460fc5SRichard Henderson             gen_helper_stdby_b(tcg_env, addr, val);
316625460fc5SRichard Henderson         }
316725460fc5SRichard Henderson     }
316825460fc5SRichard Henderson     if (a->m) {
31696fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~7);
317025460fc5SRichard Henderson         save_gpr(ctx, a->b, ofs);
317125460fc5SRichard Henderson     }
317225460fc5SRichard Henderson 
317325460fc5SRichard Henderson     return nullify_end(ctx);
317425460fc5SRichard Henderson }
317525460fc5SRichard Henderson 
31761cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a)
3177d0a851ccSRichard Henderson {
3178d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3179d0a851ccSRichard Henderson 
3180d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3181451d993dSRichard Henderson     ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX;
31821cd012a5SRichard Henderson     trans_ld(ctx, a);
3183d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
318431234768SRichard Henderson     return true;
3185d0a851ccSRichard Henderson }
3186d0a851ccSRichard Henderson 
31871cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a)
3188d0a851ccSRichard Henderson {
3189d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3190d0a851ccSRichard Henderson 
3191d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3192451d993dSRichard Henderson     ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX;
31931cd012a5SRichard Henderson     trans_st(ctx, a);
3194d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
319531234768SRichard Henderson     return true;
3196d0a851ccSRichard Henderson }
319795412a61SRichard Henderson 
31980588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
3199b2167459SRichard Henderson {
32006fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3201b2167459SRichard Henderson 
32026fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tcg_rt, a->i);
32030588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3204b2167459SRichard Henderson     cond_free(&ctx->null_cond);
320531234768SRichard Henderson     return true;
3206b2167459SRichard Henderson }
3207b2167459SRichard Henderson 
32080588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a)
3209b2167459SRichard Henderson {
32106fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
32116fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
3212b2167459SRichard Henderson 
32136fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
3214b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
3215b2167459SRichard Henderson     cond_free(&ctx->null_cond);
321631234768SRichard Henderson     return true;
3217b2167459SRichard Henderson }
3218b2167459SRichard Henderson 
32190588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
3220b2167459SRichard Henderson {
32216fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3222b2167459SRichard Henderson 
3223b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
3224d265360fSRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_i64.  */
32250588e061SRichard Henderson     if (a->b == 0) {
32266fd0c7bcSRichard Henderson         tcg_gen_movi_i64(tcg_rt, a->i);
3227b2167459SRichard Henderson     } else {
32286fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
3229b2167459SRichard Henderson     }
32300588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3231b2167459SRichard Henderson     cond_free(&ctx->null_cond);
323231234768SRichard Henderson     return true;
3233b2167459SRichard Henderson }
3234b2167459SRichard Henderson 
32356fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
3236e9efd4bcSRichard Henderson                     unsigned c, unsigned f, bool d, unsigned n, int disp)
323798cd9ca7SRichard Henderson {
32386fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv;
323998cd9ca7SRichard Henderson     DisasCond cond;
324098cd9ca7SRichard Henderson 
324198cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3242aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
324398cd9ca7SRichard Henderson 
32446fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
324598cd9ca7SRichard Henderson 
3246f764718dSRichard Henderson     sv = NULL;
3247b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
324898cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
324998cd9ca7SRichard Henderson     }
325098cd9ca7SRichard Henderson 
32514fe9533aSRichard Henderson     cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
325201afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
325398cd9ca7SRichard Henderson }
325498cd9ca7SRichard Henderson 
325501afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
325698cd9ca7SRichard Henderson {
3257e9efd4bcSRichard Henderson     if (!ctx->is_pa20 && a->d) {
3258e9efd4bcSRichard Henderson         return false;
3259e9efd4bcSRichard Henderson     }
326001afb7beSRichard Henderson     nullify_over(ctx);
3261e9efd4bcSRichard Henderson     return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
3262e9efd4bcSRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
326301afb7beSRichard Henderson }
326401afb7beSRichard Henderson 
326501afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
326601afb7beSRichard Henderson {
3267c65c3ee1SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3268c65c3ee1SRichard Henderson         return false;
3269c65c3ee1SRichard Henderson     }
327001afb7beSRichard Henderson     nullify_over(ctx);
32716fd0c7bcSRichard Henderson     return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
3272c65c3ee1SRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
327301afb7beSRichard Henderson }
327401afb7beSRichard Henderson 
32756fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
327601afb7beSRichard Henderson                     unsigned c, unsigned f, unsigned n, int disp)
327701afb7beSRichard Henderson {
32786fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv, cb_cond;
327998cd9ca7SRichard Henderson     DisasCond cond;
3280bdcccc17SRichard Henderson     bool d = false;
328198cd9ca7SRichard Henderson 
3282f25d3160SRichard Henderson     /*
3283f25d3160SRichard Henderson      * For hppa64, the ADDB conditions change with PSW.W,
3284f25d3160SRichard Henderson      * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3285f25d3160SRichard Henderson      */
3286f25d3160SRichard Henderson     if (ctx->tb_flags & PSW_W) {
3287f25d3160SRichard Henderson         d = c >= 5;
3288f25d3160SRichard Henderson         if (d) {
3289f25d3160SRichard Henderson             c &= 3;
3290f25d3160SRichard Henderson         }
3291f25d3160SRichard Henderson     }
3292f25d3160SRichard Henderson 
329398cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3294aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
3295f764718dSRichard Henderson     sv = NULL;
3296bdcccc17SRichard Henderson     cb_cond = NULL;
329798cd9ca7SRichard Henderson 
3298b47a4a02SSven Schnelle     if (cond_need_cb(c)) {
3299aac0f603SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
3300aac0f603SRichard Henderson         TCGv_i64 cb_msb = tcg_temp_new_i64();
3301bdcccc17SRichard Henderson 
33026fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cb_msb, 0);
33036fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
33046fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
33056fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
3306bdcccc17SRichard Henderson         cb_cond = get_carry(ctx, d, cb, cb_msb);
3307b47a4a02SSven Schnelle     } else {
33086fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
3309b47a4a02SSven Schnelle     }
3310b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
331198cd9ca7SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
331298cd9ca7SRichard Henderson     }
331398cd9ca7SRichard Henderson 
3314a751eb31SRichard Henderson     cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
331543675d20SSven Schnelle     save_gpr(ctx, r, dest);
331601afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
331798cd9ca7SRichard Henderson }
331898cd9ca7SRichard Henderson 
331901afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a)
332098cd9ca7SRichard Henderson {
332101afb7beSRichard Henderson     nullify_over(ctx);
332201afb7beSRichard Henderson     return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
332301afb7beSRichard Henderson }
332401afb7beSRichard Henderson 
332501afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
332601afb7beSRichard Henderson {
332701afb7beSRichard Henderson     nullify_over(ctx);
33286fd0c7bcSRichard Henderson     return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
332901afb7beSRichard Henderson }
333001afb7beSRichard Henderson 
333101afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
333201afb7beSRichard Henderson {
33336fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
333498cd9ca7SRichard Henderson     DisasCond cond;
333598cd9ca7SRichard Henderson 
333698cd9ca7SRichard Henderson     nullify_over(ctx);
333798cd9ca7SRichard Henderson 
3338aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
333901afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
334084e224d4SRichard Henderson     if (cond_need_ext(ctx, a->d)) {
33411e9ab9fbSRichard Henderson         /* Force shift into [32,63] */
33426fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_sar, 32);
33436fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, tmp);
33441e9ab9fbSRichard Henderson     } else {
33456fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
33461e9ab9fbSRichard Henderson     }
334798cd9ca7SRichard Henderson 
33481e9ab9fbSRichard Henderson     cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
334901afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
335098cd9ca7SRichard Henderson }
335198cd9ca7SRichard Henderson 
335201afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
335398cd9ca7SRichard Henderson {
33546fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
335501afb7beSRichard Henderson     DisasCond cond;
33561e9ab9fbSRichard Henderson     int p;
335701afb7beSRichard Henderson 
335801afb7beSRichard Henderson     nullify_over(ctx);
335901afb7beSRichard Henderson 
3360aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
336101afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
336284e224d4SRichard Henderson     p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0);
33636fd0c7bcSRichard Henderson     tcg_gen_shli_i64(tmp, tcg_r, p);
336401afb7beSRichard Henderson 
336501afb7beSRichard Henderson     cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
336601afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
336701afb7beSRichard Henderson }
336801afb7beSRichard Henderson 
336901afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a)
337001afb7beSRichard Henderson {
33716fd0c7bcSRichard Henderson     TCGv_i64 dest;
337298cd9ca7SRichard Henderson     DisasCond cond;
337398cd9ca7SRichard Henderson 
337498cd9ca7SRichard Henderson     nullify_over(ctx);
337598cd9ca7SRichard Henderson 
337601afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r2);
337701afb7beSRichard Henderson     if (a->r1 == 0) {
33786fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, 0);
337998cd9ca7SRichard Henderson     } else {
33806fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
338198cd9ca7SRichard Henderson     }
338298cd9ca7SRichard Henderson 
33834fa52edfSRichard Henderson     /* All MOVB conditions are 32-bit. */
33844fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
338501afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
338601afb7beSRichard Henderson }
338701afb7beSRichard Henderson 
338801afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
338901afb7beSRichard Henderson {
33906fd0c7bcSRichard Henderson     TCGv_i64 dest;
339101afb7beSRichard Henderson     DisasCond cond;
339201afb7beSRichard Henderson 
339301afb7beSRichard Henderson     nullify_over(ctx);
339401afb7beSRichard Henderson 
339501afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r);
33966fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, a->i);
339701afb7beSRichard Henderson 
33984fa52edfSRichard Henderson     /* All MOVBI conditions are 32-bit. */
33994fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
340001afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
340198cd9ca7SRichard Henderson }
340298cd9ca7SRichard Henderson 
3403f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
34040b1347d2SRichard Henderson {
34056fd0c7bcSRichard Henderson     TCGv_i64 dest, src2;
34060b1347d2SRichard Henderson 
3407f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3408f7b775a9SRichard Henderson         return false;
3409f7b775a9SRichard Henderson     }
341030878590SRichard Henderson     if (a->c) {
34110b1347d2SRichard Henderson         nullify_over(ctx);
34120b1347d2SRichard Henderson     }
34130b1347d2SRichard Henderson 
341430878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
3415f7b775a9SRichard Henderson     src2 = load_gpr(ctx, a->r2);
341630878590SRichard Henderson     if (a->r1 == 0) {
3417f7b775a9SRichard Henderson         if (a->d) {
34186fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src2, cpu_sar);
3419f7b775a9SRichard Henderson         } else {
3420aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
3421f7b775a9SRichard Henderson 
34226fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src2);
34236fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
34246fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, dest, tmp);
3425f7b775a9SRichard Henderson         }
342630878590SRichard Henderson     } else if (a->r1 == a->r2) {
3427f7b775a9SRichard Henderson         if (a->d) {
34286fd0c7bcSRichard Henderson             tcg_gen_rotr_i64(dest, src2, cpu_sar);
3429f7b775a9SRichard Henderson         } else {
34300b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
3431e1d635e8SRichard Henderson             TCGv_i32 s32 = tcg_temp_new_i32();
3432e1d635e8SRichard Henderson 
34336fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, src2);
34346fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(s32, cpu_sar);
3435f7b775a9SRichard Henderson             tcg_gen_andi_i32(s32, s32, 31);
3436e1d635e8SRichard Henderson             tcg_gen_rotr_i32(t32, t32, s32);
34376fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
3438f7b775a9SRichard Henderson         }
3439f7b775a9SRichard Henderson     } else {
34406fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
3441f7b775a9SRichard Henderson 
3442f7b775a9SRichard Henderson         if (a->d) {
3443aac0f603SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
3444aac0f603SRichard Henderson             TCGv_i64 n = tcg_temp_new_i64();
3445f7b775a9SRichard Henderson 
34466fd0c7bcSRichard Henderson             tcg_gen_xori_i64(n, cpu_sar, 63);
3447a01491a2SHelge Deller             tcg_gen_shl_i64(t, src1, n);
34486fd0c7bcSRichard Henderson             tcg_gen_shli_i64(t, t, 1);
3449a01491a2SHelge Deller             tcg_gen_shr_i64(dest, src2, cpu_sar);
34506fd0c7bcSRichard Henderson             tcg_gen_or_i64(dest, dest, t);
34510b1347d2SRichard Henderson         } else {
34520b1347d2SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
34530b1347d2SRichard Henderson             TCGv_i64 s = tcg_temp_new_i64();
34540b1347d2SRichard Henderson 
34556fd0c7bcSRichard Henderson             tcg_gen_concat32_i64(t, src2, src1);
3456967662cdSRichard Henderson             tcg_gen_andi_i64(s, cpu_sar, 31);
3457967662cdSRichard Henderson             tcg_gen_shr_i64(dest, t, s);
34580b1347d2SRichard Henderson         }
3459f7b775a9SRichard Henderson     }
346030878590SRichard Henderson     save_gpr(ctx, a->t, dest);
34610b1347d2SRichard Henderson 
34620b1347d2SRichard Henderson     /* Install the new nullification.  */
34630b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
346430878590SRichard Henderson     if (a->c) {
34654fa52edfSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
34660b1347d2SRichard Henderson     }
346731234768SRichard Henderson     return nullify_end(ctx);
34680b1347d2SRichard Henderson }
34690b1347d2SRichard Henderson 
3470f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
34710b1347d2SRichard Henderson {
3472f7b775a9SRichard Henderson     unsigned width, sa;
34736fd0c7bcSRichard Henderson     TCGv_i64 dest, t2;
34740b1347d2SRichard Henderson 
3475f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3476f7b775a9SRichard Henderson         return false;
3477f7b775a9SRichard Henderson     }
347830878590SRichard Henderson     if (a->c) {
34790b1347d2SRichard Henderson         nullify_over(ctx);
34800b1347d2SRichard Henderson     }
34810b1347d2SRichard Henderson 
3482f7b775a9SRichard Henderson     width = a->d ? 64 : 32;
3483f7b775a9SRichard Henderson     sa = width - 1 - a->cpos;
3484f7b775a9SRichard Henderson 
348530878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
348630878590SRichard Henderson     t2 = load_gpr(ctx, a->r2);
348705bfd4dbSRichard Henderson     if (a->r1 == 0) {
34886fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, t2, sa, width - sa);
3489c53e401eSRichard Henderson     } else if (width == TARGET_LONG_BITS) {
34906fd0c7bcSRichard Henderson         tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
3491f7b775a9SRichard Henderson     } else {
3492f7b775a9SRichard Henderson         assert(!a->d);
3493f7b775a9SRichard Henderson         if (a->r1 == a->r2) {
34940b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
34956fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, t2);
34960b1347d2SRichard Henderson             tcg_gen_rotri_i32(t32, t32, sa);
34976fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
34980b1347d2SRichard Henderson         } else {
3499967662cdSRichard Henderson             tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]);
3500967662cdSRichard Henderson             tcg_gen_extract_i64(dest, dest, sa, 32);
35010b1347d2SRichard Henderson         }
3502f7b775a9SRichard Henderson     }
350330878590SRichard Henderson     save_gpr(ctx, a->t, dest);
35040b1347d2SRichard Henderson 
35050b1347d2SRichard Henderson     /* Install the new nullification.  */
35060b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
350730878590SRichard Henderson     if (a->c) {
35084fa52edfSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
35090b1347d2SRichard Henderson     }
351031234768SRichard Henderson     return nullify_end(ctx);
35110b1347d2SRichard Henderson }
35120b1347d2SRichard Henderson 
3513bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
35140b1347d2SRichard Henderson {
3515bd792da3SRichard Henderson     unsigned widthm1 = a->d ? 63 : 31;
35166fd0c7bcSRichard Henderson     TCGv_i64 dest, src, tmp;
35170b1347d2SRichard Henderson 
3518bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3519bd792da3SRichard Henderson         return false;
3520bd792da3SRichard Henderson     }
352130878590SRichard Henderson     if (a->c) {
35220b1347d2SRichard Henderson         nullify_over(ctx);
35230b1347d2SRichard Henderson     }
35240b1347d2SRichard Henderson 
352530878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
352630878590SRichard Henderson     src = load_gpr(ctx, a->r);
3527aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
35280b1347d2SRichard Henderson 
35290b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
35306fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
35316fd0c7bcSRichard Henderson     tcg_gen_xori_i64(tmp, tmp, widthm1);
3532d781cb77SRichard Henderson 
353330878590SRichard Henderson     if (a->se) {
3534bd792da3SRichard Henderson         if (!a->d) {
35356fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(dest, src);
3536bd792da3SRichard Henderson             src = dest;
3537bd792da3SRichard Henderson         }
35386fd0c7bcSRichard Henderson         tcg_gen_sar_i64(dest, src, tmp);
35396fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, dest, 0, a->len);
35400b1347d2SRichard Henderson     } else {
3541bd792da3SRichard Henderson         if (!a->d) {
35426fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src);
3543bd792da3SRichard Henderson             src = dest;
3544bd792da3SRichard Henderson         }
35456fd0c7bcSRichard Henderson         tcg_gen_shr_i64(dest, src, tmp);
35466fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, dest, 0, a->len);
35470b1347d2SRichard Henderson     }
354830878590SRichard Henderson     save_gpr(ctx, a->t, dest);
35490b1347d2SRichard Henderson 
35500b1347d2SRichard Henderson     /* Install the new nullification.  */
35510b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
355230878590SRichard Henderson     if (a->c) {
3553bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
35540b1347d2SRichard Henderson     }
355531234768SRichard Henderson     return nullify_end(ctx);
35560b1347d2SRichard Henderson }
35570b1347d2SRichard Henderson 
3558bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
35590b1347d2SRichard Henderson {
3560bd792da3SRichard Henderson     unsigned len, cpos, width;
35616fd0c7bcSRichard Henderson     TCGv_i64 dest, src;
35620b1347d2SRichard Henderson 
3563bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3564bd792da3SRichard Henderson         return false;
3565bd792da3SRichard Henderson     }
356630878590SRichard Henderson     if (a->c) {
35670b1347d2SRichard Henderson         nullify_over(ctx);
35680b1347d2SRichard Henderson     }
35690b1347d2SRichard Henderson 
3570bd792da3SRichard Henderson     len = a->len;
3571bd792da3SRichard Henderson     width = a->d ? 64 : 32;
3572bd792da3SRichard Henderson     cpos = width - 1 - a->pos;
3573bd792da3SRichard Henderson     if (cpos + len > width) {
3574bd792da3SRichard Henderson         len = width - cpos;
3575bd792da3SRichard Henderson     }
3576bd792da3SRichard Henderson 
357730878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
357830878590SRichard Henderson     src = load_gpr(ctx, a->r);
357930878590SRichard Henderson     if (a->se) {
35806fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, src, cpos, len);
35810b1347d2SRichard Henderson     } else {
35826fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, src, cpos, len);
35830b1347d2SRichard Henderson     }
358430878590SRichard Henderson     save_gpr(ctx, a->t, dest);
35850b1347d2SRichard Henderson 
35860b1347d2SRichard Henderson     /* Install the new nullification.  */
35870b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
358830878590SRichard Henderson     if (a->c) {
3589bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
35900b1347d2SRichard Henderson     }
359131234768SRichard Henderson     return nullify_end(ctx);
35920b1347d2SRichard Henderson }
35930b1347d2SRichard Henderson 
359472ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
35950b1347d2SRichard Henderson {
359672ae4f2bSRichard Henderson     unsigned len, width;
3597c53e401eSRichard Henderson     uint64_t mask0, mask1;
35986fd0c7bcSRichard Henderson     TCGv_i64 dest;
35990b1347d2SRichard Henderson 
360072ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
360172ae4f2bSRichard Henderson         return false;
360272ae4f2bSRichard Henderson     }
360330878590SRichard Henderson     if (a->c) {
36040b1347d2SRichard Henderson         nullify_over(ctx);
36050b1347d2SRichard Henderson     }
360672ae4f2bSRichard Henderson 
360772ae4f2bSRichard Henderson     len = a->len;
360872ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
360972ae4f2bSRichard Henderson     if (a->cpos + len > width) {
361072ae4f2bSRichard Henderson         len = width - a->cpos;
36110b1347d2SRichard Henderson     }
36120b1347d2SRichard Henderson 
361330878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
361430878590SRichard Henderson     mask0 = deposit64(0, a->cpos, len, a->i);
361530878590SRichard Henderson     mask1 = deposit64(-1, a->cpos, len, a->i);
36160b1347d2SRichard Henderson 
361730878590SRichard Henderson     if (a->nz) {
36186fd0c7bcSRichard Henderson         TCGv_i64 src = load_gpr(ctx, a->t);
36196fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, src, mask1);
36206fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, mask0);
36210b1347d2SRichard Henderson     } else {
36226fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, mask0);
36230b1347d2SRichard Henderson     }
362430878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36250b1347d2SRichard Henderson 
36260b1347d2SRichard Henderson     /* Install the new nullification.  */
36270b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
362830878590SRichard Henderson     if (a->c) {
362972ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
36300b1347d2SRichard Henderson     }
363131234768SRichard Henderson     return nullify_end(ctx);
36320b1347d2SRichard Henderson }
36330b1347d2SRichard Henderson 
363472ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
36350b1347d2SRichard Henderson {
363630878590SRichard Henderson     unsigned rs = a->nz ? a->t : 0;
363772ae4f2bSRichard Henderson     unsigned len, width;
36386fd0c7bcSRichard Henderson     TCGv_i64 dest, val;
36390b1347d2SRichard Henderson 
364072ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
364172ae4f2bSRichard Henderson         return false;
364272ae4f2bSRichard Henderson     }
364330878590SRichard Henderson     if (a->c) {
36440b1347d2SRichard Henderson         nullify_over(ctx);
36450b1347d2SRichard Henderson     }
364672ae4f2bSRichard Henderson 
364772ae4f2bSRichard Henderson     len = a->len;
364872ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
364972ae4f2bSRichard Henderson     if (a->cpos + len > width) {
365072ae4f2bSRichard Henderson         len = width - a->cpos;
36510b1347d2SRichard Henderson     }
36520b1347d2SRichard Henderson 
365330878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
365430878590SRichard Henderson     val = load_gpr(ctx, a->r);
36550b1347d2SRichard Henderson     if (rs == 0) {
36566fd0c7bcSRichard Henderson         tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
36570b1347d2SRichard Henderson     } else {
36586fd0c7bcSRichard Henderson         tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
36590b1347d2SRichard Henderson     }
366030878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36610b1347d2SRichard Henderson 
36620b1347d2SRichard Henderson     /* Install the new nullification.  */
36630b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
366430878590SRichard Henderson     if (a->c) {
366572ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
36660b1347d2SRichard Henderson     }
366731234768SRichard Henderson     return nullify_end(ctx);
36680b1347d2SRichard Henderson }
36690b1347d2SRichard Henderson 
367072ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
36716fd0c7bcSRichard Henderson                        bool d, bool nz, unsigned len, TCGv_i64 val)
36720b1347d2SRichard Henderson {
36730b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
367472ae4f2bSRichard Henderson     unsigned widthm1 = d ? 63 : 31;
36756fd0c7bcSRichard Henderson     TCGv_i64 mask, tmp, shift, dest;
3676c53e401eSRichard Henderson     uint64_t msb = 1ULL << (len - 1);
36770b1347d2SRichard Henderson 
36780b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
3679aac0f603SRichard Henderson     shift = tcg_temp_new_i64();
3680aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
36810b1347d2SRichard Henderson 
36820b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
36836fd0c7bcSRichard Henderson     tcg_gen_andi_i64(shift, cpu_sar, widthm1);
36846fd0c7bcSRichard Henderson     tcg_gen_xori_i64(shift, shift, widthm1);
36850b1347d2SRichard Henderson 
3686aac0f603SRichard Henderson     mask = tcg_temp_new_i64();
36876fd0c7bcSRichard Henderson     tcg_gen_movi_i64(mask, msb + (msb - 1));
36886fd0c7bcSRichard Henderson     tcg_gen_and_i64(tmp, val, mask);
36890b1347d2SRichard Henderson     if (rs) {
36906fd0c7bcSRichard Henderson         tcg_gen_shl_i64(mask, mask, shift);
36916fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tmp, shift);
36926fd0c7bcSRichard Henderson         tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
36936fd0c7bcSRichard Henderson         tcg_gen_or_i64(dest, dest, tmp);
36940b1347d2SRichard Henderson     } else {
36956fd0c7bcSRichard Henderson         tcg_gen_shl_i64(dest, tmp, shift);
36960b1347d2SRichard Henderson     }
36970b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
36980b1347d2SRichard Henderson 
36990b1347d2SRichard Henderson     /* Install the new nullification.  */
37000b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
37010b1347d2SRichard Henderson     if (c) {
370272ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, c, d, dest);
37030b1347d2SRichard Henderson     }
370431234768SRichard Henderson     return nullify_end(ctx);
37050b1347d2SRichard Henderson }
37060b1347d2SRichard Henderson 
370772ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
370830878590SRichard Henderson {
370972ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
371072ae4f2bSRichard Henderson         return false;
371172ae4f2bSRichard Henderson     }
3712a6deecceSSven Schnelle     if (a->c) {
3713a6deecceSSven Schnelle         nullify_over(ctx);
3714a6deecceSSven Schnelle     }
371572ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
371672ae4f2bSRichard Henderson                       load_gpr(ctx, a->r));
371730878590SRichard Henderson }
371830878590SRichard Henderson 
371972ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
372030878590SRichard Henderson {
372172ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
372272ae4f2bSRichard Henderson         return false;
372372ae4f2bSRichard Henderson     }
3724a6deecceSSven Schnelle     if (a->c) {
3725a6deecceSSven Schnelle         nullify_over(ctx);
3726a6deecceSSven Schnelle     }
372772ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
37286fd0c7bcSRichard Henderson                       tcg_constant_i64(a->i));
372930878590SRichard Henderson }
37300b1347d2SRichard Henderson 
37318340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a)
373298cd9ca7SRichard Henderson {
37336fd0c7bcSRichard Henderson     TCGv_i64 tmp;
373498cd9ca7SRichard Henderson 
3735c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
373698cd9ca7SRichard Henderson     /* ??? It seems like there should be a good way of using
373798cd9ca7SRichard Henderson        "be disp(sr2, r0)", the canonical gateway entry mechanism
373898cd9ca7SRichard Henderson        to our advantage.  But that appears to be inconvenient to
373998cd9ca7SRichard Henderson        manage along side branch delay slots.  Therefore we handle
374098cd9ca7SRichard Henderson        entry into the gateway page via absolute address.  */
374198cd9ca7SRichard Henderson     /* Since we don't implement spaces, just branch.  Do notice the special
374298cd9ca7SRichard Henderson        case of "be disp(*,r0)" using a direct branch to disp, so that we can
374398cd9ca7SRichard Henderson        goto_tb to the TB containing the syscall.  */
37448340f534SRichard Henderson     if (a->b == 0) {
37458340f534SRichard Henderson         return do_dbranch(ctx, a->disp, a->l, a->n);
374698cd9ca7SRichard Henderson     }
3747c301f34eSRichard Henderson #else
3748c301f34eSRichard Henderson     nullify_over(ctx);
3749660eefe1SRichard Henderson #endif
3750660eefe1SRichard Henderson 
3751aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
37526fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp);
3753660eefe1SRichard Henderson     tmp = do_ibranch_priv(ctx, tmp);
3754c301f34eSRichard Henderson 
3755c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
37568340f534SRichard Henderson     return do_ibranch(ctx, tmp, a->l, a->n);
3757c301f34eSRichard Henderson #else
3758c301f34eSRichard Henderson     TCGv_i64 new_spc = tcg_temp_new_i64();
3759c301f34eSRichard Henderson 
37608340f534SRichard Henderson     load_spr(ctx, new_spc, a->sp);
37618340f534SRichard Henderson     if (a->l) {
3762741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
3763c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f);
3764c301f34eSRichard Henderson     }
37658340f534SRichard Henderson     if (a->n && use_nullify_skip(ctx)) {
3766a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
37676fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, 4);
3768a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3769c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, new_spc);
3770c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f);
3771c301f34eSRichard Henderson     } else {
3772741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3773c301f34eSRichard Henderson         if (ctx->iaoq_b == -1) {
3774c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3775c301f34eSRichard Henderson         }
3776a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3777c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, new_spc);
37788340f534SRichard Henderson         nullify_set(ctx, a->n);
3779c301f34eSRichard Henderson     }
3780c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
378131234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
378231234768SRichard Henderson     return nullify_end(ctx);
3783c301f34eSRichard Henderson #endif
378498cd9ca7SRichard Henderson }
378598cd9ca7SRichard Henderson 
37868340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a)
378798cd9ca7SRichard Henderson {
37888340f534SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n);
378998cd9ca7SRichard Henderson }
379098cd9ca7SRichard Henderson 
37918340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
379243e05652SRichard Henderson {
3793c53e401eSRichard Henderson     uint64_t dest = iaoq_dest(ctx, a->disp);
379443e05652SRichard Henderson 
37956e5f5300SSven Schnelle     nullify_over(ctx);
37966e5f5300SSven Schnelle 
379743e05652SRichard Henderson     /* Make sure the caller hasn't done something weird with the queue.
379843e05652SRichard Henderson      * ??? This is not quite the same as the PSW[B] bit, which would be
379943e05652SRichard Henderson      * expensive to track.  Real hardware will trap for
380043e05652SRichard Henderson      *    b  gateway
380143e05652SRichard Henderson      *    b  gateway+4  (in delay slot of first branch)
380243e05652SRichard Henderson      * However, checking for a non-sequential instruction queue *will*
380343e05652SRichard Henderson      * diagnose the security hole
380443e05652SRichard Henderson      *    b  gateway
380543e05652SRichard Henderson      *    b  evil
380643e05652SRichard Henderson      * in which instructions at evil would run with increased privs.
380743e05652SRichard Henderson      */
380843e05652SRichard Henderson     if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) {
380943e05652SRichard Henderson         return gen_illegal(ctx);
381043e05652SRichard Henderson     }
381143e05652SRichard Henderson 
381243e05652SRichard Henderson #ifndef CONFIG_USER_ONLY
381343e05652SRichard Henderson     if (ctx->tb_flags & PSW_C) {
3814*94956d7bSPhilippe Mathieu-Daudé         int type = hppa_artype_for_page(cpu_env(ctx->cs), ctx->base.pc_next);
381543e05652SRichard Henderson         /* If we could not find a TLB entry, then we need to generate an
381643e05652SRichard Henderson            ITLB miss exception so the kernel will provide it.
381743e05652SRichard Henderson            The resulting TLB fill operation will invalidate this TB and
381843e05652SRichard Henderson            we will re-translate, at which point we *will* be able to find
381943e05652SRichard Henderson            the TLB entry and determine if this is in fact a gateway page.  */
382043e05652SRichard Henderson         if (type < 0) {
382131234768SRichard Henderson             gen_excp(ctx, EXCP_ITLB_MISS);
382231234768SRichard Henderson             return true;
382343e05652SRichard Henderson         }
382443e05652SRichard Henderson         /* No change for non-gateway pages or for priv decrease.  */
382543e05652SRichard Henderson         if (type >= 4 && type - 4 < ctx->privilege) {
382643e05652SRichard Henderson             dest = deposit32(dest, 0, 2, type - 4);
382743e05652SRichard Henderson         }
382843e05652SRichard Henderson     } else {
382943e05652SRichard Henderson         dest &= -4;  /* priv = 0 */
383043e05652SRichard Henderson     }
383143e05652SRichard Henderson #endif
383243e05652SRichard Henderson 
38336e5f5300SSven Schnelle     if (a->l) {
38346fd0c7bcSRichard Henderson         TCGv_i64 tmp = dest_gpr(ctx, a->l);
38356e5f5300SSven Schnelle         if (ctx->privilege < 3) {
38366fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, tmp, -4);
38376e5f5300SSven Schnelle         }
38386fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
38396e5f5300SSven Schnelle         save_gpr(ctx, a->l, tmp);
38406e5f5300SSven Schnelle     }
38416e5f5300SSven Schnelle 
38426e5f5300SSven Schnelle     return do_dbranch(ctx, dest, 0, a->n);
384343e05652SRichard Henderson }
384443e05652SRichard Henderson 
38458340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a)
384698cd9ca7SRichard Henderson {
3847b35aec85SRichard Henderson     if (a->x) {
3848aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
38496fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3);
38506fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8);
3851660eefe1SRichard Henderson         /* The computation here never changes privilege level.  */
38528340f534SRichard Henderson         return do_ibranch(ctx, tmp, a->l, a->n);
3853b35aec85SRichard Henderson     } else {
3854b35aec85SRichard Henderson         /* BLR R0,RX is a good way to load PC+8 into RX.  */
3855b35aec85SRichard Henderson         return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n);
3856b35aec85SRichard Henderson     }
385798cd9ca7SRichard Henderson }
385898cd9ca7SRichard Henderson 
38598340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a)
386098cd9ca7SRichard Henderson {
38616fd0c7bcSRichard Henderson     TCGv_i64 dest;
386298cd9ca7SRichard Henderson 
38638340f534SRichard Henderson     if (a->x == 0) {
38648340f534SRichard Henderson         dest = load_gpr(ctx, a->b);
386598cd9ca7SRichard Henderson     } else {
3866aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
38676fd0c7bcSRichard Henderson         tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
38686fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
386998cd9ca7SRichard Henderson     }
3870660eefe1SRichard Henderson     dest = do_ibranch_priv(ctx, dest);
38718340f534SRichard Henderson     return do_ibranch(ctx, dest, 0, a->n);
387298cd9ca7SRichard Henderson }
387398cd9ca7SRichard Henderson 
38748340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a)
387598cd9ca7SRichard Henderson {
38766fd0c7bcSRichard Henderson     TCGv_i64 dest;
387798cd9ca7SRichard Henderson 
3878c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
38798340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
38808340f534SRichard Henderson     return do_ibranch(ctx, dest, a->l, a->n);
3881c301f34eSRichard Henderson #else
3882c301f34eSRichard Henderson     nullify_over(ctx);
38838340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
3884c301f34eSRichard Henderson 
3885741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3886c301f34eSRichard Henderson     if (ctx->iaoq_b == -1) {
3887c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3888c301f34eSRichard Henderson     }
3889741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest);
3890c301f34eSRichard Henderson     tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
38918340f534SRichard Henderson     if (a->l) {
3892741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var);
3893c301f34eSRichard Henderson     }
38948340f534SRichard Henderson     nullify_set(ctx, a->n);
3895c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
389631234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
389731234768SRichard Henderson     return nullify_end(ctx);
3898c301f34eSRichard Henderson #endif
389998cd9ca7SRichard Henderson }
390098cd9ca7SRichard Henderson 
3901a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
3902a8966ba7SRichard Henderson {
3903a8966ba7SRichard Henderson     /* All branch target stack instructions implement as nop. */
3904a8966ba7SRichard Henderson     return ctx->is_pa20;
3905a8966ba7SRichard Henderson }
3906a8966ba7SRichard Henderson 
39071ca74648SRichard Henderson /*
39081ca74648SRichard Henderson  * Float class 0
39091ca74648SRichard Henderson  */
3910ebe9383cSRichard Henderson 
39111ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3912ebe9383cSRichard Henderson {
3913ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
3914ebe9383cSRichard Henderson }
3915ebe9383cSRichard Henderson 
391659f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
391759f8c04bSHelge Deller {
3918a300dad3SRichard Henderson     uint64_t ret;
3919a300dad3SRichard Henderson 
3920c53e401eSRichard Henderson     if (ctx->is_pa20) {
3921a300dad3SRichard Henderson         ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
3922a300dad3SRichard Henderson     } else {
3923a300dad3SRichard Henderson         ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
3924a300dad3SRichard Henderson     }
3925a300dad3SRichard Henderson 
392659f8c04bSHelge Deller     nullify_over(ctx);
3927a300dad3SRichard Henderson     save_frd(0, tcg_constant_i64(ret));
392859f8c04bSHelge Deller     return nullify_end(ctx);
392959f8c04bSHelge Deller }
393059f8c04bSHelge Deller 
39311ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a)
39321ca74648SRichard Henderson {
39331ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f);
39341ca74648SRichard Henderson }
39351ca74648SRichard Henderson 
3936ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3937ebe9383cSRichard Henderson {
3938ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
3939ebe9383cSRichard Henderson }
3940ebe9383cSRichard Henderson 
39411ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a)
39421ca74648SRichard Henderson {
39431ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d);
39441ca74648SRichard Henderson }
39451ca74648SRichard Henderson 
39461ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3947ebe9383cSRichard Henderson {
3948ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
3949ebe9383cSRichard Henderson }
3950ebe9383cSRichard Henderson 
39511ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a)
39521ca74648SRichard Henderson {
39531ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fabs_f);
39541ca74648SRichard Henderson }
39551ca74648SRichard Henderson 
3956ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3957ebe9383cSRichard Henderson {
3958ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
3959ebe9383cSRichard Henderson }
3960ebe9383cSRichard Henderson 
39611ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a)
39621ca74648SRichard Henderson {
39631ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fabs_d);
39641ca74648SRichard Henderson }
39651ca74648SRichard Henderson 
39661ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a)
39671ca74648SRichard Henderson {
39681ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s);
39691ca74648SRichard Henderson }
39701ca74648SRichard Henderson 
39711ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a)
39721ca74648SRichard Henderson {
39731ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d);
39741ca74648SRichard Henderson }
39751ca74648SRichard Henderson 
39761ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a)
39771ca74648SRichard Henderson {
39781ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s);
39791ca74648SRichard Henderson }
39801ca74648SRichard Henderson 
39811ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a)
39821ca74648SRichard Henderson {
39831ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d);
39841ca74648SRichard Henderson }
39851ca74648SRichard Henderson 
39861ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3987ebe9383cSRichard Henderson {
3988ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
3989ebe9383cSRichard Henderson }
3990ebe9383cSRichard Henderson 
39911ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a)
39921ca74648SRichard Henderson {
39931ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fneg_f);
39941ca74648SRichard Henderson }
39951ca74648SRichard Henderson 
3996ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3997ebe9383cSRichard Henderson {
3998ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
3999ebe9383cSRichard Henderson }
4000ebe9383cSRichard Henderson 
40011ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a)
40021ca74648SRichard Henderson {
40031ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fneg_d);
40041ca74648SRichard Henderson }
40051ca74648SRichard Henderson 
40061ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4007ebe9383cSRichard Henderson {
4008ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
4009ebe9383cSRichard Henderson }
4010ebe9383cSRichard Henderson 
40111ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a)
40121ca74648SRichard Henderson {
40131ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f);
40141ca74648SRichard Henderson }
40151ca74648SRichard Henderson 
4016ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4017ebe9383cSRichard Henderson {
4018ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
4019ebe9383cSRichard Henderson }
4020ebe9383cSRichard Henderson 
40211ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a)
40221ca74648SRichard Henderson {
40231ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d);
40241ca74648SRichard Henderson }
40251ca74648SRichard Henderson 
40261ca74648SRichard Henderson /*
40271ca74648SRichard Henderson  * Float class 1
40281ca74648SRichard Henderson  */
40291ca74648SRichard Henderson 
40301ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a)
40311ca74648SRichard Henderson {
40321ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s);
40331ca74648SRichard Henderson }
40341ca74648SRichard Henderson 
40351ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a)
40361ca74648SRichard Henderson {
40371ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d);
40381ca74648SRichard Henderson }
40391ca74648SRichard Henderson 
40401ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a)
40411ca74648SRichard Henderson {
40421ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s);
40431ca74648SRichard Henderson }
40441ca74648SRichard Henderson 
40451ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a)
40461ca74648SRichard Henderson {
40471ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s);
40481ca74648SRichard Henderson }
40491ca74648SRichard Henderson 
40501ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a)
40511ca74648SRichard Henderson {
40521ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d);
40531ca74648SRichard Henderson }
40541ca74648SRichard Henderson 
40551ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a)
40561ca74648SRichard Henderson {
40571ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d);
40581ca74648SRichard Henderson }
40591ca74648SRichard Henderson 
40601ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a)
40611ca74648SRichard Henderson {
40621ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w);
40631ca74648SRichard Henderson }
40641ca74648SRichard Henderson 
40651ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a)
40661ca74648SRichard Henderson {
40671ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w);
40681ca74648SRichard Henderson }
40691ca74648SRichard Henderson 
40701ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a)
40711ca74648SRichard Henderson {
40721ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw);
40731ca74648SRichard Henderson }
40741ca74648SRichard Henderson 
40751ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a)
40761ca74648SRichard Henderson {
40771ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw);
40781ca74648SRichard Henderson }
40791ca74648SRichard Henderson 
40801ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a)
40811ca74648SRichard Henderson {
40821ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w);
40831ca74648SRichard Henderson }
40841ca74648SRichard Henderson 
40851ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a)
40861ca74648SRichard Henderson {
40871ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w);
40881ca74648SRichard Henderson }
40891ca74648SRichard Henderson 
40901ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a)
40911ca74648SRichard Henderson {
40921ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw);
40931ca74648SRichard Henderson }
40941ca74648SRichard Henderson 
40951ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a)
40961ca74648SRichard Henderson {
40971ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw);
40981ca74648SRichard Henderson }
40991ca74648SRichard Henderson 
41001ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a)
41011ca74648SRichard Henderson {
41021ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s);
41031ca74648SRichard Henderson }
41041ca74648SRichard Henderson 
41051ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a)
41061ca74648SRichard Henderson {
41071ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s);
41081ca74648SRichard Henderson }
41091ca74648SRichard Henderson 
41101ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a)
41111ca74648SRichard Henderson {
41121ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d);
41131ca74648SRichard Henderson }
41141ca74648SRichard Henderson 
41151ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a)
41161ca74648SRichard Henderson {
41171ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d);
41181ca74648SRichard Henderson }
41191ca74648SRichard Henderson 
41201ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a)
41211ca74648SRichard Henderson {
41221ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw);
41231ca74648SRichard Henderson }
41241ca74648SRichard Henderson 
41251ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a)
41261ca74648SRichard Henderson {
41271ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw);
41281ca74648SRichard Henderson }
41291ca74648SRichard Henderson 
41301ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a)
41311ca74648SRichard Henderson {
41321ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw);
41331ca74648SRichard Henderson }
41341ca74648SRichard Henderson 
41351ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a)
41361ca74648SRichard Henderson {
41371ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw);
41381ca74648SRichard Henderson }
41391ca74648SRichard Henderson 
41401ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a)
41411ca74648SRichard Henderson {
41421ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw);
41431ca74648SRichard Henderson }
41441ca74648SRichard Henderson 
41451ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a)
41461ca74648SRichard Henderson {
41471ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw);
41481ca74648SRichard Henderson }
41491ca74648SRichard Henderson 
41501ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a)
41511ca74648SRichard Henderson {
41521ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw);
41531ca74648SRichard Henderson }
41541ca74648SRichard Henderson 
41551ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a)
41561ca74648SRichard Henderson {
41571ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw);
41581ca74648SRichard Henderson }
41591ca74648SRichard Henderson 
41601ca74648SRichard Henderson /*
41611ca74648SRichard Henderson  * Float class 2
41621ca74648SRichard Henderson  */
41631ca74648SRichard Henderson 
41641ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a)
4165ebe9383cSRichard Henderson {
4166ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
4167ebe9383cSRichard Henderson 
4168ebe9383cSRichard Henderson     nullify_over(ctx);
4169ebe9383cSRichard Henderson 
41701ca74648SRichard Henderson     ta = load_frw0_i32(a->r1);
41711ca74648SRichard Henderson     tb = load_frw0_i32(a->r2);
417229dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
417329dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4174ebe9383cSRichard Henderson 
4175ad75a51eSRichard Henderson     gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc);
4176ebe9383cSRichard Henderson 
41771ca74648SRichard Henderson     return nullify_end(ctx);
4178ebe9383cSRichard Henderson }
4179ebe9383cSRichard Henderson 
41801ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
4181ebe9383cSRichard Henderson {
4182ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
4183ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
4184ebe9383cSRichard Henderson 
4185ebe9383cSRichard Henderson     nullify_over(ctx);
4186ebe9383cSRichard Henderson 
41871ca74648SRichard Henderson     ta = load_frd0(a->r1);
41881ca74648SRichard Henderson     tb = load_frd0(a->r2);
418929dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
419029dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4191ebe9383cSRichard Henderson 
4192ad75a51eSRichard Henderson     gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc);
4193ebe9383cSRichard Henderson 
419431234768SRichard Henderson     return nullify_end(ctx);
4195ebe9383cSRichard Henderson }
4196ebe9383cSRichard Henderson 
41971ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
4198ebe9383cSRichard Henderson {
41996fd0c7bcSRichard Henderson     TCGv_i64 t;
4200ebe9383cSRichard Henderson 
4201ebe9383cSRichard Henderson     nullify_over(ctx);
4202ebe9383cSRichard Henderson 
4203aac0f603SRichard Henderson     t = tcg_temp_new_i64();
42046fd0c7bcSRichard Henderson     tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
4205ebe9383cSRichard Henderson 
42061ca74648SRichard Henderson     if (a->y == 1) {
4207ebe9383cSRichard Henderson         int mask;
4208ebe9383cSRichard Henderson         bool inv = false;
4209ebe9383cSRichard Henderson 
42101ca74648SRichard Henderson         switch (a->c) {
4211ebe9383cSRichard Henderson         case 0: /* simple */
42126fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, 0x4000000);
4213ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_NE, t);
4214ebe9383cSRichard Henderson             goto done;
4215ebe9383cSRichard Henderson         case 2: /* rej */
4216ebe9383cSRichard Henderson             inv = true;
4217ebe9383cSRichard Henderson             /* fallthru */
4218ebe9383cSRichard Henderson         case 1: /* acc */
4219ebe9383cSRichard Henderson             mask = 0x43ff800;
4220ebe9383cSRichard Henderson             break;
4221ebe9383cSRichard Henderson         case 6: /* rej8 */
4222ebe9383cSRichard Henderson             inv = true;
4223ebe9383cSRichard Henderson             /* fallthru */
4224ebe9383cSRichard Henderson         case 5: /* acc8 */
4225ebe9383cSRichard Henderson             mask = 0x43f8000;
4226ebe9383cSRichard Henderson             break;
4227ebe9383cSRichard Henderson         case 9: /* acc6 */
4228ebe9383cSRichard Henderson             mask = 0x43e0000;
4229ebe9383cSRichard Henderson             break;
4230ebe9383cSRichard Henderson         case 13: /* acc4 */
4231ebe9383cSRichard Henderson             mask = 0x4380000;
4232ebe9383cSRichard Henderson             break;
4233ebe9383cSRichard Henderson         case 17: /* acc2 */
4234ebe9383cSRichard Henderson             mask = 0x4200000;
4235ebe9383cSRichard Henderson             break;
4236ebe9383cSRichard Henderson         default:
42371ca74648SRichard Henderson             gen_illegal(ctx);
42381ca74648SRichard Henderson             return true;
4239ebe9383cSRichard Henderson         }
4240ebe9383cSRichard Henderson         if (inv) {
42416fd0c7bcSRichard Henderson             TCGv_i64 c = tcg_constant_i64(mask);
42426fd0c7bcSRichard Henderson             tcg_gen_or_i64(t, t, c);
4243ebe9383cSRichard Henderson             ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
4244ebe9383cSRichard Henderson         } else {
42456fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, mask);
4246ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
4247ebe9383cSRichard Henderson         }
42481ca74648SRichard Henderson     } else {
42491ca74648SRichard Henderson         unsigned cbit = (a->y ^ 1) - 1;
42501ca74648SRichard Henderson 
42516fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, t, 21 - cbit, 1);
42521ca74648SRichard Henderson         ctx->null_cond = cond_make_0(TCG_COND_NE, t);
42531ca74648SRichard Henderson     }
42541ca74648SRichard Henderson 
4255ebe9383cSRichard Henderson  done:
425631234768SRichard Henderson     return nullify_end(ctx);
4257ebe9383cSRichard Henderson }
4258ebe9383cSRichard Henderson 
42591ca74648SRichard Henderson /*
42601ca74648SRichard Henderson  * Float class 2
42611ca74648SRichard Henderson  */
42621ca74648SRichard Henderson 
42631ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a)
4264ebe9383cSRichard Henderson {
42651ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s);
42661ca74648SRichard Henderson }
42671ca74648SRichard Henderson 
42681ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a)
42691ca74648SRichard Henderson {
42701ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d);
42711ca74648SRichard Henderson }
42721ca74648SRichard Henderson 
42731ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a)
42741ca74648SRichard Henderson {
42751ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s);
42761ca74648SRichard Henderson }
42771ca74648SRichard Henderson 
42781ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a)
42791ca74648SRichard Henderson {
42801ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d);
42811ca74648SRichard Henderson }
42821ca74648SRichard Henderson 
42831ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a)
42841ca74648SRichard Henderson {
42851ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s);
42861ca74648SRichard Henderson }
42871ca74648SRichard Henderson 
42881ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a)
42891ca74648SRichard Henderson {
42901ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d);
42911ca74648SRichard Henderson }
42921ca74648SRichard Henderson 
42931ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a)
42941ca74648SRichard Henderson {
42951ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s);
42961ca74648SRichard Henderson }
42971ca74648SRichard Henderson 
42981ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a)
42991ca74648SRichard Henderson {
43001ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d);
43011ca74648SRichard Henderson }
43021ca74648SRichard Henderson 
43031ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a)
43041ca74648SRichard Henderson {
43051ca74648SRichard Henderson     TCGv_i64 x, y;
4306ebe9383cSRichard Henderson 
4307ebe9383cSRichard Henderson     nullify_over(ctx);
4308ebe9383cSRichard Henderson 
43091ca74648SRichard Henderson     x = load_frw0_i64(a->r1);
43101ca74648SRichard Henderson     y = load_frw0_i64(a->r2);
43111ca74648SRichard Henderson     tcg_gen_mul_i64(x, x, y);
43121ca74648SRichard Henderson     save_frd(a->t, x);
4313ebe9383cSRichard Henderson 
431431234768SRichard Henderson     return nullify_end(ctx);
4315ebe9383cSRichard Henderson }
4316ebe9383cSRichard Henderson 
4317ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
4318ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
4319ebe9383cSRichard Henderson {
4320ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
4321ebe9383cSRichard Henderson }
4322ebe9383cSRichard Henderson 
4323b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4324ebe9383cSRichard Henderson {
4325b1e2af57SRichard Henderson     int tm = fmpyadd_s_reg(a->tm);
4326b1e2af57SRichard Henderson     int ra = fmpyadd_s_reg(a->ra);
4327b1e2af57SRichard Henderson     int ta = fmpyadd_s_reg(a->ta);
4328b1e2af57SRichard Henderson     int rm2 = fmpyadd_s_reg(a->rm2);
4329b1e2af57SRichard Henderson     int rm1 = fmpyadd_s_reg(a->rm1);
4330ebe9383cSRichard Henderson 
4331ebe9383cSRichard Henderson     nullify_over(ctx);
4332ebe9383cSRichard Henderson 
4333ebe9383cSRichard Henderson     do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4334ebe9383cSRichard Henderson     do_fop_weww(ctx, ta, ta, ra,
4335ebe9383cSRichard Henderson                 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
4336ebe9383cSRichard Henderson 
433731234768SRichard Henderson     return nullify_end(ctx);
4338ebe9383cSRichard Henderson }
4339ebe9383cSRichard Henderson 
4340b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4341b1e2af57SRichard Henderson {
4342b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, false);
4343b1e2af57SRichard Henderson }
4344b1e2af57SRichard Henderson 
4345b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4346b1e2af57SRichard Henderson {
4347b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, true);
4348b1e2af57SRichard Henderson }
4349b1e2af57SRichard Henderson 
4350b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4351b1e2af57SRichard Henderson {
4352b1e2af57SRichard Henderson     nullify_over(ctx);
4353b1e2af57SRichard Henderson 
4354b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4355b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4356b1e2af57SRichard Henderson                 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4357b1e2af57SRichard Henderson 
4358b1e2af57SRichard Henderson     return nullify_end(ctx);
4359b1e2af57SRichard Henderson }
4360b1e2af57SRichard Henderson 
4361b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4362b1e2af57SRichard Henderson {
4363b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, false);
4364b1e2af57SRichard Henderson }
4365b1e2af57SRichard Henderson 
4366b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4367b1e2af57SRichard Henderson {
4368b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, true);
4369b1e2af57SRichard Henderson }
4370b1e2af57SRichard Henderson 
4371c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a)
4372ebe9383cSRichard Henderson {
4373c3bad4f8SRichard Henderson     TCGv_i32 x, y, z;
4374ebe9383cSRichard Henderson 
4375ebe9383cSRichard Henderson     nullify_over(ctx);
4376c3bad4f8SRichard Henderson     x = load_frw0_i32(a->rm1);
4377c3bad4f8SRichard Henderson     y = load_frw0_i32(a->rm2);
4378c3bad4f8SRichard Henderson     z = load_frw0_i32(a->ra3);
4379ebe9383cSRichard Henderson 
4380c3bad4f8SRichard Henderson     if (a->neg) {
4381ad75a51eSRichard Henderson         gen_helper_fmpynfadd_s(x, tcg_env, x, y, z);
4382ebe9383cSRichard Henderson     } else {
4383ad75a51eSRichard Henderson         gen_helper_fmpyfadd_s(x, tcg_env, x, y, z);
4384ebe9383cSRichard Henderson     }
4385ebe9383cSRichard Henderson 
4386c3bad4f8SRichard Henderson     save_frw_i32(a->t, x);
438731234768SRichard Henderson     return nullify_end(ctx);
4388ebe9383cSRichard Henderson }
4389ebe9383cSRichard Henderson 
4390c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
4391ebe9383cSRichard Henderson {
4392c3bad4f8SRichard Henderson     TCGv_i64 x, y, z;
4393ebe9383cSRichard Henderson 
4394ebe9383cSRichard Henderson     nullify_over(ctx);
4395c3bad4f8SRichard Henderson     x = load_frd0(a->rm1);
4396c3bad4f8SRichard Henderson     y = load_frd0(a->rm2);
4397c3bad4f8SRichard Henderson     z = load_frd0(a->ra3);
4398ebe9383cSRichard Henderson 
4399c3bad4f8SRichard Henderson     if (a->neg) {
4400ad75a51eSRichard Henderson         gen_helper_fmpynfadd_d(x, tcg_env, x, y, z);
4401ebe9383cSRichard Henderson     } else {
4402ad75a51eSRichard Henderson         gen_helper_fmpyfadd_d(x, tcg_env, x, y, z);
4403ebe9383cSRichard Henderson     }
4404ebe9383cSRichard Henderson 
4405c3bad4f8SRichard Henderson     save_frd(a->t, x);
440631234768SRichard Henderson     return nullify_end(ctx);
4407ebe9383cSRichard Henderson }
4408ebe9383cSRichard Henderson 
440915da177bSSven Schnelle static bool trans_diag(DisasContext *ctx, arg_diag *a)
441015da177bSSven Schnelle {
4411cf6b28d4SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4412cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY
4413cf6b28d4SHelge Deller     if (a->i == 0x100) {
4414cf6b28d4SHelge Deller         /* emulate PDC BTLB, called by SeaBIOS-hppa */
4415ad75a51eSRichard Henderson         nullify_over(ctx);
4416ad75a51eSRichard Henderson         gen_helper_diag_btlb(tcg_env);
4417cf6b28d4SHelge Deller         return nullify_end(ctx);
441815da177bSSven Schnelle     }
4419dbca0835SHelge Deller     if (a->i == 0x101) {
4420dbca0835SHelge Deller         /* print char in %r26 to first serial console, used by SeaBIOS-hppa */
4421dbca0835SHelge Deller         nullify_over(ctx);
4422dbca0835SHelge Deller         gen_helper_diag_console_output(tcg_env);
4423dbca0835SHelge Deller         return nullify_end(ctx);
4424dbca0835SHelge Deller     }
4425ad75a51eSRichard Henderson #endif
4426ad75a51eSRichard Henderson     qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i);
4427ad75a51eSRichard Henderson     return true;
4428ad75a51eSRichard Henderson }
442915da177bSSven Schnelle 
4430b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
443161766fe9SRichard Henderson {
443251b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4433f764718dSRichard Henderson     int bound;
443461766fe9SRichard Henderson 
443551b061fbSRichard Henderson     ctx->cs = cs;
4436494737b7SRichard Henderson     ctx->tb_flags = ctx->base.tb->flags;
4437bd6243a3SRichard Henderson     ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
44383d68ee7bSRichard Henderson 
44393d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY
4440c01e5dfbSHelge Deller     ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX);
44413d68ee7bSRichard Henderson     ctx->mmu_idx = MMU_USER_IDX;
4442c01e5dfbSHelge Deller     ctx->iaoq_f = ctx->base.pc_first | ctx->privilege;
4443c01e5dfbSHelge Deller     ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege;
4444217d1a5eSRichard Henderson     ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
4445c301f34eSRichard Henderson #else
4446494737b7SRichard Henderson     ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
4447bb67ec32SRichard Henderson     ctx->mmu_idx = (ctx->tb_flags & PSW_D
4448bb67ec32SRichard Henderson                     ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
4449451d993dSRichard Henderson                     : ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX);
44503d68ee7bSRichard Henderson 
4451c301f34eSRichard Henderson     /* Recover the IAOQ values from the GVA + PRIV.  */
4452c301f34eSRichard Henderson     uint64_t cs_base = ctx->base.tb->cs_base;
4453c301f34eSRichard Henderson     uint64_t iasq_f = cs_base & ~0xffffffffull;
4454c301f34eSRichard Henderson     int32_t diff = cs_base;
4455c301f34eSRichard Henderson 
4456c301f34eSRichard Henderson     ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
4457c301f34eSRichard Henderson     ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1);
4458c301f34eSRichard Henderson #endif
445951b061fbSRichard Henderson     ctx->iaoq_n = -1;
4460f764718dSRichard Henderson     ctx->iaoq_n_var = NULL;
446161766fe9SRichard Henderson 
4462a4db4a78SRichard Henderson     ctx->zero = tcg_constant_i64(0);
4463a4db4a78SRichard Henderson 
44643d68ee7bSRichard Henderson     /* Bound the number of instructions by those left on the page.  */
44653d68ee7bSRichard Henderson     bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
4466b542683dSEmilio G. Cota     ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
446761766fe9SRichard Henderson }
446861766fe9SRichard Henderson 
446951b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
447051b061fbSRichard Henderson {
447151b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
447261766fe9SRichard Henderson 
44733d68ee7bSRichard Henderson     /* Seed the nullification status from PSW[N], as saved in TB->FLAGS.  */
447451b061fbSRichard Henderson     ctx->null_cond = cond_make_f();
447551b061fbSRichard Henderson     ctx->psw_n_nonzero = false;
4476494737b7SRichard Henderson     if (ctx->tb_flags & PSW_N) {
447751b061fbSRichard Henderson         ctx->null_cond.c = TCG_COND_ALWAYS;
447851b061fbSRichard Henderson         ctx->psw_n_nonzero = true;
4479129e9cc3SRichard Henderson     }
448051b061fbSRichard Henderson     ctx->null_lab = NULL;
448161766fe9SRichard Henderson }
448261766fe9SRichard Henderson 
448351b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
448451b061fbSRichard Henderson {
448551b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
448651b061fbSRichard Henderson 
4487f5b5c857SRichard Henderson     tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b, 0);
4488f5b5c857SRichard Henderson     ctx->insn_start = tcg_last_op();
448951b061fbSRichard Henderson }
449051b061fbSRichard Henderson 
449151b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
449251b061fbSRichard Henderson {
449351b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4494b77af26eSRichard Henderson     CPUHPPAState *env = cpu_env(cs);
449551b061fbSRichard Henderson     DisasJumpType ret;
449651b061fbSRichard Henderson 
449751b061fbSRichard Henderson     /* Execute one insn.  */
4498ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4499c301f34eSRichard Henderson     if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
450031234768SRichard Henderson         do_page_zero(ctx);
450131234768SRichard Henderson         ret = ctx->base.is_jmp;
4502869051eaSRichard Henderson         assert(ret != DISAS_NEXT);
4503ba1d0b44SRichard Henderson     } else
4504ba1d0b44SRichard Henderson #endif
4505ba1d0b44SRichard Henderson     {
450661766fe9SRichard Henderson         /* Always fetch the insn, even if nullified, so that we check
450761766fe9SRichard Henderson            the page permissions for execute.  */
45084e116893SIlya Leoshkevich         uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next);
450961766fe9SRichard Henderson 
451061766fe9SRichard Henderson         /* Set up the IA queue for the next insn.
451161766fe9SRichard Henderson            This will be overwritten by a branch.  */
451251b061fbSRichard Henderson         if (ctx->iaoq_b == -1) {
451351b061fbSRichard Henderson             ctx->iaoq_n = -1;
4514aac0f603SRichard Henderson             ctx->iaoq_n_var = tcg_temp_new_i64();
45156fd0c7bcSRichard Henderson             tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
451661766fe9SRichard Henderson         } else {
451751b061fbSRichard Henderson             ctx->iaoq_n = ctx->iaoq_b + 4;
4518f764718dSRichard Henderson             ctx->iaoq_n_var = NULL;
451961766fe9SRichard Henderson         }
452061766fe9SRichard Henderson 
452151b061fbSRichard Henderson         if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
452251b061fbSRichard Henderson             ctx->null_cond.c = TCG_COND_NEVER;
4523869051eaSRichard Henderson             ret = DISAS_NEXT;
4524129e9cc3SRichard Henderson         } else {
45251a19da0dSRichard Henderson             ctx->insn = insn;
452631274b46SRichard Henderson             if (!decode(ctx, insn)) {
452731274b46SRichard Henderson                 gen_illegal(ctx);
452831274b46SRichard Henderson             }
452931234768SRichard Henderson             ret = ctx->base.is_jmp;
453051b061fbSRichard Henderson             assert(ctx->null_lab == NULL);
4531129e9cc3SRichard Henderson         }
453261766fe9SRichard Henderson     }
453361766fe9SRichard Henderson 
45343d68ee7bSRichard Henderson     /* Advance the insn queue.  Note that this check also detects
45353d68ee7bSRichard Henderson        a priority change within the instruction queue.  */
453651b061fbSRichard Henderson     if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
4537c301f34eSRichard Henderson         if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1
4538c301f34eSRichard Henderson             && use_goto_tb(ctx, ctx->iaoq_b)
4539c301f34eSRichard Henderson             && (ctx->null_cond.c == TCG_COND_NEVER
4540c301f34eSRichard Henderson                 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
454151b061fbSRichard Henderson             nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
454251b061fbSRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
454331234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_NORETURN;
4544129e9cc3SRichard Henderson         } else {
454531234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE;
454661766fe9SRichard Henderson         }
4547129e9cc3SRichard Henderson     }
454851b061fbSRichard Henderson     ctx->iaoq_f = ctx->iaoq_b;
454951b061fbSRichard Henderson     ctx->iaoq_b = ctx->iaoq_n;
4550c301f34eSRichard Henderson     ctx->base.pc_next += 4;
455161766fe9SRichard Henderson 
4552c5d0aec2SRichard Henderson     switch (ret) {
4553c5d0aec2SRichard Henderson     case DISAS_NORETURN:
4554c5d0aec2SRichard Henderson     case DISAS_IAQ_N_UPDATED:
4555c5d0aec2SRichard Henderson         break;
4556c5d0aec2SRichard Henderson 
4557c5d0aec2SRichard Henderson     case DISAS_NEXT:
4558c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE:
4559c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
456051b061fbSRichard Henderson         if (ctx->iaoq_f == -1) {
4561a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b);
4562741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
4563c301f34eSRichard Henderson #ifndef CONFIG_USER_ONLY
4564c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
4565c301f34eSRichard Henderson #endif
456651b061fbSRichard Henderson             nullify_save(ctx);
4567c5d0aec2SRichard Henderson             ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT
4568c5d0aec2SRichard Henderson                                 ? DISAS_EXIT
4569c5d0aec2SRichard Henderson                                 : DISAS_IAQ_N_UPDATED);
457051b061fbSRichard Henderson         } else if (ctx->iaoq_b == -1) {
4571a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var);
457261766fe9SRichard Henderson         }
4573c5d0aec2SRichard Henderson         break;
4574c5d0aec2SRichard Henderson 
4575c5d0aec2SRichard Henderson     default:
4576c5d0aec2SRichard Henderson         g_assert_not_reached();
4577c5d0aec2SRichard Henderson     }
457861766fe9SRichard Henderson }
457961766fe9SRichard Henderson 
458051b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
458151b061fbSRichard Henderson {
458251b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4583e1b5a5edSRichard Henderson     DisasJumpType is_jmp = ctx->base.is_jmp;
458451b061fbSRichard Henderson 
4585e1b5a5edSRichard Henderson     switch (is_jmp) {
4586869051eaSRichard Henderson     case DISAS_NORETURN:
458761766fe9SRichard Henderson         break;
458851b061fbSRichard Henderson     case DISAS_TOO_MANY:
4589869051eaSRichard Henderson     case DISAS_IAQ_N_STALE:
4590e1b5a5edSRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
4591741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
4592741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
459351b061fbSRichard Henderson         nullify_save(ctx);
459461766fe9SRichard Henderson         /* FALLTHRU */
4595869051eaSRichard Henderson     case DISAS_IAQ_N_UPDATED:
45968532a14eSRichard Henderson         if (is_jmp != DISAS_IAQ_N_STALE_EXIT) {
45977f11636dSEmilio G. Cota             tcg_gen_lookup_and_goto_ptr();
45988532a14eSRichard Henderson             break;
459961766fe9SRichard Henderson         }
4600c5d0aec2SRichard Henderson         /* FALLTHRU */
4601c5d0aec2SRichard Henderson     case DISAS_EXIT:
4602c5d0aec2SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
460361766fe9SRichard Henderson         break;
460461766fe9SRichard Henderson     default:
460551b061fbSRichard Henderson         g_assert_not_reached();
460661766fe9SRichard Henderson     }
460751b061fbSRichard Henderson }
460861766fe9SRichard Henderson 
46098eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase,
46108eb806a7SRichard Henderson                               CPUState *cs, FILE *logfile)
461151b061fbSRichard Henderson {
4612c301f34eSRichard Henderson     target_ulong pc = dcbase->pc_first;
461361766fe9SRichard Henderson 
4614ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4615ba1d0b44SRichard Henderson     switch (pc) {
46167ad439dfSRichard Henderson     case 0x00:
46178eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000000:  (null)\n");
4618ba1d0b44SRichard Henderson         return;
46197ad439dfSRichard Henderson     case 0xb0:
46208eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000b0:  light-weight-syscall\n");
4621ba1d0b44SRichard Henderson         return;
46227ad439dfSRichard Henderson     case 0xe0:
46238eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000e0:  set-thread-pointer-syscall\n");
4624ba1d0b44SRichard Henderson         return;
46257ad439dfSRichard Henderson     case 0x100:
46268eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000100:  syscall\n");
4627ba1d0b44SRichard Henderson         return;
46287ad439dfSRichard Henderson     }
4629ba1d0b44SRichard Henderson #endif
4630ba1d0b44SRichard Henderson 
46318eb806a7SRichard Henderson     fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
46328eb806a7SRichard Henderson     target_disas(logfile, cs, pc, dcbase->tb->size);
463361766fe9SRichard Henderson }
463451b061fbSRichard Henderson 
463551b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = {
463651b061fbSRichard Henderson     .init_disas_context = hppa_tr_init_disas_context,
463751b061fbSRichard Henderson     .tb_start           = hppa_tr_tb_start,
463851b061fbSRichard Henderson     .insn_start         = hppa_tr_insn_start,
463951b061fbSRichard Henderson     .translate_insn     = hppa_tr_translate_insn,
464051b061fbSRichard Henderson     .tb_stop            = hppa_tr_tb_stop,
464151b061fbSRichard Henderson     .disas_log          = hppa_tr_disas_log,
464251b061fbSRichard Henderson };
464351b061fbSRichard Henderson 
4644597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
464532f0c394SAnton Johansson                            vaddr pc, void *host_pc)
464651b061fbSRichard Henderson {
464751b061fbSRichard Henderson     DisasContext ctx;
4648306c8721SRichard Henderson     translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
464961766fe9SRichard Henderson }
4650