xref: /openbmc/qemu/target/hppa/translate.c (revision 32f0c394bbf7fb2be635658cbf84c72a124720a0)
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 {
2159e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2160e1b5a5edSRichard Henderson #ifndef CONFIG_USER_ONLY
21616fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2162e1b5a5edSRichard Henderson 
2163e1b5a5edSRichard Henderson     nullify_over(ctx);
2164e1b5a5edSRichard Henderson 
2165aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
21666fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
21676fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ~a->i);
2168ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2169e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2170e1b5a5edSRichard Henderson 
2171e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_M.  */
217231234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
217331234768SRichard Henderson     return nullify_end(ctx);
2174e36f27efSRichard Henderson #endif
2175e1b5a5edSRichard Henderson }
2176e1b5a5edSRichard Henderson 
2177e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
2178e1b5a5edSRichard Henderson {
2179e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2180e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
21816fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2182e1b5a5edSRichard Henderson 
2183e1b5a5edSRichard Henderson     nullify_over(ctx);
2184e1b5a5edSRichard Henderson 
2185aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
21866fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
21876fd0c7bcSRichard Henderson     tcg_gen_ori_i64(tmp, tmp, a->i);
2188ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2189e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2190e1b5a5edSRichard Henderson 
2191e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_I.  */
219231234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
219331234768SRichard Henderson     return nullify_end(ctx);
2194e36f27efSRichard Henderson #endif
2195e1b5a5edSRichard Henderson }
2196e1b5a5edSRichard Henderson 
2197c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
2198e1b5a5edSRichard Henderson {
2199e1b5a5edSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2200c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
22016fd0c7bcSRichard Henderson     TCGv_i64 tmp, reg;
2202e1b5a5edSRichard Henderson     nullify_over(ctx);
2203e1b5a5edSRichard Henderson 
2204c603e14aSRichard Henderson     reg = load_gpr(ctx, a->r);
2205aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2206ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, reg);
2207e1b5a5edSRichard Henderson 
2208e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts.  */
220931234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
221031234768SRichard Henderson     return nullify_end(ctx);
2211c603e14aSRichard Henderson #endif
2212e1b5a5edSRichard Henderson }
2213f49b3537SRichard Henderson 
2214e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r)
2215f49b3537SRichard Henderson {
2216f49b3537SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2217e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
2218f49b3537SRichard Henderson     nullify_over(ctx);
2219f49b3537SRichard Henderson 
2220e36f27efSRichard Henderson     if (rfi_r) {
2221ad75a51eSRichard Henderson         gen_helper_rfi_r(tcg_env);
2222f49b3537SRichard Henderson     } else {
2223ad75a51eSRichard Henderson         gen_helper_rfi(tcg_env);
2224f49b3537SRichard Henderson     }
222531234768SRichard Henderson     /* Exit the TB to recognize new interrupts.  */
222607ea28b4SRichard Henderson     tcg_gen_exit_tb(NULL, 0);
222731234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
2228f49b3537SRichard Henderson 
222931234768SRichard Henderson     return nullify_end(ctx);
2230e36f27efSRichard Henderson #endif
2231f49b3537SRichard Henderson }
22326210db05SHelge Deller 
2233e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a)
2234e36f27efSRichard Henderson {
2235e36f27efSRichard Henderson     return do_rfi(ctx, false);
2236e36f27efSRichard Henderson }
2237e36f27efSRichard Henderson 
2238e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a)
2239e36f27efSRichard Henderson {
2240e36f27efSRichard Henderson     return do_rfi(ctx, true);
2241e36f27efSRichard Henderson }
2242e36f27efSRichard Henderson 
224396927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a)
22446210db05SHelge Deller {
22456210db05SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
224696927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
22476210db05SHelge Deller     nullify_over(ctx);
2248ad75a51eSRichard Henderson     gen_helper_halt(tcg_env);
224931234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
225031234768SRichard Henderson     return nullify_end(ctx);
225196927adbSRichard Henderson #endif
22526210db05SHelge Deller }
225396927adbSRichard Henderson 
225496927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a)
225596927adbSRichard Henderson {
225696927adbSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
225796927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
225896927adbSRichard Henderson     nullify_over(ctx);
2259ad75a51eSRichard Henderson     gen_helper_reset(tcg_env);
226096927adbSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
226196927adbSRichard Henderson     return nullify_end(ctx);
226296927adbSRichard Henderson #endif
226396927adbSRichard Henderson }
2264e1b5a5edSRichard Henderson 
22654a4554c6SHelge Deller static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
22664a4554c6SHelge Deller {
22674a4554c6SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
22684a4554c6SHelge Deller #ifndef CONFIG_USER_ONLY
22694a4554c6SHelge Deller     nullify_over(ctx);
2270ad75a51eSRichard Henderson     gen_helper_getshadowregs(tcg_env);
22714a4554c6SHelge Deller     return nullify_end(ctx);
22724a4554c6SHelge Deller #endif
22734a4554c6SHelge Deller }
22744a4554c6SHelge Deller 
2275deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
227698a9cb79SRichard Henderson {
2277deee69a1SRichard Henderson     if (a->m) {
22786fd0c7bcSRichard Henderson         TCGv_i64 dest = dest_gpr(ctx, a->b);
22796fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->b);
22806fd0c7bcSRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->x);
228198a9cb79SRichard Henderson 
228298a9cb79SRichard Henderson         /* The only thing we need to do is the base register modification.  */
22836fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, src1, src2);
2284deee69a1SRichard Henderson         save_gpr(ctx, a->b, dest);
2285deee69a1SRichard Henderson     }
228698a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
228731234768SRichard Henderson     return true;
228898a9cb79SRichard Henderson }
228998a9cb79SRichard Henderson 
2290deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a)
229198a9cb79SRichard Henderson {
22926fd0c7bcSRichard Henderson     TCGv_i64 dest, ofs;
2293eed14219SRichard Henderson     TCGv_i32 level, want;
22946fd0c7bcSRichard Henderson     TCGv_i64 addr;
229598a9cb79SRichard Henderson 
229698a9cb79SRichard Henderson     nullify_over(ctx);
229798a9cb79SRichard Henderson 
2298deee69a1SRichard Henderson     dest = dest_gpr(ctx, a->t);
2299deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2300eed14219SRichard Henderson 
2301deee69a1SRichard Henderson     if (a->imm) {
2302e5d487c9SRichard Henderson         level = tcg_constant_i32(a->ri & 3);
230398a9cb79SRichard Henderson     } else {
2304eed14219SRichard Henderson         level = tcg_temp_new_i32();
23056fd0c7bcSRichard Henderson         tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri));
2306eed14219SRichard Henderson         tcg_gen_andi_i32(level, level, 3);
230798a9cb79SRichard Henderson     }
230829dd6f64SRichard Henderson     want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ);
2309eed14219SRichard Henderson 
2310ad75a51eSRichard Henderson     gen_helper_probe(dest, tcg_env, addr, level, want);
2311eed14219SRichard Henderson 
2312deee69a1SRichard Henderson     save_gpr(ctx, a->t, dest);
231331234768SRichard Henderson     return nullify_end(ctx);
231498a9cb79SRichard Henderson }
231598a9cb79SRichard Henderson 
2316deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
23178d6ae7fbSRichard Henderson {
23188577f354SRichard Henderson     if (ctx->is_pa20) {
23198577f354SRichard Henderson         return false;
23208577f354SRichard Henderson     }
2321deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2322deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
23236fd0c7bcSRichard Henderson     TCGv_i64 addr;
23246fd0c7bcSRichard Henderson     TCGv_i64 ofs, reg;
23258d6ae7fbSRichard Henderson 
23268d6ae7fbSRichard Henderson     nullify_over(ctx);
23278d6ae7fbSRichard Henderson 
2328deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2329deee69a1SRichard Henderson     reg = load_gpr(ctx, a->r);
2330deee69a1SRichard Henderson     if (a->addr) {
23318577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
23328d6ae7fbSRichard Henderson     } else {
23338577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
23348d6ae7fbSRichard Henderson     }
23358d6ae7fbSRichard Henderson 
233632dc7569SSven Schnelle     /* Exit TB for TLB change if mmu is enabled.  */
233732dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
233831234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
233931234768SRichard Henderson     }
234031234768SRichard Henderson     return nullify_end(ctx);
2341deee69a1SRichard Henderson #endif
23428d6ae7fbSRichard Henderson }
234363300a00SRichard Henderson 
2344eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local)
234563300a00SRichard Henderson {
2346deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2347deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
23486fd0c7bcSRichard Henderson     TCGv_i64 addr;
23496fd0c7bcSRichard Henderson     TCGv_i64 ofs;
235063300a00SRichard Henderson 
235163300a00SRichard Henderson     nullify_over(ctx);
235263300a00SRichard Henderson 
2353deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2354eb25d10fSHelge Deller 
2355eb25d10fSHelge Deller     /*
2356eb25d10fSHelge Deller      * Page align now, rather than later, so that we can add in the
2357eb25d10fSHelge Deller      * page_size field from pa2.0 from the low 4 bits of GR[b].
2358eb25d10fSHelge Deller      */
2359eb25d10fSHelge Deller     tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK);
2360eb25d10fSHelge Deller     if (ctx->is_pa20) {
2361eb25d10fSHelge Deller         tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4);
236263300a00SRichard Henderson     }
2363eb25d10fSHelge Deller 
2364eb25d10fSHelge Deller     if (local) {
2365eb25d10fSHelge Deller         gen_helper_ptlb_l(tcg_env, addr);
236663300a00SRichard Henderson     } else {
2367ad75a51eSRichard Henderson         gen_helper_ptlb(tcg_env, addr);
236863300a00SRichard Henderson     }
236963300a00SRichard Henderson 
2370eb25d10fSHelge Deller     if (a->m) {
2371eb25d10fSHelge Deller         save_gpr(ctx, a->b, ofs);
2372eb25d10fSHelge Deller     }
2373eb25d10fSHelge Deller 
2374eb25d10fSHelge Deller     /* Exit TB for TLB change if mmu is enabled.  */
2375eb25d10fSHelge Deller     if (ctx->tb_flags & PSW_C) {
2376eb25d10fSHelge Deller         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2377eb25d10fSHelge Deller     }
2378eb25d10fSHelge Deller     return nullify_end(ctx);
2379eb25d10fSHelge Deller #endif
2380eb25d10fSHelge Deller }
2381eb25d10fSHelge Deller 
2382eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a)
2383eb25d10fSHelge Deller {
2384eb25d10fSHelge Deller     return do_pxtlb(ctx, a, false);
2385eb25d10fSHelge Deller }
2386eb25d10fSHelge Deller 
2387eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a)
2388eb25d10fSHelge Deller {
2389eb25d10fSHelge Deller     return ctx->is_pa20 && do_pxtlb(ctx, a, true);
2390eb25d10fSHelge Deller }
2391eb25d10fSHelge Deller 
2392eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a)
2393eb25d10fSHelge Deller {
2394eb25d10fSHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2395eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY
2396eb25d10fSHelge Deller     nullify_over(ctx);
2397eb25d10fSHelge Deller 
2398eb25d10fSHelge Deller     trans_nop_addrx(ctx, a);
2399eb25d10fSHelge Deller     gen_helper_ptlbe(tcg_env);
2400eb25d10fSHelge Deller 
240163300a00SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
240232dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
240331234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
240431234768SRichard Henderson     }
240531234768SRichard Henderson     return nullify_end(ctx);
2406deee69a1SRichard Henderson #endif
240763300a00SRichard Henderson }
24082dfcca9fSRichard Henderson 
24096797c315SNick Hudson /*
24106797c315SNick Hudson  * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
24116797c315SNick Hudson  * See
24126797c315SNick Hudson  *     https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
24136797c315SNick Hudson  *     page 13-9 (195/206)
24146797c315SNick Hudson  */
24156797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
24166797c315SNick Hudson {
24178577f354SRichard Henderson     if (ctx->is_pa20) {
24188577f354SRichard Henderson         return false;
24198577f354SRichard Henderson     }
24206797c315SNick Hudson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24216797c315SNick Hudson #ifndef CONFIG_USER_ONLY
24226fd0c7bcSRichard Henderson     TCGv_i64 addr, atl, stl;
24236fd0c7bcSRichard Henderson     TCGv_i64 reg;
24246797c315SNick Hudson 
24256797c315SNick Hudson     nullify_over(ctx);
24266797c315SNick Hudson 
24276797c315SNick Hudson     /*
24286797c315SNick Hudson      * FIXME:
24296797c315SNick Hudson      *  if (not (pcxl or pcxl2))
24306797c315SNick Hudson      *    return gen_illegal(ctx);
24316797c315SNick Hudson      */
24326797c315SNick Hudson 
24336fd0c7bcSRichard Henderson     atl = tcg_temp_new_i64();
24346fd0c7bcSRichard Henderson     stl = tcg_temp_new_i64();
24356fd0c7bcSRichard Henderson     addr = tcg_temp_new_i64();
24366797c315SNick Hudson 
2437ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(stl, tcg_env,
24386797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
24396797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIASQ]));
2440ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(atl, tcg_env,
24416797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
24426797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIAOQ]));
24436797c315SNick Hudson     tcg_gen_shli_i64(stl, stl, 32);
2444d265360fSRichard Henderson     tcg_gen_or_i64(addr, atl, stl);
24456797c315SNick Hudson 
24466797c315SNick Hudson     reg = load_gpr(ctx, a->r);
24476797c315SNick Hudson     if (a->addr) {
24488577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
24496797c315SNick Hudson     } else {
24508577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
24516797c315SNick Hudson     }
24526797c315SNick Hudson 
24536797c315SNick Hudson     /* Exit TB for TLB change if mmu is enabled.  */
24546797c315SNick Hudson     if (ctx->tb_flags & PSW_C) {
24556797c315SNick Hudson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
24566797c315SNick Hudson     }
24576797c315SNick Hudson     return nullify_end(ctx);
24586797c315SNick Hudson #endif
24596797c315SNick Hudson }
24606797c315SNick Hudson 
24618577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
24628577f354SRichard Henderson {
24638577f354SRichard Henderson     if (!ctx->is_pa20) {
24648577f354SRichard Henderson         return false;
24658577f354SRichard Henderson     }
24668577f354SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24678577f354SRichard Henderson #ifndef CONFIG_USER_ONLY
24688577f354SRichard Henderson     nullify_over(ctx);
24698577f354SRichard Henderson     {
24708577f354SRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
24718577f354SRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->r2);
24728577f354SRichard Henderson 
24738577f354SRichard Henderson         if (a->data) {
24748577f354SRichard Henderson             gen_helper_idtlbt_pa20(tcg_env, src1, src2);
24758577f354SRichard Henderson         } else {
24768577f354SRichard Henderson             gen_helper_iitlbt_pa20(tcg_env, src1, src2);
24778577f354SRichard Henderson         }
24788577f354SRichard Henderson     }
24798577f354SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
24808577f354SRichard Henderson     if (ctx->tb_flags & PSW_C) {
24818577f354SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
24828577f354SRichard Henderson     }
24838577f354SRichard Henderson     return nullify_end(ctx);
24848577f354SRichard Henderson #endif
24858577f354SRichard Henderson }
24868577f354SRichard Henderson 
2487deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
24882dfcca9fSRichard Henderson {
2489deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2490deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
24916fd0c7bcSRichard Henderson     TCGv_i64 vaddr;
24926fd0c7bcSRichard Henderson     TCGv_i64 ofs, paddr;
24932dfcca9fSRichard Henderson 
24942dfcca9fSRichard Henderson     nullify_over(ctx);
24952dfcca9fSRichard Henderson 
2496deee69a1SRichard Henderson     form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
24972dfcca9fSRichard Henderson 
2498aac0f603SRichard Henderson     paddr = tcg_temp_new_i64();
2499ad75a51eSRichard Henderson     gen_helper_lpa(paddr, tcg_env, vaddr);
25002dfcca9fSRichard Henderson 
25012dfcca9fSRichard Henderson     /* Note that physical address result overrides base modification.  */
2502deee69a1SRichard Henderson     if (a->m) {
2503deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
25042dfcca9fSRichard Henderson     }
2505deee69a1SRichard Henderson     save_gpr(ctx, a->t, paddr);
25062dfcca9fSRichard Henderson 
250731234768SRichard Henderson     return nullify_end(ctx);
2508deee69a1SRichard Henderson #endif
25092dfcca9fSRichard Henderson }
251043a97b81SRichard Henderson 
2511deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a)
251243a97b81SRichard Henderson {
251343a97b81SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
251443a97b81SRichard Henderson 
251543a97b81SRichard Henderson     /* The Coherence Index is an implementation-defined function of the
251643a97b81SRichard Henderson        physical address.  Two addresses with the same CI have a coherent
251743a97b81SRichard Henderson        view of the cache.  Our implementation is to return 0 for all,
251843a97b81SRichard Henderson        since the entire address space is coherent.  */
2519a4db4a78SRichard Henderson     save_gpr(ctx, a->t, ctx->zero);
252043a97b81SRichard Henderson 
252131234768SRichard Henderson     cond_free(&ctx->null_cond);
252231234768SRichard Henderson     return true;
252343a97b81SRichard Henderson }
252498a9cb79SRichard Henderson 
2525faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2526b2167459SRichard Henderson {
25270c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, false);
2528b2167459SRichard Henderson }
2529b2167459SRichard Henderson 
2530faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2531b2167459SRichard Henderson {
25320c982a28SRichard Henderson     return do_add_reg(ctx, a, true, false, false, false);
2533b2167459SRichard Henderson }
2534b2167459SRichard Henderson 
2535faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2536b2167459SRichard Henderson {
25370c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, false);
2538b2167459SRichard Henderson }
2539b2167459SRichard Henderson 
2540faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2541b2167459SRichard Henderson {
25420c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, true);
25430c982a28SRichard Henderson }
2544b2167459SRichard Henderson 
2545faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
25460c982a28SRichard Henderson {
25470c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, true);
25480c982a28SRichard Henderson }
25490c982a28SRichard Henderson 
255063c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
25510c982a28SRichard Henderson {
25520c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, false);
25530c982a28SRichard Henderson }
25540c982a28SRichard Henderson 
255563c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
25560c982a28SRichard Henderson {
25570c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, false);
25580c982a28SRichard Henderson }
25590c982a28SRichard Henderson 
256063c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
25610c982a28SRichard Henderson {
25620c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, true);
25630c982a28SRichard Henderson }
25640c982a28SRichard Henderson 
256563c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
25660c982a28SRichard Henderson {
25670c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, true);
25680c982a28SRichard Henderson }
25690c982a28SRichard Henderson 
257063c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
25710c982a28SRichard Henderson {
25720c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, true, false);
25730c982a28SRichard Henderson }
25740c982a28SRichard Henderson 
257563c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
25760c982a28SRichard Henderson {
25770c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, true, false);
25780c982a28SRichard Henderson }
25790c982a28SRichard Henderson 
2580fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
25810c982a28SRichard Henderson {
25826fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_andc_i64);
25830c982a28SRichard Henderson }
25840c982a28SRichard Henderson 
2585fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
25860c982a28SRichard Henderson {
25876fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_and_i64);
25880c982a28SRichard Henderson }
25890c982a28SRichard Henderson 
2590fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
25910c982a28SRichard Henderson {
25920c982a28SRichard Henderson     if (a->cf == 0) {
25930c982a28SRichard Henderson         unsigned r2 = a->r2;
25940c982a28SRichard Henderson         unsigned r1 = a->r1;
25950c982a28SRichard Henderson         unsigned rt = a->t;
25960c982a28SRichard Henderson 
25977aee8189SRichard Henderson         if (rt == 0) { /* NOP */
25987aee8189SRichard Henderson             cond_free(&ctx->null_cond);
25997aee8189SRichard Henderson             return true;
26007aee8189SRichard Henderson         }
26017aee8189SRichard Henderson         if (r2 == 0) { /* COPY */
2602b2167459SRichard Henderson             if (r1 == 0) {
26036fd0c7bcSRichard Henderson                 TCGv_i64 dest = dest_gpr(ctx, rt);
26046fd0c7bcSRichard Henderson                 tcg_gen_movi_i64(dest, 0);
2605b2167459SRichard Henderson                 save_gpr(ctx, rt, dest);
2606b2167459SRichard Henderson             } else {
2607b2167459SRichard Henderson                 save_gpr(ctx, rt, cpu_gr[r1]);
2608b2167459SRichard Henderson             }
2609b2167459SRichard Henderson             cond_free(&ctx->null_cond);
261031234768SRichard Henderson             return true;
2611b2167459SRichard Henderson         }
26127aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY
26137aee8189SRichard Henderson         /* These are QEMU extensions and are nops in the real architecture:
26147aee8189SRichard Henderson          *
26157aee8189SRichard Henderson          * or %r10,%r10,%r10 -- idle loop; wait for interrupt
26167aee8189SRichard Henderson          * or %r31,%r31,%r31 -- death loop; offline cpu
26177aee8189SRichard Henderson          *                      currently implemented as idle.
26187aee8189SRichard Henderson          */
26197aee8189SRichard Henderson         if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
26207aee8189SRichard Henderson             /* No need to check for supervisor, as userland can only pause
26217aee8189SRichard Henderson                until the next timer interrupt.  */
26227aee8189SRichard Henderson             nullify_over(ctx);
26237aee8189SRichard Henderson 
26247aee8189SRichard Henderson             /* Advance the instruction queue.  */
2625741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
2626741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
26277aee8189SRichard Henderson             nullify_set(ctx, 0);
26287aee8189SRichard Henderson 
26297aee8189SRichard Henderson             /* Tell the qemu main loop to halt until this cpu has work.  */
2630ad75a51eSRichard Henderson             tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
263129dd6f64SRichard Henderson                            offsetof(CPUState, halted) - offsetof(HPPACPU, env));
26327aee8189SRichard Henderson             gen_excp_1(EXCP_HALTED);
26337aee8189SRichard Henderson             ctx->base.is_jmp = DISAS_NORETURN;
26347aee8189SRichard Henderson 
26357aee8189SRichard Henderson             return nullify_end(ctx);
26367aee8189SRichard Henderson         }
26377aee8189SRichard Henderson #endif
26387aee8189SRichard Henderson     }
26396fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_or_i64);
26407aee8189SRichard Henderson }
2641b2167459SRichard Henderson 
2642fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
2643b2167459SRichard Henderson {
26446fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_xor_i64);
26450c982a28SRichard Henderson }
26460c982a28SRichard Henderson 
2647345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
26480c982a28SRichard Henderson {
26496fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2650b2167459SRichard Henderson 
26510c982a28SRichard Henderson     if (a->cf) {
2652b2167459SRichard Henderson         nullify_over(ctx);
2653b2167459SRichard Henderson     }
26540c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26550c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2656345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
265731234768SRichard Henderson     return nullify_end(ctx);
2658b2167459SRichard Henderson }
2659b2167459SRichard Henderson 
2660af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
2661b2167459SRichard Henderson {
26626fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2663b2167459SRichard Henderson 
26640c982a28SRichard Henderson     if (a->cf) {
2665b2167459SRichard Henderson         nullify_over(ctx);
2666b2167459SRichard Henderson     }
26670c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26680c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
26696fd0c7bcSRichard Henderson     do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64);
267031234768SRichard Henderson     return nullify_end(ctx);
2671b2167459SRichard Henderson }
2672b2167459SRichard Henderson 
2673af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
2674b2167459SRichard Henderson {
26756fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, tmp;
2676b2167459SRichard Henderson 
26770c982a28SRichard Henderson     if (a->cf) {
2678b2167459SRichard Henderson         nullify_over(ctx);
2679b2167459SRichard Henderson     }
26800c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26810c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2682aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
26836fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, tcg_r2);
26846fd0c7bcSRichard Henderson     do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64);
268531234768SRichard Henderson     return nullify_end(ctx);
2686b2167459SRichard Henderson }
2687b2167459SRichard Henderson 
2688af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
2689b2167459SRichard Henderson {
26900c982a28SRichard Henderson     return do_uaddcm(ctx, a, false);
26910c982a28SRichard Henderson }
26920c982a28SRichard Henderson 
2693af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
26940c982a28SRichard Henderson {
26950c982a28SRichard Henderson     return do_uaddcm(ctx, a, true);
26960c982a28SRichard Henderson }
26970c982a28SRichard Henderson 
2698af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
26990c982a28SRichard Henderson {
27006fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2701b2167459SRichard Henderson 
2702b2167459SRichard Henderson     nullify_over(ctx);
2703b2167459SRichard Henderson 
2704aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
27056fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, cpu_psw_cb, 3);
2706b2167459SRichard Henderson     if (!is_i) {
27076fd0c7bcSRichard Henderson         tcg_gen_not_i64(tmp, tmp);
2708b2167459SRichard Henderson     }
27096fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
27106fd0c7bcSRichard Henderson     tcg_gen_muli_i64(tmp, tmp, 6);
2711af240753SRichard Henderson     do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false,
27126fd0c7bcSRichard Henderson             is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64);
271331234768SRichard Henderson     return nullify_end(ctx);
2714b2167459SRichard Henderson }
2715b2167459SRichard Henderson 
2716af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
2717b2167459SRichard Henderson {
27180c982a28SRichard Henderson     return do_dcor(ctx, a, false);
27190c982a28SRichard Henderson }
27200c982a28SRichard Henderson 
2721af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
27220c982a28SRichard Henderson {
27230c982a28SRichard Henderson     return do_dcor(ctx, a, true);
27240c982a28SRichard Henderson }
27250c982a28SRichard Henderson 
27260c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
27270c982a28SRichard Henderson {
2728a4db4a78SRichard Henderson     TCGv_i64 dest, add1, add2, addc, in1, in2;
27296fd0c7bcSRichard Henderson     TCGv_i64 cout;
2730b2167459SRichard Henderson 
2731b2167459SRichard Henderson     nullify_over(ctx);
2732b2167459SRichard Henderson 
27330c982a28SRichard Henderson     in1 = load_gpr(ctx, a->r1);
27340c982a28SRichard Henderson     in2 = load_gpr(ctx, a->r2);
2735b2167459SRichard Henderson 
2736aac0f603SRichard Henderson     add1 = tcg_temp_new_i64();
2737aac0f603SRichard Henderson     add2 = tcg_temp_new_i64();
2738aac0f603SRichard Henderson     addc = tcg_temp_new_i64();
2739aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
2740b2167459SRichard Henderson 
2741b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
27426fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, in1, in1);
27436fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
2744b2167459SRichard Henderson 
274572ca8753SRichard Henderson     /*
274672ca8753SRichard Henderson      * Add or subtract R2, depending on PSW[V].  Proper computation of
274772ca8753SRichard Henderson      * carry requires that we subtract via + ~R2 + 1, as described in
274872ca8753SRichard Henderson      * the manual.  By extracting and masking V, we can produce the
274972ca8753SRichard Henderson      * proper inputs to the addition without movcond.
275072ca8753SRichard Henderson      */
27516fd0c7bcSRichard Henderson     tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
27526fd0c7bcSRichard Henderson     tcg_gen_xor_i64(add2, in2, addc);
27536fd0c7bcSRichard Henderson     tcg_gen_andi_i64(addc, addc, 1);
275472ca8753SRichard Henderson 
2755a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero);
2756a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb,
2757a4db4a78SRichard Henderson                      addc, ctx->zero);
2758b2167459SRichard Henderson 
2759b2167459SRichard Henderson     /* Write back the result register.  */
27600c982a28SRichard Henderson     save_gpr(ctx, a->t, dest);
2761b2167459SRichard Henderson 
2762b2167459SRichard Henderson     /* Write back PSW[CB].  */
27636fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
27646fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
2765b2167459SRichard Henderson 
2766b2167459SRichard Henderson     /* Write back PSW[V] for the division step.  */
276772ca8753SRichard Henderson     cout = get_psw_carry(ctx, false);
27686fd0c7bcSRichard Henderson     tcg_gen_neg_i64(cpu_psw_v, cout);
27696fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
2770b2167459SRichard Henderson 
2771b2167459SRichard Henderson     /* Install the new nullification.  */
27720c982a28SRichard Henderson     if (a->cf) {
27736fd0c7bcSRichard Henderson         TCGv_i64 sv = NULL;
2774b47a4a02SSven Schnelle         if (cond_need_sv(a->cf >> 1)) {
2775b2167459SRichard Henderson             /* ??? The lshift is supposed to contribute to overflow.  */
2776b2167459SRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2);
2777b2167459SRichard Henderson         }
2778a751eb31SRichard Henderson         ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv);
2779b2167459SRichard Henderson     }
2780b2167459SRichard Henderson 
278131234768SRichard Henderson     return nullify_end(ctx);
2782b2167459SRichard Henderson }
2783b2167459SRichard Henderson 
27840588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a)
2785b2167459SRichard Henderson {
27860588e061SRichard Henderson     return do_add_imm(ctx, a, false, false);
27870588e061SRichard Henderson }
27880588e061SRichard Henderson 
27890588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a)
27900588e061SRichard Henderson {
27910588e061SRichard Henderson     return do_add_imm(ctx, a, true, false);
27920588e061SRichard Henderson }
27930588e061SRichard Henderson 
27940588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a)
27950588e061SRichard Henderson {
27960588e061SRichard Henderson     return do_add_imm(ctx, a, false, true);
27970588e061SRichard Henderson }
27980588e061SRichard Henderson 
27990588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a)
28000588e061SRichard Henderson {
28010588e061SRichard Henderson     return do_add_imm(ctx, a, true, true);
28020588e061SRichard Henderson }
28030588e061SRichard Henderson 
28040588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a)
28050588e061SRichard Henderson {
28060588e061SRichard Henderson     return do_sub_imm(ctx, a, false);
28070588e061SRichard Henderson }
28080588e061SRichard Henderson 
28090588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
28100588e061SRichard Henderson {
28110588e061SRichard Henderson     return do_sub_imm(ctx, a, true);
28120588e061SRichard Henderson }
28130588e061SRichard Henderson 
2814345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
28150588e061SRichard Henderson {
28166fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
2817b2167459SRichard Henderson 
28180588e061SRichard Henderson     if (a->cf) {
2819b2167459SRichard Henderson         nullify_over(ctx);
2820b2167459SRichard Henderson     }
2821b2167459SRichard Henderson 
28226fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
28230588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
2824345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
2825b2167459SRichard Henderson 
282631234768SRichard Henderson     return nullify_end(ctx);
2827b2167459SRichard Henderson }
2828b2167459SRichard Henderson 
28290843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a,
28300843563fSRichard Henderson                           void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
28310843563fSRichard Henderson {
28320843563fSRichard Henderson     TCGv_i64 r1, r2, dest;
28330843563fSRichard Henderson 
28340843563fSRichard Henderson     if (!ctx->is_pa20) {
28350843563fSRichard Henderson         return false;
28360843563fSRichard Henderson     }
28370843563fSRichard Henderson 
28380843563fSRichard Henderson     nullify_over(ctx);
28390843563fSRichard Henderson 
28400843563fSRichard Henderson     r1 = load_gpr(ctx, a->r1);
28410843563fSRichard Henderson     r2 = load_gpr(ctx, a->r2);
28420843563fSRichard Henderson     dest = dest_gpr(ctx, a->t);
28430843563fSRichard Henderson 
28440843563fSRichard Henderson     fn(dest, r1, r2);
28450843563fSRichard Henderson     save_gpr(ctx, a->t, dest);
28460843563fSRichard Henderson 
28470843563fSRichard Henderson     return nullify_end(ctx);
28480843563fSRichard Henderson }
28490843563fSRichard Henderson 
2850151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a,
2851151f309bSRichard Henderson                              void (*fn)(TCGv_i64, TCGv_i64, int64_t))
2852151f309bSRichard Henderson {
2853151f309bSRichard Henderson     TCGv_i64 r, dest;
2854151f309bSRichard Henderson 
2855151f309bSRichard Henderson     if (!ctx->is_pa20) {
2856151f309bSRichard Henderson         return false;
2857151f309bSRichard Henderson     }
2858151f309bSRichard Henderson 
2859151f309bSRichard Henderson     nullify_over(ctx);
2860151f309bSRichard Henderson 
2861151f309bSRichard Henderson     r = load_gpr(ctx, a->r);
2862151f309bSRichard Henderson     dest = dest_gpr(ctx, a->t);
2863151f309bSRichard Henderson 
2864151f309bSRichard Henderson     fn(dest, r, a->i);
2865151f309bSRichard Henderson     save_gpr(ctx, a->t, dest);
2866151f309bSRichard Henderson 
2867151f309bSRichard Henderson     return nullify_end(ctx);
2868151f309bSRichard Henderson }
2869151f309bSRichard Henderson 
28703bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a,
28713bbb8e48SRichard Henderson                                 void (*fn)(TCGv_i64, TCGv_i64,
28723bbb8e48SRichard Henderson                                            TCGv_i64, TCGv_i32))
28733bbb8e48SRichard Henderson {
28743bbb8e48SRichard Henderson     TCGv_i64 r1, r2, dest;
28753bbb8e48SRichard Henderson 
28763bbb8e48SRichard Henderson     if (!ctx->is_pa20) {
28773bbb8e48SRichard Henderson         return false;
28783bbb8e48SRichard Henderson     }
28793bbb8e48SRichard Henderson 
28803bbb8e48SRichard Henderson     nullify_over(ctx);
28813bbb8e48SRichard Henderson 
28823bbb8e48SRichard Henderson     r1 = load_gpr(ctx, a->r1);
28833bbb8e48SRichard Henderson     r2 = load_gpr(ctx, a->r2);
28843bbb8e48SRichard Henderson     dest = dest_gpr(ctx, a->t);
28853bbb8e48SRichard Henderson 
28863bbb8e48SRichard Henderson     fn(dest, r1, r2, tcg_constant_i32(a->sh));
28873bbb8e48SRichard Henderson     save_gpr(ctx, a->t, dest);
28883bbb8e48SRichard Henderson 
28893bbb8e48SRichard Henderson     return nullify_end(ctx);
28903bbb8e48SRichard Henderson }
28913bbb8e48SRichard Henderson 
28920843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a)
28930843563fSRichard Henderson {
28940843563fSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_add16_i64);
28950843563fSRichard Henderson }
28960843563fSRichard Henderson 
28970843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a)
28980843563fSRichard Henderson {
28990843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_ss);
29000843563fSRichard Henderson }
29010843563fSRichard Henderson 
29020843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a)
29030843563fSRichard Henderson {
29040843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_us);
29050843563fSRichard Henderson }
29060843563fSRichard Henderson 
29071b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a)
29081b3cb7c8SRichard Henderson {
29091b3cb7c8SRichard Henderson     return do_multimedia(ctx, a, gen_helper_havg);
29101b3cb7c8SRichard Henderson }
29111b3cb7c8SRichard Henderson 
2912151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a)
2913151f309bSRichard Henderson {
2914151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64);
2915151f309bSRichard Henderson }
2916151f309bSRichard Henderson 
2917151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a)
2918151f309bSRichard Henderson {
2919151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64);
2920151f309bSRichard Henderson }
2921151f309bSRichard Henderson 
2922151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a)
2923151f309bSRichard Henderson {
2924151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64);
2925151f309bSRichard Henderson }
2926151f309bSRichard Henderson 
29273bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a)
29283bbb8e48SRichard Henderson {
29293bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshladd);
29303bbb8e48SRichard Henderson }
29313bbb8e48SRichard Henderson 
29323bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a)
29333bbb8e48SRichard Henderson {
29343bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshradd);
29353bbb8e48SRichard Henderson }
29363bbb8e48SRichard Henderson 
293710c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a)
293810c9e58dSRichard Henderson {
293910c9e58dSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64);
294010c9e58dSRichard Henderson }
294110c9e58dSRichard Henderson 
294210c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a)
294310c9e58dSRichard Henderson {
294410c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_ss);
294510c9e58dSRichard Henderson }
294610c9e58dSRichard Henderson 
294710c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a)
294810c9e58dSRichard Henderson {
294910c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_us);
295010c9e58dSRichard Henderson }
295110c9e58dSRichard Henderson 
2952c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2953c2a7ee3fSRichard Henderson {
2954c2a7ee3fSRichard Henderson     uint64_t mask = 0xffff0000ffff0000ull;
2955c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2956c2a7ee3fSRichard Henderson 
2957c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r2, mask);
2958c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r1, mask);
2959c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, tmp, 16);
2960c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
2961c2a7ee3fSRichard Henderson }
2962c2a7ee3fSRichard Henderson 
2963c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a)
2964c2a7ee3fSRichard Henderson {
2965c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_l);
2966c2a7ee3fSRichard Henderson }
2967c2a7ee3fSRichard Henderson 
2968c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2969c2a7ee3fSRichard Henderson {
2970c2a7ee3fSRichard Henderson     uint64_t mask = 0x0000ffff0000ffffull;
2971c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2972c2a7ee3fSRichard Henderson 
2973c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r1, mask);
2974c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r2, mask);
2975c2a7ee3fSRichard Henderson     tcg_gen_shli_i64(tmp, tmp, 16);
2976c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
2977c2a7ee3fSRichard Henderson }
2978c2a7ee3fSRichard Henderson 
2979c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a)
2980c2a7ee3fSRichard Henderson {
2981c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_r);
2982c2a7ee3fSRichard Henderson }
2983c2a7ee3fSRichard Henderson 
2984c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2985c2a7ee3fSRichard Henderson {
2986c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2987c2a7ee3fSRichard Henderson 
2988c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, r2, 32);
2989c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r1, tmp, 0, 32);
2990c2a7ee3fSRichard Henderson }
2991c2a7ee3fSRichard Henderson 
2992c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a)
2993c2a7ee3fSRichard Henderson {
2994c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_l);
2995c2a7ee3fSRichard Henderson }
2996c2a7ee3fSRichard Henderson 
2997c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2998c2a7ee3fSRichard Henderson {
2999c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r2, r1, 32, 32);
3000c2a7ee3fSRichard Henderson }
3001c2a7ee3fSRichard Henderson 
3002c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a)
3003c2a7ee3fSRichard Henderson {
3004c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_r);
3005c2a7ee3fSRichard Henderson }
3006c2a7ee3fSRichard Henderson 
30074e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a)
30084e7abdb1SRichard Henderson {
30094e7abdb1SRichard Henderson     TCGv_i64 r, t0, t1, t2, t3;
30104e7abdb1SRichard Henderson 
30114e7abdb1SRichard Henderson     if (!ctx->is_pa20) {
30124e7abdb1SRichard Henderson         return false;
30134e7abdb1SRichard Henderson     }
30144e7abdb1SRichard Henderson 
30154e7abdb1SRichard Henderson     nullify_over(ctx);
30164e7abdb1SRichard Henderson 
30174e7abdb1SRichard Henderson     r = load_gpr(ctx, a->r1);
30184e7abdb1SRichard Henderson     t0 = tcg_temp_new_i64();
30194e7abdb1SRichard Henderson     t1 = tcg_temp_new_i64();
30204e7abdb1SRichard Henderson     t2 = tcg_temp_new_i64();
30214e7abdb1SRichard Henderson     t3 = tcg_temp_new_i64();
30224e7abdb1SRichard Henderson 
30234e7abdb1SRichard Henderson     tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16);
30244e7abdb1SRichard Henderson     tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16);
30254e7abdb1SRichard Henderson     tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16);
30264e7abdb1SRichard Henderson     tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16);
30274e7abdb1SRichard Henderson 
30284e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t1, t0, 16, 48);
30294e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t2, t3, t2, 16, 48);
30304e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t2, t0, 32, 32);
30314e7abdb1SRichard Henderson 
30324e7abdb1SRichard Henderson     save_gpr(ctx, a->t, t0);
30334e7abdb1SRichard Henderson     return nullify_end(ctx);
30344e7abdb1SRichard Henderson }
30354e7abdb1SRichard Henderson 
30361cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a)
303796d6407fSRichard Henderson {
3038b5caa17cSRichard Henderson     if (ctx->is_pa20) {
3039b5caa17cSRichard Henderson        /*
3040b5caa17cSRichard Henderson         * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches.
3041b5caa17cSRichard Henderson         * Any base modification still occurs.
3042b5caa17cSRichard Henderson         */
3043b5caa17cSRichard Henderson         if (a->t == 0) {
3044b5caa17cSRichard Henderson             return trans_nop_addrx(ctx, a);
3045b5caa17cSRichard Henderson         }
3046b5caa17cSRichard Henderson     } else if (a->size > MO_32) {
30470786a3b6SHelge Deller         return gen_illegal(ctx);
3048c53e401eSRichard Henderson     }
30491cd012a5SRichard Henderson     return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
30501cd012a5SRichard Henderson                    a->disp, a->sp, a->m, a->size | MO_TE);
305196d6407fSRichard Henderson }
305296d6407fSRichard Henderson 
30531cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a)
305496d6407fSRichard Henderson {
30551cd012a5SRichard Henderson     assert(a->x == 0 && a->scale == 0);
3056c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
30570786a3b6SHelge Deller         return gen_illegal(ctx);
305896d6407fSRichard Henderson     }
3059c53e401eSRichard Henderson     return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
30600786a3b6SHelge Deller }
306196d6407fSRichard Henderson 
30621cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
306396d6407fSRichard Henderson {
3064b1af755cSRichard Henderson     MemOp mop = MO_TE | MO_ALIGN | a->size;
3065a4db4a78SRichard Henderson     TCGv_i64 dest, ofs;
30666fd0c7bcSRichard Henderson     TCGv_i64 addr;
306796d6407fSRichard Henderson 
3068c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
306951416c4eSRichard Henderson         return gen_illegal(ctx);
307051416c4eSRichard Henderson     }
307151416c4eSRichard Henderson 
307296d6407fSRichard Henderson     nullify_over(ctx);
307396d6407fSRichard Henderson 
30741cd012a5SRichard Henderson     if (a->m) {
307586f8d05fSRichard Henderson         /* Base register modification.  Make sure if RT == RB,
307686f8d05fSRichard Henderson            we see the result of the load.  */
3077aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
307896d6407fSRichard Henderson     } else {
30791cd012a5SRichard Henderson         dest = dest_gpr(ctx, a->t);
308096d6407fSRichard Henderson     }
308196d6407fSRichard Henderson 
30821cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0,
308317fe594cSRichard Henderson              a->disp, a->sp, a->m, MMU_DISABLED(ctx));
3084b1af755cSRichard Henderson 
3085b1af755cSRichard Henderson     /*
3086b1af755cSRichard Henderson      * For hppa1.1, LDCW is undefined unless aligned mod 16.
3087b1af755cSRichard Henderson      * However actual hardware succeeds with aligned mod 4.
3088b1af755cSRichard Henderson      * Detect this case and log a GUEST_ERROR.
3089b1af755cSRichard Henderson      *
3090b1af755cSRichard Henderson      * TODO: HPPA64 relaxes the over-alignment requirement
3091b1af755cSRichard Henderson      * with the ,co completer.
3092b1af755cSRichard Henderson      */
3093b1af755cSRichard Henderson     gen_helper_ldc_check(addr);
3094b1af755cSRichard Henderson 
3095a4db4a78SRichard Henderson     tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop);
3096b1af755cSRichard Henderson 
30971cd012a5SRichard Henderson     if (a->m) {
30981cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
309996d6407fSRichard Henderson     }
31001cd012a5SRichard Henderson     save_gpr(ctx, a->t, dest);
310196d6407fSRichard Henderson 
310231234768SRichard Henderson     return nullify_end(ctx);
310396d6407fSRichard Henderson }
310496d6407fSRichard Henderson 
31051cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a)
310696d6407fSRichard Henderson {
31076fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
31086fd0c7bcSRichard Henderson     TCGv_i64 addr;
310996d6407fSRichard Henderson 
311096d6407fSRichard Henderson     nullify_over(ctx);
311196d6407fSRichard Henderson 
31121cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
311317fe594cSRichard Henderson              MMU_DISABLED(ctx));
31141cd012a5SRichard Henderson     val = load_gpr(ctx, a->r);
31151cd012a5SRichard Henderson     if (a->a) {
3116f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3117ad75a51eSRichard Henderson             gen_helper_stby_e_parallel(tcg_env, addr, val);
3118f9f46db4SEmilio G. Cota         } else {
3119ad75a51eSRichard Henderson             gen_helper_stby_e(tcg_env, addr, val);
3120f9f46db4SEmilio G. Cota         }
3121f9f46db4SEmilio G. Cota     } else {
3122f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3123ad75a51eSRichard Henderson             gen_helper_stby_b_parallel(tcg_env, addr, val);
312496d6407fSRichard Henderson         } else {
3125ad75a51eSRichard Henderson             gen_helper_stby_b(tcg_env, addr, val);
312696d6407fSRichard Henderson         }
3127f9f46db4SEmilio G. Cota     }
31281cd012a5SRichard Henderson     if (a->m) {
31296fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~3);
31301cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
313196d6407fSRichard Henderson     }
313296d6407fSRichard Henderson 
313331234768SRichard Henderson     return nullify_end(ctx);
313496d6407fSRichard Henderson }
313596d6407fSRichard Henderson 
313625460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a)
313725460fc5SRichard Henderson {
31386fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
31396fd0c7bcSRichard Henderson     TCGv_i64 addr;
314025460fc5SRichard Henderson 
314125460fc5SRichard Henderson     if (!ctx->is_pa20) {
314225460fc5SRichard Henderson         return false;
314325460fc5SRichard Henderson     }
314425460fc5SRichard Henderson     nullify_over(ctx);
314525460fc5SRichard Henderson 
314625460fc5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
314717fe594cSRichard Henderson              MMU_DISABLED(ctx));
314825460fc5SRichard Henderson     val = load_gpr(ctx, a->r);
314925460fc5SRichard Henderson     if (a->a) {
315025460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
315125460fc5SRichard Henderson             gen_helper_stdby_e_parallel(tcg_env, addr, val);
315225460fc5SRichard Henderson         } else {
315325460fc5SRichard Henderson             gen_helper_stdby_e(tcg_env, addr, val);
315425460fc5SRichard Henderson         }
315525460fc5SRichard Henderson     } else {
315625460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
315725460fc5SRichard Henderson             gen_helper_stdby_b_parallel(tcg_env, addr, val);
315825460fc5SRichard Henderson         } else {
315925460fc5SRichard Henderson             gen_helper_stdby_b(tcg_env, addr, val);
316025460fc5SRichard Henderson         }
316125460fc5SRichard Henderson     }
316225460fc5SRichard Henderson     if (a->m) {
31636fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~7);
316425460fc5SRichard Henderson         save_gpr(ctx, a->b, ofs);
316525460fc5SRichard Henderson     }
316625460fc5SRichard Henderson 
316725460fc5SRichard Henderson     return nullify_end(ctx);
316825460fc5SRichard Henderson }
316925460fc5SRichard Henderson 
31701cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a)
3171d0a851ccSRichard Henderson {
3172d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3173d0a851ccSRichard Henderson 
3174d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3175451d993dSRichard Henderson     ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX;
31761cd012a5SRichard Henderson     trans_ld(ctx, a);
3177d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
317831234768SRichard Henderson     return true;
3179d0a851ccSRichard Henderson }
3180d0a851ccSRichard Henderson 
31811cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a)
3182d0a851ccSRichard Henderson {
3183d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3184d0a851ccSRichard Henderson 
3185d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3186451d993dSRichard Henderson     ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX;
31871cd012a5SRichard Henderson     trans_st(ctx, a);
3188d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
318931234768SRichard Henderson     return true;
3190d0a851ccSRichard Henderson }
319195412a61SRichard Henderson 
31920588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
3193b2167459SRichard Henderson {
31946fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3195b2167459SRichard Henderson 
31966fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tcg_rt, a->i);
31970588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3198b2167459SRichard Henderson     cond_free(&ctx->null_cond);
319931234768SRichard Henderson     return true;
3200b2167459SRichard Henderson }
3201b2167459SRichard Henderson 
32020588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a)
3203b2167459SRichard Henderson {
32046fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
32056fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
3206b2167459SRichard Henderson 
32076fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
3208b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
3209b2167459SRichard Henderson     cond_free(&ctx->null_cond);
321031234768SRichard Henderson     return true;
3211b2167459SRichard Henderson }
3212b2167459SRichard Henderson 
32130588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
3214b2167459SRichard Henderson {
32156fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3216b2167459SRichard Henderson 
3217b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
3218d265360fSRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_i64.  */
32190588e061SRichard Henderson     if (a->b == 0) {
32206fd0c7bcSRichard Henderson         tcg_gen_movi_i64(tcg_rt, a->i);
3221b2167459SRichard Henderson     } else {
32226fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
3223b2167459SRichard Henderson     }
32240588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3225b2167459SRichard Henderson     cond_free(&ctx->null_cond);
322631234768SRichard Henderson     return true;
3227b2167459SRichard Henderson }
3228b2167459SRichard Henderson 
32296fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
3230e9efd4bcSRichard Henderson                     unsigned c, unsigned f, bool d, unsigned n, int disp)
323198cd9ca7SRichard Henderson {
32326fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv;
323398cd9ca7SRichard Henderson     DisasCond cond;
323498cd9ca7SRichard Henderson 
323598cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3236aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
323798cd9ca7SRichard Henderson 
32386fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
323998cd9ca7SRichard Henderson 
3240f764718dSRichard Henderson     sv = NULL;
3241b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
324298cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
324398cd9ca7SRichard Henderson     }
324498cd9ca7SRichard Henderson 
32454fe9533aSRichard Henderson     cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
324601afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
324798cd9ca7SRichard Henderson }
324898cd9ca7SRichard Henderson 
324901afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
325098cd9ca7SRichard Henderson {
3251e9efd4bcSRichard Henderson     if (!ctx->is_pa20 && a->d) {
3252e9efd4bcSRichard Henderson         return false;
3253e9efd4bcSRichard Henderson     }
325401afb7beSRichard Henderson     nullify_over(ctx);
3255e9efd4bcSRichard Henderson     return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
3256e9efd4bcSRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
325701afb7beSRichard Henderson }
325801afb7beSRichard Henderson 
325901afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
326001afb7beSRichard Henderson {
3261c65c3ee1SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3262c65c3ee1SRichard Henderson         return false;
3263c65c3ee1SRichard Henderson     }
326401afb7beSRichard Henderson     nullify_over(ctx);
32656fd0c7bcSRichard Henderson     return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
3266c65c3ee1SRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
326701afb7beSRichard Henderson }
326801afb7beSRichard Henderson 
32696fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
327001afb7beSRichard Henderson                     unsigned c, unsigned f, unsigned n, int disp)
327101afb7beSRichard Henderson {
32726fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv, cb_cond;
327398cd9ca7SRichard Henderson     DisasCond cond;
3274bdcccc17SRichard Henderson     bool d = false;
327598cd9ca7SRichard Henderson 
3276f25d3160SRichard Henderson     /*
3277f25d3160SRichard Henderson      * For hppa64, the ADDB conditions change with PSW.W,
3278f25d3160SRichard Henderson      * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3279f25d3160SRichard Henderson      */
3280f25d3160SRichard Henderson     if (ctx->tb_flags & PSW_W) {
3281f25d3160SRichard Henderson         d = c >= 5;
3282f25d3160SRichard Henderson         if (d) {
3283f25d3160SRichard Henderson             c &= 3;
3284f25d3160SRichard Henderson         }
3285f25d3160SRichard Henderson     }
3286f25d3160SRichard Henderson 
328798cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3288aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
3289f764718dSRichard Henderson     sv = NULL;
3290bdcccc17SRichard Henderson     cb_cond = NULL;
329198cd9ca7SRichard Henderson 
3292b47a4a02SSven Schnelle     if (cond_need_cb(c)) {
3293aac0f603SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
3294aac0f603SRichard Henderson         TCGv_i64 cb_msb = tcg_temp_new_i64();
3295bdcccc17SRichard Henderson 
32966fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cb_msb, 0);
32976fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
32986fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
32996fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
3300bdcccc17SRichard Henderson         cb_cond = get_carry(ctx, d, cb, cb_msb);
3301b47a4a02SSven Schnelle     } else {
33026fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
3303b47a4a02SSven Schnelle     }
3304b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
330598cd9ca7SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
330698cd9ca7SRichard Henderson     }
330798cd9ca7SRichard Henderson 
3308a751eb31SRichard Henderson     cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
330943675d20SSven Schnelle     save_gpr(ctx, r, dest);
331001afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
331198cd9ca7SRichard Henderson }
331298cd9ca7SRichard Henderson 
331301afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a)
331498cd9ca7SRichard Henderson {
331501afb7beSRichard Henderson     nullify_over(ctx);
331601afb7beSRichard Henderson     return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
331701afb7beSRichard Henderson }
331801afb7beSRichard Henderson 
331901afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
332001afb7beSRichard Henderson {
332101afb7beSRichard Henderson     nullify_over(ctx);
33226fd0c7bcSRichard Henderson     return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
332301afb7beSRichard Henderson }
332401afb7beSRichard Henderson 
332501afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
332601afb7beSRichard Henderson {
33276fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
332898cd9ca7SRichard Henderson     DisasCond cond;
332998cd9ca7SRichard Henderson 
333098cd9ca7SRichard Henderson     nullify_over(ctx);
333198cd9ca7SRichard Henderson 
3332aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
333301afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
333484e224d4SRichard Henderson     if (cond_need_ext(ctx, a->d)) {
33351e9ab9fbSRichard Henderson         /* Force shift into [32,63] */
33366fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_sar, 32);
33376fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, tmp);
33381e9ab9fbSRichard Henderson     } else {
33396fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
33401e9ab9fbSRichard Henderson     }
334198cd9ca7SRichard Henderson 
33421e9ab9fbSRichard Henderson     cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
334301afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
334498cd9ca7SRichard Henderson }
334598cd9ca7SRichard Henderson 
334601afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
334798cd9ca7SRichard Henderson {
33486fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
334901afb7beSRichard Henderson     DisasCond cond;
33501e9ab9fbSRichard Henderson     int p;
335101afb7beSRichard Henderson 
335201afb7beSRichard Henderson     nullify_over(ctx);
335301afb7beSRichard Henderson 
3354aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
335501afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
335684e224d4SRichard Henderson     p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0);
33576fd0c7bcSRichard Henderson     tcg_gen_shli_i64(tmp, tcg_r, p);
335801afb7beSRichard Henderson 
335901afb7beSRichard Henderson     cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
336001afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
336101afb7beSRichard Henderson }
336201afb7beSRichard Henderson 
336301afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a)
336401afb7beSRichard Henderson {
33656fd0c7bcSRichard Henderson     TCGv_i64 dest;
336698cd9ca7SRichard Henderson     DisasCond cond;
336798cd9ca7SRichard Henderson 
336898cd9ca7SRichard Henderson     nullify_over(ctx);
336998cd9ca7SRichard Henderson 
337001afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r2);
337101afb7beSRichard Henderson     if (a->r1 == 0) {
33726fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, 0);
337398cd9ca7SRichard Henderson     } else {
33746fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
337598cd9ca7SRichard Henderson     }
337698cd9ca7SRichard Henderson 
33774fa52edfSRichard Henderson     /* All MOVB conditions are 32-bit. */
33784fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
337901afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
338001afb7beSRichard Henderson }
338101afb7beSRichard Henderson 
338201afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
338301afb7beSRichard Henderson {
33846fd0c7bcSRichard Henderson     TCGv_i64 dest;
338501afb7beSRichard Henderson     DisasCond cond;
338601afb7beSRichard Henderson 
338701afb7beSRichard Henderson     nullify_over(ctx);
338801afb7beSRichard Henderson 
338901afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r);
33906fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, a->i);
339101afb7beSRichard Henderson 
33924fa52edfSRichard Henderson     /* All MOVBI conditions are 32-bit. */
33934fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
339401afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
339598cd9ca7SRichard Henderson }
339698cd9ca7SRichard Henderson 
3397f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
33980b1347d2SRichard Henderson {
33996fd0c7bcSRichard Henderson     TCGv_i64 dest, src2;
34000b1347d2SRichard Henderson 
3401f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3402f7b775a9SRichard Henderson         return false;
3403f7b775a9SRichard Henderson     }
340430878590SRichard Henderson     if (a->c) {
34050b1347d2SRichard Henderson         nullify_over(ctx);
34060b1347d2SRichard Henderson     }
34070b1347d2SRichard Henderson 
340830878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
3409f7b775a9SRichard Henderson     src2 = load_gpr(ctx, a->r2);
341030878590SRichard Henderson     if (a->r1 == 0) {
3411f7b775a9SRichard Henderson         if (a->d) {
34126fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src2, cpu_sar);
3413f7b775a9SRichard Henderson         } else {
3414aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
3415f7b775a9SRichard Henderson 
34166fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src2);
34176fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
34186fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, dest, tmp);
3419f7b775a9SRichard Henderson         }
342030878590SRichard Henderson     } else if (a->r1 == a->r2) {
3421f7b775a9SRichard Henderson         if (a->d) {
34226fd0c7bcSRichard Henderson             tcg_gen_rotr_i64(dest, src2, cpu_sar);
3423f7b775a9SRichard Henderson         } else {
34240b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
3425e1d635e8SRichard Henderson             TCGv_i32 s32 = tcg_temp_new_i32();
3426e1d635e8SRichard Henderson 
34276fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, src2);
34286fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(s32, cpu_sar);
3429f7b775a9SRichard Henderson             tcg_gen_andi_i32(s32, s32, 31);
3430e1d635e8SRichard Henderson             tcg_gen_rotr_i32(t32, t32, s32);
34316fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
3432f7b775a9SRichard Henderson         }
3433f7b775a9SRichard Henderson     } else {
34346fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
3435f7b775a9SRichard Henderson 
3436f7b775a9SRichard Henderson         if (a->d) {
3437aac0f603SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
3438aac0f603SRichard Henderson             TCGv_i64 n = tcg_temp_new_i64();
3439f7b775a9SRichard Henderson 
34406fd0c7bcSRichard Henderson             tcg_gen_xori_i64(n, cpu_sar, 63);
3441a01491a2SHelge Deller             tcg_gen_shl_i64(t, src1, n);
34426fd0c7bcSRichard Henderson             tcg_gen_shli_i64(t, t, 1);
3443a01491a2SHelge Deller             tcg_gen_shr_i64(dest, src2, cpu_sar);
34446fd0c7bcSRichard Henderson             tcg_gen_or_i64(dest, dest, t);
34450b1347d2SRichard Henderson         } else {
34460b1347d2SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
34470b1347d2SRichard Henderson             TCGv_i64 s = tcg_temp_new_i64();
34480b1347d2SRichard Henderson 
34496fd0c7bcSRichard Henderson             tcg_gen_concat32_i64(t, src2, src1);
3450967662cdSRichard Henderson             tcg_gen_andi_i64(s, cpu_sar, 31);
3451967662cdSRichard Henderson             tcg_gen_shr_i64(dest, t, s);
34520b1347d2SRichard Henderson         }
3453f7b775a9SRichard Henderson     }
345430878590SRichard Henderson     save_gpr(ctx, a->t, dest);
34550b1347d2SRichard Henderson 
34560b1347d2SRichard Henderson     /* Install the new nullification.  */
34570b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
345830878590SRichard Henderson     if (a->c) {
34594fa52edfSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
34600b1347d2SRichard Henderson     }
346131234768SRichard Henderson     return nullify_end(ctx);
34620b1347d2SRichard Henderson }
34630b1347d2SRichard Henderson 
3464f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
34650b1347d2SRichard Henderson {
3466f7b775a9SRichard Henderson     unsigned width, sa;
34676fd0c7bcSRichard Henderson     TCGv_i64 dest, t2;
34680b1347d2SRichard Henderson 
3469f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3470f7b775a9SRichard Henderson         return false;
3471f7b775a9SRichard Henderson     }
347230878590SRichard Henderson     if (a->c) {
34730b1347d2SRichard Henderson         nullify_over(ctx);
34740b1347d2SRichard Henderson     }
34750b1347d2SRichard Henderson 
3476f7b775a9SRichard Henderson     width = a->d ? 64 : 32;
3477f7b775a9SRichard Henderson     sa = width - 1 - a->cpos;
3478f7b775a9SRichard Henderson 
347930878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
348030878590SRichard Henderson     t2 = load_gpr(ctx, a->r2);
348105bfd4dbSRichard Henderson     if (a->r1 == 0) {
34826fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, t2, sa, width - sa);
3483c53e401eSRichard Henderson     } else if (width == TARGET_LONG_BITS) {
34846fd0c7bcSRichard Henderson         tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
3485f7b775a9SRichard Henderson     } else {
3486f7b775a9SRichard Henderson         assert(!a->d);
3487f7b775a9SRichard Henderson         if (a->r1 == a->r2) {
34880b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
34896fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, t2);
34900b1347d2SRichard Henderson             tcg_gen_rotri_i32(t32, t32, sa);
34916fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
34920b1347d2SRichard Henderson         } else {
3493967662cdSRichard Henderson             tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]);
3494967662cdSRichard Henderson             tcg_gen_extract_i64(dest, dest, sa, 32);
34950b1347d2SRichard Henderson         }
3496f7b775a9SRichard Henderson     }
349730878590SRichard Henderson     save_gpr(ctx, a->t, dest);
34980b1347d2SRichard Henderson 
34990b1347d2SRichard Henderson     /* Install the new nullification.  */
35000b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
350130878590SRichard Henderson     if (a->c) {
35024fa52edfSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
35030b1347d2SRichard Henderson     }
350431234768SRichard Henderson     return nullify_end(ctx);
35050b1347d2SRichard Henderson }
35060b1347d2SRichard Henderson 
3507bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
35080b1347d2SRichard Henderson {
3509bd792da3SRichard Henderson     unsigned widthm1 = a->d ? 63 : 31;
35106fd0c7bcSRichard Henderson     TCGv_i64 dest, src, tmp;
35110b1347d2SRichard Henderson 
3512bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3513bd792da3SRichard Henderson         return false;
3514bd792da3SRichard Henderson     }
351530878590SRichard Henderson     if (a->c) {
35160b1347d2SRichard Henderson         nullify_over(ctx);
35170b1347d2SRichard Henderson     }
35180b1347d2SRichard Henderson 
351930878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
352030878590SRichard Henderson     src = load_gpr(ctx, a->r);
3521aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
35220b1347d2SRichard Henderson 
35230b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
35246fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
35256fd0c7bcSRichard Henderson     tcg_gen_xori_i64(tmp, tmp, widthm1);
3526d781cb77SRichard Henderson 
352730878590SRichard Henderson     if (a->se) {
3528bd792da3SRichard Henderson         if (!a->d) {
35296fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(dest, src);
3530bd792da3SRichard Henderson             src = dest;
3531bd792da3SRichard Henderson         }
35326fd0c7bcSRichard Henderson         tcg_gen_sar_i64(dest, src, tmp);
35336fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, dest, 0, a->len);
35340b1347d2SRichard Henderson     } else {
3535bd792da3SRichard Henderson         if (!a->d) {
35366fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src);
3537bd792da3SRichard Henderson             src = dest;
3538bd792da3SRichard Henderson         }
35396fd0c7bcSRichard Henderson         tcg_gen_shr_i64(dest, src, tmp);
35406fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, dest, 0, a->len);
35410b1347d2SRichard Henderson     }
354230878590SRichard Henderson     save_gpr(ctx, a->t, dest);
35430b1347d2SRichard Henderson 
35440b1347d2SRichard Henderson     /* Install the new nullification.  */
35450b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
354630878590SRichard Henderson     if (a->c) {
3547bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
35480b1347d2SRichard Henderson     }
354931234768SRichard Henderson     return nullify_end(ctx);
35500b1347d2SRichard Henderson }
35510b1347d2SRichard Henderson 
3552bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
35530b1347d2SRichard Henderson {
3554bd792da3SRichard Henderson     unsigned len, cpos, width;
35556fd0c7bcSRichard Henderson     TCGv_i64 dest, src;
35560b1347d2SRichard Henderson 
3557bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3558bd792da3SRichard Henderson         return false;
3559bd792da3SRichard Henderson     }
356030878590SRichard Henderson     if (a->c) {
35610b1347d2SRichard Henderson         nullify_over(ctx);
35620b1347d2SRichard Henderson     }
35630b1347d2SRichard Henderson 
3564bd792da3SRichard Henderson     len = a->len;
3565bd792da3SRichard Henderson     width = a->d ? 64 : 32;
3566bd792da3SRichard Henderson     cpos = width - 1 - a->pos;
3567bd792da3SRichard Henderson     if (cpos + len > width) {
3568bd792da3SRichard Henderson         len = width - cpos;
3569bd792da3SRichard Henderson     }
3570bd792da3SRichard Henderson 
357130878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
357230878590SRichard Henderson     src = load_gpr(ctx, a->r);
357330878590SRichard Henderson     if (a->se) {
35746fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, src, cpos, len);
35750b1347d2SRichard Henderson     } else {
35766fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, src, cpos, len);
35770b1347d2SRichard Henderson     }
357830878590SRichard Henderson     save_gpr(ctx, a->t, dest);
35790b1347d2SRichard Henderson 
35800b1347d2SRichard Henderson     /* Install the new nullification.  */
35810b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
358230878590SRichard Henderson     if (a->c) {
3583bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
35840b1347d2SRichard Henderson     }
358531234768SRichard Henderson     return nullify_end(ctx);
35860b1347d2SRichard Henderson }
35870b1347d2SRichard Henderson 
358872ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
35890b1347d2SRichard Henderson {
359072ae4f2bSRichard Henderson     unsigned len, width;
3591c53e401eSRichard Henderson     uint64_t mask0, mask1;
35926fd0c7bcSRichard Henderson     TCGv_i64 dest;
35930b1347d2SRichard Henderson 
359472ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
359572ae4f2bSRichard Henderson         return false;
359672ae4f2bSRichard Henderson     }
359730878590SRichard Henderson     if (a->c) {
35980b1347d2SRichard Henderson         nullify_over(ctx);
35990b1347d2SRichard Henderson     }
360072ae4f2bSRichard Henderson 
360172ae4f2bSRichard Henderson     len = a->len;
360272ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
360372ae4f2bSRichard Henderson     if (a->cpos + len > width) {
360472ae4f2bSRichard Henderson         len = width - a->cpos;
36050b1347d2SRichard Henderson     }
36060b1347d2SRichard Henderson 
360730878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
360830878590SRichard Henderson     mask0 = deposit64(0, a->cpos, len, a->i);
360930878590SRichard Henderson     mask1 = deposit64(-1, a->cpos, len, a->i);
36100b1347d2SRichard Henderson 
361130878590SRichard Henderson     if (a->nz) {
36126fd0c7bcSRichard Henderson         TCGv_i64 src = load_gpr(ctx, a->t);
36136fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, src, mask1);
36146fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, mask0);
36150b1347d2SRichard Henderson     } else {
36166fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, mask0);
36170b1347d2SRichard Henderson     }
361830878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36190b1347d2SRichard Henderson 
36200b1347d2SRichard Henderson     /* Install the new nullification.  */
36210b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
362230878590SRichard Henderson     if (a->c) {
362372ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
36240b1347d2SRichard Henderson     }
362531234768SRichard Henderson     return nullify_end(ctx);
36260b1347d2SRichard Henderson }
36270b1347d2SRichard Henderson 
362872ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
36290b1347d2SRichard Henderson {
363030878590SRichard Henderson     unsigned rs = a->nz ? a->t : 0;
363172ae4f2bSRichard Henderson     unsigned len, width;
36326fd0c7bcSRichard Henderson     TCGv_i64 dest, val;
36330b1347d2SRichard Henderson 
363472ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
363572ae4f2bSRichard Henderson         return false;
363672ae4f2bSRichard Henderson     }
363730878590SRichard Henderson     if (a->c) {
36380b1347d2SRichard Henderson         nullify_over(ctx);
36390b1347d2SRichard Henderson     }
364072ae4f2bSRichard Henderson 
364172ae4f2bSRichard Henderson     len = a->len;
364272ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
364372ae4f2bSRichard Henderson     if (a->cpos + len > width) {
364472ae4f2bSRichard Henderson         len = width - a->cpos;
36450b1347d2SRichard Henderson     }
36460b1347d2SRichard Henderson 
364730878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
364830878590SRichard Henderson     val = load_gpr(ctx, a->r);
36490b1347d2SRichard Henderson     if (rs == 0) {
36506fd0c7bcSRichard Henderson         tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
36510b1347d2SRichard Henderson     } else {
36526fd0c7bcSRichard Henderson         tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
36530b1347d2SRichard Henderson     }
365430878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36550b1347d2SRichard Henderson 
36560b1347d2SRichard Henderson     /* Install the new nullification.  */
36570b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
365830878590SRichard Henderson     if (a->c) {
365972ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
36600b1347d2SRichard Henderson     }
366131234768SRichard Henderson     return nullify_end(ctx);
36620b1347d2SRichard Henderson }
36630b1347d2SRichard Henderson 
366472ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
36656fd0c7bcSRichard Henderson                        bool d, bool nz, unsigned len, TCGv_i64 val)
36660b1347d2SRichard Henderson {
36670b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
366872ae4f2bSRichard Henderson     unsigned widthm1 = d ? 63 : 31;
36696fd0c7bcSRichard Henderson     TCGv_i64 mask, tmp, shift, dest;
3670c53e401eSRichard Henderson     uint64_t msb = 1ULL << (len - 1);
36710b1347d2SRichard Henderson 
36720b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
3673aac0f603SRichard Henderson     shift = tcg_temp_new_i64();
3674aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
36750b1347d2SRichard Henderson 
36760b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
36776fd0c7bcSRichard Henderson     tcg_gen_andi_i64(shift, cpu_sar, widthm1);
36786fd0c7bcSRichard Henderson     tcg_gen_xori_i64(shift, shift, widthm1);
36790b1347d2SRichard Henderson 
3680aac0f603SRichard Henderson     mask = tcg_temp_new_i64();
36816fd0c7bcSRichard Henderson     tcg_gen_movi_i64(mask, msb + (msb - 1));
36826fd0c7bcSRichard Henderson     tcg_gen_and_i64(tmp, val, mask);
36830b1347d2SRichard Henderson     if (rs) {
36846fd0c7bcSRichard Henderson         tcg_gen_shl_i64(mask, mask, shift);
36856fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tmp, shift);
36866fd0c7bcSRichard Henderson         tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
36876fd0c7bcSRichard Henderson         tcg_gen_or_i64(dest, dest, tmp);
36880b1347d2SRichard Henderson     } else {
36896fd0c7bcSRichard Henderson         tcg_gen_shl_i64(dest, tmp, shift);
36900b1347d2SRichard Henderson     }
36910b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
36920b1347d2SRichard Henderson 
36930b1347d2SRichard Henderson     /* Install the new nullification.  */
36940b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
36950b1347d2SRichard Henderson     if (c) {
369672ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, c, d, dest);
36970b1347d2SRichard Henderson     }
369831234768SRichard Henderson     return nullify_end(ctx);
36990b1347d2SRichard Henderson }
37000b1347d2SRichard Henderson 
370172ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
370230878590SRichard Henderson {
370372ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
370472ae4f2bSRichard Henderson         return false;
370572ae4f2bSRichard Henderson     }
3706a6deecceSSven Schnelle     if (a->c) {
3707a6deecceSSven Schnelle         nullify_over(ctx);
3708a6deecceSSven Schnelle     }
370972ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
371072ae4f2bSRichard Henderson                       load_gpr(ctx, a->r));
371130878590SRichard Henderson }
371230878590SRichard Henderson 
371372ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
371430878590SRichard Henderson {
371572ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
371672ae4f2bSRichard Henderson         return false;
371772ae4f2bSRichard Henderson     }
3718a6deecceSSven Schnelle     if (a->c) {
3719a6deecceSSven Schnelle         nullify_over(ctx);
3720a6deecceSSven Schnelle     }
372172ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
37226fd0c7bcSRichard Henderson                       tcg_constant_i64(a->i));
372330878590SRichard Henderson }
37240b1347d2SRichard Henderson 
37258340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a)
372698cd9ca7SRichard Henderson {
37276fd0c7bcSRichard Henderson     TCGv_i64 tmp;
372898cd9ca7SRichard Henderson 
3729c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
373098cd9ca7SRichard Henderson     /* ??? It seems like there should be a good way of using
373198cd9ca7SRichard Henderson        "be disp(sr2, r0)", the canonical gateway entry mechanism
373298cd9ca7SRichard Henderson        to our advantage.  But that appears to be inconvenient to
373398cd9ca7SRichard Henderson        manage along side branch delay slots.  Therefore we handle
373498cd9ca7SRichard Henderson        entry into the gateway page via absolute address.  */
373598cd9ca7SRichard Henderson     /* Since we don't implement spaces, just branch.  Do notice the special
373698cd9ca7SRichard Henderson        case of "be disp(*,r0)" using a direct branch to disp, so that we can
373798cd9ca7SRichard Henderson        goto_tb to the TB containing the syscall.  */
37388340f534SRichard Henderson     if (a->b == 0) {
37398340f534SRichard Henderson         return do_dbranch(ctx, a->disp, a->l, a->n);
374098cd9ca7SRichard Henderson     }
3741c301f34eSRichard Henderson #else
3742c301f34eSRichard Henderson     nullify_over(ctx);
3743660eefe1SRichard Henderson #endif
3744660eefe1SRichard Henderson 
3745aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
37466fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp);
3747660eefe1SRichard Henderson     tmp = do_ibranch_priv(ctx, tmp);
3748c301f34eSRichard Henderson 
3749c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
37508340f534SRichard Henderson     return do_ibranch(ctx, tmp, a->l, a->n);
3751c301f34eSRichard Henderson #else
3752c301f34eSRichard Henderson     TCGv_i64 new_spc = tcg_temp_new_i64();
3753c301f34eSRichard Henderson 
37548340f534SRichard Henderson     load_spr(ctx, new_spc, a->sp);
37558340f534SRichard Henderson     if (a->l) {
3756741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
3757c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f);
3758c301f34eSRichard Henderson     }
37598340f534SRichard Henderson     if (a->n && use_nullify_skip(ctx)) {
3760a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
37616fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, 4);
3762a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3763c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, new_spc);
3764c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f);
3765c301f34eSRichard Henderson     } else {
3766741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3767c301f34eSRichard Henderson         if (ctx->iaoq_b == -1) {
3768c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3769c301f34eSRichard Henderson         }
3770a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3771c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, new_spc);
37728340f534SRichard Henderson         nullify_set(ctx, a->n);
3773c301f34eSRichard Henderson     }
3774c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
377531234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
377631234768SRichard Henderson     return nullify_end(ctx);
3777c301f34eSRichard Henderson #endif
377898cd9ca7SRichard Henderson }
377998cd9ca7SRichard Henderson 
37808340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a)
378198cd9ca7SRichard Henderson {
37828340f534SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n);
378398cd9ca7SRichard Henderson }
378498cd9ca7SRichard Henderson 
37858340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
378643e05652SRichard Henderson {
3787c53e401eSRichard Henderson     uint64_t dest = iaoq_dest(ctx, a->disp);
378843e05652SRichard Henderson 
37896e5f5300SSven Schnelle     nullify_over(ctx);
37906e5f5300SSven Schnelle 
379143e05652SRichard Henderson     /* Make sure the caller hasn't done something weird with the queue.
379243e05652SRichard Henderson      * ??? This is not quite the same as the PSW[B] bit, which would be
379343e05652SRichard Henderson      * expensive to track.  Real hardware will trap for
379443e05652SRichard Henderson      *    b  gateway
379543e05652SRichard Henderson      *    b  gateway+4  (in delay slot of first branch)
379643e05652SRichard Henderson      * However, checking for a non-sequential instruction queue *will*
379743e05652SRichard Henderson      * diagnose the security hole
379843e05652SRichard Henderson      *    b  gateway
379943e05652SRichard Henderson      *    b  evil
380043e05652SRichard Henderson      * in which instructions at evil would run with increased privs.
380143e05652SRichard Henderson      */
380243e05652SRichard Henderson     if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) {
380343e05652SRichard Henderson         return gen_illegal(ctx);
380443e05652SRichard Henderson     }
380543e05652SRichard Henderson 
380643e05652SRichard Henderson #ifndef CONFIG_USER_ONLY
380743e05652SRichard Henderson     if (ctx->tb_flags & PSW_C) {
3808b77af26eSRichard Henderson         CPUHPPAState *env = cpu_env(ctx->cs);
380943e05652SRichard Henderson         int type = hppa_artype_for_page(env, ctx->base.pc_next);
381043e05652SRichard Henderson         /* If we could not find a TLB entry, then we need to generate an
381143e05652SRichard Henderson            ITLB miss exception so the kernel will provide it.
381243e05652SRichard Henderson            The resulting TLB fill operation will invalidate this TB and
381343e05652SRichard Henderson            we will re-translate, at which point we *will* be able to find
381443e05652SRichard Henderson            the TLB entry and determine if this is in fact a gateway page.  */
381543e05652SRichard Henderson         if (type < 0) {
381631234768SRichard Henderson             gen_excp(ctx, EXCP_ITLB_MISS);
381731234768SRichard Henderson             return true;
381843e05652SRichard Henderson         }
381943e05652SRichard Henderson         /* No change for non-gateway pages or for priv decrease.  */
382043e05652SRichard Henderson         if (type >= 4 && type - 4 < ctx->privilege) {
382143e05652SRichard Henderson             dest = deposit32(dest, 0, 2, type - 4);
382243e05652SRichard Henderson         }
382343e05652SRichard Henderson     } else {
382443e05652SRichard Henderson         dest &= -4;  /* priv = 0 */
382543e05652SRichard Henderson     }
382643e05652SRichard Henderson #endif
382743e05652SRichard Henderson 
38286e5f5300SSven Schnelle     if (a->l) {
38296fd0c7bcSRichard Henderson         TCGv_i64 tmp = dest_gpr(ctx, a->l);
38306e5f5300SSven Schnelle         if (ctx->privilege < 3) {
38316fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, tmp, -4);
38326e5f5300SSven Schnelle         }
38336fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
38346e5f5300SSven Schnelle         save_gpr(ctx, a->l, tmp);
38356e5f5300SSven Schnelle     }
38366e5f5300SSven Schnelle 
38376e5f5300SSven Schnelle     return do_dbranch(ctx, dest, 0, a->n);
383843e05652SRichard Henderson }
383943e05652SRichard Henderson 
38408340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a)
384198cd9ca7SRichard Henderson {
3842b35aec85SRichard Henderson     if (a->x) {
3843aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
38446fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3);
38456fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8);
3846660eefe1SRichard Henderson         /* The computation here never changes privilege level.  */
38478340f534SRichard Henderson         return do_ibranch(ctx, tmp, a->l, a->n);
3848b35aec85SRichard Henderson     } else {
3849b35aec85SRichard Henderson         /* BLR R0,RX is a good way to load PC+8 into RX.  */
3850b35aec85SRichard Henderson         return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n);
3851b35aec85SRichard Henderson     }
385298cd9ca7SRichard Henderson }
385398cd9ca7SRichard Henderson 
38548340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a)
385598cd9ca7SRichard Henderson {
38566fd0c7bcSRichard Henderson     TCGv_i64 dest;
385798cd9ca7SRichard Henderson 
38588340f534SRichard Henderson     if (a->x == 0) {
38598340f534SRichard Henderson         dest = load_gpr(ctx, a->b);
386098cd9ca7SRichard Henderson     } else {
3861aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
38626fd0c7bcSRichard Henderson         tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
38636fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
386498cd9ca7SRichard Henderson     }
3865660eefe1SRichard Henderson     dest = do_ibranch_priv(ctx, dest);
38668340f534SRichard Henderson     return do_ibranch(ctx, dest, 0, a->n);
386798cd9ca7SRichard Henderson }
386898cd9ca7SRichard Henderson 
38698340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a)
387098cd9ca7SRichard Henderson {
38716fd0c7bcSRichard Henderson     TCGv_i64 dest;
387298cd9ca7SRichard Henderson 
3873c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
38748340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
38758340f534SRichard Henderson     return do_ibranch(ctx, dest, a->l, a->n);
3876c301f34eSRichard Henderson #else
3877c301f34eSRichard Henderson     nullify_over(ctx);
38788340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
3879c301f34eSRichard Henderson 
3880741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3881c301f34eSRichard Henderson     if (ctx->iaoq_b == -1) {
3882c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3883c301f34eSRichard Henderson     }
3884741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest);
3885c301f34eSRichard Henderson     tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
38868340f534SRichard Henderson     if (a->l) {
3887741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var);
3888c301f34eSRichard Henderson     }
38898340f534SRichard Henderson     nullify_set(ctx, a->n);
3890c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
389131234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
389231234768SRichard Henderson     return nullify_end(ctx);
3893c301f34eSRichard Henderson #endif
389498cd9ca7SRichard Henderson }
389598cd9ca7SRichard Henderson 
3896a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
3897a8966ba7SRichard Henderson {
3898a8966ba7SRichard Henderson     /* All branch target stack instructions implement as nop. */
3899a8966ba7SRichard Henderson     return ctx->is_pa20;
3900a8966ba7SRichard Henderson }
3901a8966ba7SRichard Henderson 
39021ca74648SRichard Henderson /*
39031ca74648SRichard Henderson  * Float class 0
39041ca74648SRichard Henderson  */
3905ebe9383cSRichard Henderson 
39061ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3907ebe9383cSRichard Henderson {
3908ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
3909ebe9383cSRichard Henderson }
3910ebe9383cSRichard Henderson 
391159f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
391259f8c04bSHelge Deller {
3913a300dad3SRichard Henderson     uint64_t ret;
3914a300dad3SRichard Henderson 
3915c53e401eSRichard Henderson     if (ctx->is_pa20) {
3916a300dad3SRichard Henderson         ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
3917a300dad3SRichard Henderson     } else {
3918a300dad3SRichard Henderson         ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
3919a300dad3SRichard Henderson     }
3920a300dad3SRichard Henderson 
392159f8c04bSHelge Deller     nullify_over(ctx);
3922a300dad3SRichard Henderson     save_frd(0, tcg_constant_i64(ret));
392359f8c04bSHelge Deller     return nullify_end(ctx);
392459f8c04bSHelge Deller }
392559f8c04bSHelge Deller 
39261ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a)
39271ca74648SRichard Henderson {
39281ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f);
39291ca74648SRichard Henderson }
39301ca74648SRichard Henderson 
3931ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3932ebe9383cSRichard Henderson {
3933ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
3934ebe9383cSRichard Henderson }
3935ebe9383cSRichard Henderson 
39361ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a)
39371ca74648SRichard Henderson {
39381ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d);
39391ca74648SRichard Henderson }
39401ca74648SRichard Henderson 
39411ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3942ebe9383cSRichard Henderson {
3943ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
3944ebe9383cSRichard Henderson }
3945ebe9383cSRichard Henderson 
39461ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a)
39471ca74648SRichard Henderson {
39481ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fabs_f);
39491ca74648SRichard Henderson }
39501ca74648SRichard Henderson 
3951ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3952ebe9383cSRichard Henderson {
3953ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
3954ebe9383cSRichard Henderson }
3955ebe9383cSRichard Henderson 
39561ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a)
39571ca74648SRichard Henderson {
39581ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fabs_d);
39591ca74648SRichard Henderson }
39601ca74648SRichard Henderson 
39611ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a)
39621ca74648SRichard Henderson {
39631ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s);
39641ca74648SRichard Henderson }
39651ca74648SRichard Henderson 
39661ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a)
39671ca74648SRichard Henderson {
39681ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d);
39691ca74648SRichard Henderson }
39701ca74648SRichard Henderson 
39711ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a)
39721ca74648SRichard Henderson {
39731ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s);
39741ca74648SRichard Henderson }
39751ca74648SRichard Henderson 
39761ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a)
39771ca74648SRichard Henderson {
39781ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d);
39791ca74648SRichard Henderson }
39801ca74648SRichard Henderson 
39811ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3982ebe9383cSRichard Henderson {
3983ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
3984ebe9383cSRichard Henderson }
3985ebe9383cSRichard Henderson 
39861ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a)
39871ca74648SRichard Henderson {
39881ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fneg_f);
39891ca74648SRichard Henderson }
39901ca74648SRichard Henderson 
3991ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3992ebe9383cSRichard Henderson {
3993ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
3994ebe9383cSRichard Henderson }
3995ebe9383cSRichard Henderson 
39961ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a)
39971ca74648SRichard Henderson {
39981ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fneg_d);
39991ca74648SRichard Henderson }
40001ca74648SRichard Henderson 
40011ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4002ebe9383cSRichard Henderson {
4003ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
4004ebe9383cSRichard Henderson }
4005ebe9383cSRichard Henderson 
40061ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a)
40071ca74648SRichard Henderson {
40081ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f);
40091ca74648SRichard Henderson }
40101ca74648SRichard Henderson 
4011ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4012ebe9383cSRichard Henderson {
4013ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
4014ebe9383cSRichard Henderson }
4015ebe9383cSRichard Henderson 
40161ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a)
40171ca74648SRichard Henderson {
40181ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d);
40191ca74648SRichard Henderson }
40201ca74648SRichard Henderson 
40211ca74648SRichard Henderson /*
40221ca74648SRichard Henderson  * Float class 1
40231ca74648SRichard Henderson  */
40241ca74648SRichard Henderson 
40251ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a)
40261ca74648SRichard Henderson {
40271ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s);
40281ca74648SRichard Henderson }
40291ca74648SRichard Henderson 
40301ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a)
40311ca74648SRichard Henderson {
40321ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d);
40331ca74648SRichard Henderson }
40341ca74648SRichard Henderson 
40351ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a)
40361ca74648SRichard Henderson {
40371ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s);
40381ca74648SRichard Henderson }
40391ca74648SRichard Henderson 
40401ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a)
40411ca74648SRichard Henderson {
40421ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s);
40431ca74648SRichard Henderson }
40441ca74648SRichard Henderson 
40451ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a)
40461ca74648SRichard Henderson {
40471ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d);
40481ca74648SRichard Henderson }
40491ca74648SRichard Henderson 
40501ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a)
40511ca74648SRichard Henderson {
40521ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d);
40531ca74648SRichard Henderson }
40541ca74648SRichard Henderson 
40551ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a)
40561ca74648SRichard Henderson {
40571ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w);
40581ca74648SRichard Henderson }
40591ca74648SRichard Henderson 
40601ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a)
40611ca74648SRichard Henderson {
40621ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w);
40631ca74648SRichard Henderson }
40641ca74648SRichard Henderson 
40651ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a)
40661ca74648SRichard Henderson {
40671ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw);
40681ca74648SRichard Henderson }
40691ca74648SRichard Henderson 
40701ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a)
40711ca74648SRichard Henderson {
40721ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw);
40731ca74648SRichard Henderson }
40741ca74648SRichard Henderson 
40751ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a)
40761ca74648SRichard Henderson {
40771ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w);
40781ca74648SRichard Henderson }
40791ca74648SRichard Henderson 
40801ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a)
40811ca74648SRichard Henderson {
40821ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w);
40831ca74648SRichard Henderson }
40841ca74648SRichard Henderson 
40851ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a)
40861ca74648SRichard Henderson {
40871ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw);
40881ca74648SRichard Henderson }
40891ca74648SRichard Henderson 
40901ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a)
40911ca74648SRichard Henderson {
40921ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw);
40931ca74648SRichard Henderson }
40941ca74648SRichard Henderson 
40951ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a)
40961ca74648SRichard Henderson {
40971ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s);
40981ca74648SRichard Henderson }
40991ca74648SRichard Henderson 
41001ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a)
41011ca74648SRichard Henderson {
41021ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s);
41031ca74648SRichard Henderson }
41041ca74648SRichard Henderson 
41051ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a)
41061ca74648SRichard Henderson {
41071ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d);
41081ca74648SRichard Henderson }
41091ca74648SRichard Henderson 
41101ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a)
41111ca74648SRichard Henderson {
41121ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d);
41131ca74648SRichard Henderson }
41141ca74648SRichard Henderson 
41151ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a)
41161ca74648SRichard Henderson {
41171ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw);
41181ca74648SRichard Henderson }
41191ca74648SRichard Henderson 
41201ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a)
41211ca74648SRichard Henderson {
41221ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw);
41231ca74648SRichard Henderson }
41241ca74648SRichard Henderson 
41251ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a)
41261ca74648SRichard Henderson {
41271ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw);
41281ca74648SRichard Henderson }
41291ca74648SRichard Henderson 
41301ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a)
41311ca74648SRichard Henderson {
41321ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw);
41331ca74648SRichard Henderson }
41341ca74648SRichard Henderson 
41351ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a)
41361ca74648SRichard Henderson {
41371ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw);
41381ca74648SRichard Henderson }
41391ca74648SRichard Henderson 
41401ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a)
41411ca74648SRichard Henderson {
41421ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw);
41431ca74648SRichard Henderson }
41441ca74648SRichard Henderson 
41451ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a)
41461ca74648SRichard Henderson {
41471ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw);
41481ca74648SRichard Henderson }
41491ca74648SRichard Henderson 
41501ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a)
41511ca74648SRichard Henderson {
41521ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw);
41531ca74648SRichard Henderson }
41541ca74648SRichard Henderson 
41551ca74648SRichard Henderson /*
41561ca74648SRichard Henderson  * Float class 2
41571ca74648SRichard Henderson  */
41581ca74648SRichard Henderson 
41591ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a)
4160ebe9383cSRichard Henderson {
4161ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
4162ebe9383cSRichard Henderson 
4163ebe9383cSRichard Henderson     nullify_over(ctx);
4164ebe9383cSRichard Henderson 
41651ca74648SRichard Henderson     ta = load_frw0_i32(a->r1);
41661ca74648SRichard Henderson     tb = load_frw0_i32(a->r2);
416729dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
416829dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4169ebe9383cSRichard Henderson 
4170ad75a51eSRichard Henderson     gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc);
4171ebe9383cSRichard Henderson 
41721ca74648SRichard Henderson     return nullify_end(ctx);
4173ebe9383cSRichard Henderson }
4174ebe9383cSRichard Henderson 
41751ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
4176ebe9383cSRichard Henderson {
4177ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
4178ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
4179ebe9383cSRichard Henderson 
4180ebe9383cSRichard Henderson     nullify_over(ctx);
4181ebe9383cSRichard Henderson 
41821ca74648SRichard Henderson     ta = load_frd0(a->r1);
41831ca74648SRichard Henderson     tb = load_frd0(a->r2);
418429dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
418529dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4186ebe9383cSRichard Henderson 
4187ad75a51eSRichard Henderson     gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc);
4188ebe9383cSRichard Henderson 
418931234768SRichard Henderson     return nullify_end(ctx);
4190ebe9383cSRichard Henderson }
4191ebe9383cSRichard Henderson 
41921ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
4193ebe9383cSRichard Henderson {
41946fd0c7bcSRichard Henderson     TCGv_i64 t;
4195ebe9383cSRichard Henderson 
4196ebe9383cSRichard Henderson     nullify_over(ctx);
4197ebe9383cSRichard Henderson 
4198aac0f603SRichard Henderson     t = tcg_temp_new_i64();
41996fd0c7bcSRichard Henderson     tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
4200ebe9383cSRichard Henderson 
42011ca74648SRichard Henderson     if (a->y == 1) {
4202ebe9383cSRichard Henderson         int mask;
4203ebe9383cSRichard Henderson         bool inv = false;
4204ebe9383cSRichard Henderson 
42051ca74648SRichard Henderson         switch (a->c) {
4206ebe9383cSRichard Henderson         case 0: /* simple */
42076fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, 0x4000000);
4208ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_NE, t);
4209ebe9383cSRichard Henderson             goto done;
4210ebe9383cSRichard Henderson         case 2: /* rej */
4211ebe9383cSRichard Henderson             inv = true;
4212ebe9383cSRichard Henderson             /* fallthru */
4213ebe9383cSRichard Henderson         case 1: /* acc */
4214ebe9383cSRichard Henderson             mask = 0x43ff800;
4215ebe9383cSRichard Henderson             break;
4216ebe9383cSRichard Henderson         case 6: /* rej8 */
4217ebe9383cSRichard Henderson             inv = true;
4218ebe9383cSRichard Henderson             /* fallthru */
4219ebe9383cSRichard Henderson         case 5: /* acc8 */
4220ebe9383cSRichard Henderson             mask = 0x43f8000;
4221ebe9383cSRichard Henderson             break;
4222ebe9383cSRichard Henderson         case 9: /* acc6 */
4223ebe9383cSRichard Henderson             mask = 0x43e0000;
4224ebe9383cSRichard Henderson             break;
4225ebe9383cSRichard Henderson         case 13: /* acc4 */
4226ebe9383cSRichard Henderson             mask = 0x4380000;
4227ebe9383cSRichard Henderson             break;
4228ebe9383cSRichard Henderson         case 17: /* acc2 */
4229ebe9383cSRichard Henderson             mask = 0x4200000;
4230ebe9383cSRichard Henderson             break;
4231ebe9383cSRichard Henderson         default:
42321ca74648SRichard Henderson             gen_illegal(ctx);
42331ca74648SRichard Henderson             return true;
4234ebe9383cSRichard Henderson         }
4235ebe9383cSRichard Henderson         if (inv) {
42366fd0c7bcSRichard Henderson             TCGv_i64 c = tcg_constant_i64(mask);
42376fd0c7bcSRichard Henderson             tcg_gen_or_i64(t, t, c);
4238ebe9383cSRichard Henderson             ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
4239ebe9383cSRichard Henderson         } else {
42406fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, mask);
4241ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
4242ebe9383cSRichard Henderson         }
42431ca74648SRichard Henderson     } else {
42441ca74648SRichard Henderson         unsigned cbit = (a->y ^ 1) - 1;
42451ca74648SRichard Henderson 
42466fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, t, 21 - cbit, 1);
42471ca74648SRichard Henderson         ctx->null_cond = cond_make_0(TCG_COND_NE, t);
42481ca74648SRichard Henderson     }
42491ca74648SRichard Henderson 
4250ebe9383cSRichard Henderson  done:
425131234768SRichard Henderson     return nullify_end(ctx);
4252ebe9383cSRichard Henderson }
4253ebe9383cSRichard Henderson 
42541ca74648SRichard Henderson /*
42551ca74648SRichard Henderson  * Float class 2
42561ca74648SRichard Henderson  */
42571ca74648SRichard Henderson 
42581ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a)
4259ebe9383cSRichard Henderson {
42601ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s);
42611ca74648SRichard Henderson }
42621ca74648SRichard Henderson 
42631ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a)
42641ca74648SRichard Henderson {
42651ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d);
42661ca74648SRichard Henderson }
42671ca74648SRichard Henderson 
42681ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a)
42691ca74648SRichard Henderson {
42701ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s);
42711ca74648SRichard Henderson }
42721ca74648SRichard Henderson 
42731ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a)
42741ca74648SRichard Henderson {
42751ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d);
42761ca74648SRichard Henderson }
42771ca74648SRichard Henderson 
42781ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a)
42791ca74648SRichard Henderson {
42801ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s);
42811ca74648SRichard Henderson }
42821ca74648SRichard Henderson 
42831ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a)
42841ca74648SRichard Henderson {
42851ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d);
42861ca74648SRichard Henderson }
42871ca74648SRichard Henderson 
42881ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a)
42891ca74648SRichard Henderson {
42901ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s);
42911ca74648SRichard Henderson }
42921ca74648SRichard Henderson 
42931ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a)
42941ca74648SRichard Henderson {
42951ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d);
42961ca74648SRichard Henderson }
42971ca74648SRichard Henderson 
42981ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a)
42991ca74648SRichard Henderson {
43001ca74648SRichard Henderson     TCGv_i64 x, y;
4301ebe9383cSRichard Henderson 
4302ebe9383cSRichard Henderson     nullify_over(ctx);
4303ebe9383cSRichard Henderson 
43041ca74648SRichard Henderson     x = load_frw0_i64(a->r1);
43051ca74648SRichard Henderson     y = load_frw0_i64(a->r2);
43061ca74648SRichard Henderson     tcg_gen_mul_i64(x, x, y);
43071ca74648SRichard Henderson     save_frd(a->t, x);
4308ebe9383cSRichard Henderson 
430931234768SRichard Henderson     return nullify_end(ctx);
4310ebe9383cSRichard Henderson }
4311ebe9383cSRichard Henderson 
4312ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
4313ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
4314ebe9383cSRichard Henderson {
4315ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
4316ebe9383cSRichard Henderson }
4317ebe9383cSRichard Henderson 
4318b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4319ebe9383cSRichard Henderson {
4320b1e2af57SRichard Henderson     int tm = fmpyadd_s_reg(a->tm);
4321b1e2af57SRichard Henderson     int ra = fmpyadd_s_reg(a->ra);
4322b1e2af57SRichard Henderson     int ta = fmpyadd_s_reg(a->ta);
4323b1e2af57SRichard Henderson     int rm2 = fmpyadd_s_reg(a->rm2);
4324b1e2af57SRichard Henderson     int rm1 = fmpyadd_s_reg(a->rm1);
4325ebe9383cSRichard Henderson 
4326ebe9383cSRichard Henderson     nullify_over(ctx);
4327ebe9383cSRichard Henderson 
4328ebe9383cSRichard Henderson     do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4329ebe9383cSRichard Henderson     do_fop_weww(ctx, ta, ta, ra,
4330ebe9383cSRichard Henderson                 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
4331ebe9383cSRichard Henderson 
433231234768SRichard Henderson     return nullify_end(ctx);
4333ebe9383cSRichard Henderson }
4334ebe9383cSRichard Henderson 
4335b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4336b1e2af57SRichard Henderson {
4337b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, false);
4338b1e2af57SRichard Henderson }
4339b1e2af57SRichard Henderson 
4340b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4341b1e2af57SRichard Henderson {
4342b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, true);
4343b1e2af57SRichard Henderson }
4344b1e2af57SRichard Henderson 
4345b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4346b1e2af57SRichard Henderson {
4347b1e2af57SRichard Henderson     nullify_over(ctx);
4348b1e2af57SRichard Henderson 
4349b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4350b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4351b1e2af57SRichard Henderson                 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4352b1e2af57SRichard Henderson 
4353b1e2af57SRichard Henderson     return nullify_end(ctx);
4354b1e2af57SRichard Henderson }
4355b1e2af57SRichard Henderson 
4356b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4357b1e2af57SRichard Henderson {
4358b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, false);
4359b1e2af57SRichard Henderson }
4360b1e2af57SRichard Henderson 
4361b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4362b1e2af57SRichard Henderson {
4363b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, true);
4364b1e2af57SRichard Henderson }
4365b1e2af57SRichard Henderson 
4366c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a)
4367ebe9383cSRichard Henderson {
4368c3bad4f8SRichard Henderson     TCGv_i32 x, y, z;
4369ebe9383cSRichard Henderson 
4370ebe9383cSRichard Henderson     nullify_over(ctx);
4371c3bad4f8SRichard Henderson     x = load_frw0_i32(a->rm1);
4372c3bad4f8SRichard Henderson     y = load_frw0_i32(a->rm2);
4373c3bad4f8SRichard Henderson     z = load_frw0_i32(a->ra3);
4374ebe9383cSRichard Henderson 
4375c3bad4f8SRichard Henderson     if (a->neg) {
4376ad75a51eSRichard Henderson         gen_helper_fmpynfadd_s(x, tcg_env, x, y, z);
4377ebe9383cSRichard Henderson     } else {
4378ad75a51eSRichard Henderson         gen_helper_fmpyfadd_s(x, tcg_env, x, y, z);
4379ebe9383cSRichard Henderson     }
4380ebe9383cSRichard Henderson 
4381c3bad4f8SRichard Henderson     save_frw_i32(a->t, x);
438231234768SRichard Henderson     return nullify_end(ctx);
4383ebe9383cSRichard Henderson }
4384ebe9383cSRichard Henderson 
4385c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
4386ebe9383cSRichard Henderson {
4387c3bad4f8SRichard Henderson     TCGv_i64 x, y, z;
4388ebe9383cSRichard Henderson 
4389ebe9383cSRichard Henderson     nullify_over(ctx);
4390c3bad4f8SRichard Henderson     x = load_frd0(a->rm1);
4391c3bad4f8SRichard Henderson     y = load_frd0(a->rm2);
4392c3bad4f8SRichard Henderson     z = load_frd0(a->ra3);
4393ebe9383cSRichard Henderson 
4394c3bad4f8SRichard Henderson     if (a->neg) {
4395ad75a51eSRichard Henderson         gen_helper_fmpynfadd_d(x, tcg_env, x, y, z);
4396ebe9383cSRichard Henderson     } else {
4397ad75a51eSRichard Henderson         gen_helper_fmpyfadd_d(x, tcg_env, x, y, z);
4398ebe9383cSRichard Henderson     }
4399ebe9383cSRichard Henderson 
4400c3bad4f8SRichard Henderson     save_frd(a->t, x);
440131234768SRichard Henderson     return nullify_end(ctx);
4402ebe9383cSRichard Henderson }
4403ebe9383cSRichard Henderson 
440415da177bSSven Schnelle static bool trans_diag(DisasContext *ctx, arg_diag *a)
440515da177bSSven Schnelle {
4406cf6b28d4SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4407cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY
4408cf6b28d4SHelge Deller     if (a->i == 0x100) {
4409cf6b28d4SHelge Deller         /* emulate PDC BTLB, called by SeaBIOS-hppa */
4410ad75a51eSRichard Henderson         nullify_over(ctx);
4411ad75a51eSRichard Henderson         gen_helper_diag_btlb(tcg_env);
4412cf6b28d4SHelge Deller         return nullify_end(ctx);
441315da177bSSven Schnelle     }
4414ad75a51eSRichard Henderson #endif
4415ad75a51eSRichard Henderson     qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i);
4416ad75a51eSRichard Henderson     return true;
4417ad75a51eSRichard Henderson }
441815da177bSSven Schnelle 
4419b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
442061766fe9SRichard Henderson {
442151b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4422f764718dSRichard Henderson     int bound;
442361766fe9SRichard Henderson 
442451b061fbSRichard Henderson     ctx->cs = cs;
4425494737b7SRichard Henderson     ctx->tb_flags = ctx->base.tb->flags;
4426bd6243a3SRichard Henderson     ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
44273d68ee7bSRichard Henderson 
44283d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY
4429c01e5dfbSHelge Deller     ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX);
44303d68ee7bSRichard Henderson     ctx->mmu_idx = MMU_USER_IDX;
4431c01e5dfbSHelge Deller     ctx->iaoq_f = ctx->base.pc_first | ctx->privilege;
4432c01e5dfbSHelge Deller     ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege;
4433217d1a5eSRichard Henderson     ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
4434c301f34eSRichard Henderson #else
4435494737b7SRichard Henderson     ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
4436bb67ec32SRichard Henderson     ctx->mmu_idx = (ctx->tb_flags & PSW_D
4437bb67ec32SRichard Henderson                     ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
4438451d993dSRichard Henderson                     : ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX);
44393d68ee7bSRichard Henderson 
4440c301f34eSRichard Henderson     /* Recover the IAOQ values from the GVA + PRIV.  */
4441c301f34eSRichard Henderson     uint64_t cs_base = ctx->base.tb->cs_base;
4442c301f34eSRichard Henderson     uint64_t iasq_f = cs_base & ~0xffffffffull;
4443c301f34eSRichard Henderson     int32_t diff = cs_base;
4444c301f34eSRichard Henderson 
4445c301f34eSRichard Henderson     ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
4446c301f34eSRichard Henderson     ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1);
4447c301f34eSRichard Henderson #endif
444851b061fbSRichard Henderson     ctx->iaoq_n = -1;
4449f764718dSRichard Henderson     ctx->iaoq_n_var = NULL;
445061766fe9SRichard Henderson 
4451a4db4a78SRichard Henderson     ctx->zero = tcg_constant_i64(0);
4452a4db4a78SRichard Henderson 
44533d68ee7bSRichard Henderson     /* Bound the number of instructions by those left on the page.  */
44543d68ee7bSRichard Henderson     bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
4455b542683dSEmilio G. Cota     ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
445661766fe9SRichard Henderson }
445761766fe9SRichard Henderson 
445851b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
445951b061fbSRichard Henderson {
446051b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
446161766fe9SRichard Henderson 
44623d68ee7bSRichard Henderson     /* Seed the nullification status from PSW[N], as saved in TB->FLAGS.  */
446351b061fbSRichard Henderson     ctx->null_cond = cond_make_f();
446451b061fbSRichard Henderson     ctx->psw_n_nonzero = false;
4465494737b7SRichard Henderson     if (ctx->tb_flags & PSW_N) {
446651b061fbSRichard Henderson         ctx->null_cond.c = TCG_COND_ALWAYS;
446751b061fbSRichard Henderson         ctx->psw_n_nonzero = true;
4468129e9cc3SRichard Henderson     }
446951b061fbSRichard Henderson     ctx->null_lab = NULL;
447061766fe9SRichard Henderson }
447161766fe9SRichard Henderson 
447251b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
447351b061fbSRichard Henderson {
447451b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
447551b061fbSRichard Henderson 
4476f5b5c857SRichard Henderson     tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b, 0);
4477f5b5c857SRichard Henderson     ctx->insn_start = tcg_last_op();
447851b061fbSRichard Henderson }
447951b061fbSRichard Henderson 
448051b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
448151b061fbSRichard Henderson {
448251b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4483b77af26eSRichard Henderson     CPUHPPAState *env = cpu_env(cs);
448451b061fbSRichard Henderson     DisasJumpType ret;
448551b061fbSRichard Henderson 
448651b061fbSRichard Henderson     /* Execute one insn.  */
4487ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4488c301f34eSRichard Henderson     if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
448931234768SRichard Henderson         do_page_zero(ctx);
449031234768SRichard Henderson         ret = ctx->base.is_jmp;
4491869051eaSRichard Henderson         assert(ret != DISAS_NEXT);
4492ba1d0b44SRichard Henderson     } else
4493ba1d0b44SRichard Henderson #endif
4494ba1d0b44SRichard Henderson     {
449561766fe9SRichard Henderson         /* Always fetch the insn, even if nullified, so that we check
449661766fe9SRichard Henderson            the page permissions for execute.  */
44974e116893SIlya Leoshkevich         uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next);
449861766fe9SRichard Henderson 
449961766fe9SRichard Henderson         /* Set up the IA queue for the next insn.
450061766fe9SRichard Henderson            This will be overwritten by a branch.  */
450151b061fbSRichard Henderson         if (ctx->iaoq_b == -1) {
450251b061fbSRichard Henderson             ctx->iaoq_n = -1;
4503aac0f603SRichard Henderson             ctx->iaoq_n_var = tcg_temp_new_i64();
45046fd0c7bcSRichard Henderson             tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
450561766fe9SRichard Henderson         } else {
450651b061fbSRichard Henderson             ctx->iaoq_n = ctx->iaoq_b + 4;
4507f764718dSRichard Henderson             ctx->iaoq_n_var = NULL;
450861766fe9SRichard Henderson         }
450961766fe9SRichard Henderson 
451051b061fbSRichard Henderson         if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
451151b061fbSRichard Henderson             ctx->null_cond.c = TCG_COND_NEVER;
4512869051eaSRichard Henderson             ret = DISAS_NEXT;
4513129e9cc3SRichard Henderson         } else {
45141a19da0dSRichard Henderson             ctx->insn = insn;
451531274b46SRichard Henderson             if (!decode(ctx, insn)) {
451631274b46SRichard Henderson                 gen_illegal(ctx);
451731274b46SRichard Henderson             }
451831234768SRichard Henderson             ret = ctx->base.is_jmp;
451951b061fbSRichard Henderson             assert(ctx->null_lab == NULL);
4520129e9cc3SRichard Henderson         }
452161766fe9SRichard Henderson     }
452261766fe9SRichard Henderson 
45233d68ee7bSRichard Henderson     /* Advance the insn queue.  Note that this check also detects
45243d68ee7bSRichard Henderson        a priority change within the instruction queue.  */
452551b061fbSRichard Henderson     if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
4526c301f34eSRichard Henderson         if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1
4527c301f34eSRichard Henderson             && use_goto_tb(ctx, ctx->iaoq_b)
4528c301f34eSRichard Henderson             && (ctx->null_cond.c == TCG_COND_NEVER
4529c301f34eSRichard Henderson                 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
453051b061fbSRichard Henderson             nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
453151b061fbSRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
453231234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_NORETURN;
4533129e9cc3SRichard Henderson         } else {
453431234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE;
453561766fe9SRichard Henderson         }
4536129e9cc3SRichard Henderson     }
453751b061fbSRichard Henderson     ctx->iaoq_f = ctx->iaoq_b;
453851b061fbSRichard Henderson     ctx->iaoq_b = ctx->iaoq_n;
4539c301f34eSRichard Henderson     ctx->base.pc_next += 4;
454061766fe9SRichard Henderson 
4541c5d0aec2SRichard Henderson     switch (ret) {
4542c5d0aec2SRichard Henderson     case DISAS_NORETURN:
4543c5d0aec2SRichard Henderson     case DISAS_IAQ_N_UPDATED:
4544c5d0aec2SRichard Henderson         break;
4545c5d0aec2SRichard Henderson 
4546c5d0aec2SRichard Henderson     case DISAS_NEXT:
4547c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE:
4548c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
454951b061fbSRichard Henderson         if (ctx->iaoq_f == -1) {
4550a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b);
4551741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
4552c301f34eSRichard Henderson #ifndef CONFIG_USER_ONLY
4553c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
4554c301f34eSRichard Henderson #endif
455551b061fbSRichard Henderson             nullify_save(ctx);
4556c5d0aec2SRichard Henderson             ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT
4557c5d0aec2SRichard Henderson                                 ? DISAS_EXIT
4558c5d0aec2SRichard Henderson                                 : DISAS_IAQ_N_UPDATED);
455951b061fbSRichard Henderson         } else if (ctx->iaoq_b == -1) {
4560a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var);
456161766fe9SRichard Henderson         }
4562c5d0aec2SRichard Henderson         break;
4563c5d0aec2SRichard Henderson 
4564c5d0aec2SRichard Henderson     default:
4565c5d0aec2SRichard Henderson         g_assert_not_reached();
4566c5d0aec2SRichard Henderson     }
456761766fe9SRichard Henderson }
456861766fe9SRichard Henderson 
456951b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
457051b061fbSRichard Henderson {
457151b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4572e1b5a5edSRichard Henderson     DisasJumpType is_jmp = ctx->base.is_jmp;
457351b061fbSRichard Henderson 
4574e1b5a5edSRichard Henderson     switch (is_jmp) {
4575869051eaSRichard Henderson     case DISAS_NORETURN:
457661766fe9SRichard Henderson         break;
457751b061fbSRichard Henderson     case DISAS_TOO_MANY:
4578869051eaSRichard Henderson     case DISAS_IAQ_N_STALE:
4579e1b5a5edSRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
4580741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
4581741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
458251b061fbSRichard Henderson         nullify_save(ctx);
458361766fe9SRichard Henderson         /* FALLTHRU */
4584869051eaSRichard Henderson     case DISAS_IAQ_N_UPDATED:
45858532a14eSRichard Henderson         if (is_jmp != DISAS_IAQ_N_STALE_EXIT) {
45867f11636dSEmilio G. Cota             tcg_gen_lookup_and_goto_ptr();
45878532a14eSRichard Henderson             break;
458861766fe9SRichard Henderson         }
4589c5d0aec2SRichard Henderson         /* FALLTHRU */
4590c5d0aec2SRichard Henderson     case DISAS_EXIT:
4591c5d0aec2SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
459261766fe9SRichard Henderson         break;
459361766fe9SRichard Henderson     default:
459451b061fbSRichard Henderson         g_assert_not_reached();
459561766fe9SRichard Henderson     }
459651b061fbSRichard Henderson }
459761766fe9SRichard Henderson 
45988eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase,
45998eb806a7SRichard Henderson                               CPUState *cs, FILE *logfile)
460051b061fbSRichard Henderson {
4601c301f34eSRichard Henderson     target_ulong pc = dcbase->pc_first;
460261766fe9SRichard Henderson 
4603ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4604ba1d0b44SRichard Henderson     switch (pc) {
46057ad439dfSRichard Henderson     case 0x00:
46068eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000000:  (null)\n");
4607ba1d0b44SRichard Henderson         return;
46087ad439dfSRichard Henderson     case 0xb0:
46098eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000b0:  light-weight-syscall\n");
4610ba1d0b44SRichard Henderson         return;
46117ad439dfSRichard Henderson     case 0xe0:
46128eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000e0:  set-thread-pointer-syscall\n");
4613ba1d0b44SRichard Henderson         return;
46147ad439dfSRichard Henderson     case 0x100:
46158eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000100:  syscall\n");
4616ba1d0b44SRichard Henderson         return;
46177ad439dfSRichard Henderson     }
4618ba1d0b44SRichard Henderson #endif
4619ba1d0b44SRichard Henderson 
46208eb806a7SRichard Henderson     fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
46218eb806a7SRichard Henderson     target_disas(logfile, cs, pc, dcbase->tb->size);
462261766fe9SRichard Henderson }
462351b061fbSRichard Henderson 
462451b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = {
462551b061fbSRichard Henderson     .init_disas_context = hppa_tr_init_disas_context,
462651b061fbSRichard Henderson     .tb_start           = hppa_tr_tb_start,
462751b061fbSRichard Henderson     .insn_start         = hppa_tr_insn_start,
462851b061fbSRichard Henderson     .translate_insn     = hppa_tr_translate_insn,
462951b061fbSRichard Henderson     .tb_stop            = hppa_tr_tb_stop,
463051b061fbSRichard Henderson     .disas_log          = hppa_tr_disas_log,
463151b061fbSRichard Henderson };
463251b061fbSRichard Henderson 
4633597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
4634*32f0c394SAnton Johansson                            vaddr pc, void *host_pc)
463551b061fbSRichard Henderson {
463651b061fbSRichard Henderson     DisasContext ctx;
4637306c8721SRichard Henderson     translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
463861766fe9SRichard Henderson }
4639