xref: /openbmc/qemu/target/hppa/translate.c (revision 4e7abdb120d7456aaa754a7101ef43a5916ed8a0)
161766fe9SRichard Henderson /*
261766fe9SRichard Henderson  * HPPA emulation cpu translation for qemu.
361766fe9SRichard Henderson  *
461766fe9SRichard Henderson  * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
561766fe9SRichard Henderson  *
661766fe9SRichard Henderson  * This library is free software; you can redistribute it and/or
761766fe9SRichard Henderson  * modify it under the terms of the GNU Lesser General Public
861766fe9SRichard Henderson  * License as published by the Free Software Foundation; either
9d6ea4236SChetan Pant  * version 2.1 of the License, or (at your option) any later version.
1061766fe9SRichard Henderson  *
1161766fe9SRichard Henderson  * This library is distributed in the hope that it will be useful,
1261766fe9SRichard Henderson  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1361766fe9SRichard Henderson  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1461766fe9SRichard Henderson  * Lesser General Public License for more details.
1561766fe9SRichard Henderson  *
1661766fe9SRichard Henderson  * You should have received a copy of the GNU Lesser General Public
1761766fe9SRichard Henderson  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1861766fe9SRichard Henderson  */
1961766fe9SRichard Henderson 
2061766fe9SRichard Henderson #include "qemu/osdep.h"
2161766fe9SRichard Henderson #include "cpu.h"
2261766fe9SRichard Henderson #include "disas/disas.h"
2361766fe9SRichard Henderson #include "qemu/host-utils.h"
2461766fe9SRichard Henderson #include "exec/exec-all.h"
25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
260843563fSRichard Henderson #include "tcg/tcg-op-gvec.h"
2761766fe9SRichard Henderson #include "exec/helper-proto.h"
2861766fe9SRichard Henderson #include "exec/helper-gen.h"
29869051eaSRichard Henderson #include "exec/translator.h"
3061766fe9SRichard Henderson #include "exec/log.h"
3161766fe9SRichard Henderson 
32d53106c9SRichard Henderson #define HELPER_H "helper.h"
33d53106c9SRichard Henderson #include "exec/helper-info.c.inc"
34d53106c9SRichard Henderson #undef  HELPER_H
35d53106c9SRichard Henderson 
36aac0f603SRichard Henderson /* Choose to use explicit sizes within this file. */
37aac0f603SRichard Henderson #undef tcg_temp_new
38d53106c9SRichard Henderson 
3961766fe9SRichard Henderson typedef struct DisasCond {
4061766fe9SRichard Henderson     TCGCond c;
416fd0c7bcSRichard Henderson     TCGv_i64 a0, a1;
4261766fe9SRichard Henderson } DisasCond;
4361766fe9SRichard Henderson 
4461766fe9SRichard Henderson typedef struct DisasContext {
45d01a3625SRichard Henderson     DisasContextBase base;
4661766fe9SRichard Henderson     CPUState *cs;
4761766fe9SRichard Henderson 
48c53e401eSRichard Henderson     uint64_t iaoq_f;
49c53e401eSRichard Henderson     uint64_t iaoq_b;
50c53e401eSRichard Henderson     uint64_t iaoq_n;
516fd0c7bcSRichard Henderson     TCGv_i64 iaoq_n_var;
5261766fe9SRichard Henderson 
5361766fe9SRichard Henderson     DisasCond null_cond;
5461766fe9SRichard Henderson     TCGLabel *null_lab;
5561766fe9SRichard Henderson 
561a19da0dSRichard Henderson     uint32_t insn;
57494737b7SRichard Henderson     uint32_t tb_flags;
583d68ee7bSRichard Henderson     int mmu_idx;
593d68ee7bSRichard Henderson     int privilege;
6061766fe9SRichard Henderson     bool psw_n_nonzero;
61bd6243a3SRichard Henderson     bool is_pa20;
62217d1a5eSRichard Henderson 
63217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
64217d1a5eSRichard Henderson     MemOp unalign;
65217d1a5eSRichard Henderson #endif
6661766fe9SRichard Henderson } DisasContext;
6761766fe9SRichard Henderson 
68217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
69217d1a5eSRichard Henderson #define UNALIGN(C)  (C)->unalign
70217d1a5eSRichard Henderson #else
712d4afb03SRichard Henderson #define UNALIGN(C)  MO_ALIGN
72217d1a5eSRichard Henderson #endif
73217d1a5eSRichard Henderson 
74e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently.  */
75451e4ffdSRichard Henderson static int expand_sm_imm(DisasContext *ctx, int val)
76e36f27efSRichard Henderson {
77e36f27efSRichard Henderson     if (val & PSW_SM_E) {
78e36f27efSRichard Henderson         val = (val & ~PSW_SM_E) | PSW_E;
79e36f27efSRichard Henderson     }
80e36f27efSRichard Henderson     if (val & PSW_SM_W) {
81e36f27efSRichard Henderson         val = (val & ~PSW_SM_W) | PSW_W;
82e36f27efSRichard Henderson     }
83e36f27efSRichard Henderson     return val;
84e36f27efSRichard Henderson }
85e36f27efSRichard Henderson 
86deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base.  */
87451e4ffdSRichard Henderson static int expand_sr3x(DisasContext *ctx, int val)
88deee69a1SRichard Henderson {
89deee69a1SRichard Henderson     return ~val;
90deee69a1SRichard Henderson }
91deee69a1SRichard Henderson 
921cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value
931cd012a5SRichard Henderson    we use for the final M.  */
94451e4ffdSRichard Henderson static int ma_to_m(DisasContext *ctx, int val)
951cd012a5SRichard Henderson {
961cd012a5SRichard Henderson     return val & 2 ? (val & 1 ? -1 : 1) : 0;
971cd012a5SRichard Henderson }
981cd012a5SRichard Henderson 
99740038d7SRichard Henderson /* Convert the sign of the displacement to a pre or post-modify.  */
100451e4ffdSRichard Henderson static int pos_to_m(DisasContext *ctx, int val)
101740038d7SRichard Henderson {
102740038d7SRichard Henderson     return val ? 1 : -1;
103740038d7SRichard Henderson }
104740038d7SRichard Henderson 
105451e4ffdSRichard Henderson static int neg_to_m(DisasContext *ctx, int val)
106740038d7SRichard Henderson {
107740038d7SRichard Henderson     return val ? -1 : 1;
108740038d7SRichard Henderson }
109740038d7SRichard Henderson 
110740038d7SRichard Henderson /* Used for branch targets and fp memory ops.  */
111451e4ffdSRichard Henderson static int expand_shl2(DisasContext *ctx, int val)
11201afb7beSRichard Henderson {
11301afb7beSRichard Henderson     return val << 2;
11401afb7beSRichard Henderson }
11501afb7beSRichard Henderson 
116740038d7SRichard Henderson /* Used for fp memory ops.  */
117451e4ffdSRichard Henderson static int expand_shl3(DisasContext *ctx, int val)
118740038d7SRichard Henderson {
119740038d7SRichard Henderson     return val << 3;
120740038d7SRichard Henderson }
121740038d7SRichard Henderson 
1220588e061SRichard Henderson /* Used for assemble_21.  */
123451e4ffdSRichard Henderson static int expand_shl11(DisasContext *ctx, int val)
1240588e061SRichard Henderson {
1250588e061SRichard Henderson     return val << 11;
1260588e061SRichard Henderson }
1270588e061SRichard Henderson 
12872ae4f2bSRichard Henderson static int assemble_6(DisasContext *ctx, int val)
12972ae4f2bSRichard Henderson {
13072ae4f2bSRichard Henderson     /*
13172ae4f2bSRichard Henderson      * Officially, 32 * x + 32 - y.
13272ae4f2bSRichard Henderson      * Here, x is already in bit 5, and y is [4:0].
13372ae4f2bSRichard Henderson      * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1,
13472ae4f2bSRichard Henderson      * with the overflow from bit 4 summing with x.
13572ae4f2bSRichard Henderson      */
13672ae4f2bSRichard Henderson     return (val ^ 31) + 1;
13772ae4f2bSRichard Henderson }
13872ae4f2bSRichard Henderson 
139c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */
140c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val)
141c65c3ee1SRichard Henderson {
142c65c3ee1SRichard Henderson     return val ? val : 4; /* 0 == "*<<" */
143c65c3ee1SRichard Henderson }
144c65c3ee1SRichard Henderson 
14501afb7beSRichard Henderson 
14640f9f908SRichard Henderson /* Include the auto-generated decoder.  */
147abff1abfSPaolo Bonzini #include "decode-insns.c.inc"
14840f9f908SRichard Henderson 
14961766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated
15061766fe9SRichard Henderson    the iaq (for whatever reason), so don't do it again on exit.  */
151869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED  DISAS_TARGET_0
15261766fe9SRichard Henderson 
15361766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor
15461766fe9SRichard Henderson    updated the iaq for the next instruction to be executed.  */
155869051eaSRichard Henderson #define DISAS_IAQ_N_STALE    DISAS_TARGET_1
15661766fe9SRichard Henderson 
157e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately
158e1b5a5edSRichard Henderson    to recognize unmasked interrupts.  */
159e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT      DISAS_TARGET_2
160c5d0aec2SRichard Henderson #define DISAS_EXIT                  DISAS_TARGET_3
161e1b5a5edSRichard Henderson 
16261766fe9SRichard Henderson /* global register indexes */
1636fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32];
16433423472SRichard Henderson static TCGv_i64 cpu_sr[4];
165494737b7SRichard Henderson static TCGv_i64 cpu_srH;
1666fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f;
1676fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b;
168c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f;
169c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b;
1706fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar;
1716fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n;
1726fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v;
1736fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb;
1746fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb;
17561766fe9SRichard Henderson 
17661766fe9SRichard Henderson void hppa_translate_init(void)
17761766fe9SRichard Henderson {
17861766fe9SRichard Henderson #define DEF_VAR(V)  { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
17961766fe9SRichard Henderson 
1806fd0c7bcSRichard Henderson     typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar;
18161766fe9SRichard Henderson     static const GlobalVar vars[] = {
18235136a77SRichard Henderson         { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) },
18361766fe9SRichard Henderson         DEF_VAR(psw_n),
18461766fe9SRichard Henderson         DEF_VAR(psw_v),
18561766fe9SRichard Henderson         DEF_VAR(psw_cb),
18661766fe9SRichard Henderson         DEF_VAR(psw_cb_msb),
18761766fe9SRichard Henderson         DEF_VAR(iaoq_f),
18861766fe9SRichard Henderson         DEF_VAR(iaoq_b),
18961766fe9SRichard Henderson     };
19061766fe9SRichard Henderson 
19161766fe9SRichard Henderson #undef DEF_VAR
19261766fe9SRichard Henderson 
19361766fe9SRichard Henderson     /* Use the symbolic register names that match the disassembler.  */
19461766fe9SRichard Henderson     static const char gr_names[32][4] = {
19561766fe9SRichard Henderson         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
19661766fe9SRichard Henderson         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
19761766fe9SRichard Henderson         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
19861766fe9SRichard Henderson         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
19961766fe9SRichard Henderson     };
20033423472SRichard Henderson     /* SR[4-7] are not global registers so that we can index them.  */
201494737b7SRichard Henderson     static const char sr_names[5][4] = {
202494737b7SRichard Henderson         "sr0", "sr1", "sr2", "sr3", "srH"
20333423472SRichard Henderson     };
20461766fe9SRichard Henderson 
20561766fe9SRichard Henderson     int i;
20661766fe9SRichard Henderson 
207f764718dSRichard Henderson     cpu_gr[0] = NULL;
20861766fe9SRichard Henderson     for (i = 1; i < 32; i++) {
209ad75a51eSRichard Henderson         cpu_gr[i] = tcg_global_mem_new(tcg_env,
21061766fe9SRichard Henderson                                        offsetof(CPUHPPAState, gr[i]),
21161766fe9SRichard Henderson                                        gr_names[i]);
21261766fe9SRichard Henderson     }
21333423472SRichard Henderson     for (i = 0; i < 4; i++) {
214ad75a51eSRichard Henderson         cpu_sr[i] = tcg_global_mem_new_i64(tcg_env,
21533423472SRichard Henderson                                            offsetof(CPUHPPAState, sr[i]),
21633423472SRichard Henderson                                            sr_names[i]);
21733423472SRichard Henderson     }
218ad75a51eSRichard Henderson     cpu_srH = tcg_global_mem_new_i64(tcg_env,
219494737b7SRichard Henderson                                      offsetof(CPUHPPAState, sr[4]),
220494737b7SRichard Henderson                                      sr_names[4]);
22161766fe9SRichard Henderson 
22261766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(vars); ++i) {
22361766fe9SRichard Henderson         const GlobalVar *v = &vars[i];
224ad75a51eSRichard Henderson         *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name);
22561766fe9SRichard Henderson     }
226c301f34eSRichard Henderson 
227ad75a51eSRichard Henderson     cpu_iasq_f = tcg_global_mem_new_i64(tcg_env,
228c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_f),
229c301f34eSRichard Henderson                                         "iasq_f");
230ad75a51eSRichard Henderson     cpu_iasq_b = tcg_global_mem_new_i64(tcg_env,
231c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_b),
232c301f34eSRichard Henderson                                         "iasq_b");
23361766fe9SRichard Henderson }
23461766fe9SRichard Henderson 
235129e9cc3SRichard Henderson static DisasCond cond_make_f(void)
236129e9cc3SRichard Henderson {
237f764718dSRichard Henderson     return (DisasCond){
238f764718dSRichard Henderson         .c = TCG_COND_NEVER,
239f764718dSRichard Henderson         .a0 = NULL,
240f764718dSRichard Henderson         .a1 = NULL,
241f764718dSRichard Henderson     };
242129e9cc3SRichard Henderson }
243129e9cc3SRichard Henderson 
244df0232feSRichard Henderson static DisasCond cond_make_t(void)
245df0232feSRichard Henderson {
246df0232feSRichard Henderson     return (DisasCond){
247df0232feSRichard Henderson         .c = TCG_COND_ALWAYS,
248df0232feSRichard Henderson         .a0 = NULL,
249df0232feSRichard Henderson         .a1 = NULL,
250df0232feSRichard Henderson     };
251df0232feSRichard Henderson }
252df0232feSRichard Henderson 
253129e9cc3SRichard Henderson static DisasCond cond_make_n(void)
254129e9cc3SRichard Henderson {
255f764718dSRichard Henderson     return (DisasCond){
256f764718dSRichard Henderson         .c = TCG_COND_NE,
257f764718dSRichard Henderson         .a0 = cpu_psw_n,
2586fd0c7bcSRichard Henderson         .a1 = tcg_constant_i64(0)
259f764718dSRichard Henderson     };
260129e9cc3SRichard Henderson }
261129e9cc3SRichard Henderson 
2626fd0c7bcSRichard Henderson static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
263b47a4a02SSven Schnelle {
264b47a4a02SSven Schnelle     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
2654fe9533aSRichard Henderson     return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 };
2664fe9533aSRichard Henderson }
2674fe9533aSRichard Henderson 
2686fd0c7bcSRichard Henderson static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0)
2694fe9533aSRichard Henderson {
2706fd0c7bcSRichard Henderson     return cond_make_tmp(c, a0, tcg_constant_i64(0));
271b47a4a02SSven Schnelle }
272b47a4a02SSven Schnelle 
2736fd0c7bcSRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0)
274129e9cc3SRichard Henderson {
275aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2766fd0c7bcSRichard Henderson     tcg_gen_mov_i64(tmp, a0);
277b47a4a02SSven Schnelle     return cond_make_0_tmp(c, tmp);
278129e9cc3SRichard Henderson }
279129e9cc3SRichard Henderson 
2806fd0c7bcSRichard Henderson static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
281129e9cc3SRichard Henderson {
282aac0f603SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
283aac0f603SRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
284129e9cc3SRichard Henderson 
2856fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t0, a0);
2866fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t1, a1);
2874fe9533aSRichard Henderson     return cond_make_tmp(c, t0, t1);
288129e9cc3SRichard Henderson }
289129e9cc3SRichard Henderson 
290129e9cc3SRichard Henderson static void cond_free(DisasCond *cond)
291129e9cc3SRichard Henderson {
292129e9cc3SRichard Henderson     switch (cond->c) {
293129e9cc3SRichard Henderson     default:
294f764718dSRichard Henderson         cond->a0 = NULL;
295f764718dSRichard Henderson         cond->a1 = NULL;
296129e9cc3SRichard Henderson         /* fallthru */
297129e9cc3SRichard Henderson     case TCG_COND_ALWAYS:
298129e9cc3SRichard Henderson         cond->c = TCG_COND_NEVER;
299129e9cc3SRichard Henderson         break;
300129e9cc3SRichard Henderson     case TCG_COND_NEVER:
301129e9cc3SRichard Henderson         break;
302129e9cc3SRichard Henderson     }
303129e9cc3SRichard Henderson }
304129e9cc3SRichard Henderson 
3056fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg)
30661766fe9SRichard Henderson {
30761766fe9SRichard Henderson     if (reg == 0) {
308aac0f603SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
3096fd0c7bcSRichard Henderson         tcg_gen_movi_i64(t, 0);
31061766fe9SRichard Henderson         return t;
31161766fe9SRichard Henderson     } else {
31261766fe9SRichard Henderson         return cpu_gr[reg];
31361766fe9SRichard Henderson     }
31461766fe9SRichard Henderson }
31561766fe9SRichard Henderson 
3166fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg)
31761766fe9SRichard Henderson {
318129e9cc3SRichard Henderson     if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
319aac0f603SRichard Henderson         return tcg_temp_new_i64();
32061766fe9SRichard Henderson     } else {
32161766fe9SRichard Henderson         return cpu_gr[reg];
32261766fe9SRichard Henderson     }
32361766fe9SRichard Henderson }
32461766fe9SRichard Henderson 
3256fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t)
326129e9cc3SRichard Henderson {
327129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
3286fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0,
329129e9cc3SRichard Henderson                             ctx->null_cond.a1, dest, t);
330129e9cc3SRichard Henderson     } else {
3316fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, t);
332129e9cc3SRichard Henderson     }
333129e9cc3SRichard Henderson }
334129e9cc3SRichard Henderson 
3356fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t)
336129e9cc3SRichard Henderson {
337129e9cc3SRichard Henderson     if (reg != 0) {
338129e9cc3SRichard Henderson         save_or_nullify(ctx, cpu_gr[reg], t);
339129e9cc3SRichard Henderson     }
340129e9cc3SRichard Henderson }
341129e9cc3SRichard Henderson 
342e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
34396d6407fSRichard Henderson # define HI_OFS  0
34496d6407fSRichard Henderson # define LO_OFS  4
34596d6407fSRichard Henderson #else
34696d6407fSRichard Henderson # define HI_OFS  4
34796d6407fSRichard Henderson # define LO_OFS  0
34896d6407fSRichard Henderson #endif
34996d6407fSRichard Henderson 
35096d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt)
35196d6407fSRichard Henderson {
35296d6407fSRichard Henderson     TCGv_i32 ret = tcg_temp_new_i32();
353ad75a51eSRichard Henderson     tcg_gen_ld_i32(ret, tcg_env,
35496d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
35596d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
35696d6407fSRichard Henderson     return ret;
35796d6407fSRichard Henderson }
35896d6407fSRichard Henderson 
359ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt)
360ebe9383cSRichard Henderson {
361ebe9383cSRichard Henderson     if (rt == 0) {
3620992a930SRichard Henderson         TCGv_i32 ret = tcg_temp_new_i32();
3630992a930SRichard Henderson         tcg_gen_movi_i32(ret, 0);
3640992a930SRichard Henderson         return ret;
365ebe9383cSRichard Henderson     } else {
366ebe9383cSRichard Henderson         return load_frw_i32(rt);
367ebe9383cSRichard Henderson     }
368ebe9383cSRichard Henderson }
369ebe9383cSRichard Henderson 
370ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt)
371ebe9383cSRichard Henderson {
372ebe9383cSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
3730992a930SRichard Henderson     if (rt == 0) {
3740992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
3750992a930SRichard Henderson     } else {
376ad75a51eSRichard Henderson         tcg_gen_ld32u_i64(ret, tcg_env,
377ebe9383cSRichard Henderson                           offsetof(CPUHPPAState, fr[rt & 31])
378ebe9383cSRichard Henderson                           + (rt & 32 ? LO_OFS : HI_OFS));
379ebe9383cSRichard Henderson     }
3800992a930SRichard Henderson     return ret;
381ebe9383cSRichard Henderson }
382ebe9383cSRichard Henderson 
38396d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val)
38496d6407fSRichard Henderson {
385ad75a51eSRichard Henderson     tcg_gen_st_i32(val, tcg_env,
38696d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
38796d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
38896d6407fSRichard Henderson }
38996d6407fSRichard Henderson 
39096d6407fSRichard Henderson #undef HI_OFS
39196d6407fSRichard Henderson #undef LO_OFS
39296d6407fSRichard Henderson 
39396d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt)
39496d6407fSRichard Henderson {
39596d6407fSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
396ad75a51eSRichard Henderson     tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt]));
39796d6407fSRichard Henderson     return ret;
39896d6407fSRichard Henderson }
39996d6407fSRichard Henderson 
400ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt)
401ebe9383cSRichard Henderson {
402ebe9383cSRichard Henderson     if (rt == 0) {
4030992a930SRichard Henderson         TCGv_i64 ret = tcg_temp_new_i64();
4040992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
4050992a930SRichard Henderson         return ret;
406ebe9383cSRichard Henderson     } else {
407ebe9383cSRichard Henderson         return load_frd(rt);
408ebe9383cSRichard Henderson     }
409ebe9383cSRichard Henderson }
410ebe9383cSRichard Henderson 
41196d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val)
41296d6407fSRichard Henderson {
413ad75a51eSRichard Henderson     tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt]));
41496d6407fSRichard Henderson }
41596d6407fSRichard Henderson 
41633423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg)
41733423472SRichard Henderson {
41833423472SRichard Henderson #ifdef CONFIG_USER_ONLY
41933423472SRichard Henderson     tcg_gen_movi_i64(dest, 0);
42033423472SRichard Henderson #else
42133423472SRichard Henderson     if (reg < 4) {
42233423472SRichard Henderson         tcg_gen_mov_i64(dest, cpu_sr[reg]);
423494737b7SRichard Henderson     } else if (ctx->tb_flags & TB_FLAG_SR_SAME) {
424494737b7SRichard Henderson         tcg_gen_mov_i64(dest, cpu_srH);
42533423472SRichard Henderson     } else {
426ad75a51eSRichard Henderson         tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg]));
42733423472SRichard Henderson     }
42833423472SRichard Henderson #endif
42933423472SRichard Henderson }
43033423472SRichard Henderson 
431129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified.
432129e9cc3SRichard Henderson    Use this when the insn is too complex for a conditional move.  */
433129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx)
434129e9cc3SRichard Henderson {
435129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
436129e9cc3SRichard Henderson         /* The always condition should have been handled in the main loop.  */
437129e9cc3SRichard Henderson         assert(ctx->null_cond.c != TCG_COND_ALWAYS);
438129e9cc3SRichard Henderson 
439129e9cc3SRichard Henderson         ctx->null_lab = gen_new_label();
440129e9cc3SRichard Henderson 
441129e9cc3SRichard Henderson         /* If we're using PSW[N], copy it to a temp because... */
4426e94937aSRichard Henderson         if (ctx->null_cond.a0 == cpu_psw_n) {
443aac0f603SRichard Henderson             ctx->null_cond.a0 = tcg_temp_new_i64();
4446fd0c7bcSRichard Henderson             tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n);
445129e9cc3SRichard Henderson         }
446129e9cc3SRichard Henderson         /* ... we clear it before branching over the implementation,
447129e9cc3SRichard Henderson            so that (1) it's clear after nullifying this insn and
448129e9cc3SRichard Henderson            (2) if this insn nullifies the next, PSW[N] is valid.  */
449129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
450129e9cc3SRichard Henderson             ctx->psw_n_nonzero = false;
4516fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
452129e9cc3SRichard Henderson         }
453129e9cc3SRichard Henderson 
4546fd0c7bcSRichard Henderson         tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0,
455129e9cc3SRichard Henderson                            ctx->null_cond.a1, ctx->null_lab);
456129e9cc3SRichard Henderson         cond_free(&ctx->null_cond);
457129e9cc3SRichard Henderson     }
458129e9cc3SRichard Henderson }
459129e9cc3SRichard Henderson 
460129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N].  */
461129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx)
462129e9cc3SRichard Henderson {
463129e9cc3SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
464129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
4656fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
466129e9cc3SRichard Henderson         }
467129e9cc3SRichard Henderson         return;
468129e9cc3SRichard Henderson     }
4696e94937aSRichard Henderson     if (ctx->null_cond.a0 != cpu_psw_n) {
4706fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n,
471129e9cc3SRichard Henderson                             ctx->null_cond.a0, ctx->null_cond.a1);
472129e9cc3SRichard Henderson         ctx->psw_n_nonzero = true;
473129e9cc3SRichard Henderson     }
474129e9cc3SRichard Henderson     cond_free(&ctx->null_cond);
475129e9cc3SRichard Henderson }
476129e9cc3SRichard Henderson 
477129e9cc3SRichard Henderson /* Set a PSW[N] to X.  The intention is that this is used immediately
478129e9cc3SRichard Henderson    before a goto_tb/exit_tb, so that there is no fallthru path to other
479129e9cc3SRichard Henderson    code within the TB.  Therefore we do not update psw_n_nonzero.  */
480129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x)
481129e9cc3SRichard Henderson {
482129e9cc3SRichard Henderson     if (ctx->psw_n_nonzero || x) {
4836fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, x);
484129e9cc3SRichard Henderson     }
485129e9cc3SRichard Henderson }
486129e9cc3SRichard Henderson 
487129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified.
48840f9f908SRichard Henderson    This is the pair to nullify_over.  Always returns true so that
48940f9f908SRichard Henderson    it may be tail-called from a translate function.  */
49031234768SRichard Henderson static bool nullify_end(DisasContext *ctx)
491129e9cc3SRichard Henderson {
492129e9cc3SRichard Henderson     TCGLabel *null_lab = ctx->null_lab;
49331234768SRichard Henderson     DisasJumpType status = ctx->base.is_jmp;
494129e9cc3SRichard Henderson 
495f49b3537SRichard Henderson     /* For NEXT, NORETURN, STALE, we can easily continue (or exit).
496f49b3537SRichard Henderson        For UPDATED, we cannot update on the nullified path.  */
497f49b3537SRichard Henderson     assert(status != DISAS_IAQ_N_UPDATED);
498f49b3537SRichard Henderson 
499129e9cc3SRichard Henderson     if (likely(null_lab == NULL)) {
500129e9cc3SRichard Henderson         /* The current insn wasn't conditional or handled the condition
501129e9cc3SRichard Henderson            applied to it without a branch, so the (new) setting of
502129e9cc3SRichard Henderson            NULL_COND can be applied directly to the next insn.  */
50331234768SRichard Henderson         return true;
504129e9cc3SRichard Henderson     }
505129e9cc3SRichard Henderson     ctx->null_lab = NULL;
506129e9cc3SRichard Henderson 
507129e9cc3SRichard Henderson     if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
508129e9cc3SRichard Henderson         /* The next instruction will be unconditional,
509129e9cc3SRichard Henderson            and NULL_COND already reflects that.  */
510129e9cc3SRichard Henderson         gen_set_label(null_lab);
511129e9cc3SRichard Henderson     } else {
512129e9cc3SRichard Henderson         /* The insn that we just executed is itself nullifying the next
513129e9cc3SRichard Henderson            instruction.  Store the condition in the PSW[N] global.
514129e9cc3SRichard Henderson            We asserted PSW[N] = 0 in nullify_over, so that after the
515129e9cc3SRichard Henderson            label we have the proper value in place.  */
516129e9cc3SRichard Henderson         nullify_save(ctx);
517129e9cc3SRichard Henderson         gen_set_label(null_lab);
518129e9cc3SRichard Henderson         ctx->null_cond = cond_make_n();
519129e9cc3SRichard Henderson     }
520869051eaSRichard Henderson     if (status == DISAS_NORETURN) {
52131234768SRichard Henderson         ctx->base.is_jmp = DISAS_NEXT;
522129e9cc3SRichard Henderson     }
52331234768SRichard Henderson     return true;
524129e9cc3SRichard Henderson }
525129e9cc3SRichard Henderson 
526c53e401eSRichard Henderson static uint64_t gva_offset_mask(DisasContext *ctx)
527698240d1SRichard Henderson {
528698240d1SRichard Henderson     return (ctx->tb_flags & PSW_W
529698240d1SRichard Henderson             ? MAKE_64BIT_MASK(0, 62)
530698240d1SRichard Henderson             : MAKE_64BIT_MASK(0, 32));
531698240d1SRichard Henderson }
532698240d1SRichard Henderson 
5336fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest,
5346fd0c7bcSRichard Henderson                             uint64_t ival, TCGv_i64 vval)
53561766fe9SRichard Henderson {
536c53e401eSRichard Henderson     uint64_t mask = gva_offset_mask(ctx);
537f13bf343SRichard Henderson 
538f13bf343SRichard Henderson     if (ival != -1) {
5396fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, ival & mask);
540f13bf343SRichard Henderson         return;
541f13bf343SRichard Henderson     }
542f13bf343SRichard Henderson     tcg_debug_assert(vval != NULL);
543f13bf343SRichard Henderson 
544f13bf343SRichard Henderson     /*
545f13bf343SRichard Henderson      * We know that the IAOQ is already properly masked.
546f13bf343SRichard Henderson      * This optimization is primarily for "iaoq_f = iaoq_b".
547f13bf343SRichard Henderson      */
548f13bf343SRichard Henderson     if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) {
5496fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, vval);
55061766fe9SRichard Henderson     } else {
5516fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, vval, mask);
55261766fe9SRichard Henderson     }
55361766fe9SRichard Henderson }
55461766fe9SRichard Henderson 
555c53e401eSRichard Henderson static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp)
55661766fe9SRichard Henderson {
55761766fe9SRichard Henderson     return ctx->iaoq_f + disp + 8;
55861766fe9SRichard Henderson }
55961766fe9SRichard Henderson 
56061766fe9SRichard Henderson static void gen_excp_1(int exception)
56161766fe9SRichard Henderson {
562ad75a51eSRichard Henderson     gen_helper_excp(tcg_env, tcg_constant_i32(exception));
56361766fe9SRichard Henderson }
56461766fe9SRichard Henderson 
56531234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception)
56661766fe9SRichard Henderson {
567741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
568741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
569129e9cc3SRichard Henderson     nullify_save(ctx);
57061766fe9SRichard Henderson     gen_excp_1(exception);
57131234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
57261766fe9SRichard Henderson }
57361766fe9SRichard Henderson 
57431234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc)
5751a19da0dSRichard Henderson {
57631234768SRichard Henderson     nullify_over(ctx);
5776fd0c7bcSRichard Henderson     tcg_gen_st_i64(tcg_constant_i64(ctx->insn),
578ad75a51eSRichard Henderson                    tcg_env, offsetof(CPUHPPAState, cr[CR_IIR]));
57931234768SRichard Henderson     gen_excp(ctx, exc);
58031234768SRichard Henderson     return nullify_end(ctx);
5811a19da0dSRichard Henderson }
5821a19da0dSRichard Henderson 
58331234768SRichard Henderson static bool gen_illegal(DisasContext *ctx)
58461766fe9SRichard Henderson {
58531234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_ILL);
58661766fe9SRichard Henderson }
58761766fe9SRichard Henderson 
58840f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY
58940f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
59040f9f908SRichard Henderson     return gen_excp_iir(ctx, EXCP)
59140f9f908SRichard Henderson #else
592e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
593e1b5a5edSRichard Henderson     do {                                     \
594e1b5a5edSRichard Henderson         if (ctx->privilege != 0) {           \
59531234768SRichard Henderson             return gen_excp_iir(ctx, EXCP);  \
596e1b5a5edSRichard Henderson         }                                    \
597e1b5a5edSRichard Henderson     } while (0)
59840f9f908SRichard Henderson #endif
599e1b5a5edSRichard Henderson 
600c53e401eSRichard Henderson static bool use_goto_tb(DisasContext *ctx, uint64_t dest)
60161766fe9SRichard Henderson {
60257f91498SRichard Henderson     return translator_use_goto_tb(&ctx->base, dest);
60361766fe9SRichard Henderson }
60461766fe9SRichard Henderson 
605129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page,
606129e9cc3SRichard Henderson    and we're not attempting to set a breakpoint on it, then we can
607129e9cc3SRichard Henderson    totally skip the nullified insn.  This avoids creating and
608129e9cc3SRichard Henderson    executing a TB that merely branches to the next TB.  */
609129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx)
610129e9cc3SRichard Henderson {
611129e9cc3SRichard Henderson     return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
612129e9cc3SRichard Henderson             && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
613129e9cc3SRichard Henderson }
614129e9cc3SRichard Henderson 
61561766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which,
616c53e401eSRichard Henderson                         uint64_t f, uint64_t b)
61761766fe9SRichard Henderson {
61861766fe9SRichard Henderson     if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
61961766fe9SRichard Henderson         tcg_gen_goto_tb(which);
620a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, f, NULL);
621a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, b, NULL);
62207ea28b4SRichard Henderson         tcg_gen_exit_tb(ctx->base.tb, which);
62361766fe9SRichard Henderson     } else {
624741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, f, cpu_iaoq_b);
625741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, b, ctx->iaoq_n_var);
6267f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
62761766fe9SRichard Henderson     }
62861766fe9SRichard Henderson }
62961766fe9SRichard Henderson 
630b47a4a02SSven Schnelle static bool cond_need_sv(int c)
631b47a4a02SSven Schnelle {
632b47a4a02SSven Schnelle     return c == 2 || c == 3 || c == 6;
633b47a4a02SSven Schnelle }
634b47a4a02SSven Schnelle 
635b47a4a02SSven Schnelle static bool cond_need_cb(int c)
636b47a4a02SSven Schnelle {
637b47a4a02SSven Schnelle     return c == 4 || c == 5;
638b47a4a02SSven Schnelle }
639b47a4a02SSven Schnelle 
6406fd0c7bcSRichard Henderson /* Need extensions from TCGv_i32 to TCGv_i64. */
64172ca8753SRichard Henderson static bool cond_need_ext(DisasContext *ctx, bool d)
64272ca8753SRichard Henderson {
643c53e401eSRichard Henderson     return !(ctx->is_pa20 && d);
64472ca8753SRichard Henderson }
64572ca8753SRichard Henderson 
646b47a4a02SSven Schnelle /*
647b47a4a02SSven Schnelle  * Compute conditional for arithmetic.  See Page 5-3, Table 5-1, of
648b47a4a02SSven Schnelle  * the Parisc 1.1 Architecture Reference Manual for details.
649b47a4a02SSven Schnelle  */
650b2167459SRichard Henderson 
651a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d,
6526fd0c7bcSRichard Henderson                          TCGv_i64 res, TCGv_i64 cb_msb, TCGv_i64 sv)
653b2167459SRichard Henderson {
654b2167459SRichard Henderson     DisasCond cond;
6556fd0c7bcSRichard Henderson     TCGv_i64 tmp;
656b2167459SRichard Henderson 
657b2167459SRichard Henderson     switch (cf >> 1) {
658b47a4a02SSven Schnelle     case 0: /* Never / TR    (0 / 1) */
659b2167459SRichard Henderson         cond = cond_make_f();
660b2167459SRichard Henderson         break;
661b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
662a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
663aac0f603SRichard Henderson             tmp = tcg_temp_new_i64();
6646fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
665a751eb31SRichard Henderson             res = tmp;
666a751eb31SRichard Henderson         }
667b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, res);
668b2167459SRichard Henderson         break;
669b47a4a02SSven Schnelle     case 2: /* < / >=        (N ^ V / !(N ^ V) */
670aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
6716fd0c7bcSRichard Henderson         tcg_gen_xor_i64(tmp, res, sv);
672a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
6736fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, tmp);
674a751eb31SRichard Henderson         }
675b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_LT, tmp);
676b2167459SRichard Henderson         break;
677b47a4a02SSven Schnelle     case 3: /* <= / >        (N ^ V) | Z / !((N ^ V) | Z) */
678b47a4a02SSven Schnelle         /*
679b47a4a02SSven Schnelle          * Simplify:
680b47a4a02SSven Schnelle          *   (N ^ V) | Z
681b47a4a02SSven Schnelle          *   ((res < 0) ^ (sv < 0)) | !res
682b47a4a02SSven Schnelle          *   ((res ^ sv) < 0) | !res
683b47a4a02SSven Schnelle          *   (~(res ^ sv) >= 0) | !res
684b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31) | !res
685b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31 & res)
686b47a4a02SSven Schnelle          */
687aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
6886fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(tmp, res, sv);
689a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
6906fd0c7bcSRichard Henderson             tcg_gen_sextract_i64(tmp, tmp, 31, 1);
6916fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
6926fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
693a751eb31SRichard Henderson         } else {
6946fd0c7bcSRichard Henderson             tcg_gen_sari_i64(tmp, tmp, 63);
6956fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
696a751eb31SRichard Henderson         }
697b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
698b2167459SRichard Henderson         break;
699b2167459SRichard Henderson     case 4: /* NUV / UV      (!C / C) */
700a751eb31SRichard Henderson         /* Only bit 0 of cb_msb is ever set. */
701b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, cb_msb);
702b2167459SRichard Henderson         break;
703b2167459SRichard Henderson     case 5: /* ZNV / VNZ     (!C | Z / C & !Z) */
704aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
7056fd0c7bcSRichard Henderson         tcg_gen_neg_i64(tmp, cb_msb);
7066fd0c7bcSRichard Henderson         tcg_gen_and_i64(tmp, tmp, res);
707a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
7086fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
709a751eb31SRichard Henderson         }
710b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
711b2167459SRichard Henderson         break;
712b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
713a751eb31SRichard Henderson         if (cond_need_ext(ctx, d)) {
714aac0f603SRichard Henderson             tmp = tcg_temp_new_i64();
7156fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, sv);
716a751eb31SRichard Henderson             sv = tmp;
717a751eb31SRichard Henderson         }
718b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, sv);
719b2167459SRichard Henderson         break;
720b2167459SRichard Henderson     case 7: /* OD / EV */
721aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
7226fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, res, 1);
723b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_NE, tmp);
724b2167459SRichard Henderson         break;
725b2167459SRichard Henderson     default:
726b2167459SRichard Henderson         g_assert_not_reached();
727b2167459SRichard Henderson     }
728b2167459SRichard Henderson     if (cf & 1) {
729b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
730b2167459SRichard Henderson     }
731b2167459SRichard Henderson 
732b2167459SRichard Henderson     return cond;
733b2167459SRichard Henderson }
734b2167459SRichard Henderson 
735b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
736b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
737b2167459SRichard Henderson    deleted as unused.  */
738b2167459SRichard Henderson 
7394fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d,
7406fd0c7bcSRichard Henderson                              TCGv_i64 res, TCGv_i64 in1,
7416fd0c7bcSRichard Henderson                              TCGv_i64 in2, TCGv_i64 sv)
742b2167459SRichard Henderson {
7434fe9533aSRichard Henderson     TCGCond tc;
7444fe9533aSRichard Henderson     bool ext_uns;
745b2167459SRichard Henderson 
746b2167459SRichard Henderson     switch (cf >> 1) {
747b2167459SRichard Henderson     case 1: /* = / <> */
7484fe9533aSRichard Henderson         tc = TCG_COND_EQ;
7494fe9533aSRichard Henderson         ext_uns = true;
750b2167459SRichard Henderson         break;
751b2167459SRichard Henderson     case 2: /* < / >= */
7524fe9533aSRichard Henderson         tc = TCG_COND_LT;
7534fe9533aSRichard Henderson         ext_uns = false;
754b2167459SRichard Henderson         break;
755b2167459SRichard Henderson     case 3: /* <= / > */
7564fe9533aSRichard Henderson         tc = TCG_COND_LE;
7574fe9533aSRichard Henderson         ext_uns = false;
758b2167459SRichard Henderson         break;
759b2167459SRichard Henderson     case 4: /* << / >>= */
7604fe9533aSRichard Henderson         tc = TCG_COND_LTU;
7614fe9533aSRichard Henderson         ext_uns = true;
762b2167459SRichard Henderson         break;
763b2167459SRichard Henderson     case 5: /* <<= / >> */
7644fe9533aSRichard Henderson         tc = TCG_COND_LEU;
7654fe9533aSRichard Henderson         ext_uns = true;
766b2167459SRichard Henderson         break;
767b2167459SRichard Henderson     default:
768a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, sv);
769b2167459SRichard Henderson     }
770b2167459SRichard Henderson 
7714fe9533aSRichard Henderson     if (cf & 1) {
7724fe9533aSRichard Henderson         tc = tcg_invert_cond(tc);
7734fe9533aSRichard Henderson     }
7744fe9533aSRichard Henderson     if (cond_need_ext(ctx, d)) {
775aac0f603SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
776aac0f603SRichard Henderson         TCGv_i64 t2 = tcg_temp_new_i64();
7774fe9533aSRichard Henderson 
7784fe9533aSRichard Henderson         if (ext_uns) {
7796fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t1, in1);
7806fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t2, in2);
7814fe9533aSRichard Henderson         } else {
7826fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t1, in1);
7836fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t2, in2);
7844fe9533aSRichard Henderson         }
7854fe9533aSRichard Henderson         return cond_make_tmp(tc, t1, t2);
7864fe9533aSRichard Henderson     }
7874fe9533aSRichard Henderson     return cond_make(tc, in1, in2);
788b2167459SRichard Henderson }
789b2167459SRichard Henderson 
790df0232feSRichard Henderson /*
791df0232feSRichard Henderson  * Similar, but for logicals, where the carry and overflow bits are not
792df0232feSRichard Henderson  * computed, and use of them is undefined.
793df0232feSRichard Henderson  *
794df0232feSRichard Henderson  * Undefined or not, hardware does not trap.  It seems reasonable to
795df0232feSRichard Henderson  * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's
796df0232feSRichard Henderson  * how cases c={2,3} are treated.
797df0232feSRichard Henderson  */
798b2167459SRichard Henderson 
799b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d,
8006fd0c7bcSRichard Henderson                              TCGv_i64 res)
801b2167459SRichard Henderson {
802b5af8423SRichard Henderson     TCGCond tc;
803b5af8423SRichard Henderson     bool ext_uns;
804a751eb31SRichard Henderson 
805df0232feSRichard Henderson     switch (cf) {
806df0232feSRichard Henderson     case 0:  /* never */
807df0232feSRichard Henderson     case 9:  /* undef, C */
808df0232feSRichard Henderson     case 11: /* undef, C & !Z */
809df0232feSRichard Henderson     case 12: /* undef, V */
810df0232feSRichard Henderson         return cond_make_f();
811df0232feSRichard Henderson 
812df0232feSRichard Henderson     case 1:  /* true */
813df0232feSRichard Henderson     case 8:  /* undef, !C */
814df0232feSRichard Henderson     case 10: /* undef, !C | Z */
815df0232feSRichard Henderson     case 13: /* undef, !V */
816df0232feSRichard Henderson         return cond_make_t();
817df0232feSRichard Henderson 
818df0232feSRichard Henderson     case 2:  /* == */
819b5af8423SRichard Henderson         tc = TCG_COND_EQ;
820b5af8423SRichard Henderson         ext_uns = true;
821b5af8423SRichard Henderson         break;
822df0232feSRichard Henderson     case 3:  /* <> */
823b5af8423SRichard Henderson         tc = TCG_COND_NE;
824b5af8423SRichard Henderson         ext_uns = true;
825b5af8423SRichard Henderson         break;
826df0232feSRichard Henderson     case 4:  /* < */
827b5af8423SRichard Henderson         tc = TCG_COND_LT;
828b5af8423SRichard Henderson         ext_uns = false;
829b5af8423SRichard Henderson         break;
830df0232feSRichard Henderson     case 5:  /* >= */
831b5af8423SRichard Henderson         tc = TCG_COND_GE;
832b5af8423SRichard Henderson         ext_uns = false;
833b5af8423SRichard Henderson         break;
834df0232feSRichard Henderson     case 6:  /* <= */
835b5af8423SRichard Henderson         tc = TCG_COND_LE;
836b5af8423SRichard Henderson         ext_uns = false;
837b5af8423SRichard Henderson         break;
838df0232feSRichard Henderson     case 7:  /* > */
839b5af8423SRichard Henderson         tc = TCG_COND_GT;
840b5af8423SRichard Henderson         ext_uns = false;
841b5af8423SRichard Henderson         break;
842df0232feSRichard Henderson 
843df0232feSRichard Henderson     case 14: /* OD */
844df0232feSRichard Henderson     case 15: /* EV */
845a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, NULL);
846df0232feSRichard Henderson 
847df0232feSRichard Henderson     default:
848df0232feSRichard Henderson         g_assert_not_reached();
849b2167459SRichard Henderson     }
850b5af8423SRichard Henderson 
851b5af8423SRichard Henderson     if (cond_need_ext(ctx, d)) {
852aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
853b5af8423SRichard Henderson 
854b5af8423SRichard Henderson         if (ext_uns) {
8556fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
856b5af8423SRichard Henderson         } else {
8576fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, res);
858b5af8423SRichard Henderson         }
859b5af8423SRichard Henderson         return cond_make_0_tmp(tc, tmp);
860b5af8423SRichard Henderson     }
861b5af8423SRichard Henderson     return cond_make_0(tc, res);
862b2167459SRichard Henderson }
863b2167459SRichard Henderson 
86498cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
86598cd9ca7SRichard Henderson 
8664fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d,
8676fd0c7bcSRichard Henderson                              TCGv_i64 res)
86898cd9ca7SRichard Henderson {
86998cd9ca7SRichard Henderson     unsigned c, f;
87098cd9ca7SRichard Henderson 
87198cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
87298cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
87398cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
87498cd9ca7SRichard Henderson     c = orig & 3;
87598cd9ca7SRichard Henderson     if (c == 3) {
87698cd9ca7SRichard Henderson         c = 7;
87798cd9ca7SRichard Henderson     }
87898cd9ca7SRichard Henderson     f = (orig & 4) / 4;
87998cd9ca7SRichard Henderson 
880b5af8423SRichard Henderson     return do_log_cond(ctx, c * 2 + f, d, res);
88198cd9ca7SRichard Henderson }
88298cd9ca7SRichard Henderson 
883b2167459SRichard Henderson /* Similar, but for unit conditions.  */
884b2167459SRichard Henderson 
8856fd0c7bcSRichard Henderson static DisasCond do_unit_cond(unsigned cf, bool d, TCGv_i64 res,
8866fd0c7bcSRichard Henderson                               TCGv_i64 in1, TCGv_i64 in2)
887b2167459SRichard Henderson {
888b2167459SRichard Henderson     DisasCond cond;
8896fd0c7bcSRichard Henderson     TCGv_i64 tmp, cb = NULL;
890c53e401eSRichard Henderson     uint64_t d_repl = d ? 0x0000000100000001ull : 1;
891b2167459SRichard Henderson 
892b2167459SRichard Henderson     if (cf & 8) {
893b2167459SRichard Henderson         /* Since we want to test lots of carry-out bits all at once, do not
894b2167459SRichard Henderson          * do our normal thing and compute carry-in of bit B+1 since that
895b2167459SRichard Henderson          * leaves us with carry bits spread across two words.
896b2167459SRichard Henderson          */
897aac0f603SRichard Henderson         cb = tcg_temp_new_i64();
898aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
8996fd0c7bcSRichard Henderson         tcg_gen_or_i64(cb, in1, in2);
9006fd0c7bcSRichard Henderson         tcg_gen_and_i64(tmp, in1, in2);
9016fd0c7bcSRichard Henderson         tcg_gen_andc_i64(cb, cb, res);
9026fd0c7bcSRichard Henderson         tcg_gen_or_i64(cb, cb, tmp);
903b2167459SRichard Henderson     }
904b2167459SRichard Henderson 
905b2167459SRichard Henderson     switch (cf >> 1) {
906b2167459SRichard Henderson     case 0: /* never / TR */
907b2167459SRichard Henderson     case 1: /* undefined */
908b2167459SRichard Henderson     case 5: /* undefined */
909b2167459SRichard Henderson         cond = cond_make_f();
910b2167459SRichard Henderson         break;
911b2167459SRichard Henderson 
912b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
913b2167459SRichard Henderson         /* See hasless(v,1) from
914b2167459SRichard Henderson          * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
915b2167459SRichard Henderson          */
916aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
9176fd0c7bcSRichard Henderson         tcg_gen_subi_i64(tmp, res, d_repl * 0x01010101u);
9186fd0c7bcSRichard Henderson         tcg_gen_andc_i64(tmp, tmp, res);
9196fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80808080u);
920b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
921b2167459SRichard Henderson         break;
922b2167459SRichard Henderson 
923b2167459SRichard Henderson     case 3: /* SHZ / NHZ */
924aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
9256fd0c7bcSRichard Henderson         tcg_gen_subi_i64(tmp, res, d_repl * 0x00010001u);
9266fd0c7bcSRichard Henderson         tcg_gen_andc_i64(tmp, tmp, res);
9276fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80008000u);
928b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
929b2167459SRichard Henderson         break;
930b2167459SRichard Henderson 
931b2167459SRichard Henderson     case 4: /* SDC / NDC */
9326fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x88888888u);
933b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
934b2167459SRichard Henderson         break;
935b2167459SRichard Henderson 
936b2167459SRichard Henderson     case 6: /* SBC / NBC */
9376fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x80808080u);
938b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
939b2167459SRichard Henderson         break;
940b2167459SRichard Henderson 
941b2167459SRichard Henderson     case 7: /* SHC / NHC */
9426fd0c7bcSRichard Henderson         tcg_gen_andi_i64(cb, cb, d_repl * 0x80008000u);
943b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
944b2167459SRichard Henderson         break;
945b2167459SRichard Henderson 
946b2167459SRichard Henderson     default:
947b2167459SRichard Henderson         g_assert_not_reached();
948b2167459SRichard Henderson     }
949b2167459SRichard Henderson     if (cf & 1) {
950b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
951b2167459SRichard Henderson     }
952b2167459SRichard Henderson 
953b2167459SRichard Henderson     return cond;
954b2167459SRichard Henderson }
955b2167459SRichard Henderson 
9566fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d,
9576fd0c7bcSRichard Henderson                           TCGv_i64 cb, TCGv_i64 cb_msb)
95872ca8753SRichard Henderson {
95972ca8753SRichard Henderson     if (cond_need_ext(ctx, d)) {
960aac0f603SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
9616fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, cb, 32, 1);
96272ca8753SRichard Henderson         return t;
96372ca8753SRichard Henderson     }
96472ca8753SRichard Henderson     return cb_msb;
96572ca8753SRichard Henderson }
96672ca8753SRichard Henderson 
9676fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d)
96872ca8753SRichard Henderson {
96972ca8753SRichard Henderson     return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb);
97072ca8753SRichard Henderson }
97172ca8753SRichard Henderson 
972b2167459SRichard Henderson /* Compute signed overflow for addition.  */
9736fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res,
9746fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
975b2167459SRichard Henderson {
976aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
977aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
978b2167459SRichard Henderson 
9796fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
9806fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
9816fd0c7bcSRichard Henderson     tcg_gen_andc_i64(sv, sv, tmp);
982b2167459SRichard Henderson 
983b2167459SRichard Henderson     return sv;
984b2167459SRichard Henderson }
985b2167459SRichard Henderson 
986b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
9876fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res,
9886fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
989b2167459SRichard Henderson {
990aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
991aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
992b2167459SRichard Henderson 
9936fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
9946fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
9956fd0c7bcSRichard Henderson     tcg_gen_and_i64(sv, sv, tmp);
996b2167459SRichard Henderson 
997b2167459SRichard Henderson     return sv;
998b2167459SRichard Henderson }
999b2167459SRichard Henderson 
10006fd0c7bcSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
10016fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned shift, bool is_l,
1002faf97ba1SRichard Henderson                    bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d)
1003b2167459SRichard Henderson {
10046fd0c7bcSRichard Henderson     TCGv_i64 dest, cb, cb_msb, cb_cond, sv, tmp;
1005b2167459SRichard Henderson     unsigned c = cf >> 1;
1006b2167459SRichard Henderson     DisasCond cond;
1007b2167459SRichard Henderson 
1008aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1009f764718dSRichard Henderson     cb = NULL;
1010f764718dSRichard Henderson     cb_msb = NULL;
1011bdcccc17SRichard Henderson     cb_cond = NULL;
1012b2167459SRichard Henderson 
1013b2167459SRichard Henderson     if (shift) {
1014aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
10156fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, in1, shift);
1016b2167459SRichard Henderson         in1 = tmp;
1017b2167459SRichard Henderson     }
1018b2167459SRichard Henderson 
1019b47a4a02SSven Schnelle     if (!is_l || cond_need_cb(c)) {
10206fd0c7bcSRichard Henderson         TCGv_i64 zero = tcg_constant_i64(0);
1021aac0f603SRichard Henderson         cb_msb = tcg_temp_new_i64();
1022aac0f603SRichard Henderson         cb = tcg_temp_new_i64();
1023bdcccc17SRichard Henderson 
10246fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, zero, in2, zero);
1025b2167459SRichard Henderson         if (is_c) {
10266fd0c7bcSRichard Henderson             tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb,
1027bdcccc17SRichard Henderson                              get_psw_carry(ctx, d), zero);
1028b2167459SRichard Henderson         }
10296fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
10306fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1031bdcccc17SRichard Henderson         if (cond_need_cb(c)) {
1032bdcccc17SRichard Henderson             cb_cond = get_carry(ctx, d, cb, cb_msb);
1033b2167459SRichard Henderson         }
1034b2167459SRichard Henderson     } else {
10356fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
1036b2167459SRichard Henderson         if (is_c) {
10376fd0c7bcSRichard Henderson             tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d));
1038b2167459SRichard Henderson         }
1039b2167459SRichard Henderson     }
1040b2167459SRichard Henderson 
1041b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1042f764718dSRichard Henderson     sv = NULL;
1043b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1044b2167459SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
1045b2167459SRichard Henderson         if (is_tsv) {
1046b2167459SRichard Henderson             /* ??? Need to include overflow from shift.  */
1047ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1048b2167459SRichard Henderson         }
1049b2167459SRichard Henderson     }
1050b2167459SRichard Henderson 
1051b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1052a751eb31SRichard Henderson     cond = do_cond(ctx, cf, d, dest, cb_cond, sv);
1053b2167459SRichard Henderson     if (is_tc) {
1054aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
10556fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1056ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1057b2167459SRichard Henderson     }
1058b2167459SRichard Henderson 
1059b2167459SRichard Henderson     /* Write back the result.  */
1060b2167459SRichard Henderson     if (!is_l) {
1061b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
1062b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1063b2167459SRichard Henderson     }
1064b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1065b2167459SRichard Henderson 
1066b2167459SRichard Henderson     /* Install the new nullification.  */
1067b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1068b2167459SRichard Henderson     ctx->null_cond = cond;
1069b2167459SRichard Henderson }
1070b2167459SRichard Henderson 
1071faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a,
10720c982a28SRichard Henderson                        bool is_l, bool is_tsv, bool is_tc, bool is_c)
10730c982a28SRichard Henderson {
10746fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
10750c982a28SRichard Henderson 
10760c982a28SRichard Henderson     if (a->cf) {
10770c982a28SRichard Henderson         nullify_over(ctx);
10780c982a28SRichard Henderson     }
10790c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
10800c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1081faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l,
1082faf97ba1SRichard Henderson            is_tsv, is_tc, is_c, a->cf, a->d);
10830c982a28SRichard Henderson     return nullify_end(ctx);
10840c982a28SRichard Henderson }
10850c982a28SRichard Henderson 
10860588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a,
10870588e061SRichard Henderson                        bool is_tsv, bool is_tc)
10880588e061SRichard Henderson {
10896fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
10900588e061SRichard Henderson 
10910588e061SRichard Henderson     if (a->cf) {
10920588e061SRichard Henderson         nullify_over(ctx);
10930588e061SRichard Henderson     }
10946fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
10950588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
1096faf97ba1SRichard Henderson     /* All ADDI conditions are 32-bit. */
1097faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false);
10980588e061SRichard Henderson     return nullify_end(ctx);
10990588e061SRichard Henderson }
11000588e061SRichard Henderson 
11016fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
11026fd0c7bcSRichard Henderson                    TCGv_i64 in2, bool is_tsv, bool is_b,
110363c427c6SRichard Henderson                    bool is_tc, unsigned cf, bool d)
1104b2167459SRichard Henderson {
11056fd0c7bcSRichard Henderson     TCGv_i64 dest, sv, cb, cb_msb, zero, tmp;
1106b2167459SRichard Henderson     unsigned c = cf >> 1;
1107b2167459SRichard Henderson     DisasCond cond;
1108b2167459SRichard Henderson 
1109aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1110aac0f603SRichard Henderson     cb = tcg_temp_new_i64();
1111aac0f603SRichard Henderson     cb_msb = tcg_temp_new_i64();
1112b2167459SRichard Henderson 
11136fd0c7bcSRichard Henderson     zero = tcg_constant_i64(0);
1114b2167459SRichard Henderson     if (is_b) {
1115b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
11166fd0c7bcSRichard Henderson         tcg_gen_not_i64(cb, in2);
11176fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, zero, get_psw_carry(ctx, d), zero);
11186fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, zero);
11196fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, in1);
11206fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1121b2167459SRichard Henderson     } else {
1122bdcccc17SRichard Henderson         /*
1123bdcccc17SRichard Henderson          * DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
1124bdcccc17SRichard Henderson          * operations by seeding the high word with 1 and subtracting.
1125bdcccc17SRichard Henderson          */
11266fd0c7bcSRichard Henderson         TCGv_i64 one = tcg_constant_i64(1);
11276fd0c7bcSRichard Henderson         tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, zero);
11286fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(cb, in1, in2);
11296fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1130b2167459SRichard Henderson     }
1131b2167459SRichard Henderson 
1132b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1133f764718dSRichard Henderson     sv = NULL;
1134b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1135b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1136b2167459SRichard Henderson         if (is_tsv) {
1137ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1138b2167459SRichard Henderson         }
1139b2167459SRichard Henderson     }
1140b2167459SRichard Henderson 
1141b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
1142b2167459SRichard Henderson     if (!is_b) {
11434fe9533aSRichard Henderson         cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1144b2167459SRichard Henderson     } else {
1145a751eb31SRichard Henderson         cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv);
1146b2167459SRichard Henderson     }
1147b2167459SRichard Henderson 
1148b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1149b2167459SRichard Henderson     if (is_tc) {
1150aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
11516fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1152ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1153b2167459SRichard Henderson     }
1154b2167459SRichard Henderson 
1155b2167459SRichard Henderson     /* Write back the result.  */
1156b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
1157b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1158b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1159b2167459SRichard Henderson 
1160b2167459SRichard Henderson     /* Install the new nullification.  */
1161b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1162b2167459SRichard Henderson     ctx->null_cond = cond;
1163b2167459SRichard Henderson }
1164b2167459SRichard Henderson 
116563c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a,
11660c982a28SRichard Henderson                        bool is_tsv, bool is_b, bool is_tc)
11670c982a28SRichard Henderson {
11686fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
11690c982a28SRichard Henderson 
11700c982a28SRichard Henderson     if (a->cf) {
11710c982a28SRichard Henderson         nullify_over(ctx);
11720c982a28SRichard Henderson     }
11730c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
11740c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
117563c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d);
11760c982a28SRichard Henderson     return nullify_end(ctx);
11770c982a28SRichard Henderson }
11780c982a28SRichard Henderson 
11790588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv)
11800588e061SRichard Henderson {
11816fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
11820588e061SRichard Henderson 
11830588e061SRichard Henderson     if (a->cf) {
11840588e061SRichard Henderson         nullify_over(ctx);
11850588e061SRichard Henderson     }
11866fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
11870588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
118863c427c6SRichard Henderson     /* All SUBI conditions are 32-bit. */
118963c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false);
11900588e061SRichard Henderson     return nullify_end(ctx);
11910588e061SRichard Henderson }
11920588e061SRichard Henderson 
11936fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
11946fd0c7bcSRichard Henderson                       TCGv_i64 in2, unsigned cf, bool d)
1195b2167459SRichard Henderson {
11966fd0c7bcSRichard Henderson     TCGv_i64 dest, sv;
1197b2167459SRichard Henderson     DisasCond cond;
1198b2167459SRichard Henderson 
1199aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
12006fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
1201b2167459SRichard Henderson 
1202b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1203f764718dSRichard Henderson     sv = NULL;
1204b47a4a02SSven Schnelle     if (cond_need_sv(cf >> 1)) {
1205b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1206b2167459SRichard Henderson     }
1207b2167459SRichard Henderson 
1208b2167459SRichard Henderson     /* Form the condition for the compare.  */
12094fe9533aSRichard Henderson     cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1210b2167459SRichard Henderson 
1211b2167459SRichard Henderson     /* Clear.  */
12126fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
1213b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1214b2167459SRichard Henderson 
1215b2167459SRichard Henderson     /* Install the new nullification.  */
1216b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1217b2167459SRichard Henderson     ctx->null_cond = cond;
1218b2167459SRichard Henderson }
1219b2167459SRichard Henderson 
12206fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12216fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned cf, bool d,
12226fd0c7bcSRichard Henderson                    void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1223b2167459SRichard Henderson {
12246fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, rt);
1225b2167459SRichard Henderson 
1226b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
1227b2167459SRichard Henderson     fn(dest, in1, in2);
1228b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1229b2167459SRichard Henderson 
1230b2167459SRichard Henderson     /* Install the new nullification.  */
1231b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1232b2167459SRichard Henderson     if (cf) {
1233b5af8423SRichard Henderson         ctx->null_cond = do_log_cond(ctx, cf, d, dest);
1234b2167459SRichard Henderson     }
1235b2167459SRichard Henderson }
1236b2167459SRichard Henderson 
1237fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a,
12386fd0c7bcSRichard Henderson                        void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
12390c982a28SRichard Henderson {
12406fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
12410c982a28SRichard Henderson 
12420c982a28SRichard Henderson     if (a->cf) {
12430c982a28SRichard Henderson         nullify_over(ctx);
12440c982a28SRichard Henderson     }
12450c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
12460c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1247fa8e3bedSRichard Henderson     do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn);
12480c982a28SRichard Henderson     return nullify_end(ctx);
12490c982a28SRichard Henderson }
12500c982a28SRichard Henderson 
12516fd0c7bcSRichard Henderson static void do_unit(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12526fd0c7bcSRichard Henderson                     TCGv_i64 in2, unsigned cf, bool d, bool is_tc,
12536fd0c7bcSRichard Henderson                     void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1254b2167459SRichard Henderson {
12556fd0c7bcSRichard Henderson     TCGv_i64 dest;
1256b2167459SRichard Henderson     DisasCond cond;
1257b2167459SRichard Henderson 
1258b2167459SRichard Henderson     if (cf == 0) {
1259b2167459SRichard Henderson         dest = dest_gpr(ctx, rt);
1260b2167459SRichard Henderson         fn(dest, in1, in2);
1261b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1262b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1263b2167459SRichard Henderson     } else {
1264aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
1265b2167459SRichard Henderson         fn(dest, in1, in2);
1266b2167459SRichard Henderson 
126759963d8fSRichard Henderson         cond = do_unit_cond(cf, d, dest, in1, in2);
1268b2167459SRichard Henderson 
1269b2167459SRichard Henderson         if (is_tc) {
1270aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
12716fd0c7bcSRichard Henderson             tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1272ad75a51eSRichard Henderson             gen_helper_tcond(tcg_env, tmp);
1273b2167459SRichard Henderson         }
1274b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1275b2167459SRichard Henderson 
1276b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1277b2167459SRichard Henderson         ctx->null_cond = cond;
1278b2167459SRichard Henderson     }
1279b2167459SRichard Henderson }
1280b2167459SRichard Henderson 
128186f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY
12828d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space
12838d6ae7fbSRichard Henderson    from the top 2 bits of the base register.  There are a few system
12848d6ae7fbSRichard Henderson    instructions that have a 3-bit space specifier, for which SR0 is
12858d6ae7fbSRichard Henderson    not special.  To handle this, pass ~SP.  */
12866fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base)
128786f8d05fSRichard Henderson {
128886f8d05fSRichard Henderson     TCGv_ptr ptr;
12896fd0c7bcSRichard Henderson     TCGv_i64 tmp;
129086f8d05fSRichard Henderson     TCGv_i64 spc;
129186f8d05fSRichard Henderson 
129286f8d05fSRichard Henderson     if (sp != 0) {
12938d6ae7fbSRichard Henderson         if (sp < 0) {
12948d6ae7fbSRichard Henderson             sp = ~sp;
12958d6ae7fbSRichard Henderson         }
12966fd0c7bcSRichard Henderson         spc = tcg_temp_new_i64();
12978d6ae7fbSRichard Henderson         load_spr(ctx, spc, sp);
12988d6ae7fbSRichard Henderson         return spc;
129986f8d05fSRichard Henderson     }
1300494737b7SRichard Henderson     if (ctx->tb_flags & TB_FLAG_SR_SAME) {
1301494737b7SRichard Henderson         return cpu_srH;
1302494737b7SRichard Henderson     }
130386f8d05fSRichard Henderson 
130486f8d05fSRichard Henderson     ptr = tcg_temp_new_ptr();
1305aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
13066fd0c7bcSRichard Henderson     spc = tcg_temp_new_i64();
130786f8d05fSRichard Henderson 
1308698240d1SRichard Henderson     /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */
13096fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5);
13106fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, 030);
13116fd0c7bcSRichard Henderson     tcg_gen_trunc_i64_ptr(ptr, tmp);
131286f8d05fSRichard Henderson 
1313ad75a51eSRichard Henderson     tcg_gen_add_ptr(ptr, ptr, tcg_env);
131486f8d05fSRichard Henderson     tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4]));
131586f8d05fSRichard Henderson 
131686f8d05fSRichard Henderson     return spc;
131786f8d05fSRichard Henderson }
131886f8d05fSRichard Henderson #endif
131986f8d05fSRichard Henderson 
13206fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
1321c53e401eSRichard Henderson                      unsigned rb, unsigned rx, int scale, int64_t disp,
132286f8d05fSRichard Henderson                      unsigned sp, int modify, bool is_phys)
132386f8d05fSRichard Henderson {
13246fd0c7bcSRichard Henderson     TCGv_i64 base = load_gpr(ctx, rb);
13256fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13266fd0c7bcSRichard Henderson     TCGv_i64 addr;
132786f8d05fSRichard Henderson 
132886f8d05fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
132986f8d05fSRichard Henderson     if (rx) {
1330aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
13316fd0c7bcSRichard Henderson         tcg_gen_shli_i64(ofs, cpu_gr[rx], scale);
13326fd0c7bcSRichard Henderson         tcg_gen_add_i64(ofs, ofs, base);
133386f8d05fSRichard Henderson     } else if (disp || modify) {
1334aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
13356fd0c7bcSRichard Henderson         tcg_gen_addi_i64(ofs, base, disp);
133686f8d05fSRichard Henderson     } else {
133786f8d05fSRichard Henderson         ofs = base;
133886f8d05fSRichard Henderson     }
133986f8d05fSRichard Henderson 
134086f8d05fSRichard Henderson     *pofs = ofs;
13416fd0c7bcSRichard Henderson     *pgva = addr = tcg_temp_new_i64();
1342d265360fSRichard Henderson     tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base, gva_offset_mask(ctx));
1343698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY
134486f8d05fSRichard Henderson     if (!is_phys) {
1345d265360fSRichard Henderson         tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base));
134686f8d05fSRichard Henderson     }
134786f8d05fSRichard Henderson #endif
134886f8d05fSRichard Henderson }
134986f8d05fSRichard Henderson 
135096d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
135196d6407fSRichard Henderson  * < 0 for pre-modify,
135296d6407fSRichard Henderson  * > 0 for post-modify,
135396d6407fSRichard Henderson  * = 0 for no base register update.
135496d6407fSRichard Henderson  */
135596d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1356c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
135714776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
135896d6407fSRichard Henderson {
13596fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13606fd0c7bcSRichard Henderson     TCGv_i64 addr;
136196d6407fSRichard Henderson 
136296d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
136396d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
136496d6407fSRichard Henderson 
136586f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
136686f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1367c1f55d97SRichard Henderson     tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
136886f8d05fSRichard Henderson     if (modify) {
136986f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
137096d6407fSRichard Henderson     }
137196d6407fSRichard Henderson }
137296d6407fSRichard Henderson 
137396d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1374c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
137514776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
137696d6407fSRichard Henderson {
13776fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13786fd0c7bcSRichard Henderson     TCGv_i64 addr;
137996d6407fSRichard Henderson 
138096d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
138196d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
138296d6407fSRichard Henderson 
138386f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
138486f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1385217d1a5eSRichard Henderson     tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
138686f8d05fSRichard Henderson     if (modify) {
138786f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
138896d6407fSRichard Henderson     }
138996d6407fSRichard Henderson }
139096d6407fSRichard Henderson 
139196d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1392c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
139314776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
139496d6407fSRichard Henderson {
13956fd0c7bcSRichard Henderson     TCGv_i64 ofs;
13966fd0c7bcSRichard Henderson     TCGv_i64 addr;
139796d6407fSRichard Henderson 
139896d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
139996d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
140096d6407fSRichard Henderson 
140186f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
140286f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1403217d1a5eSRichard Henderson     tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
140486f8d05fSRichard Henderson     if (modify) {
140586f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
140696d6407fSRichard Henderson     }
140796d6407fSRichard Henderson }
140896d6407fSRichard Henderson 
140996d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1410c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
141114776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
141296d6407fSRichard Henderson {
14136fd0c7bcSRichard Henderson     TCGv_i64 ofs;
14146fd0c7bcSRichard Henderson     TCGv_i64 addr;
141596d6407fSRichard Henderson 
141696d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
141796d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
141896d6407fSRichard Henderson 
141986f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
142086f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
1421217d1a5eSRichard Henderson     tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
142286f8d05fSRichard Henderson     if (modify) {
142386f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
142496d6407fSRichard Henderson     }
142596d6407fSRichard Henderson }
142696d6407fSRichard Henderson 
14271cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1428c53e401eSRichard Henderson                     unsigned rx, int scale, int64_t disp,
142914776ab5STony Nguyen                     unsigned sp, int modify, MemOp mop)
143096d6407fSRichard Henderson {
14316fd0c7bcSRichard Henderson     TCGv_i64 dest;
143296d6407fSRichard Henderson 
143396d6407fSRichard Henderson     nullify_over(ctx);
143496d6407fSRichard Henderson 
143596d6407fSRichard Henderson     if (modify == 0) {
143696d6407fSRichard Henderson         /* No base register update.  */
143796d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
143896d6407fSRichard Henderson     } else {
143996d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
1440aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
144196d6407fSRichard Henderson     }
14426fd0c7bcSRichard Henderson     do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
144396d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
144496d6407fSRichard Henderson 
14451cd012a5SRichard Henderson     return nullify_end(ctx);
144696d6407fSRichard Henderson }
144796d6407fSRichard Henderson 
1448740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
1449c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
145086f8d05fSRichard Henderson                       unsigned sp, int modify)
145196d6407fSRichard Henderson {
145296d6407fSRichard Henderson     TCGv_i32 tmp;
145396d6407fSRichard Henderson 
145496d6407fSRichard Henderson     nullify_over(ctx);
145596d6407fSRichard Henderson 
145696d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
145786f8d05fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
145896d6407fSRichard Henderson     save_frw_i32(rt, tmp);
145996d6407fSRichard Henderson 
146096d6407fSRichard Henderson     if (rt == 0) {
1461ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
146296d6407fSRichard Henderson     }
146396d6407fSRichard Henderson 
1464740038d7SRichard Henderson     return nullify_end(ctx);
146596d6407fSRichard Henderson }
146696d6407fSRichard Henderson 
1467740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a)
1468740038d7SRichard Henderson {
1469740038d7SRichard Henderson     return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1470740038d7SRichard Henderson                      a->disp, a->sp, a->m);
1471740038d7SRichard Henderson }
1472740038d7SRichard Henderson 
1473740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1474c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
147586f8d05fSRichard Henderson                       unsigned sp, int modify)
147696d6407fSRichard Henderson {
147796d6407fSRichard Henderson     TCGv_i64 tmp;
147896d6407fSRichard Henderson 
147996d6407fSRichard Henderson     nullify_over(ctx);
148096d6407fSRichard Henderson 
148196d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
1482fc313c64SFrédéric Pétrot     do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
148396d6407fSRichard Henderson     save_frd(rt, tmp);
148496d6407fSRichard Henderson 
148596d6407fSRichard Henderson     if (rt == 0) {
1486ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
148796d6407fSRichard Henderson     }
148896d6407fSRichard Henderson 
1489740038d7SRichard Henderson     return nullify_end(ctx);
1490740038d7SRichard Henderson }
1491740038d7SRichard Henderson 
1492740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a)
1493740038d7SRichard Henderson {
1494740038d7SRichard Henderson     return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1495740038d7SRichard Henderson                      a->disp, a->sp, a->m);
149696d6407fSRichard Henderson }
149796d6407fSRichard Henderson 
14981cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb,
1499c53e401eSRichard Henderson                      int64_t disp, unsigned sp,
150014776ab5STony Nguyen                      int modify, MemOp mop)
150196d6407fSRichard Henderson {
150296d6407fSRichard Henderson     nullify_over(ctx);
15036fd0c7bcSRichard Henderson     do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
15041cd012a5SRichard Henderson     return nullify_end(ctx);
150596d6407fSRichard Henderson }
150696d6407fSRichard Henderson 
1507740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1508c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
150986f8d05fSRichard Henderson                        unsigned sp, int modify)
151096d6407fSRichard Henderson {
151196d6407fSRichard Henderson     TCGv_i32 tmp;
151296d6407fSRichard Henderson 
151396d6407fSRichard Henderson     nullify_over(ctx);
151496d6407fSRichard Henderson 
151596d6407fSRichard Henderson     tmp = load_frw_i32(rt);
151686f8d05fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
151796d6407fSRichard Henderson 
1518740038d7SRichard Henderson     return nullify_end(ctx);
151996d6407fSRichard Henderson }
152096d6407fSRichard Henderson 
1521740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a)
1522740038d7SRichard Henderson {
1523740038d7SRichard Henderson     return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1524740038d7SRichard Henderson                       a->disp, a->sp, a->m);
1525740038d7SRichard Henderson }
1526740038d7SRichard Henderson 
1527740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1528c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
152986f8d05fSRichard Henderson                        unsigned sp, int modify)
153096d6407fSRichard Henderson {
153196d6407fSRichard Henderson     TCGv_i64 tmp;
153296d6407fSRichard Henderson 
153396d6407fSRichard Henderson     nullify_over(ctx);
153496d6407fSRichard Henderson 
153596d6407fSRichard Henderson     tmp = load_frd(rt);
1536fc313c64SFrédéric Pétrot     do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
153796d6407fSRichard Henderson 
1538740038d7SRichard Henderson     return nullify_end(ctx);
1539740038d7SRichard Henderson }
1540740038d7SRichard Henderson 
1541740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a)
1542740038d7SRichard Henderson {
1543740038d7SRichard Henderson     return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1544740038d7SRichard Henderson                       a->disp, a->sp, a->m);
154596d6407fSRichard Henderson }
154696d6407fSRichard Henderson 
15471ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1548ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1549ebe9383cSRichard Henderson {
1550ebe9383cSRichard Henderson     TCGv_i32 tmp;
1551ebe9383cSRichard Henderson 
1552ebe9383cSRichard Henderson     nullify_over(ctx);
1553ebe9383cSRichard Henderson     tmp = load_frw0_i32(ra);
1554ebe9383cSRichard Henderson 
1555ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1556ebe9383cSRichard Henderson 
1557ebe9383cSRichard Henderson     save_frw_i32(rt, tmp);
15581ca74648SRichard Henderson     return nullify_end(ctx);
1559ebe9383cSRichard Henderson }
1560ebe9383cSRichard Henderson 
15611ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1562ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1563ebe9383cSRichard Henderson {
1564ebe9383cSRichard Henderson     TCGv_i32 dst;
1565ebe9383cSRichard Henderson     TCGv_i64 src;
1566ebe9383cSRichard Henderson 
1567ebe9383cSRichard Henderson     nullify_over(ctx);
1568ebe9383cSRichard Henderson     src = load_frd(ra);
1569ebe9383cSRichard Henderson     dst = tcg_temp_new_i32();
1570ebe9383cSRichard Henderson 
1571ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1572ebe9383cSRichard Henderson 
1573ebe9383cSRichard Henderson     save_frw_i32(rt, dst);
15741ca74648SRichard Henderson     return nullify_end(ctx);
1575ebe9383cSRichard Henderson }
1576ebe9383cSRichard Henderson 
15771ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1578ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1579ebe9383cSRichard Henderson {
1580ebe9383cSRichard Henderson     TCGv_i64 tmp;
1581ebe9383cSRichard Henderson 
1582ebe9383cSRichard Henderson     nullify_over(ctx);
1583ebe9383cSRichard Henderson     tmp = load_frd0(ra);
1584ebe9383cSRichard Henderson 
1585ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1586ebe9383cSRichard Henderson 
1587ebe9383cSRichard Henderson     save_frd(rt, tmp);
15881ca74648SRichard Henderson     return nullify_end(ctx);
1589ebe9383cSRichard Henderson }
1590ebe9383cSRichard Henderson 
15911ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1592ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1593ebe9383cSRichard Henderson {
1594ebe9383cSRichard Henderson     TCGv_i32 src;
1595ebe9383cSRichard Henderson     TCGv_i64 dst;
1596ebe9383cSRichard Henderson 
1597ebe9383cSRichard Henderson     nullify_over(ctx);
1598ebe9383cSRichard Henderson     src = load_frw0_i32(ra);
1599ebe9383cSRichard Henderson     dst = tcg_temp_new_i64();
1600ebe9383cSRichard Henderson 
1601ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1602ebe9383cSRichard Henderson 
1603ebe9383cSRichard Henderson     save_frd(rt, dst);
16041ca74648SRichard Henderson     return nullify_end(ctx);
1605ebe9383cSRichard Henderson }
1606ebe9383cSRichard Henderson 
16071ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt,
1608ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
160931234768SRichard Henderson                         void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
1610ebe9383cSRichard Henderson {
1611ebe9383cSRichard Henderson     TCGv_i32 a, b;
1612ebe9383cSRichard Henderson 
1613ebe9383cSRichard Henderson     nullify_over(ctx);
1614ebe9383cSRichard Henderson     a = load_frw0_i32(ra);
1615ebe9383cSRichard Henderson     b = load_frw0_i32(rb);
1616ebe9383cSRichard Henderson 
1617ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1618ebe9383cSRichard Henderson 
1619ebe9383cSRichard Henderson     save_frw_i32(rt, a);
16201ca74648SRichard Henderson     return nullify_end(ctx);
1621ebe9383cSRichard Henderson }
1622ebe9383cSRichard Henderson 
16231ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt,
1624ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
162531234768SRichard Henderson                         void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
1626ebe9383cSRichard Henderson {
1627ebe9383cSRichard Henderson     TCGv_i64 a, b;
1628ebe9383cSRichard Henderson 
1629ebe9383cSRichard Henderson     nullify_over(ctx);
1630ebe9383cSRichard Henderson     a = load_frd0(ra);
1631ebe9383cSRichard Henderson     b = load_frd0(rb);
1632ebe9383cSRichard Henderson 
1633ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1634ebe9383cSRichard Henderson 
1635ebe9383cSRichard Henderson     save_frd(rt, a);
16361ca74648SRichard Henderson     return nullify_end(ctx);
1637ebe9383cSRichard Henderson }
1638ebe9383cSRichard Henderson 
163998cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
164098cd9ca7SRichard Henderson    have already had nullification handled.  */
1641c53e401eSRichard Henderson static bool do_dbranch(DisasContext *ctx, uint64_t dest,
164298cd9ca7SRichard Henderson                        unsigned link, bool is_n)
164398cd9ca7SRichard Henderson {
164498cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
164598cd9ca7SRichard Henderson         if (link != 0) {
1646741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
164798cd9ca7SRichard Henderson         }
164898cd9ca7SRichard Henderson         ctx->iaoq_n = dest;
164998cd9ca7SRichard Henderson         if (is_n) {
165098cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
165198cd9ca7SRichard Henderson         }
165298cd9ca7SRichard Henderson     } else {
165398cd9ca7SRichard Henderson         nullify_over(ctx);
165498cd9ca7SRichard Henderson 
165598cd9ca7SRichard Henderson         if (link != 0) {
1656741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
165798cd9ca7SRichard Henderson         }
165898cd9ca7SRichard Henderson 
165998cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
166098cd9ca7SRichard Henderson             nullify_set(ctx, 0);
166198cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, dest, dest + 4);
166298cd9ca7SRichard Henderson         } else {
166398cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
166498cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
166598cd9ca7SRichard Henderson         }
166698cd9ca7SRichard Henderson 
166731234768SRichard Henderson         nullify_end(ctx);
166898cd9ca7SRichard Henderson 
166998cd9ca7SRichard Henderson         nullify_set(ctx, 0);
167098cd9ca7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
167131234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
167298cd9ca7SRichard Henderson     }
167301afb7beSRichard Henderson     return true;
167498cd9ca7SRichard Henderson }
167598cd9ca7SRichard Henderson 
167698cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
167798cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
1678c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n,
167998cd9ca7SRichard Henderson                        DisasCond *cond)
168098cd9ca7SRichard Henderson {
1681c53e401eSRichard Henderson     uint64_t dest = iaoq_dest(ctx, disp);
168298cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
168398cd9ca7SRichard Henderson     TCGCond c = cond->c;
168498cd9ca7SRichard Henderson     bool n;
168598cd9ca7SRichard Henderson 
168698cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
168798cd9ca7SRichard Henderson 
168898cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
168998cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
169001afb7beSRichard Henderson         return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
169198cd9ca7SRichard Henderson     }
169298cd9ca7SRichard Henderson     if (c == TCG_COND_NEVER) {
169301afb7beSRichard Henderson         return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
169498cd9ca7SRichard Henderson     }
169598cd9ca7SRichard Henderson 
169698cd9ca7SRichard Henderson     taken = gen_new_label();
16976fd0c7bcSRichard Henderson     tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken);
169898cd9ca7SRichard Henderson     cond_free(cond);
169998cd9ca7SRichard Henderson 
170098cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
170198cd9ca7SRichard Henderson     n = is_n && disp < 0;
170298cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
170398cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1704a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
170598cd9ca7SRichard Henderson     } else {
170698cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
170798cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
170898cd9ca7SRichard Henderson             ctx->null_lab = NULL;
170998cd9ca7SRichard Henderson         }
171098cd9ca7SRichard Henderson         nullify_set(ctx, n);
1711c301f34eSRichard Henderson         if (ctx->iaoq_n == -1) {
1712c301f34eSRichard Henderson             /* The temporary iaoq_n_var died at the branch above.
1713c301f34eSRichard Henderson                Regenerate it here instead of saving it.  */
17146fd0c7bcSRichard Henderson             tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
1715c301f34eSRichard Henderson         }
1716a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
171798cd9ca7SRichard Henderson     }
171898cd9ca7SRichard Henderson 
171998cd9ca7SRichard Henderson     gen_set_label(taken);
172098cd9ca7SRichard Henderson 
172198cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
172298cd9ca7SRichard Henderson     n = is_n && disp >= 0;
172398cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
172498cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1725a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, dest, dest + 4);
172698cd9ca7SRichard Henderson     } else {
172798cd9ca7SRichard Henderson         nullify_set(ctx, n);
1728a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
172998cd9ca7SRichard Henderson     }
173098cd9ca7SRichard Henderson 
173198cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
173298cd9ca7SRichard Henderson     if (ctx->null_lab) {
173398cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
173498cd9ca7SRichard Henderson         ctx->null_lab = NULL;
173531234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
173698cd9ca7SRichard Henderson     } else {
173731234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
173898cd9ca7SRichard Henderson     }
173901afb7beSRichard Henderson     return true;
174098cd9ca7SRichard Henderson }
174198cd9ca7SRichard Henderson 
174298cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target.  This handles
174398cd9ca7SRichard Henderson    nullification of the branch itself.  */
17446fd0c7bcSRichard Henderson static bool do_ibranch(DisasContext *ctx, TCGv_i64 dest,
174598cd9ca7SRichard Henderson                        unsigned link, bool is_n)
174698cd9ca7SRichard Henderson {
17476fd0c7bcSRichard Henderson     TCGv_i64 a0, a1, next, tmp;
174898cd9ca7SRichard Henderson     TCGCond c;
174998cd9ca7SRichard Henderson 
175098cd9ca7SRichard Henderson     assert(ctx->null_lab == NULL);
175198cd9ca7SRichard Henderson 
175298cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
175398cd9ca7SRichard Henderson         if (link != 0) {
1754741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
175598cd9ca7SRichard Henderson         }
1756aac0f603SRichard Henderson         next = tcg_temp_new_i64();
17576fd0c7bcSRichard Henderson         tcg_gen_mov_i64(next, dest);
175898cd9ca7SRichard Henderson         if (is_n) {
1759c301f34eSRichard Henderson             if (use_nullify_skip(ctx)) {
1760a0180973SRichard Henderson                 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, next);
17616fd0c7bcSRichard Henderson                 tcg_gen_addi_i64(next, next, 4);
1762a0180973SRichard Henderson                 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
1763c301f34eSRichard Henderson                 nullify_set(ctx, 0);
176431234768SRichard Henderson                 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
176501afb7beSRichard Henderson                 return true;
1766c301f34eSRichard Henderson             }
176798cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
176898cd9ca7SRichard Henderson         }
1769c301f34eSRichard Henderson         ctx->iaoq_n = -1;
1770c301f34eSRichard Henderson         ctx->iaoq_n_var = next;
177198cd9ca7SRichard Henderson     } else if (is_n && use_nullify_skip(ctx)) {
177298cd9ca7SRichard Henderson         /* The (conditional) branch, B, nullifies the next insn, N,
177398cd9ca7SRichard Henderson            and we're allowed to skip execution N (no single-step or
17744137cb83SRichard Henderson            tracepoint in effect).  Since the goto_ptr that we must use
177598cd9ca7SRichard Henderson            for the indirect branch consumes no special resources, we
177698cd9ca7SRichard Henderson            can (conditionally) skip B and continue execution.  */
177798cd9ca7SRichard Henderson         /* The use_nullify_skip test implies we have a known control path.  */
177898cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_b != -1);
177998cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_n != -1);
178098cd9ca7SRichard Henderson 
178198cd9ca7SRichard Henderson         /* We do have to handle the non-local temporary, DEST, before
178298cd9ca7SRichard Henderson            branching.  Since IOAQ_F is not really live at this point, we
178398cd9ca7SRichard Henderson            can simply store DEST optimistically.  Similarly with IAOQ_B.  */
1784a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, dest);
1785aac0f603SRichard Henderson         next = tcg_temp_new_i64();
17866fd0c7bcSRichard Henderson         tcg_gen_addi_i64(next, dest, 4);
1787a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
178898cd9ca7SRichard Henderson 
178998cd9ca7SRichard Henderson         nullify_over(ctx);
179098cd9ca7SRichard Henderson         if (link != 0) {
17919a91dd84SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
179298cd9ca7SRichard Henderson         }
17937f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
179401afb7beSRichard Henderson         return nullify_end(ctx);
179598cd9ca7SRichard Henderson     } else {
179698cd9ca7SRichard Henderson         c = ctx->null_cond.c;
179798cd9ca7SRichard Henderson         a0 = ctx->null_cond.a0;
179898cd9ca7SRichard Henderson         a1 = ctx->null_cond.a1;
179998cd9ca7SRichard Henderson 
1800aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
1801aac0f603SRichard Henderson         next = tcg_temp_new_i64();
180298cd9ca7SRichard Henderson 
1803741322f4SRichard Henderson         copy_iaoq_entry(ctx, tmp, ctx->iaoq_n, ctx->iaoq_n_var);
18046fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(c, next, a0, a1, tmp, dest);
180598cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
180698cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
180798cd9ca7SRichard Henderson 
180898cd9ca7SRichard Henderson         if (link != 0) {
18096fd0c7bcSRichard Henderson             tcg_gen_movcond_i64(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
181098cd9ca7SRichard Henderson         }
181198cd9ca7SRichard Henderson 
181298cd9ca7SRichard Henderson         if (is_n) {
181398cd9ca7SRichard Henderson             /* The branch nullifies the next insn, which means the state of N
181498cd9ca7SRichard Henderson                after the branch is the inverse of the state of N that applied
181598cd9ca7SRichard Henderson                to the branch.  */
18166fd0c7bcSRichard Henderson             tcg_gen_setcond_i64(tcg_invert_cond(c), cpu_psw_n, a0, a1);
181798cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
181898cd9ca7SRichard Henderson             ctx->null_cond = cond_make_n();
181998cd9ca7SRichard Henderson             ctx->psw_n_nonzero = true;
182098cd9ca7SRichard Henderson         } else {
182198cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
182298cd9ca7SRichard Henderson         }
182398cd9ca7SRichard Henderson     }
182401afb7beSRichard Henderson     return true;
182598cd9ca7SRichard Henderson }
182698cd9ca7SRichard Henderson 
1827660eefe1SRichard Henderson /* Implement
1828660eefe1SRichard Henderson  *    if (IAOQ_Front{30..31} < GR[b]{30..31})
1829660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← GR[b]{30..31};
1830660eefe1SRichard Henderson  *    else
1831660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← IAOQ_Front{30..31};
1832660eefe1SRichard Henderson  * which keeps the privilege level from being increased.
1833660eefe1SRichard Henderson  */
18346fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset)
1835660eefe1SRichard Henderson {
18366fd0c7bcSRichard Henderson     TCGv_i64 dest;
1837660eefe1SRichard Henderson     switch (ctx->privilege) {
1838660eefe1SRichard Henderson     case 0:
1839660eefe1SRichard Henderson         /* Privilege 0 is maximum and is allowed to decrease.  */
1840660eefe1SRichard Henderson         return offset;
1841660eefe1SRichard Henderson     case 3:
1842993119feSRichard Henderson         /* Privilege 3 is minimum and is never allowed to increase.  */
1843aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
18446fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, offset, 3);
1845660eefe1SRichard Henderson         break;
1846660eefe1SRichard Henderson     default:
1847aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
18486fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, offset, -4);
18496fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, ctx->privilege);
18506fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(TCG_COND_GTU, dest, dest, offset, dest, offset);
1851660eefe1SRichard Henderson         break;
1852660eefe1SRichard Henderson     }
1853660eefe1SRichard Henderson     return dest;
1854660eefe1SRichard Henderson }
1855660eefe1SRichard Henderson 
1856ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
18577ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
18587ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
18597ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
18607ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
18617ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
18627ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
18637ad439dfSRichard Henderson    aforementioned BE.  */
186431234768SRichard Henderson static void do_page_zero(DisasContext *ctx)
18657ad439dfSRichard Henderson {
18666fd0c7bcSRichard Henderson     TCGv_i64 tmp;
1867a0180973SRichard Henderson 
18687ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
18697ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
18708b81968cSMichael Tokarev        next insn within the privileged page.  */
18717ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
18727ad439dfSRichard Henderson     case TCG_COND_NEVER:
18737ad439dfSRichard Henderson         break;
18747ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
18756fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, 0);
18767ad439dfSRichard Henderson         goto do_sigill;
18777ad439dfSRichard Henderson     default:
18787ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
18797ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
18807ad439dfSRichard Henderson         g_assert_not_reached();
18817ad439dfSRichard Henderson     }
18827ad439dfSRichard Henderson 
18837ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
18847ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
18857ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
18867ad439dfSRichard Henderson        under such conditions.  */
18877ad439dfSRichard Henderson     if (ctx->iaoq_b != ctx->iaoq_f + 4) {
18887ad439dfSRichard Henderson         goto do_sigill;
18897ad439dfSRichard Henderson     }
18907ad439dfSRichard Henderson 
1891ebd0e151SRichard Henderson     switch (ctx->iaoq_f & -4) {
18927ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
18932986721dSRichard Henderson         gen_excp_1(EXCP_IMP);
189431234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
189531234768SRichard Henderson         break;
18967ad439dfSRichard Henderson 
18977ad439dfSRichard Henderson     case 0xb0: /* LWS */
18987ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
189931234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
190031234768SRichard Henderson         break;
19017ad439dfSRichard Henderson 
19027ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
19036fd0c7bcSRichard Henderson         tcg_gen_st_i64(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27]));
1904aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
19056fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_gr[31], 3);
1906a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
19076fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, 4);
1908a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
190931234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
191031234768SRichard Henderson         break;
19117ad439dfSRichard Henderson 
19127ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
19137ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
191431234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
191531234768SRichard Henderson         break;
19167ad439dfSRichard Henderson 
19177ad439dfSRichard Henderson     default:
19187ad439dfSRichard Henderson     do_sigill:
19192986721dSRichard Henderson         gen_excp_1(EXCP_ILL);
192031234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
192131234768SRichard Henderson         break;
19227ad439dfSRichard Henderson     }
19237ad439dfSRichard Henderson }
1924ba1d0b44SRichard Henderson #endif
19257ad439dfSRichard Henderson 
1926deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a)
1927b2167459SRichard Henderson {
1928b2167459SRichard Henderson     cond_free(&ctx->null_cond);
192931234768SRichard Henderson     return true;
1930b2167459SRichard Henderson }
1931b2167459SRichard Henderson 
193240f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a)
193398a9cb79SRichard Henderson {
193431234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_BREAK);
193598a9cb79SRichard Henderson }
193698a9cb79SRichard Henderson 
1937e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a)
193898a9cb79SRichard Henderson {
193998a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
194098a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
194198a9cb79SRichard Henderson 
194298a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
194331234768SRichard Henderson     return true;
194498a9cb79SRichard Henderson }
194598a9cb79SRichard Henderson 
1946c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a)
194798a9cb79SRichard Henderson {
1948c603e14aSRichard Henderson     unsigned rt = a->t;
19496fd0c7bcSRichard Henderson     TCGv_i64 tmp = dest_gpr(ctx, rt);
19506fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tmp, ctx->iaoq_f);
195198a9cb79SRichard Henderson     save_gpr(ctx, rt, tmp);
195298a9cb79SRichard Henderson 
195398a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
195431234768SRichard Henderson     return true;
195598a9cb79SRichard Henderson }
195698a9cb79SRichard Henderson 
1957c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a)
195898a9cb79SRichard Henderson {
1959c603e14aSRichard Henderson     unsigned rt = a->t;
1960c603e14aSRichard Henderson     unsigned rs = a->sp;
196133423472SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
196298a9cb79SRichard Henderson 
196333423472SRichard Henderson     load_spr(ctx, t0, rs);
196433423472SRichard Henderson     tcg_gen_shri_i64(t0, t0, 32);
196533423472SRichard Henderson 
1966967662cdSRichard Henderson     save_gpr(ctx, rt, t0);
196798a9cb79SRichard Henderson 
196898a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
196931234768SRichard Henderson     return true;
197098a9cb79SRichard Henderson }
197198a9cb79SRichard Henderson 
1972c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a)
197398a9cb79SRichard Henderson {
1974c603e14aSRichard Henderson     unsigned rt = a->t;
1975c603e14aSRichard Henderson     unsigned ctl = a->r;
19766fd0c7bcSRichard Henderson     TCGv_i64 tmp;
197798a9cb79SRichard Henderson 
197898a9cb79SRichard Henderson     switch (ctl) {
197935136a77SRichard Henderson     case CR_SAR:
1980c603e14aSRichard Henderson         if (a->e == 0) {
198198a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
198298a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
19836fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
198498a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
198535136a77SRichard Henderson             goto done;
198698a9cb79SRichard Henderson         }
198798a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
198835136a77SRichard Henderson         goto done;
198935136a77SRichard Henderson     case CR_IT: /* Interval Timer */
199035136a77SRichard Henderson         /* FIXME: Respect PSW_S bit.  */
199135136a77SRichard Henderson         nullify_over(ctx);
199298a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
1993dfd1b812SRichard Henderson         if (translator_io_start(&ctx->base)) {
199449c29d6cSRichard Henderson             gen_helper_read_interval_timer(tmp);
199531234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
199649c29d6cSRichard Henderson         } else {
199749c29d6cSRichard Henderson             gen_helper_read_interval_timer(tmp);
199849c29d6cSRichard Henderson         }
199998a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
200031234768SRichard Henderson         return nullify_end(ctx);
200198a9cb79SRichard Henderson     case 26:
200298a9cb79SRichard Henderson     case 27:
200398a9cb79SRichard Henderson         break;
200498a9cb79SRichard Henderson     default:
200598a9cb79SRichard Henderson         /* All other control registers are privileged.  */
200635136a77SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
200735136a77SRichard Henderson         break;
200898a9cb79SRichard Henderson     }
200998a9cb79SRichard Henderson 
2010aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
20116fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
201235136a77SRichard Henderson     save_gpr(ctx, rt, tmp);
201335136a77SRichard Henderson 
201435136a77SRichard Henderson  done:
201598a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
201631234768SRichard Henderson     return true;
201798a9cb79SRichard Henderson }
201898a9cb79SRichard Henderson 
2019c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
202033423472SRichard Henderson {
2021c603e14aSRichard Henderson     unsigned rr = a->r;
2022c603e14aSRichard Henderson     unsigned rs = a->sp;
2023967662cdSRichard Henderson     TCGv_i64 tmp;
202433423472SRichard Henderson 
202533423472SRichard Henderson     if (rs >= 5) {
202633423472SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
202733423472SRichard Henderson     }
202833423472SRichard Henderson     nullify_over(ctx);
202933423472SRichard Henderson 
2030967662cdSRichard Henderson     tmp = tcg_temp_new_i64();
2031967662cdSRichard Henderson     tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32);
203233423472SRichard Henderson 
203333423472SRichard Henderson     if (rs >= 4) {
2034967662cdSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs]));
2035494737b7SRichard Henderson         ctx->tb_flags &= ~TB_FLAG_SR_SAME;
203633423472SRichard Henderson     } else {
2037967662cdSRichard Henderson         tcg_gen_mov_i64(cpu_sr[rs], tmp);
203833423472SRichard Henderson     }
203933423472SRichard Henderson 
204031234768SRichard Henderson     return nullify_end(ctx);
204133423472SRichard Henderson }
204233423472SRichard Henderson 
2043c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
204498a9cb79SRichard Henderson {
2045c603e14aSRichard Henderson     unsigned ctl = a->t;
20466fd0c7bcSRichard Henderson     TCGv_i64 reg;
20476fd0c7bcSRichard Henderson     TCGv_i64 tmp;
204898a9cb79SRichard Henderson 
204935136a77SRichard Henderson     if (ctl == CR_SAR) {
20504845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
2051aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
20526fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31);
205398a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
205498a9cb79SRichard Henderson 
205598a9cb79SRichard Henderson         cond_free(&ctx->null_cond);
205631234768SRichard Henderson         return true;
205798a9cb79SRichard Henderson     }
205898a9cb79SRichard Henderson 
205935136a77SRichard Henderson     /* All other control registers are privileged or read-only.  */
206035136a77SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
206135136a77SRichard Henderson 
2062c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
206335136a77SRichard Henderson     nullify_over(ctx);
20644845f015SSven Schnelle     reg = load_gpr(ctx, a->r);
20654845f015SSven Schnelle 
206635136a77SRichard Henderson     switch (ctl) {
206735136a77SRichard Henderson     case CR_IT:
2068ad75a51eSRichard Henderson         gen_helper_write_interval_timer(tcg_env, reg);
206935136a77SRichard Henderson         break;
20704f5f2548SRichard Henderson     case CR_EIRR:
2071ad75a51eSRichard Henderson         gen_helper_write_eirr(tcg_env, reg);
20724f5f2548SRichard Henderson         break;
20734f5f2548SRichard Henderson     case CR_EIEM:
2074ad75a51eSRichard Henderson         gen_helper_write_eiem(tcg_env, reg);
207531234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
20764f5f2548SRichard Henderson         break;
20774f5f2548SRichard Henderson 
207835136a77SRichard Henderson     case CR_IIASQ:
207935136a77SRichard Henderson     case CR_IIAOQ:
208035136a77SRichard Henderson         /* FIXME: Respect PSW_Q bit */
208135136a77SRichard Henderson         /* The write advances the queue and stores to the back element.  */
2082aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
20836fd0c7bcSRichard Henderson         tcg_gen_ld_i64(tmp, tcg_env,
208435136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
20856fd0c7bcSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
20866fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env,
208735136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
208835136a77SRichard Henderson         break;
208935136a77SRichard Henderson 
2090d5de20bdSSven Schnelle     case CR_PID1:
2091d5de20bdSSven Schnelle     case CR_PID2:
2092d5de20bdSSven Schnelle     case CR_PID3:
2093d5de20bdSSven Schnelle     case CR_PID4:
20946fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
2095d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY
2096ad75a51eSRichard Henderson         gen_helper_change_prot_id(tcg_env);
2097d5de20bdSSven Schnelle #endif
2098d5de20bdSSven Schnelle         break;
2099d5de20bdSSven Schnelle 
210035136a77SRichard Henderson     default:
21016fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
210235136a77SRichard Henderson         break;
210335136a77SRichard Henderson     }
210431234768SRichard Henderson     return nullify_end(ctx);
21054f5f2548SRichard Henderson #endif
210635136a77SRichard Henderson }
210735136a77SRichard Henderson 
2108c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
210998a9cb79SRichard Henderson {
2110aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
211198a9cb79SRichard Henderson 
21126fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, load_gpr(ctx, a->r));
21136fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31);
211498a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
211598a9cb79SRichard Henderson 
211698a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
211731234768SRichard Henderson     return true;
211898a9cb79SRichard Henderson }
211998a9cb79SRichard Henderson 
2120e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a)
212198a9cb79SRichard Henderson {
21226fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
212398a9cb79SRichard Henderson 
21242330504cSHelge Deller #ifdef CONFIG_USER_ONLY
21252330504cSHelge Deller     /* We don't implement space registers in user mode. */
21266fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
21272330504cSHelge Deller #else
2128967662cdSRichard Henderson     tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
2129967662cdSRichard Henderson     tcg_gen_shri_i64(dest, dest, 32);
21302330504cSHelge Deller #endif
2131e36f27efSRichard Henderson     save_gpr(ctx, a->t, dest);
213298a9cb79SRichard Henderson 
213398a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
213431234768SRichard Henderson     return true;
213598a9cb79SRichard Henderson }
213698a9cb79SRichard Henderson 
2137e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a)
2138e36f27efSRichard Henderson {
2139e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2140e1b5a5edSRichard Henderson #ifndef CONFIG_USER_ONLY
21416fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2142e1b5a5edSRichard Henderson 
2143e1b5a5edSRichard Henderson     nullify_over(ctx);
2144e1b5a5edSRichard Henderson 
2145aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
21466fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
21476fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ~a->i);
2148ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2149e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2150e1b5a5edSRichard Henderson 
2151e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_M.  */
215231234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
215331234768SRichard Henderson     return nullify_end(ctx);
2154e36f27efSRichard Henderson #endif
2155e1b5a5edSRichard Henderson }
2156e1b5a5edSRichard Henderson 
2157e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
2158e1b5a5edSRichard Henderson {
2159e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2160e36f27efSRichard 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_ori_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_I.  */
217231234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
217331234768SRichard Henderson     return nullify_end(ctx);
2174e36f27efSRichard Henderson #endif
2175e1b5a5edSRichard Henderson }
2176e1b5a5edSRichard Henderson 
2177c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
2178e1b5a5edSRichard Henderson {
2179e1b5a5edSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2180c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
21816fd0c7bcSRichard Henderson     TCGv_i64 tmp, reg;
2182e1b5a5edSRichard Henderson     nullify_over(ctx);
2183e1b5a5edSRichard Henderson 
2184c603e14aSRichard Henderson     reg = load_gpr(ctx, a->r);
2185aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2186ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, reg);
2187e1b5a5edSRichard Henderson 
2188e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts.  */
218931234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
219031234768SRichard Henderson     return nullify_end(ctx);
2191c603e14aSRichard Henderson #endif
2192e1b5a5edSRichard Henderson }
2193f49b3537SRichard Henderson 
2194e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r)
2195f49b3537SRichard Henderson {
2196f49b3537SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2197e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
2198f49b3537SRichard Henderson     nullify_over(ctx);
2199f49b3537SRichard Henderson 
2200e36f27efSRichard Henderson     if (rfi_r) {
2201ad75a51eSRichard Henderson         gen_helper_rfi_r(tcg_env);
2202f49b3537SRichard Henderson     } else {
2203ad75a51eSRichard Henderson         gen_helper_rfi(tcg_env);
2204f49b3537SRichard Henderson     }
220531234768SRichard Henderson     /* Exit the TB to recognize new interrupts.  */
220607ea28b4SRichard Henderson     tcg_gen_exit_tb(NULL, 0);
220731234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
2208f49b3537SRichard Henderson 
220931234768SRichard Henderson     return nullify_end(ctx);
2210e36f27efSRichard Henderson #endif
2211f49b3537SRichard Henderson }
22126210db05SHelge Deller 
2213e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a)
2214e36f27efSRichard Henderson {
2215e36f27efSRichard Henderson     return do_rfi(ctx, false);
2216e36f27efSRichard Henderson }
2217e36f27efSRichard Henderson 
2218e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a)
2219e36f27efSRichard Henderson {
2220e36f27efSRichard Henderson     return do_rfi(ctx, true);
2221e36f27efSRichard Henderson }
2222e36f27efSRichard Henderson 
222396927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a)
22246210db05SHelge Deller {
22256210db05SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
222696927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
22276210db05SHelge Deller     nullify_over(ctx);
2228ad75a51eSRichard Henderson     gen_helper_halt(tcg_env);
222931234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
223031234768SRichard Henderson     return nullify_end(ctx);
223196927adbSRichard Henderson #endif
22326210db05SHelge Deller }
223396927adbSRichard Henderson 
223496927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a)
223596927adbSRichard Henderson {
223696927adbSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
223796927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
223896927adbSRichard Henderson     nullify_over(ctx);
2239ad75a51eSRichard Henderson     gen_helper_reset(tcg_env);
224096927adbSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
224196927adbSRichard Henderson     return nullify_end(ctx);
224296927adbSRichard Henderson #endif
224396927adbSRichard Henderson }
2244e1b5a5edSRichard Henderson 
22454a4554c6SHelge Deller static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
22464a4554c6SHelge Deller {
22474a4554c6SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
22484a4554c6SHelge Deller #ifndef CONFIG_USER_ONLY
22494a4554c6SHelge Deller     nullify_over(ctx);
2250ad75a51eSRichard Henderson     gen_helper_getshadowregs(tcg_env);
22514a4554c6SHelge Deller     return nullify_end(ctx);
22524a4554c6SHelge Deller #endif
22534a4554c6SHelge Deller }
22544a4554c6SHelge Deller 
2255deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
225698a9cb79SRichard Henderson {
2257deee69a1SRichard Henderson     if (a->m) {
22586fd0c7bcSRichard Henderson         TCGv_i64 dest = dest_gpr(ctx, a->b);
22596fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->b);
22606fd0c7bcSRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->x);
226198a9cb79SRichard Henderson 
226298a9cb79SRichard Henderson         /* The only thing we need to do is the base register modification.  */
22636fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, src1, src2);
2264deee69a1SRichard Henderson         save_gpr(ctx, a->b, dest);
2265deee69a1SRichard Henderson     }
226698a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
226731234768SRichard Henderson     return true;
226898a9cb79SRichard Henderson }
226998a9cb79SRichard Henderson 
2270deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a)
227198a9cb79SRichard Henderson {
22726fd0c7bcSRichard Henderson     TCGv_i64 dest, ofs;
2273eed14219SRichard Henderson     TCGv_i32 level, want;
22746fd0c7bcSRichard Henderson     TCGv_i64 addr;
227598a9cb79SRichard Henderson 
227698a9cb79SRichard Henderson     nullify_over(ctx);
227798a9cb79SRichard Henderson 
2278deee69a1SRichard Henderson     dest = dest_gpr(ctx, a->t);
2279deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2280eed14219SRichard Henderson 
2281deee69a1SRichard Henderson     if (a->imm) {
228229dd6f64SRichard Henderson         level = tcg_constant_i32(a->ri);
228398a9cb79SRichard Henderson     } else {
2284eed14219SRichard Henderson         level = tcg_temp_new_i32();
22856fd0c7bcSRichard Henderson         tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri));
2286eed14219SRichard Henderson         tcg_gen_andi_i32(level, level, 3);
228798a9cb79SRichard Henderson     }
228829dd6f64SRichard Henderson     want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ);
2289eed14219SRichard Henderson 
2290ad75a51eSRichard Henderson     gen_helper_probe(dest, tcg_env, addr, level, want);
2291eed14219SRichard Henderson 
2292deee69a1SRichard Henderson     save_gpr(ctx, a->t, dest);
229331234768SRichard Henderson     return nullify_end(ctx);
229498a9cb79SRichard Henderson }
229598a9cb79SRichard Henderson 
2296deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
22978d6ae7fbSRichard Henderson {
22988577f354SRichard Henderson     if (ctx->is_pa20) {
22998577f354SRichard Henderson         return false;
23008577f354SRichard Henderson     }
2301deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2302deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
23036fd0c7bcSRichard Henderson     TCGv_i64 addr;
23046fd0c7bcSRichard Henderson     TCGv_i64 ofs, reg;
23058d6ae7fbSRichard Henderson 
23068d6ae7fbSRichard Henderson     nullify_over(ctx);
23078d6ae7fbSRichard Henderson 
2308deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2309deee69a1SRichard Henderson     reg = load_gpr(ctx, a->r);
2310deee69a1SRichard Henderson     if (a->addr) {
23118577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
23128d6ae7fbSRichard Henderson     } else {
23138577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
23148d6ae7fbSRichard Henderson     }
23158d6ae7fbSRichard Henderson 
231632dc7569SSven Schnelle     /* Exit TB for TLB change if mmu is enabled.  */
231732dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
231831234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
231931234768SRichard Henderson     }
232031234768SRichard Henderson     return nullify_end(ctx);
2321deee69a1SRichard Henderson #endif
23228d6ae7fbSRichard Henderson }
232363300a00SRichard Henderson 
2324deee69a1SRichard Henderson static bool trans_pxtlbx(DisasContext *ctx, arg_pxtlbx *a)
232563300a00SRichard Henderson {
2326deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2327deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
23286fd0c7bcSRichard Henderson     TCGv_i64 addr;
23296fd0c7bcSRichard Henderson     TCGv_i64 ofs;
233063300a00SRichard Henderson 
233163300a00SRichard Henderson     nullify_over(ctx);
233263300a00SRichard Henderson 
2333deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2334deee69a1SRichard Henderson     if (a->m) {
2335deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
233663300a00SRichard Henderson     }
2337deee69a1SRichard Henderson     if (a->local) {
2338ad75a51eSRichard Henderson         gen_helper_ptlbe(tcg_env);
233963300a00SRichard Henderson     } else {
2340ad75a51eSRichard Henderson         gen_helper_ptlb(tcg_env, addr);
234163300a00SRichard Henderson     }
234263300a00SRichard Henderson 
234363300a00SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
234432dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
234531234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
234631234768SRichard Henderson     }
234731234768SRichard Henderson     return nullify_end(ctx);
2348deee69a1SRichard Henderson #endif
234963300a00SRichard Henderson }
23502dfcca9fSRichard Henderson 
23516797c315SNick Hudson /*
23526797c315SNick Hudson  * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
23536797c315SNick Hudson  * See
23546797c315SNick Hudson  *     https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
23556797c315SNick Hudson  *     page 13-9 (195/206)
23566797c315SNick Hudson  */
23576797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
23586797c315SNick Hudson {
23598577f354SRichard Henderson     if (ctx->is_pa20) {
23608577f354SRichard Henderson         return false;
23618577f354SRichard Henderson     }
23626797c315SNick Hudson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
23636797c315SNick Hudson #ifndef CONFIG_USER_ONLY
23646fd0c7bcSRichard Henderson     TCGv_i64 addr, atl, stl;
23656fd0c7bcSRichard Henderson     TCGv_i64 reg;
23666797c315SNick Hudson 
23676797c315SNick Hudson     nullify_over(ctx);
23686797c315SNick Hudson 
23696797c315SNick Hudson     /*
23706797c315SNick Hudson      * FIXME:
23716797c315SNick Hudson      *  if (not (pcxl or pcxl2))
23726797c315SNick Hudson      *    return gen_illegal(ctx);
23736797c315SNick Hudson      */
23746797c315SNick Hudson 
23756fd0c7bcSRichard Henderson     atl = tcg_temp_new_i64();
23766fd0c7bcSRichard Henderson     stl = tcg_temp_new_i64();
23776fd0c7bcSRichard Henderson     addr = tcg_temp_new_i64();
23786797c315SNick Hudson 
2379ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(stl, tcg_env,
23806797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
23816797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIASQ]));
2382ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(atl, tcg_env,
23836797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
23846797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIAOQ]));
23856797c315SNick Hudson     tcg_gen_shli_i64(stl, stl, 32);
2386d265360fSRichard Henderson     tcg_gen_or_i64(addr, atl, stl);
23876797c315SNick Hudson 
23886797c315SNick Hudson     reg = load_gpr(ctx, a->r);
23896797c315SNick Hudson     if (a->addr) {
23908577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
23916797c315SNick Hudson     } else {
23928577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
23936797c315SNick Hudson     }
23946797c315SNick Hudson 
23956797c315SNick Hudson     /* Exit TB for TLB change if mmu is enabled.  */
23966797c315SNick Hudson     if (ctx->tb_flags & PSW_C) {
23976797c315SNick Hudson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
23986797c315SNick Hudson     }
23996797c315SNick Hudson     return nullify_end(ctx);
24006797c315SNick Hudson #endif
24016797c315SNick Hudson }
24026797c315SNick Hudson 
24038577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
24048577f354SRichard Henderson {
24058577f354SRichard Henderson     if (!ctx->is_pa20) {
24068577f354SRichard Henderson         return false;
24078577f354SRichard Henderson     }
24088577f354SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24098577f354SRichard Henderson #ifndef CONFIG_USER_ONLY
24108577f354SRichard Henderson     nullify_over(ctx);
24118577f354SRichard Henderson     {
24128577f354SRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
24138577f354SRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->r2);
24148577f354SRichard Henderson 
24158577f354SRichard Henderson         if (a->data) {
24168577f354SRichard Henderson             gen_helper_idtlbt_pa20(tcg_env, src1, src2);
24178577f354SRichard Henderson         } else {
24188577f354SRichard Henderson             gen_helper_iitlbt_pa20(tcg_env, src1, src2);
24198577f354SRichard Henderson         }
24208577f354SRichard Henderson     }
24218577f354SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
24228577f354SRichard Henderson     if (ctx->tb_flags & PSW_C) {
24238577f354SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
24248577f354SRichard Henderson     }
24258577f354SRichard Henderson     return nullify_end(ctx);
24268577f354SRichard Henderson #endif
24278577f354SRichard Henderson }
24288577f354SRichard Henderson 
2429deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
24302dfcca9fSRichard Henderson {
2431deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2432deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
24336fd0c7bcSRichard Henderson     TCGv_i64 vaddr;
24346fd0c7bcSRichard Henderson     TCGv_i64 ofs, paddr;
24352dfcca9fSRichard Henderson 
24362dfcca9fSRichard Henderson     nullify_over(ctx);
24372dfcca9fSRichard Henderson 
2438deee69a1SRichard Henderson     form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
24392dfcca9fSRichard Henderson 
2440aac0f603SRichard Henderson     paddr = tcg_temp_new_i64();
2441ad75a51eSRichard Henderson     gen_helper_lpa(paddr, tcg_env, vaddr);
24422dfcca9fSRichard Henderson 
24432dfcca9fSRichard Henderson     /* Note that physical address result overrides base modification.  */
2444deee69a1SRichard Henderson     if (a->m) {
2445deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
24462dfcca9fSRichard Henderson     }
2447deee69a1SRichard Henderson     save_gpr(ctx, a->t, paddr);
24482dfcca9fSRichard Henderson 
244931234768SRichard Henderson     return nullify_end(ctx);
2450deee69a1SRichard Henderson #endif
24512dfcca9fSRichard Henderson }
245243a97b81SRichard Henderson 
2453deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a)
245443a97b81SRichard Henderson {
245543a97b81SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
245643a97b81SRichard Henderson 
245743a97b81SRichard Henderson     /* The Coherence Index is an implementation-defined function of the
245843a97b81SRichard Henderson        physical address.  Two addresses with the same CI have a coherent
245943a97b81SRichard Henderson        view of the cache.  Our implementation is to return 0 for all,
246043a97b81SRichard Henderson        since the entire address space is coherent.  */
24616fd0c7bcSRichard Henderson     save_gpr(ctx, a->t, tcg_constant_i64(0));
246243a97b81SRichard Henderson 
246331234768SRichard Henderson     cond_free(&ctx->null_cond);
246431234768SRichard Henderson     return true;
246543a97b81SRichard Henderson }
246698a9cb79SRichard Henderson 
2467faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2468b2167459SRichard Henderson {
24690c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, false);
2470b2167459SRichard Henderson }
2471b2167459SRichard Henderson 
2472faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2473b2167459SRichard Henderson {
24740c982a28SRichard Henderson     return do_add_reg(ctx, a, true, false, false, false);
2475b2167459SRichard Henderson }
2476b2167459SRichard Henderson 
2477faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2478b2167459SRichard Henderson {
24790c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, false);
2480b2167459SRichard Henderson }
2481b2167459SRichard Henderson 
2482faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2483b2167459SRichard Henderson {
24840c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, true);
24850c982a28SRichard Henderson }
2486b2167459SRichard Henderson 
2487faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
24880c982a28SRichard Henderson {
24890c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, true);
24900c982a28SRichard Henderson }
24910c982a28SRichard Henderson 
249263c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
24930c982a28SRichard Henderson {
24940c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, false);
24950c982a28SRichard Henderson }
24960c982a28SRichard Henderson 
249763c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
24980c982a28SRichard Henderson {
24990c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, false);
25000c982a28SRichard Henderson }
25010c982a28SRichard Henderson 
250263c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
25030c982a28SRichard Henderson {
25040c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, true);
25050c982a28SRichard Henderson }
25060c982a28SRichard Henderson 
250763c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
25080c982a28SRichard Henderson {
25090c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, true);
25100c982a28SRichard Henderson }
25110c982a28SRichard Henderson 
251263c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
25130c982a28SRichard Henderson {
25140c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, true, false);
25150c982a28SRichard Henderson }
25160c982a28SRichard Henderson 
251763c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
25180c982a28SRichard Henderson {
25190c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, true, false);
25200c982a28SRichard Henderson }
25210c982a28SRichard Henderson 
2522fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
25230c982a28SRichard Henderson {
25246fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_andc_i64);
25250c982a28SRichard Henderson }
25260c982a28SRichard Henderson 
2527fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
25280c982a28SRichard Henderson {
25296fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_and_i64);
25300c982a28SRichard Henderson }
25310c982a28SRichard Henderson 
2532fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
25330c982a28SRichard Henderson {
25340c982a28SRichard Henderson     if (a->cf == 0) {
25350c982a28SRichard Henderson         unsigned r2 = a->r2;
25360c982a28SRichard Henderson         unsigned r1 = a->r1;
25370c982a28SRichard Henderson         unsigned rt = a->t;
25380c982a28SRichard Henderson 
25397aee8189SRichard Henderson         if (rt == 0) { /* NOP */
25407aee8189SRichard Henderson             cond_free(&ctx->null_cond);
25417aee8189SRichard Henderson             return true;
25427aee8189SRichard Henderson         }
25437aee8189SRichard Henderson         if (r2 == 0) { /* COPY */
2544b2167459SRichard Henderson             if (r1 == 0) {
25456fd0c7bcSRichard Henderson                 TCGv_i64 dest = dest_gpr(ctx, rt);
25466fd0c7bcSRichard Henderson                 tcg_gen_movi_i64(dest, 0);
2547b2167459SRichard Henderson                 save_gpr(ctx, rt, dest);
2548b2167459SRichard Henderson             } else {
2549b2167459SRichard Henderson                 save_gpr(ctx, rt, cpu_gr[r1]);
2550b2167459SRichard Henderson             }
2551b2167459SRichard Henderson             cond_free(&ctx->null_cond);
255231234768SRichard Henderson             return true;
2553b2167459SRichard Henderson         }
25547aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY
25557aee8189SRichard Henderson         /* These are QEMU extensions and are nops in the real architecture:
25567aee8189SRichard Henderson          *
25577aee8189SRichard Henderson          * or %r10,%r10,%r10 -- idle loop; wait for interrupt
25587aee8189SRichard Henderson          * or %r31,%r31,%r31 -- death loop; offline cpu
25597aee8189SRichard Henderson          *                      currently implemented as idle.
25607aee8189SRichard Henderson          */
25617aee8189SRichard Henderson         if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
25627aee8189SRichard Henderson             /* No need to check for supervisor, as userland can only pause
25637aee8189SRichard Henderson                until the next timer interrupt.  */
25647aee8189SRichard Henderson             nullify_over(ctx);
25657aee8189SRichard Henderson 
25667aee8189SRichard Henderson             /* Advance the instruction queue.  */
2567741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
2568741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
25697aee8189SRichard Henderson             nullify_set(ctx, 0);
25707aee8189SRichard Henderson 
25717aee8189SRichard Henderson             /* Tell the qemu main loop to halt until this cpu has work.  */
2572ad75a51eSRichard Henderson             tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
257329dd6f64SRichard Henderson                            offsetof(CPUState, halted) - offsetof(HPPACPU, env));
25747aee8189SRichard Henderson             gen_excp_1(EXCP_HALTED);
25757aee8189SRichard Henderson             ctx->base.is_jmp = DISAS_NORETURN;
25767aee8189SRichard Henderson 
25777aee8189SRichard Henderson             return nullify_end(ctx);
25787aee8189SRichard Henderson         }
25797aee8189SRichard Henderson #endif
25807aee8189SRichard Henderson     }
25816fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_or_i64);
25827aee8189SRichard Henderson }
2583b2167459SRichard Henderson 
2584fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
2585b2167459SRichard Henderson {
25866fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_xor_i64);
25870c982a28SRichard Henderson }
25880c982a28SRichard Henderson 
2589345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
25900c982a28SRichard Henderson {
25916fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2592b2167459SRichard Henderson 
25930c982a28SRichard Henderson     if (a->cf) {
2594b2167459SRichard Henderson         nullify_over(ctx);
2595b2167459SRichard Henderson     }
25960c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
25970c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2598345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
259931234768SRichard Henderson     return nullify_end(ctx);
2600b2167459SRichard Henderson }
2601b2167459SRichard Henderson 
2602af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
2603b2167459SRichard Henderson {
26046fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2605b2167459SRichard Henderson 
26060c982a28SRichard Henderson     if (a->cf) {
2607b2167459SRichard Henderson         nullify_over(ctx);
2608b2167459SRichard Henderson     }
26090c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26100c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
26116fd0c7bcSRichard Henderson     do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64);
261231234768SRichard Henderson     return nullify_end(ctx);
2613b2167459SRichard Henderson }
2614b2167459SRichard Henderson 
2615af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
2616b2167459SRichard Henderson {
26176fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, tmp;
2618b2167459SRichard Henderson 
26190c982a28SRichard Henderson     if (a->cf) {
2620b2167459SRichard Henderson         nullify_over(ctx);
2621b2167459SRichard Henderson     }
26220c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26230c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2624aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
26256fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, tcg_r2);
26266fd0c7bcSRichard Henderson     do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64);
262731234768SRichard Henderson     return nullify_end(ctx);
2628b2167459SRichard Henderson }
2629b2167459SRichard Henderson 
2630af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
2631b2167459SRichard Henderson {
26320c982a28SRichard Henderson     return do_uaddcm(ctx, a, false);
26330c982a28SRichard Henderson }
26340c982a28SRichard Henderson 
2635af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
26360c982a28SRichard Henderson {
26370c982a28SRichard Henderson     return do_uaddcm(ctx, a, true);
26380c982a28SRichard Henderson }
26390c982a28SRichard Henderson 
2640af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
26410c982a28SRichard Henderson {
26426fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2643b2167459SRichard Henderson 
2644b2167459SRichard Henderson     nullify_over(ctx);
2645b2167459SRichard Henderson 
2646aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
26476fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, cpu_psw_cb, 3);
2648b2167459SRichard Henderson     if (!is_i) {
26496fd0c7bcSRichard Henderson         tcg_gen_not_i64(tmp, tmp);
2650b2167459SRichard Henderson     }
26516fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
26526fd0c7bcSRichard Henderson     tcg_gen_muli_i64(tmp, tmp, 6);
2653af240753SRichard Henderson     do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false,
26546fd0c7bcSRichard Henderson             is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64);
265531234768SRichard Henderson     return nullify_end(ctx);
2656b2167459SRichard Henderson }
2657b2167459SRichard Henderson 
2658af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
2659b2167459SRichard Henderson {
26600c982a28SRichard Henderson     return do_dcor(ctx, a, false);
26610c982a28SRichard Henderson }
26620c982a28SRichard Henderson 
2663af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
26640c982a28SRichard Henderson {
26650c982a28SRichard Henderson     return do_dcor(ctx, a, true);
26660c982a28SRichard Henderson }
26670c982a28SRichard Henderson 
26680c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
26690c982a28SRichard Henderson {
26706fd0c7bcSRichard Henderson     TCGv_i64 dest, add1, add2, addc, zero, in1, in2;
26716fd0c7bcSRichard Henderson     TCGv_i64 cout;
2672b2167459SRichard Henderson 
2673b2167459SRichard Henderson     nullify_over(ctx);
2674b2167459SRichard Henderson 
26750c982a28SRichard Henderson     in1 = load_gpr(ctx, a->r1);
26760c982a28SRichard Henderson     in2 = load_gpr(ctx, a->r2);
2677b2167459SRichard Henderson 
2678aac0f603SRichard Henderson     add1 = tcg_temp_new_i64();
2679aac0f603SRichard Henderson     add2 = tcg_temp_new_i64();
2680aac0f603SRichard Henderson     addc = tcg_temp_new_i64();
2681aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
26826fd0c7bcSRichard Henderson     zero = tcg_constant_i64(0);
2683b2167459SRichard Henderson 
2684b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
26856fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, in1, in1);
26866fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
2687b2167459SRichard Henderson 
268872ca8753SRichard Henderson     /*
268972ca8753SRichard Henderson      * Add or subtract R2, depending on PSW[V].  Proper computation of
269072ca8753SRichard Henderson      * carry requires that we subtract via + ~R2 + 1, as described in
269172ca8753SRichard Henderson      * the manual.  By extracting and masking V, we can produce the
269272ca8753SRichard Henderson      * proper inputs to the addition without movcond.
269372ca8753SRichard Henderson      */
26946fd0c7bcSRichard Henderson     tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
26956fd0c7bcSRichard Henderson     tcg_gen_xor_i64(add2, in2, addc);
26966fd0c7bcSRichard Henderson     tcg_gen_andi_i64(addc, addc, 1);
269772ca8753SRichard Henderson 
26986fd0c7bcSRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
26996fd0c7bcSRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
2700b2167459SRichard Henderson 
2701b2167459SRichard Henderson     /* Write back the result register.  */
27020c982a28SRichard Henderson     save_gpr(ctx, a->t, dest);
2703b2167459SRichard Henderson 
2704b2167459SRichard Henderson     /* Write back PSW[CB].  */
27056fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
27066fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
2707b2167459SRichard Henderson 
2708b2167459SRichard Henderson     /* Write back PSW[V] for the division step.  */
270972ca8753SRichard Henderson     cout = get_psw_carry(ctx, false);
27106fd0c7bcSRichard Henderson     tcg_gen_neg_i64(cpu_psw_v, cout);
27116fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
2712b2167459SRichard Henderson 
2713b2167459SRichard Henderson     /* Install the new nullification.  */
27140c982a28SRichard Henderson     if (a->cf) {
27156fd0c7bcSRichard Henderson         TCGv_i64 sv = NULL;
2716b47a4a02SSven Schnelle         if (cond_need_sv(a->cf >> 1)) {
2717b2167459SRichard Henderson             /* ??? The lshift is supposed to contribute to overflow.  */
2718b2167459SRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2);
2719b2167459SRichard Henderson         }
2720a751eb31SRichard Henderson         ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv);
2721b2167459SRichard Henderson     }
2722b2167459SRichard Henderson 
272331234768SRichard Henderson     return nullify_end(ctx);
2724b2167459SRichard Henderson }
2725b2167459SRichard Henderson 
27260588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a)
2727b2167459SRichard Henderson {
27280588e061SRichard Henderson     return do_add_imm(ctx, a, false, false);
27290588e061SRichard Henderson }
27300588e061SRichard Henderson 
27310588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a)
27320588e061SRichard Henderson {
27330588e061SRichard Henderson     return do_add_imm(ctx, a, true, false);
27340588e061SRichard Henderson }
27350588e061SRichard Henderson 
27360588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a)
27370588e061SRichard Henderson {
27380588e061SRichard Henderson     return do_add_imm(ctx, a, false, true);
27390588e061SRichard Henderson }
27400588e061SRichard Henderson 
27410588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a)
27420588e061SRichard Henderson {
27430588e061SRichard Henderson     return do_add_imm(ctx, a, true, true);
27440588e061SRichard Henderson }
27450588e061SRichard Henderson 
27460588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a)
27470588e061SRichard Henderson {
27480588e061SRichard Henderson     return do_sub_imm(ctx, a, false);
27490588e061SRichard Henderson }
27500588e061SRichard Henderson 
27510588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
27520588e061SRichard Henderson {
27530588e061SRichard Henderson     return do_sub_imm(ctx, a, true);
27540588e061SRichard Henderson }
27550588e061SRichard Henderson 
2756345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
27570588e061SRichard Henderson {
27586fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
2759b2167459SRichard Henderson 
27600588e061SRichard Henderson     if (a->cf) {
2761b2167459SRichard Henderson         nullify_over(ctx);
2762b2167459SRichard Henderson     }
2763b2167459SRichard Henderson 
27646fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
27650588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
2766345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
2767b2167459SRichard Henderson 
276831234768SRichard Henderson     return nullify_end(ctx);
2769b2167459SRichard Henderson }
2770b2167459SRichard Henderson 
27710843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a,
27720843563fSRichard Henderson                           void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
27730843563fSRichard Henderson {
27740843563fSRichard Henderson     TCGv_i64 r1, r2, dest;
27750843563fSRichard Henderson 
27760843563fSRichard Henderson     if (!ctx->is_pa20) {
27770843563fSRichard Henderson         return false;
27780843563fSRichard Henderson     }
27790843563fSRichard Henderson 
27800843563fSRichard Henderson     nullify_over(ctx);
27810843563fSRichard Henderson 
27820843563fSRichard Henderson     r1 = load_gpr(ctx, a->r1);
27830843563fSRichard Henderson     r2 = load_gpr(ctx, a->r2);
27840843563fSRichard Henderson     dest = dest_gpr(ctx, a->t);
27850843563fSRichard Henderson 
27860843563fSRichard Henderson     fn(dest, r1, r2);
27870843563fSRichard Henderson     save_gpr(ctx, a->t, dest);
27880843563fSRichard Henderson 
27890843563fSRichard Henderson     return nullify_end(ctx);
27900843563fSRichard Henderson }
27910843563fSRichard Henderson 
2792151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a,
2793151f309bSRichard Henderson                              void (*fn)(TCGv_i64, TCGv_i64, int64_t))
2794151f309bSRichard Henderson {
2795151f309bSRichard Henderson     TCGv_i64 r, dest;
2796151f309bSRichard Henderson 
2797151f309bSRichard Henderson     if (!ctx->is_pa20) {
2798151f309bSRichard Henderson         return false;
2799151f309bSRichard Henderson     }
2800151f309bSRichard Henderson 
2801151f309bSRichard Henderson     nullify_over(ctx);
2802151f309bSRichard Henderson 
2803151f309bSRichard Henderson     r = load_gpr(ctx, a->r);
2804151f309bSRichard Henderson     dest = dest_gpr(ctx, a->t);
2805151f309bSRichard Henderson 
2806151f309bSRichard Henderson     fn(dest, r, a->i);
2807151f309bSRichard Henderson     save_gpr(ctx, a->t, dest);
2808151f309bSRichard Henderson 
2809151f309bSRichard Henderson     return nullify_end(ctx);
2810151f309bSRichard Henderson }
2811151f309bSRichard Henderson 
28123bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a,
28133bbb8e48SRichard Henderson                                 void (*fn)(TCGv_i64, TCGv_i64,
28143bbb8e48SRichard Henderson                                            TCGv_i64, TCGv_i32))
28153bbb8e48SRichard Henderson {
28163bbb8e48SRichard Henderson     TCGv_i64 r1, r2, dest;
28173bbb8e48SRichard Henderson 
28183bbb8e48SRichard Henderson     if (!ctx->is_pa20) {
28193bbb8e48SRichard Henderson         return false;
28203bbb8e48SRichard Henderson     }
28213bbb8e48SRichard Henderson 
28223bbb8e48SRichard Henderson     nullify_over(ctx);
28233bbb8e48SRichard Henderson 
28243bbb8e48SRichard Henderson     r1 = load_gpr(ctx, a->r1);
28253bbb8e48SRichard Henderson     r2 = load_gpr(ctx, a->r2);
28263bbb8e48SRichard Henderson     dest = dest_gpr(ctx, a->t);
28273bbb8e48SRichard Henderson 
28283bbb8e48SRichard Henderson     fn(dest, r1, r2, tcg_constant_i32(a->sh));
28293bbb8e48SRichard Henderson     save_gpr(ctx, a->t, dest);
28303bbb8e48SRichard Henderson 
28313bbb8e48SRichard Henderson     return nullify_end(ctx);
28323bbb8e48SRichard Henderson }
28333bbb8e48SRichard Henderson 
28340843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a)
28350843563fSRichard Henderson {
28360843563fSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_add16_i64);
28370843563fSRichard Henderson }
28380843563fSRichard Henderson 
28390843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a)
28400843563fSRichard Henderson {
28410843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_ss);
28420843563fSRichard Henderson }
28430843563fSRichard Henderson 
28440843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a)
28450843563fSRichard Henderson {
28460843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_us);
28470843563fSRichard Henderson }
28480843563fSRichard Henderson 
28491b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a)
28501b3cb7c8SRichard Henderson {
28511b3cb7c8SRichard Henderson     return do_multimedia(ctx, a, gen_helper_havg);
28521b3cb7c8SRichard Henderson }
28531b3cb7c8SRichard Henderson 
2854151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a)
2855151f309bSRichard Henderson {
2856151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64);
2857151f309bSRichard Henderson }
2858151f309bSRichard Henderson 
2859151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a)
2860151f309bSRichard Henderson {
2861151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64);
2862151f309bSRichard Henderson }
2863151f309bSRichard Henderson 
2864151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a)
2865151f309bSRichard Henderson {
2866151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64);
2867151f309bSRichard Henderson }
2868151f309bSRichard Henderson 
28693bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a)
28703bbb8e48SRichard Henderson {
28713bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshladd);
28723bbb8e48SRichard Henderson }
28733bbb8e48SRichard Henderson 
28743bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a)
28753bbb8e48SRichard Henderson {
28763bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshradd);
28773bbb8e48SRichard Henderson }
28783bbb8e48SRichard Henderson 
287910c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a)
288010c9e58dSRichard Henderson {
288110c9e58dSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64);
288210c9e58dSRichard Henderson }
288310c9e58dSRichard Henderson 
288410c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a)
288510c9e58dSRichard Henderson {
288610c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_ss);
288710c9e58dSRichard Henderson }
288810c9e58dSRichard Henderson 
288910c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a)
289010c9e58dSRichard Henderson {
289110c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_us);
289210c9e58dSRichard Henderson }
289310c9e58dSRichard Henderson 
2894c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2895c2a7ee3fSRichard Henderson {
2896c2a7ee3fSRichard Henderson     uint64_t mask = 0xffff0000ffff0000ull;
2897c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2898c2a7ee3fSRichard Henderson 
2899c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r2, mask);
2900c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r1, mask);
2901c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, tmp, 16);
2902c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
2903c2a7ee3fSRichard Henderson }
2904c2a7ee3fSRichard Henderson 
2905c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a)
2906c2a7ee3fSRichard Henderson {
2907c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_l);
2908c2a7ee3fSRichard Henderson }
2909c2a7ee3fSRichard Henderson 
2910c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2911c2a7ee3fSRichard Henderson {
2912c2a7ee3fSRichard Henderson     uint64_t mask = 0x0000ffff0000ffffull;
2913c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2914c2a7ee3fSRichard Henderson 
2915c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r1, mask);
2916c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r2, mask);
2917c2a7ee3fSRichard Henderson     tcg_gen_shli_i64(tmp, tmp, 16);
2918c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
2919c2a7ee3fSRichard Henderson }
2920c2a7ee3fSRichard Henderson 
2921c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a)
2922c2a7ee3fSRichard Henderson {
2923c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_r);
2924c2a7ee3fSRichard Henderson }
2925c2a7ee3fSRichard Henderson 
2926c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2927c2a7ee3fSRichard Henderson {
2928c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
2929c2a7ee3fSRichard Henderson 
2930c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, r2, 32);
2931c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r1, tmp, 0, 32);
2932c2a7ee3fSRichard Henderson }
2933c2a7ee3fSRichard Henderson 
2934c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a)
2935c2a7ee3fSRichard Henderson {
2936c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_l);
2937c2a7ee3fSRichard Henderson }
2938c2a7ee3fSRichard Henderson 
2939c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2940c2a7ee3fSRichard Henderson {
2941c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r2, r1, 32, 32);
2942c2a7ee3fSRichard Henderson }
2943c2a7ee3fSRichard Henderson 
2944c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a)
2945c2a7ee3fSRichard Henderson {
2946c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_r);
2947c2a7ee3fSRichard Henderson }
2948c2a7ee3fSRichard Henderson 
2949*4e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a)
2950*4e7abdb1SRichard Henderson {
2951*4e7abdb1SRichard Henderson     TCGv_i64 r, t0, t1, t2, t3;
2952*4e7abdb1SRichard Henderson 
2953*4e7abdb1SRichard Henderson     if (!ctx->is_pa20) {
2954*4e7abdb1SRichard Henderson         return false;
2955*4e7abdb1SRichard Henderson     }
2956*4e7abdb1SRichard Henderson 
2957*4e7abdb1SRichard Henderson     nullify_over(ctx);
2958*4e7abdb1SRichard Henderson 
2959*4e7abdb1SRichard Henderson     r = load_gpr(ctx, a->r1);
2960*4e7abdb1SRichard Henderson     t0 = tcg_temp_new_i64();
2961*4e7abdb1SRichard Henderson     t1 = tcg_temp_new_i64();
2962*4e7abdb1SRichard Henderson     t2 = tcg_temp_new_i64();
2963*4e7abdb1SRichard Henderson     t3 = tcg_temp_new_i64();
2964*4e7abdb1SRichard Henderson 
2965*4e7abdb1SRichard Henderson     tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16);
2966*4e7abdb1SRichard Henderson     tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16);
2967*4e7abdb1SRichard Henderson     tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16);
2968*4e7abdb1SRichard Henderson     tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16);
2969*4e7abdb1SRichard Henderson 
2970*4e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t1, t0, 16, 48);
2971*4e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t2, t3, t2, 16, 48);
2972*4e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t2, t0, 32, 32);
2973*4e7abdb1SRichard Henderson 
2974*4e7abdb1SRichard Henderson     save_gpr(ctx, a->t, t0);
2975*4e7abdb1SRichard Henderson     return nullify_end(ctx);
2976*4e7abdb1SRichard Henderson }
2977*4e7abdb1SRichard Henderson 
29781cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a)
297996d6407fSRichard Henderson {
2980c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
29810786a3b6SHelge Deller         return gen_illegal(ctx);
2982c53e401eSRichard Henderson     }
29831cd012a5SRichard Henderson     return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
29841cd012a5SRichard Henderson                    a->disp, a->sp, a->m, a->size | MO_TE);
298596d6407fSRichard Henderson }
298696d6407fSRichard Henderson 
29871cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a)
298896d6407fSRichard Henderson {
29891cd012a5SRichard Henderson     assert(a->x == 0 && a->scale == 0);
2990c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
29910786a3b6SHelge Deller         return gen_illegal(ctx);
299296d6407fSRichard Henderson     }
2993c53e401eSRichard Henderson     return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
29940786a3b6SHelge Deller }
299596d6407fSRichard Henderson 
29961cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
299796d6407fSRichard Henderson {
2998b1af755cSRichard Henderson     MemOp mop = MO_TE | MO_ALIGN | a->size;
29996fd0c7bcSRichard Henderson     TCGv_i64 zero, dest, ofs;
30006fd0c7bcSRichard Henderson     TCGv_i64 addr;
300196d6407fSRichard Henderson 
3002c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
300351416c4eSRichard Henderson         return gen_illegal(ctx);
300451416c4eSRichard Henderson     }
300551416c4eSRichard Henderson 
300696d6407fSRichard Henderson     nullify_over(ctx);
300796d6407fSRichard Henderson 
30081cd012a5SRichard Henderson     if (a->m) {
300986f8d05fSRichard Henderson         /* Base register modification.  Make sure if RT == RB,
301086f8d05fSRichard Henderson            we see the result of the load.  */
3011aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
301296d6407fSRichard Henderson     } else {
30131cd012a5SRichard Henderson         dest = dest_gpr(ctx, a->t);
301496d6407fSRichard Henderson     }
301596d6407fSRichard Henderson 
30161cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0,
30171cd012a5SRichard Henderson              a->disp, a->sp, a->m, ctx->mmu_idx == MMU_PHYS_IDX);
3018b1af755cSRichard Henderson 
3019b1af755cSRichard Henderson     /*
3020b1af755cSRichard Henderson      * For hppa1.1, LDCW is undefined unless aligned mod 16.
3021b1af755cSRichard Henderson      * However actual hardware succeeds with aligned mod 4.
3022b1af755cSRichard Henderson      * Detect this case and log a GUEST_ERROR.
3023b1af755cSRichard Henderson      *
3024b1af755cSRichard Henderson      * TODO: HPPA64 relaxes the over-alignment requirement
3025b1af755cSRichard Henderson      * with the ,co completer.
3026b1af755cSRichard Henderson      */
3027b1af755cSRichard Henderson     gen_helper_ldc_check(addr);
3028b1af755cSRichard Henderson 
30296fd0c7bcSRichard Henderson     zero = tcg_constant_i64(0);
30306fd0c7bcSRichard Henderson     tcg_gen_atomic_xchg_i64(dest, addr, zero, ctx->mmu_idx, mop);
3031b1af755cSRichard Henderson 
30321cd012a5SRichard Henderson     if (a->m) {
30331cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
303496d6407fSRichard Henderson     }
30351cd012a5SRichard Henderson     save_gpr(ctx, a->t, dest);
303696d6407fSRichard Henderson 
303731234768SRichard Henderson     return nullify_end(ctx);
303896d6407fSRichard Henderson }
303996d6407fSRichard Henderson 
30401cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a)
304196d6407fSRichard Henderson {
30426fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
30436fd0c7bcSRichard Henderson     TCGv_i64 addr;
304496d6407fSRichard Henderson 
304596d6407fSRichard Henderson     nullify_over(ctx);
304696d6407fSRichard Henderson 
30471cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
304886f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
30491cd012a5SRichard Henderson     val = load_gpr(ctx, a->r);
30501cd012a5SRichard Henderson     if (a->a) {
3051f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3052ad75a51eSRichard Henderson             gen_helper_stby_e_parallel(tcg_env, addr, val);
3053f9f46db4SEmilio G. Cota         } else {
3054ad75a51eSRichard Henderson             gen_helper_stby_e(tcg_env, addr, val);
3055f9f46db4SEmilio G. Cota         }
3056f9f46db4SEmilio G. Cota     } else {
3057f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3058ad75a51eSRichard Henderson             gen_helper_stby_b_parallel(tcg_env, addr, val);
305996d6407fSRichard Henderson         } else {
3060ad75a51eSRichard Henderson             gen_helper_stby_b(tcg_env, addr, val);
306196d6407fSRichard Henderson         }
3062f9f46db4SEmilio G. Cota     }
30631cd012a5SRichard Henderson     if (a->m) {
30646fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~3);
30651cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
306696d6407fSRichard Henderson     }
306796d6407fSRichard Henderson 
306831234768SRichard Henderson     return nullify_end(ctx);
306996d6407fSRichard Henderson }
307096d6407fSRichard Henderson 
307125460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a)
307225460fc5SRichard Henderson {
30736fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
30746fd0c7bcSRichard Henderson     TCGv_i64 addr;
307525460fc5SRichard Henderson 
307625460fc5SRichard Henderson     if (!ctx->is_pa20) {
307725460fc5SRichard Henderson         return false;
307825460fc5SRichard Henderson     }
307925460fc5SRichard Henderson     nullify_over(ctx);
308025460fc5SRichard Henderson 
308125460fc5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
308225460fc5SRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
308325460fc5SRichard Henderson     val = load_gpr(ctx, a->r);
308425460fc5SRichard Henderson     if (a->a) {
308525460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
308625460fc5SRichard Henderson             gen_helper_stdby_e_parallel(tcg_env, addr, val);
308725460fc5SRichard Henderson         } else {
308825460fc5SRichard Henderson             gen_helper_stdby_e(tcg_env, addr, val);
308925460fc5SRichard Henderson         }
309025460fc5SRichard Henderson     } else {
309125460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
309225460fc5SRichard Henderson             gen_helper_stdby_b_parallel(tcg_env, addr, val);
309325460fc5SRichard Henderson         } else {
309425460fc5SRichard Henderson             gen_helper_stdby_b(tcg_env, addr, val);
309525460fc5SRichard Henderson         }
309625460fc5SRichard Henderson     }
309725460fc5SRichard Henderson     if (a->m) {
30986fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~7);
309925460fc5SRichard Henderson         save_gpr(ctx, a->b, ofs);
310025460fc5SRichard Henderson     }
310125460fc5SRichard Henderson 
310225460fc5SRichard Henderson     return nullify_end(ctx);
310325460fc5SRichard Henderson }
310425460fc5SRichard Henderson 
31051cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a)
3106d0a851ccSRichard Henderson {
3107d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3108d0a851ccSRichard Henderson 
3109d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3110d0a851ccSRichard Henderson     ctx->mmu_idx = MMU_PHYS_IDX;
31111cd012a5SRichard Henderson     trans_ld(ctx, a);
3112d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
311331234768SRichard Henderson     return true;
3114d0a851ccSRichard Henderson }
3115d0a851ccSRichard Henderson 
31161cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a)
3117d0a851ccSRichard Henderson {
3118d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3119d0a851ccSRichard Henderson 
3120d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3121d0a851ccSRichard Henderson     ctx->mmu_idx = MMU_PHYS_IDX;
31221cd012a5SRichard Henderson     trans_st(ctx, a);
3123d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
312431234768SRichard Henderson     return true;
3125d0a851ccSRichard Henderson }
312695412a61SRichard Henderson 
31270588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
3128b2167459SRichard Henderson {
31296fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3130b2167459SRichard Henderson 
31316fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tcg_rt, a->i);
31320588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3133b2167459SRichard Henderson     cond_free(&ctx->null_cond);
313431234768SRichard Henderson     return true;
3135b2167459SRichard Henderson }
3136b2167459SRichard Henderson 
31370588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a)
3138b2167459SRichard Henderson {
31396fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
31406fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
3141b2167459SRichard Henderson 
31426fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
3143b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
3144b2167459SRichard Henderson     cond_free(&ctx->null_cond);
314531234768SRichard Henderson     return true;
3146b2167459SRichard Henderson }
3147b2167459SRichard Henderson 
31480588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
3149b2167459SRichard Henderson {
31506fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3151b2167459SRichard Henderson 
3152b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
3153d265360fSRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_i64.  */
31540588e061SRichard Henderson     if (a->b == 0) {
31556fd0c7bcSRichard Henderson         tcg_gen_movi_i64(tcg_rt, a->i);
3156b2167459SRichard Henderson     } else {
31576fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
3158b2167459SRichard Henderson     }
31590588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3160b2167459SRichard Henderson     cond_free(&ctx->null_cond);
316131234768SRichard Henderson     return true;
3162b2167459SRichard Henderson }
3163b2167459SRichard Henderson 
31646fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
3165e9efd4bcSRichard Henderson                     unsigned c, unsigned f, bool d, unsigned n, int disp)
316698cd9ca7SRichard Henderson {
31676fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv;
316898cd9ca7SRichard Henderson     DisasCond cond;
316998cd9ca7SRichard Henderson 
317098cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3171aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
317298cd9ca7SRichard Henderson 
31736fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
317498cd9ca7SRichard Henderson 
3175f764718dSRichard Henderson     sv = NULL;
3176b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
317798cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
317898cd9ca7SRichard Henderson     }
317998cd9ca7SRichard Henderson 
31804fe9533aSRichard Henderson     cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
318101afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
318298cd9ca7SRichard Henderson }
318398cd9ca7SRichard Henderson 
318401afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
318598cd9ca7SRichard Henderson {
3186e9efd4bcSRichard Henderson     if (!ctx->is_pa20 && a->d) {
3187e9efd4bcSRichard Henderson         return false;
3188e9efd4bcSRichard Henderson     }
318901afb7beSRichard Henderson     nullify_over(ctx);
3190e9efd4bcSRichard Henderson     return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
3191e9efd4bcSRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
319201afb7beSRichard Henderson }
319301afb7beSRichard Henderson 
319401afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
319501afb7beSRichard Henderson {
3196c65c3ee1SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3197c65c3ee1SRichard Henderson         return false;
3198c65c3ee1SRichard Henderson     }
319901afb7beSRichard Henderson     nullify_over(ctx);
32006fd0c7bcSRichard Henderson     return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
3201c65c3ee1SRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
320201afb7beSRichard Henderson }
320301afb7beSRichard Henderson 
32046fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
320501afb7beSRichard Henderson                     unsigned c, unsigned f, unsigned n, int disp)
320601afb7beSRichard Henderson {
32076fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv, cb_cond;
320898cd9ca7SRichard Henderson     DisasCond cond;
3209bdcccc17SRichard Henderson     bool d = false;
321098cd9ca7SRichard Henderson 
3211f25d3160SRichard Henderson     /*
3212f25d3160SRichard Henderson      * For hppa64, the ADDB conditions change with PSW.W,
3213f25d3160SRichard Henderson      * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3214f25d3160SRichard Henderson      */
3215f25d3160SRichard Henderson     if (ctx->tb_flags & PSW_W) {
3216f25d3160SRichard Henderson         d = c >= 5;
3217f25d3160SRichard Henderson         if (d) {
3218f25d3160SRichard Henderson             c &= 3;
3219f25d3160SRichard Henderson         }
3220f25d3160SRichard Henderson     }
3221f25d3160SRichard Henderson 
322298cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3223aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
3224f764718dSRichard Henderson     sv = NULL;
3225bdcccc17SRichard Henderson     cb_cond = NULL;
322698cd9ca7SRichard Henderson 
3227b47a4a02SSven Schnelle     if (cond_need_cb(c)) {
3228aac0f603SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
3229aac0f603SRichard Henderson         TCGv_i64 cb_msb = tcg_temp_new_i64();
3230bdcccc17SRichard Henderson 
32316fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cb_msb, 0);
32326fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
32336fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
32346fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
3235bdcccc17SRichard Henderson         cb_cond = get_carry(ctx, d, cb, cb_msb);
3236b47a4a02SSven Schnelle     } else {
32376fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
3238b47a4a02SSven Schnelle     }
3239b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
324098cd9ca7SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
324198cd9ca7SRichard Henderson     }
324298cd9ca7SRichard Henderson 
3243a751eb31SRichard Henderson     cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
324443675d20SSven Schnelle     save_gpr(ctx, r, dest);
324501afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
324698cd9ca7SRichard Henderson }
324798cd9ca7SRichard Henderson 
324801afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a)
324998cd9ca7SRichard Henderson {
325001afb7beSRichard Henderson     nullify_over(ctx);
325101afb7beSRichard Henderson     return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
325201afb7beSRichard Henderson }
325301afb7beSRichard Henderson 
325401afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
325501afb7beSRichard Henderson {
325601afb7beSRichard Henderson     nullify_over(ctx);
32576fd0c7bcSRichard Henderson     return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
325801afb7beSRichard Henderson }
325901afb7beSRichard Henderson 
326001afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
326101afb7beSRichard Henderson {
32626fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
326398cd9ca7SRichard Henderson     DisasCond cond;
326498cd9ca7SRichard Henderson 
326598cd9ca7SRichard Henderson     nullify_over(ctx);
326698cd9ca7SRichard Henderson 
3267aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
326801afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
326984e224d4SRichard Henderson     if (cond_need_ext(ctx, a->d)) {
32701e9ab9fbSRichard Henderson         /* Force shift into [32,63] */
32716fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_sar, 32);
32726fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, tmp);
32731e9ab9fbSRichard Henderson     } else {
32746fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
32751e9ab9fbSRichard Henderson     }
327698cd9ca7SRichard Henderson 
32771e9ab9fbSRichard Henderson     cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
327801afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
327998cd9ca7SRichard Henderson }
328098cd9ca7SRichard Henderson 
328101afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
328298cd9ca7SRichard Henderson {
32836fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
328401afb7beSRichard Henderson     DisasCond cond;
32851e9ab9fbSRichard Henderson     int p;
328601afb7beSRichard Henderson 
328701afb7beSRichard Henderson     nullify_over(ctx);
328801afb7beSRichard Henderson 
3289aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
329001afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
329184e224d4SRichard Henderson     p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0);
32926fd0c7bcSRichard Henderson     tcg_gen_shli_i64(tmp, tcg_r, p);
329301afb7beSRichard Henderson 
329401afb7beSRichard Henderson     cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
329501afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
329601afb7beSRichard Henderson }
329701afb7beSRichard Henderson 
329801afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a)
329901afb7beSRichard Henderson {
33006fd0c7bcSRichard Henderson     TCGv_i64 dest;
330198cd9ca7SRichard Henderson     DisasCond cond;
330298cd9ca7SRichard Henderson 
330398cd9ca7SRichard Henderson     nullify_over(ctx);
330498cd9ca7SRichard Henderson 
330501afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r2);
330601afb7beSRichard Henderson     if (a->r1 == 0) {
33076fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, 0);
330898cd9ca7SRichard Henderson     } else {
33096fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
331098cd9ca7SRichard Henderson     }
331198cd9ca7SRichard Henderson 
33124fa52edfSRichard Henderson     /* All MOVB conditions are 32-bit. */
33134fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
331401afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
331501afb7beSRichard Henderson }
331601afb7beSRichard Henderson 
331701afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
331801afb7beSRichard Henderson {
33196fd0c7bcSRichard Henderson     TCGv_i64 dest;
332001afb7beSRichard Henderson     DisasCond cond;
332101afb7beSRichard Henderson 
332201afb7beSRichard Henderson     nullify_over(ctx);
332301afb7beSRichard Henderson 
332401afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r);
33256fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, a->i);
332601afb7beSRichard Henderson 
33274fa52edfSRichard Henderson     /* All MOVBI conditions are 32-bit. */
33284fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
332901afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
333098cd9ca7SRichard Henderson }
333198cd9ca7SRichard Henderson 
3332f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
33330b1347d2SRichard Henderson {
33346fd0c7bcSRichard Henderson     TCGv_i64 dest, src2;
33350b1347d2SRichard Henderson 
3336f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3337f7b775a9SRichard Henderson         return false;
3338f7b775a9SRichard Henderson     }
333930878590SRichard Henderson     if (a->c) {
33400b1347d2SRichard Henderson         nullify_over(ctx);
33410b1347d2SRichard Henderson     }
33420b1347d2SRichard Henderson 
334330878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
3344f7b775a9SRichard Henderson     src2 = load_gpr(ctx, a->r2);
334530878590SRichard Henderson     if (a->r1 == 0) {
3346f7b775a9SRichard Henderson         if (a->d) {
33476fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src2, cpu_sar);
3348f7b775a9SRichard Henderson         } else {
3349aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
3350f7b775a9SRichard Henderson 
33516fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src2);
33526fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
33536fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, dest, tmp);
3354f7b775a9SRichard Henderson         }
335530878590SRichard Henderson     } else if (a->r1 == a->r2) {
3356f7b775a9SRichard Henderson         if (a->d) {
33576fd0c7bcSRichard Henderson             tcg_gen_rotr_i64(dest, src2, cpu_sar);
3358f7b775a9SRichard Henderson         } else {
33590b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
3360e1d635e8SRichard Henderson             TCGv_i32 s32 = tcg_temp_new_i32();
3361e1d635e8SRichard Henderson 
33626fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, src2);
33636fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(s32, cpu_sar);
3364f7b775a9SRichard Henderson             tcg_gen_andi_i32(s32, s32, 31);
3365e1d635e8SRichard Henderson             tcg_gen_rotr_i32(t32, t32, s32);
33666fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
3367f7b775a9SRichard Henderson         }
3368f7b775a9SRichard Henderson     } else {
33696fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
3370f7b775a9SRichard Henderson 
3371f7b775a9SRichard Henderson         if (a->d) {
3372aac0f603SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
3373aac0f603SRichard Henderson             TCGv_i64 n = tcg_temp_new_i64();
3374f7b775a9SRichard Henderson 
33756fd0c7bcSRichard Henderson             tcg_gen_xori_i64(n, cpu_sar, 63);
33766fd0c7bcSRichard Henderson             tcg_gen_shl_i64(t, src2, n);
33776fd0c7bcSRichard Henderson             tcg_gen_shli_i64(t, t, 1);
33786fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src1, cpu_sar);
33796fd0c7bcSRichard Henderson             tcg_gen_or_i64(dest, dest, t);
33800b1347d2SRichard Henderson         } else {
33810b1347d2SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
33820b1347d2SRichard Henderson             TCGv_i64 s = tcg_temp_new_i64();
33830b1347d2SRichard Henderson 
33846fd0c7bcSRichard Henderson             tcg_gen_concat32_i64(t, src2, src1);
3385967662cdSRichard Henderson             tcg_gen_andi_i64(s, cpu_sar, 31);
3386967662cdSRichard Henderson             tcg_gen_shr_i64(dest, t, s);
33870b1347d2SRichard Henderson         }
3388f7b775a9SRichard Henderson     }
338930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
33900b1347d2SRichard Henderson 
33910b1347d2SRichard Henderson     /* Install the new nullification.  */
33920b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
339330878590SRichard Henderson     if (a->c) {
33944fa52edfSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
33950b1347d2SRichard Henderson     }
339631234768SRichard Henderson     return nullify_end(ctx);
33970b1347d2SRichard Henderson }
33980b1347d2SRichard Henderson 
3399f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
34000b1347d2SRichard Henderson {
3401f7b775a9SRichard Henderson     unsigned width, sa;
34026fd0c7bcSRichard Henderson     TCGv_i64 dest, t2;
34030b1347d2SRichard Henderson 
3404f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3405f7b775a9SRichard Henderson         return false;
3406f7b775a9SRichard Henderson     }
340730878590SRichard Henderson     if (a->c) {
34080b1347d2SRichard Henderson         nullify_over(ctx);
34090b1347d2SRichard Henderson     }
34100b1347d2SRichard Henderson 
3411f7b775a9SRichard Henderson     width = a->d ? 64 : 32;
3412f7b775a9SRichard Henderson     sa = width - 1 - a->cpos;
3413f7b775a9SRichard Henderson 
341430878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
341530878590SRichard Henderson     t2 = load_gpr(ctx, a->r2);
341605bfd4dbSRichard Henderson     if (a->r1 == 0) {
34176fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, t2, sa, width - sa);
3418c53e401eSRichard Henderson     } else if (width == TARGET_LONG_BITS) {
34196fd0c7bcSRichard Henderson         tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
3420f7b775a9SRichard Henderson     } else {
3421f7b775a9SRichard Henderson         assert(!a->d);
3422f7b775a9SRichard Henderson         if (a->r1 == a->r2) {
34230b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
34246fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, t2);
34250b1347d2SRichard Henderson             tcg_gen_rotri_i32(t32, t32, sa);
34266fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
34270b1347d2SRichard Henderson         } else {
3428967662cdSRichard Henderson             tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]);
3429967662cdSRichard Henderson             tcg_gen_extract_i64(dest, dest, sa, 32);
34300b1347d2SRichard Henderson         }
3431f7b775a9SRichard Henderson     }
343230878590SRichard Henderson     save_gpr(ctx, a->t, dest);
34330b1347d2SRichard Henderson 
34340b1347d2SRichard Henderson     /* Install the new nullification.  */
34350b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
343630878590SRichard Henderson     if (a->c) {
34374fa52edfSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
34380b1347d2SRichard Henderson     }
343931234768SRichard Henderson     return nullify_end(ctx);
34400b1347d2SRichard Henderson }
34410b1347d2SRichard Henderson 
3442bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
34430b1347d2SRichard Henderson {
3444bd792da3SRichard Henderson     unsigned widthm1 = a->d ? 63 : 31;
34456fd0c7bcSRichard Henderson     TCGv_i64 dest, src, tmp;
34460b1347d2SRichard Henderson 
3447bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3448bd792da3SRichard Henderson         return false;
3449bd792da3SRichard Henderson     }
345030878590SRichard Henderson     if (a->c) {
34510b1347d2SRichard Henderson         nullify_over(ctx);
34520b1347d2SRichard Henderson     }
34530b1347d2SRichard Henderson 
345430878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
345530878590SRichard Henderson     src = load_gpr(ctx, a->r);
3456aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
34570b1347d2SRichard Henderson 
34580b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
34596fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
34606fd0c7bcSRichard Henderson     tcg_gen_xori_i64(tmp, tmp, widthm1);
3461d781cb77SRichard Henderson 
346230878590SRichard Henderson     if (a->se) {
3463bd792da3SRichard Henderson         if (!a->d) {
34646fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(dest, src);
3465bd792da3SRichard Henderson             src = dest;
3466bd792da3SRichard Henderson         }
34676fd0c7bcSRichard Henderson         tcg_gen_sar_i64(dest, src, tmp);
34686fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, dest, 0, a->len);
34690b1347d2SRichard Henderson     } else {
3470bd792da3SRichard Henderson         if (!a->d) {
34716fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src);
3472bd792da3SRichard Henderson             src = dest;
3473bd792da3SRichard Henderson         }
34746fd0c7bcSRichard Henderson         tcg_gen_shr_i64(dest, src, tmp);
34756fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, dest, 0, a->len);
34760b1347d2SRichard Henderson     }
347730878590SRichard Henderson     save_gpr(ctx, a->t, dest);
34780b1347d2SRichard Henderson 
34790b1347d2SRichard Henderson     /* Install the new nullification.  */
34800b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
348130878590SRichard Henderson     if (a->c) {
3482bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
34830b1347d2SRichard Henderson     }
348431234768SRichard Henderson     return nullify_end(ctx);
34850b1347d2SRichard Henderson }
34860b1347d2SRichard Henderson 
3487bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
34880b1347d2SRichard Henderson {
3489bd792da3SRichard Henderson     unsigned len, cpos, width;
34906fd0c7bcSRichard Henderson     TCGv_i64 dest, src;
34910b1347d2SRichard Henderson 
3492bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3493bd792da3SRichard Henderson         return false;
3494bd792da3SRichard Henderson     }
349530878590SRichard Henderson     if (a->c) {
34960b1347d2SRichard Henderson         nullify_over(ctx);
34970b1347d2SRichard Henderson     }
34980b1347d2SRichard Henderson 
3499bd792da3SRichard Henderson     len = a->len;
3500bd792da3SRichard Henderson     width = a->d ? 64 : 32;
3501bd792da3SRichard Henderson     cpos = width - 1 - a->pos;
3502bd792da3SRichard Henderson     if (cpos + len > width) {
3503bd792da3SRichard Henderson         len = width - cpos;
3504bd792da3SRichard Henderson     }
3505bd792da3SRichard Henderson 
350630878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
350730878590SRichard Henderson     src = load_gpr(ctx, a->r);
350830878590SRichard Henderson     if (a->se) {
35096fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, src, cpos, len);
35100b1347d2SRichard Henderson     } else {
35116fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, src, cpos, len);
35120b1347d2SRichard Henderson     }
351330878590SRichard Henderson     save_gpr(ctx, a->t, dest);
35140b1347d2SRichard Henderson 
35150b1347d2SRichard Henderson     /* Install the new nullification.  */
35160b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
351730878590SRichard Henderson     if (a->c) {
3518bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
35190b1347d2SRichard Henderson     }
352031234768SRichard Henderson     return nullify_end(ctx);
35210b1347d2SRichard Henderson }
35220b1347d2SRichard Henderson 
352372ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
35240b1347d2SRichard Henderson {
352572ae4f2bSRichard Henderson     unsigned len, width;
3526c53e401eSRichard Henderson     uint64_t mask0, mask1;
35276fd0c7bcSRichard Henderson     TCGv_i64 dest;
35280b1347d2SRichard Henderson 
352972ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
353072ae4f2bSRichard Henderson         return false;
353172ae4f2bSRichard Henderson     }
353230878590SRichard Henderson     if (a->c) {
35330b1347d2SRichard Henderson         nullify_over(ctx);
35340b1347d2SRichard Henderson     }
353572ae4f2bSRichard Henderson 
353672ae4f2bSRichard Henderson     len = a->len;
353772ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
353872ae4f2bSRichard Henderson     if (a->cpos + len > width) {
353972ae4f2bSRichard Henderson         len = width - a->cpos;
35400b1347d2SRichard Henderson     }
35410b1347d2SRichard Henderson 
354230878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
354330878590SRichard Henderson     mask0 = deposit64(0, a->cpos, len, a->i);
354430878590SRichard Henderson     mask1 = deposit64(-1, a->cpos, len, a->i);
35450b1347d2SRichard Henderson 
354630878590SRichard Henderson     if (a->nz) {
35476fd0c7bcSRichard Henderson         TCGv_i64 src = load_gpr(ctx, a->t);
35486fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, src, mask1);
35496fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, mask0);
35500b1347d2SRichard Henderson     } else {
35516fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, mask0);
35520b1347d2SRichard Henderson     }
355330878590SRichard Henderson     save_gpr(ctx, a->t, dest);
35540b1347d2SRichard Henderson 
35550b1347d2SRichard Henderson     /* Install the new nullification.  */
35560b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
355730878590SRichard Henderson     if (a->c) {
355872ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
35590b1347d2SRichard Henderson     }
356031234768SRichard Henderson     return nullify_end(ctx);
35610b1347d2SRichard Henderson }
35620b1347d2SRichard Henderson 
356372ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
35640b1347d2SRichard Henderson {
356530878590SRichard Henderson     unsigned rs = a->nz ? a->t : 0;
356672ae4f2bSRichard Henderson     unsigned len, width;
35676fd0c7bcSRichard Henderson     TCGv_i64 dest, val;
35680b1347d2SRichard Henderson 
356972ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
357072ae4f2bSRichard Henderson         return false;
357172ae4f2bSRichard Henderson     }
357230878590SRichard Henderson     if (a->c) {
35730b1347d2SRichard Henderson         nullify_over(ctx);
35740b1347d2SRichard Henderson     }
357572ae4f2bSRichard Henderson 
357672ae4f2bSRichard Henderson     len = a->len;
357772ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
357872ae4f2bSRichard Henderson     if (a->cpos + len > width) {
357972ae4f2bSRichard Henderson         len = width - a->cpos;
35800b1347d2SRichard Henderson     }
35810b1347d2SRichard Henderson 
358230878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
358330878590SRichard Henderson     val = load_gpr(ctx, a->r);
35840b1347d2SRichard Henderson     if (rs == 0) {
35856fd0c7bcSRichard Henderson         tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
35860b1347d2SRichard Henderson     } else {
35876fd0c7bcSRichard Henderson         tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
35880b1347d2SRichard Henderson     }
358930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
35900b1347d2SRichard Henderson 
35910b1347d2SRichard Henderson     /* Install the new nullification.  */
35920b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
359330878590SRichard Henderson     if (a->c) {
359472ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
35950b1347d2SRichard Henderson     }
359631234768SRichard Henderson     return nullify_end(ctx);
35970b1347d2SRichard Henderson }
35980b1347d2SRichard Henderson 
359972ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
36006fd0c7bcSRichard Henderson                        bool d, bool nz, unsigned len, TCGv_i64 val)
36010b1347d2SRichard Henderson {
36020b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
360372ae4f2bSRichard Henderson     unsigned widthm1 = d ? 63 : 31;
36046fd0c7bcSRichard Henderson     TCGv_i64 mask, tmp, shift, dest;
3605c53e401eSRichard Henderson     uint64_t msb = 1ULL << (len - 1);
36060b1347d2SRichard Henderson 
36070b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
3608aac0f603SRichard Henderson     shift = tcg_temp_new_i64();
3609aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
36100b1347d2SRichard Henderson 
36110b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
36126fd0c7bcSRichard Henderson     tcg_gen_andi_i64(shift, cpu_sar, widthm1);
36136fd0c7bcSRichard Henderson     tcg_gen_xori_i64(shift, shift, widthm1);
36140b1347d2SRichard Henderson 
3615aac0f603SRichard Henderson     mask = tcg_temp_new_i64();
36166fd0c7bcSRichard Henderson     tcg_gen_movi_i64(mask, msb + (msb - 1));
36176fd0c7bcSRichard Henderson     tcg_gen_and_i64(tmp, val, mask);
36180b1347d2SRichard Henderson     if (rs) {
36196fd0c7bcSRichard Henderson         tcg_gen_shl_i64(mask, mask, shift);
36206fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tmp, shift);
36216fd0c7bcSRichard Henderson         tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
36226fd0c7bcSRichard Henderson         tcg_gen_or_i64(dest, dest, tmp);
36230b1347d2SRichard Henderson     } else {
36246fd0c7bcSRichard Henderson         tcg_gen_shl_i64(dest, tmp, shift);
36250b1347d2SRichard Henderson     }
36260b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
36270b1347d2SRichard Henderson 
36280b1347d2SRichard Henderson     /* Install the new nullification.  */
36290b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
36300b1347d2SRichard Henderson     if (c) {
363172ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, c, d, dest);
36320b1347d2SRichard Henderson     }
363331234768SRichard Henderson     return nullify_end(ctx);
36340b1347d2SRichard Henderson }
36350b1347d2SRichard Henderson 
363672ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
363730878590SRichard Henderson {
363872ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
363972ae4f2bSRichard Henderson         return false;
364072ae4f2bSRichard Henderson     }
3641a6deecceSSven Schnelle     if (a->c) {
3642a6deecceSSven Schnelle         nullify_over(ctx);
3643a6deecceSSven Schnelle     }
364472ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
364572ae4f2bSRichard Henderson                       load_gpr(ctx, a->r));
364630878590SRichard Henderson }
364730878590SRichard Henderson 
364872ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
364930878590SRichard Henderson {
365072ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
365172ae4f2bSRichard Henderson         return false;
365272ae4f2bSRichard Henderson     }
3653a6deecceSSven Schnelle     if (a->c) {
3654a6deecceSSven Schnelle         nullify_over(ctx);
3655a6deecceSSven Schnelle     }
365672ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
36576fd0c7bcSRichard Henderson                       tcg_constant_i64(a->i));
365830878590SRichard Henderson }
36590b1347d2SRichard Henderson 
36608340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a)
366198cd9ca7SRichard Henderson {
36626fd0c7bcSRichard Henderson     TCGv_i64 tmp;
366398cd9ca7SRichard Henderson 
3664c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
366598cd9ca7SRichard Henderson     /* ??? It seems like there should be a good way of using
366698cd9ca7SRichard Henderson        "be disp(sr2, r0)", the canonical gateway entry mechanism
366798cd9ca7SRichard Henderson        to our advantage.  But that appears to be inconvenient to
366898cd9ca7SRichard Henderson        manage along side branch delay slots.  Therefore we handle
366998cd9ca7SRichard Henderson        entry into the gateway page via absolute address.  */
367098cd9ca7SRichard Henderson     /* Since we don't implement spaces, just branch.  Do notice the special
367198cd9ca7SRichard Henderson        case of "be disp(*,r0)" using a direct branch to disp, so that we can
367298cd9ca7SRichard Henderson        goto_tb to the TB containing the syscall.  */
36738340f534SRichard Henderson     if (a->b == 0) {
36748340f534SRichard Henderson         return do_dbranch(ctx, a->disp, a->l, a->n);
367598cd9ca7SRichard Henderson     }
3676c301f34eSRichard Henderson #else
3677c301f34eSRichard Henderson     nullify_over(ctx);
3678660eefe1SRichard Henderson #endif
3679660eefe1SRichard Henderson 
3680aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
36816fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp);
3682660eefe1SRichard Henderson     tmp = do_ibranch_priv(ctx, tmp);
3683c301f34eSRichard Henderson 
3684c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
36858340f534SRichard Henderson     return do_ibranch(ctx, tmp, a->l, a->n);
3686c301f34eSRichard Henderson #else
3687c301f34eSRichard Henderson     TCGv_i64 new_spc = tcg_temp_new_i64();
3688c301f34eSRichard Henderson 
36898340f534SRichard Henderson     load_spr(ctx, new_spc, a->sp);
36908340f534SRichard Henderson     if (a->l) {
3691741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
3692c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f);
3693c301f34eSRichard Henderson     }
36948340f534SRichard Henderson     if (a->n && use_nullify_skip(ctx)) {
3695a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
36966fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, 4);
3697a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3698c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, new_spc);
3699c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f);
3700c301f34eSRichard Henderson     } else {
3701741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3702c301f34eSRichard Henderson         if (ctx->iaoq_b == -1) {
3703c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3704c301f34eSRichard Henderson         }
3705a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3706c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, new_spc);
37078340f534SRichard Henderson         nullify_set(ctx, a->n);
3708c301f34eSRichard Henderson     }
3709c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
371031234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
371131234768SRichard Henderson     return nullify_end(ctx);
3712c301f34eSRichard Henderson #endif
371398cd9ca7SRichard Henderson }
371498cd9ca7SRichard Henderson 
37158340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a)
371698cd9ca7SRichard Henderson {
37178340f534SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n);
371898cd9ca7SRichard Henderson }
371998cd9ca7SRichard Henderson 
37208340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
372143e05652SRichard Henderson {
3722c53e401eSRichard Henderson     uint64_t dest = iaoq_dest(ctx, a->disp);
372343e05652SRichard Henderson 
37246e5f5300SSven Schnelle     nullify_over(ctx);
37256e5f5300SSven Schnelle 
372643e05652SRichard Henderson     /* Make sure the caller hasn't done something weird with the queue.
372743e05652SRichard Henderson      * ??? This is not quite the same as the PSW[B] bit, which would be
372843e05652SRichard Henderson      * expensive to track.  Real hardware will trap for
372943e05652SRichard Henderson      *    b  gateway
373043e05652SRichard Henderson      *    b  gateway+4  (in delay slot of first branch)
373143e05652SRichard Henderson      * However, checking for a non-sequential instruction queue *will*
373243e05652SRichard Henderson      * diagnose the security hole
373343e05652SRichard Henderson      *    b  gateway
373443e05652SRichard Henderson      *    b  evil
373543e05652SRichard Henderson      * in which instructions at evil would run with increased privs.
373643e05652SRichard Henderson      */
373743e05652SRichard Henderson     if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) {
373843e05652SRichard Henderson         return gen_illegal(ctx);
373943e05652SRichard Henderson     }
374043e05652SRichard Henderson 
374143e05652SRichard Henderson #ifndef CONFIG_USER_ONLY
374243e05652SRichard Henderson     if (ctx->tb_flags & PSW_C) {
3743b77af26eSRichard Henderson         CPUHPPAState *env = cpu_env(ctx->cs);
374443e05652SRichard Henderson         int type = hppa_artype_for_page(env, ctx->base.pc_next);
374543e05652SRichard Henderson         /* If we could not find a TLB entry, then we need to generate an
374643e05652SRichard Henderson            ITLB miss exception so the kernel will provide it.
374743e05652SRichard Henderson            The resulting TLB fill operation will invalidate this TB and
374843e05652SRichard Henderson            we will re-translate, at which point we *will* be able to find
374943e05652SRichard Henderson            the TLB entry and determine if this is in fact a gateway page.  */
375043e05652SRichard Henderson         if (type < 0) {
375131234768SRichard Henderson             gen_excp(ctx, EXCP_ITLB_MISS);
375231234768SRichard Henderson             return true;
375343e05652SRichard Henderson         }
375443e05652SRichard Henderson         /* No change for non-gateway pages or for priv decrease.  */
375543e05652SRichard Henderson         if (type >= 4 && type - 4 < ctx->privilege) {
375643e05652SRichard Henderson             dest = deposit32(dest, 0, 2, type - 4);
375743e05652SRichard Henderson         }
375843e05652SRichard Henderson     } else {
375943e05652SRichard Henderson         dest &= -4;  /* priv = 0 */
376043e05652SRichard Henderson     }
376143e05652SRichard Henderson #endif
376243e05652SRichard Henderson 
37636e5f5300SSven Schnelle     if (a->l) {
37646fd0c7bcSRichard Henderson         TCGv_i64 tmp = dest_gpr(ctx, a->l);
37656e5f5300SSven Schnelle         if (ctx->privilege < 3) {
37666fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, tmp, -4);
37676e5f5300SSven Schnelle         }
37686fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
37696e5f5300SSven Schnelle         save_gpr(ctx, a->l, tmp);
37706e5f5300SSven Schnelle     }
37716e5f5300SSven Schnelle 
37726e5f5300SSven Schnelle     return do_dbranch(ctx, dest, 0, a->n);
377343e05652SRichard Henderson }
377443e05652SRichard Henderson 
37758340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a)
377698cd9ca7SRichard Henderson {
3777b35aec85SRichard Henderson     if (a->x) {
3778aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
37796fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3);
37806fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8);
3781660eefe1SRichard Henderson         /* The computation here never changes privilege level.  */
37828340f534SRichard Henderson         return do_ibranch(ctx, tmp, a->l, a->n);
3783b35aec85SRichard Henderson     } else {
3784b35aec85SRichard Henderson         /* BLR R0,RX is a good way to load PC+8 into RX.  */
3785b35aec85SRichard Henderson         return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n);
3786b35aec85SRichard Henderson     }
378798cd9ca7SRichard Henderson }
378898cd9ca7SRichard Henderson 
37898340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a)
379098cd9ca7SRichard Henderson {
37916fd0c7bcSRichard Henderson     TCGv_i64 dest;
379298cd9ca7SRichard Henderson 
37938340f534SRichard Henderson     if (a->x == 0) {
37948340f534SRichard Henderson         dest = load_gpr(ctx, a->b);
379598cd9ca7SRichard Henderson     } else {
3796aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
37976fd0c7bcSRichard Henderson         tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
37986fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
379998cd9ca7SRichard Henderson     }
3800660eefe1SRichard Henderson     dest = do_ibranch_priv(ctx, dest);
38018340f534SRichard Henderson     return do_ibranch(ctx, dest, 0, a->n);
380298cd9ca7SRichard Henderson }
380398cd9ca7SRichard Henderson 
38048340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a)
380598cd9ca7SRichard Henderson {
38066fd0c7bcSRichard Henderson     TCGv_i64 dest;
380798cd9ca7SRichard Henderson 
3808c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
38098340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
38108340f534SRichard Henderson     return do_ibranch(ctx, dest, a->l, a->n);
3811c301f34eSRichard Henderson #else
3812c301f34eSRichard Henderson     nullify_over(ctx);
38138340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
3814c301f34eSRichard Henderson 
3815741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3816c301f34eSRichard Henderson     if (ctx->iaoq_b == -1) {
3817c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3818c301f34eSRichard Henderson     }
3819741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest);
3820c301f34eSRichard Henderson     tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
38218340f534SRichard Henderson     if (a->l) {
3822741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var);
3823c301f34eSRichard Henderson     }
38248340f534SRichard Henderson     nullify_set(ctx, a->n);
3825c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
382631234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
382731234768SRichard Henderson     return nullify_end(ctx);
3828c301f34eSRichard Henderson #endif
382998cd9ca7SRichard Henderson }
383098cd9ca7SRichard Henderson 
3831a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
3832a8966ba7SRichard Henderson {
3833a8966ba7SRichard Henderson     /* All branch target stack instructions implement as nop. */
3834a8966ba7SRichard Henderson     return ctx->is_pa20;
3835a8966ba7SRichard Henderson }
3836a8966ba7SRichard Henderson 
38371ca74648SRichard Henderson /*
38381ca74648SRichard Henderson  * Float class 0
38391ca74648SRichard Henderson  */
3840ebe9383cSRichard Henderson 
38411ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3842ebe9383cSRichard Henderson {
3843ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
3844ebe9383cSRichard Henderson }
3845ebe9383cSRichard Henderson 
384659f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
384759f8c04bSHelge Deller {
3848a300dad3SRichard Henderson     uint64_t ret;
3849a300dad3SRichard Henderson 
3850c53e401eSRichard Henderson     if (ctx->is_pa20) {
3851a300dad3SRichard Henderson         ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
3852a300dad3SRichard Henderson     } else {
3853a300dad3SRichard Henderson         ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
3854a300dad3SRichard Henderson     }
3855a300dad3SRichard Henderson 
385659f8c04bSHelge Deller     nullify_over(ctx);
3857a300dad3SRichard Henderson     save_frd(0, tcg_constant_i64(ret));
385859f8c04bSHelge Deller     return nullify_end(ctx);
385959f8c04bSHelge Deller }
386059f8c04bSHelge Deller 
38611ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a)
38621ca74648SRichard Henderson {
38631ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f);
38641ca74648SRichard Henderson }
38651ca74648SRichard Henderson 
3866ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3867ebe9383cSRichard Henderson {
3868ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
3869ebe9383cSRichard Henderson }
3870ebe9383cSRichard Henderson 
38711ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a)
38721ca74648SRichard Henderson {
38731ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d);
38741ca74648SRichard Henderson }
38751ca74648SRichard Henderson 
38761ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3877ebe9383cSRichard Henderson {
3878ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
3879ebe9383cSRichard Henderson }
3880ebe9383cSRichard Henderson 
38811ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a)
38821ca74648SRichard Henderson {
38831ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fabs_f);
38841ca74648SRichard Henderson }
38851ca74648SRichard Henderson 
3886ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3887ebe9383cSRichard Henderson {
3888ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
3889ebe9383cSRichard Henderson }
3890ebe9383cSRichard Henderson 
38911ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a)
38921ca74648SRichard Henderson {
38931ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fabs_d);
38941ca74648SRichard Henderson }
38951ca74648SRichard Henderson 
38961ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a)
38971ca74648SRichard Henderson {
38981ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s);
38991ca74648SRichard Henderson }
39001ca74648SRichard Henderson 
39011ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a)
39021ca74648SRichard Henderson {
39031ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d);
39041ca74648SRichard Henderson }
39051ca74648SRichard Henderson 
39061ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a)
39071ca74648SRichard Henderson {
39081ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s);
39091ca74648SRichard Henderson }
39101ca74648SRichard Henderson 
39111ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a)
39121ca74648SRichard Henderson {
39131ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d);
39141ca74648SRichard Henderson }
39151ca74648SRichard Henderson 
39161ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3917ebe9383cSRichard Henderson {
3918ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
3919ebe9383cSRichard Henderson }
3920ebe9383cSRichard Henderson 
39211ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a)
39221ca74648SRichard Henderson {
39231ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fneg_f);
39241ca74648SRichard Henderson }
39251ca74648SRichard Henderson 
3926ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3927ebe9383cSRichard Henderson {
3928ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
3929ebe9383cSRichard Henderson }
3930ebe9383cSRichard Henderson 
39311ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a)
39321ca74648SRichard Henderson {
39331ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fneg_d);
39341ca74648SRichard Henderson }
39351ca74648SRichard Henderson 
39361ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3937ebe9383cSRichard Henderson {
3938ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
3939ebe9383cSRichard Henderson }
3940ebe9383cSRichard Henderson 
39411ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a)
39421ca74648SRichard Henderson {
39431ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f);
39441ca74648SRichard Henderson }
39451ca74648SRichard Henderson 
3946ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3947ebe9383cSRichard Henderson {
3948ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
3949ebe9383cSRichard Henderson }
3950ebe9383cSRichard Henderson 
39511ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a)
39521ca74648SRichard Henderson {
39531ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d);
39541ca74648SRichard Henderson }
39551ca74648SRichard Henderson 
39561ca74648SRichard Henderson /*
39571ca74648SRichard Henderson  * Float class 1
39581ca74648SRichard Henderson  */
39591ca74648SRichard Henderson 
39601ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a)
39611ca74648SRichard Henderson {
39621ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s);
39631ca74648SRichard Henderson }
39641ca74648SRichard Henderson 
39651ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a)
39661ca74648SRichard Henderson {
39671ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d);
39681ca74648SRichard Henderson }
39691ca74648SRichard Henderson 
39701ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a)
39711ca74648SRichard Henderson {
39721ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s);
39731ca74648SRichard Henderson }
39741ca74648SRichard Henderson 
39751ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a)
39761ca74648SRichard Henderson {
39771ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s);
39781ca74648SRichard Henderson }
39791ca74648SRichard Henderson 
39801ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a)
39811ca74648SRichard Henderson {
39821ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d);
39831ca74648SRichard Henderson }
39841ca74648SRichard Henderson 
39851ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a)
39861ca74648SRichard Henderson {
39871ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d);
39881ca74648SRichard Henderson }
39891ca74648SRichard Henderson 
39901ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a)
39911ca74648SRichard Henderson {
39921ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w);
39931ca74648SRichard Henderson }
39941ca74648SRichard Henderson 
39951ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a)
39961ca74648SRichard Henderson {
39971ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w);
39981ca74648SRichard Henderson }
39991ca74648SRichard Henderson 
40001ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a)
40011ca74648SRichard Henderson {
40021ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw);
40031ca74648SRichard Henderson }
40041ca74648SRichard Henderson 
40051ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a)
40061ca74648SRichard Henderson {
40071ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw);
40081ca74648SRichard Henderson }
40091ca74648SRichard Henderson 
40101ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a)
40111ca74648SRichard Henderson {
40121ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w);
40131ca74648SRichard Henderson }
40141ca74648SRichard Henderson 
40151ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a)
40161ca74648SRichard Henderson {
40171ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w);
40181ca74648SRichard Henderson }
40191ca74648SRichard Henderson 
40201ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a)
40211ca74648SRichard Henderson {
40221ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw);
40231ca74648SRichard Henderson }
40241ca74648SRichard Henderson 
40251ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a)
40261ca74648SRichard Henderson {
40271ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw);
40281ca74648SRichard Henderson }
40291ca74648SRichard Henderson 
40301ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a)
40311ca74648SRichard Henderson {
40321ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s);
40331ca74648SRichard Henderson }
40341ca74648SRichard Henderson 
40351ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a)
40361ca74648SRichard Henderson {
40371ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s);
40381ca74648SRichard Henderson }
40391ca74648SRichard Henderson 
40401ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a)
40411ca74648SRichard Henderson {
40421ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d);
40431ca74648SRichard Henderson }
40441ca74648SRichard Henderson 
40451ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a)
40461ca74648SRichard Henderson {
40471ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d);
40481ca74648SRichard Henderson }
40491ca74648SRichard Henderson 
40501ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a)
40511ca74648SRichard Henderson {
40521ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw);
40531ca74648SRichard Henderson }
40541ca74648SRichard Henderson 
40551ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a)
40561ca74648SRichard Henderson {
40571ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw);
40581ca74648SRichard Henderson }
40591ca74648SRichard Henderson 
40601ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a)
40611ca74648SRichard Henderson {
40621ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw);
40631ca74648SRichard Henderson }
40641ca74648SRichard Henderson 
40651ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a)
40661ca74648SRichard Henderson {
40671ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw);
40681ca74648SRichard Henderson }
40691ca74648SRichard Henderson 
40701ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a)
40711ca74648SRichard Henderson {
40721ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw);
40731ca74648SRichard Henderson }
40741ca74648SRichard Henderson 
40751ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a)
40761ca74648SRichard Henderson {
40771ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw);
40781ca74648SRichard Henderson }
40791ca74648SRichard Henderson 
40801ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a)
40811ca74648SRichard Henderson {
40821ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw);
40831ca74648SRichard Henderson }
40841ca74648SRichard Henderson 
40851ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a)
40861ca74648SRichard Henderson {
40871ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw);
40881ca74648SRichard Henderson }
40891ca74648SRichard Henderson 
40901ca74648SRichard Henderson /*
40911ca74648SRichard Henderson  * Float class 2
40921ca74648SRichard Henderson  */
40931ca74648SRichard Henderson 
40941ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a)
4095ebe9383cSRichard Henderson {
4096ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
4097ebe9383cSRichard Henderson 
4098ebe9383cSRichard Henderson     nullify_over(ctx);
4099ebe9383cSRichard Henderson 
41001ca74648SRichard Henderson     ta = load_frw0_i32(a->r1);
41011ca74648SRichard Henderson     tb = load_frw0_i32(a->r2);
410229dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
410329dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4104ebe9383cSRichard Henderson 
4105ad75a51eSRichard Henderson     gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc);
4106ebe9383cSRichard Henderson 
41071ca74648SRichard Henderson     return nullify_end(ctx);
4108ebe9383cSRichard Henderson }
4109ebe9383cSRichard Henderson 
41101ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
4111ebe9383cSRichard Henderson {
4112ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
4113ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
4114ebe9383cSRichard Henderson 
4115ebe9383cSRichard Henderson     nullify_over(ctx);
4116ebe9383cSRichard Henderson 
41171ca74648SRichard Henderson     ta = load_frd0(a->r1);
41181ca74648SRichard Henderson     tb = load_frd0(a->r2);
411929dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
412029dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4121ebe9383cSRichard Henderson 
4122ad75a51eSRichard Henderson     gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc);
4123ebe9383cSRichard Henderson 
412431234768SRichard Henderson     return nullify_end(ctx);
4125ebe9383cSRichard Henderson }
4126ebe9383cSRichard Henderson 
41271ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
4128ebe9383cSRichard Henderson {
41296fd0c7bcSRichard Henderson     TCGv_i64 t;
4130ebe9383cSRichard Henderson 
4131ebe9383cSRichard Henderson     nullify_over(ctx);
4132ebe9383cSRichard Henderson 
4133aac0f603SRichard Henderson     t = tcg_temp_new_i64();
41346fd0c7bcSRichard Henderson     tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
4135ebe9383cSRichard Henderson 
41361ca74648SRichard Henderson     if (a->y == 1) {
4137ebe9383cSRichard Henderson         int mask;
4138ebe9383cSRichard Henderson         bool inv = false;
4139ebe9383cSRichard Henderson 
41401ca74648SRichard Henderson         switch (a->c) {
4141ebe9383cSRichard Henderson         case 0: /* simple */
41426fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, 0x4000000);
4143ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_NE, t);
4144ebe9383cSRichard Henderson             goto done;
4145ebe9383cSRichard Henderson         case 2: /* rej */
4146ebe9383cSRichard Henderson             inv = true;
4147ebe9383cSRichard Henderson             /* fallthru */
4148ebe9383cSRichard Henderson         case 1: /* acc */
4149ebe9383cSRichard Henderson             mask = 0x43ff800;
4150ebe9383cSRichard Henderson             break;
4151ebe9383cSRichard Henderson         case 6: /* rej8 */
4152ebe9383cSRichard Henderson             inv = true;
4153ebe9383cSRichard Henderson             /* fallthru */
4154ebe9383cSRichard Henderson         case 5: /* acc8 */
4155ebe9383cSRichard Henderson             mask = 0x43f8000;
4156ebe9383cSRichard Henderson             break;
4157ebe9383cSRichard Henderson         case 9: /* acc6 */
4158ebe9383cSRichard Henderson             mask = 0x43e0000;
4159ebe9383cSRichard Henderson             break;
4160ebe9383cSRichard Henderson         case 13: /* acc4 */
4161ebe9383cSRichard Henderson             mask = 0x4380000;
4162ebe9383cSRichard Henderson             break;
4163ebe9383cSRichard Henderson         case 17: /* acc2 */
4164ebe9383cSRichard Henderson             mask = 0x4200000;
4165ebe9383cSRichard Henderson             break;
4166ebe9383cSRichard Henderson         default:
41671ca74648SRichard Henderson             gen_illegal(ctx);
41681ca74648SRichard Henderson             return true;
4169ebe9383cSRichard Henderson         }
4170ebe9383cSRichard Henderson         if (inv) {
41716fd0c7bcSRichard Henderson             TCGv_i64 c = tcg_constant_i64(mask);
41726fd0c7bcSRichard Henderson             tcg_gen_or_i64(t, t, c);
4173ebe9383cSRichard Henderson             ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
4174ebe9383cSRichard Henderson         } else {
41756fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, mask);
4176ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
4177ebe9383cSRichard Henderson         }
41781ca74648SRichard Henderson     } else {
41791ca74648SRichard Henderson         unsigned cbit = (a->y ^ 1) - 1;
41801ca74648SRichard Henderson 
41816fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, t, 21 - cbit, 1);
41821ca74648SRichard Henderson         ctx->null_cond = cond_make_0(TCG_COND_NE, t);
41831ca74648SRichard Henderson     }
41841ca74648SRichard Henderson 
4185ebe9383cSRichard Henderson  done:
418631234768SRichard Henderson     return nullify_end(ctx);
4187ebe9383cSRichard Henderson }
4188ebe9383cSRichard Henderson 
41891ca74648SRichard Henderson /*
41901ca74648SRichard Henderson  * Float class 2
41911ca74648SRichard Henderson  */
41921ca74648SRichard Henderson 
41931ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a)
4194ebe9383cSRichard Henderson {
41951ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s);
41961ca74648SRichard Henderson }
41971ca74648SRichard Henderson 
41981ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a)
41991ca74648SRichard Henderson {
42001ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d);
42011ca74648SRichard Henderson }
42021ca74648SRichard Henderson 
42031ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a)
42041ca74648SRichard Henderson {
42051ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s);
42061ca74648SRichard Henderson }
42071ca74648SRichard Henderson 
42081ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a)
42091ca74648SRichard Henderson {
42101ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d);
42111ca74648SRichard Henderson }
42121ca74648SRichard Henderson 
42131ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a)
42141ca74648SRichard Henderson {
42151ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s);
42161ca74648SRichard Henderson }
42171ca74648SRichard Henderson 
42181ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a)
42191ca74648SRichard Henderson {
42201ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d);
42211ca74648SRichard Henderson }
42221ca74648SRichard Henderson 
42231ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a)
42241ca74648SRichard Henderson {
42251ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s);
42261ca74648SRichard Henderson }
42271ca74648SRichard Henderson 
42281ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a)
42291ca74648SRichard Henderson {
42301ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d);
42311ca74648SRichard Henderson }
42321ca74648SRichard Henderson 
42331ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a)
42341ca74648SRichard Henderson {
42351ca74648SRichard Henderson     TCGv_i64 x, y;
4236ebe9383cSRichard Henderson 
4237ebe9383cSRichard Henderson     nullify_over(ctx);
4238ebe9383cSRichard Henderson 
42391ca74648SRichard Henderson     x = load_frw0_i64(a->r1);
42401ca74648SRichard Henderson     y = load_frw0_i64(a->r2);
42411ca74648SRichard Henderson     tcg_gen_mul_i64(x, x, y);
42421ca74648SRichard Henderson     save_frd(a->t, x);
4243ebe9383cSRichard Henderson 
424431234768SRichard Henderson     return nullify_end(ctx);
4245ebe9383cSRichard Henderson }
4246ebe9383cSRichard Henderson 
4247ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
4248ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
4249ebe9383cSRichard Henderson {
4250ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
4251ebe9383cSRichard Henderson }
4252ebe9383cSRichard Henderson 
4253b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4254ebe9383cSRichard Henderson {
4255b1e2af57SRichard Henderson     int tm = fmpyadd_s_reg(a->tm);
4256b1e2af57SRichard Henderson     int ra = fmpyadd_s_reg(a->ra);
4257b1e2af57SRichard Henderson     int ta = fmpyadd_s_reg(a->ta);
4258b1e2af57SRichard Henderson     int rm2 = fmpyadd_s_reg(a->rm2);
4259b1e2af57SRichard Henderson     int rm1 = fmpyadd_s_reg(a->rm1);
4260ebe9383cSRichard Henderson 
4261ebe9383cSRichard Henderson     nullify_over(ctx);
4262ebe9383cSRichard Henderson 
4263ebe9383cSRichard Henderson     do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4264ebe9383cSRichard Henderson     do_fop_weww(ctx, ta, ta, ra,
4265ebe9383cSRichard Henderson                 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
4266ebe9383cSRichard Henderson 
426731234768SRichard Henderson     return nullify_end(ctx);
4268ebe9383cSRichard Henderson }
4269ebe9383cSRichard Henderson 
4270b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4271b1e2af57SRichard Henderson {
4272b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, false);
4273b1e2af57SRichard Henderson }
4274b1e2af57SRichard Henderson 
4275b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4276b1e2af57SRichard Henderson {
4277b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, true);
4278b1e2af57SRichard Henderson }
4279b1e2af57SRichard Henderson 
4280b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4281b1e2af57SRichard Henderson {
4282b1e2af57SRichard Henderson     nullify_over(ctx);
4283b1e2af57SRichard Henderson 
4284b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4285b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4286b1e2af57SRichard Henderson                 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4287b1e2af57SRichard Henderson 
4288b1e2af57SRichard Henderson     return nullify_end(ctx);
4289b1e2af57SRichard Henderson }
4290b1e2af57SRichard Henderson 
4291b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4292b1e2af57SRichard Henderson {
4293b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, false);
4294b1e2af57SRichard Henderson }
4295b1e2af57SRichard Henderson 
4296b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4297b1e2af57SRichard Henderson {
4298b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, true);
4299b1e2af57SRichard Henderson }
4300b1e2af57SRichard Henderson 
4301c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a)
4302ebe9383cSRichard Henderson {
4303c3bad4f8SRichard Henderson     TCGv_i32 x, y, z;
4304ebe9383cSRichard Henderson 
4305ebe9383cSRichard Henderson     nullify_over(ctx);
4306c3bad4f8SRichard Henderson     x = load_frw0_i32(a->rm1);
4307c3bad4f8SRichard Henderson     y = load_frw0_i32(a->rm2);
4308c3bad4f8SRichard Henderson     z = load_frw0_i32(a->ra3);
4309ebe9383cSRichard Henderson 
4310c3bad4f8SRichard Henderson     if (a->neg) {
4311ad75a51eSRichard Henderson         gen_helper_fmpynfadd_s(x, tcg_env, x, y, z);
4312ebe9383cSRichard Henderson     } else {
4313ad75a51eSRichard Henderson         gen_helper_fmpyfadd_s(x, tcg_env, x, y, z);
4314ebe9383cSRichard Henderson     }
4315ebe9383cSRichard Henderson 
4316c3bad4f8SRichard Henderson     save_frw_i32(a->t, x);
431731234768SRichard Henderson     return nullify_end(ctx);
4318ebe9383cSRichard Henderson }
4319ebe9383cSRichard Henderson 
4320c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
4321ebe9383cSRichard Henderson {
4322c3bad4f8SRichard Henderson     TCGv_i64 x, y, z;
4323ebe9383cSRichard Henderson 
4324ebe9383cSRichard Henderson     nullify_over(ctx);
4325c3bad4f8SRichard Henderson     x = load_frd0(a->rm1);
4326c3bad4f8SRichard Henderson     y = load_frd0(a->rm2);
4327c3bad4f8SRichard Henderson     z = load_frd0(a->ra3);
4328ebe9383cSRichard Henderson 
4329c3bad4f8SRichard Henderson     if (a->neg) {
4330ad75a51eSRichard Henderson         gen_helper_fmpynfadd_d(x, tcg_env, x, y, z);
4331ebe9383cSRichard Henderson     } else {
4332ad75a51eSRichard Henderson         gen_helper_fmpyfadd_d(x, tcg_env, x, y, z);
4333ebe9383cSRichard Henderson     }
4334ebe9383cSRichard Henderson 
4335c3bad4f8SRichard Henderson     save_frd(a->t, x);
433631234768SRichard Henderson     return nullify_end(ctx);
4337ebe9383cSRichard Henderson }
4338ebe9383cSRichard Henderson 
433915da177bSSven Schnelle static bool trans_diag(DisasContext *ctx, arg_diag *a)
434015da177bSSven Schnelle {
4341cf6b28d4SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4342cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY
4343cf6b28d4SHelge Deller     if (a->i == 0x100) {
4344cf6b28d4SHelge Deller         /* emulate PDC BTLB, called by SeaBIOS-hppa */
4345ad75a51eSRichard Henderson         nullify_over(ctx);
4346ad75a51eSRichard Henderson         gen_helper_diag_btlb(tcg_env);
4347cf6b28d4SHelge Deller         return nullify_end(ctx);
434815da177bSSven Schnelle     }
4349ad75a51eSRichard Henderson #endif
4350ad75a51eSRichard Henderson     qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i);
4351ad75a51eSRichard Henderson     return true;
4352ad75a51eSRichard Henderson }
435315da177bSSven Schnelle 
4354b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
435561766fe9SRichard Henderson {
435651b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4357f764718dSRichard Henderson     int bound;
435861766fe9SRichard Henderson 
435951b061fbSRichard Henderson     ctx->cs = cs;
4360494737b7SRichard Henderson     ctx->tb_flags = ctx->base.tb->flags;
4361bd6243a3SRichard Henderson     ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
43623d68ee7bSRichard Henderson 
43633d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY
4364c01e5dfbSHelge Deller     ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX);
43653d68ee7bSRichard Henderson     ctx->mmu_idx = MMU_USER_IDX;
4366c01e5dfbSHelge Deller     ctx->iaoq_f = ctx->base.pc_first | ctx->privilege;
4367c01e5dfbSHelge Deller     ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege;
4368217d1a5eSRichard Henderson     ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
4369c301f34eSRichard Henderson #else
4370494737b7SRichard Henderson     ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
4371bb67ec32SRichard Henderson     ctx->mmu_idx = (ctx->tb_flags & PSW_D
4372bb67ec32SRichard Henderson                     ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
4373bb67ec32SRichard Henderson                     : MMU_PHYS_IDX);
43743d68ee7bSRichard Henderson 
4375c301f34eSRichard Henderson     /* Recover the IAOQ values from the GVA + PRIV.  */
4376c301f34eSRichard Henderson     uint64_t cs_base = ctx->base.tb->cs_base;
4377c301f34eSRichard Henderson     uint64_t iasq_f = cs_base & ~0xffffffffull;
4378c301f34eSRichard Henderson     int32_t diff = cs_base;
4379c301f34eSRichard Henderson 
4380c301f34eSRichard Henderson     ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
4381c301f34eSRichard Henderson     ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1);
4382c301f34eSRichard Henderson #endif
438351b061fbSRichard Henderson     ctx->iaoq_n = -1;
4384f764718dSRichard Henderson     ctx->iaoq_n_var = NULL;
438561766fe9SRichard Henderson 
43863d68ee7bSRichard Henderson     /* Bound the number of instructions by those left on the page.  */
43873d68ee7bSRichard Henderson     bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
4388b542683dSEmilio G. Cota     ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
438961766fe9SRichard Henderson }
439061766fe9SRichard Henderson 
439151b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
439251b061fbSRichard Henderson {
439351b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
439461766fe9SRichard Henderson 
43953d68ee7bSRichard Henderson     /* Seed the nullification status from PSW[N], as saved in TB->FLAGS.  */
439651b061fbSRichard Henderson     ctx->null_cond = cond_make_f();
439751b061fbSRichard Henderson     ctx->psw_n_nonzero = false;
4398494737b7SRichard Henderson     if (ctx->tb_flags & PSW_N) {
439951b061fbSRichard Henderson         ctx->null_cond.c = TCG_COND_ALWAYS;
440051b061fbSRichard Henderson         ctx->psw_n_nonzero = true;
4401129e9cc3SRichard Henderson     }
440251b061fbSRichard Henderson     ctx->null_lab = NULL;
440361766fe9SRichard Henderson }
440461766fe9SRichard Henderson 
440551b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
440651b061fbSRichard Henderson {
440751b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
440851b061fbSRichard Henderson 
440951b061fbSRichard Henderson     tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b);
441051b061fbSRichard Henderson }
441151b061fbSRichard Henderson 
441251b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
441351b061fbSRichard Henderson {
441451b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4415b77af26eSRichard Henderson     CPUHPPAState *env = cpu_env(cs);
441651b061fbSRichard Henderson     DisasJumpType ret;
441751b061fbSRichard Henderson 
441851b061fbSRichard Henderson     /* Execute one insn.  */
4419ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4420c301f34eSRichard Henderson     if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
442131234768SRichard Henderson         do_page_zero(ctx);
442231234768SRichard Henderson         ret = ctx->base.is_jmp;
4423869051eaSRichard Henderson         assert(ret != DISAS_NEXT);
4424ba1d0b44SRichard Henderson     } else
4425ba1d0b44SRichard Henderson #endif
4426ba1d0b44SRichard Henderson     {
442761766fe9SRichard Henderson         /* Always fetch the insn, even if nullified, so that we check
442861766fe9SRichard Henderson            the page permissions for execute.  */
44294e116893SIlya Leoshkevich         uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next);
443061766fe9SRichard Henderson 
443161766fe9SRichard Henderson         /* Set up the IA queue for the next insn.
443261766fe9SRichard Henderson            This will be overwritten by a branch.  */
443351b061fbSRichard Henderson         if (ctx->iaoq_b == -1) {
443451b061fbSRichard Henderson             ctx->iaoq_n = -1;
4435aac0f603SRichard Henderson             ctx->iaoq_n_var = tcg_temp_new_i64();
44366fd0c7bcSRichard Henderson             tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
443761766fe9SRichard Henderson         } else {
443851b061fbSRichard Henderson             ctx->iaoq_n = ctx->iaoq_b + 4;
4439f764718dSRichard Henderson             ctx->iaoq_n_var = NULL;
444061766fe9SRichard Henderson         }
444161766fe9SRichard Henderson 
444251b061fbSRichard Henderson         if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
444351b061fbSRichard Henderson             ctx->null_cond.c = TCG_COND_NEVER;
4444869051eaSRichard Henderson             ret = DISAS_NEXT;
4445129e9cc3SRichard Henderson         } else {
44461a19da0dSRichard Henderson             ctx->insn = insn;
444731274b46SRichard Henderson             if (!decode(ctx, insn)) {
444831274b46SRichard Henderson                 gen_illegal(ctx);
444931274b46SRichard Henderson             }
445031234768SRichard Henderson             ret = ctx->base.is_jmp;
445151b061fbSRichard Henderson             assert(ctx->null_lab == NULL);
4452129e9cc3SRichard Henderson         }
445361766fe9SRichard Henderson     }
445461766fe9SRichard Henderson 
44553d68ee7bSRichard Henderson     /* Advance the insn queue.  Note that this check also detects
44563d68ee7bSRichard Henderson        a priority change within the instruction queue.  */
445751b061fbSRichard Henderson     if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
4458c301f34eSRichard Henderson         if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1
4459c301f34eSRichard Henderson             && use_goto_tb(ctx, ctx->iaoq_b)
4460c301f34eSRichard Henderson             && (ctx->null_cond.c == TCG_COND_NEVER
4461c301f34eSRichard Henderson                 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
446251b061fbSRichard Henderson             nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
446351b061fbSRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
446431234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_NORETURN;
4465129e9cc3SRichard Henderson         } else {
446631234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE;
446761766fe9SRichard Henderson         }
4468129e9cc3SRichard Henderson     }
446951b061fbSRichard Henderson     ctx->iaoq_f = ctx->iaoq_b;
447051b061fbSRichard Henderson     ctx->iaoq_b = ctx->iaoq_n;
4471c301f34eSRichard Henderson     ctx->base.pc_next += 4;
447261766fe9SRichard Henderson 
4473c5d0aec2SRichard Henderson     switch (ret) {
4474c5d0aec2SRichard Henderson     case DISAS_NORETURN:
4475c5d0aec2SRichard Henderson     case DISAS_IAQ_N_UPDATED:
4476c5d0aec2SRichard Henderson         break;
4477c5d0aec2SRichard Henderson 
4478c5d0aec2SRichard Henderson     case DISAS_NEXT:
4479c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE:
4480c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
448151b061fbSRichard Henderson         if (ctx->iaoq_f == -1) {
4482a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b);
4483741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
4484c301f34eSRichard Henderson #ifndef CONFIG_USER_ONLY
4485c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
4486c301f34eSRichard Henderson #endif
448751b061fbSRichard Henderson             nullify_save(ctx);
4488c5d0aec2SRichard Henderson             ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT
4489c5d0aec2SRichard Henderson                                 ? DISAS_EXIT
4490c5d0aec2SRichard Henderson                                 : DISAS_IAQ_N_UPDATED);
449151b061fbSRichard Henderson         } else if (ctx->iaoq_b == -1) {
4492a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var);
449361766fe9SRichard Henderson         }
4494c5d0aec2SRichard Henderson         break;
4495c5d0aec2SRichard Henderson 
4496c5d0aec2SRichard Henderson     default:
4497c5d0aec2SRichard Henderson         g_assert_not_reached();
4498c5d0aec2SRichard Henderson     }
449961766fe9SRichard Henderson }
450061766fe9SRichard Henderson 
450151b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
450251b061fbSRichard Henderson {
450351b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4504e1b5a5edSRichard Henderson     DisasJumpType is_jmp = ctx->base.is_jmp;
450551b061fbSRichard Henderson 
4506e1b5a5edSRichard Henderson     switch (is_jmp) {
4507869051eaSRichard Henderson     case DISAS_NORETURN:
450861766fe9SRichard Henderson         break;
450951b061fbSRichard Henderson     case DISAS_TOO_MANY:
4510869051eaSRichard Henderson     case DISAS_IAQ_N_STALE:
4511e1b5a5edSRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
4512741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
4513741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
451451b061fbSRichard Henderson         nullify_save(ctx);
451561766fe9SRichard Henderson         /* FALLTHRU */
4516869051eaSRichard Henderson     case DISAS_IAQ_N_UPDATED:
45178532a14eSRichard Henderson         if (is_jmp != DISAS_IAQ_N_STALE_EXIT) {
45187f11636dSEmilio G. Cota             tcg_gen_lookup_and_goto_ptr();
45198532a14eSRichard Henderson             break;
452061766fe9SRichard Henderson         }
4521c5d0aec2SRichard Henderson         /* FALLTHRU */
4522c5d0aec2SRichard Henderson     case DISAS_EXIT:
4523c5d0aec2SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
452461766fe9SRichard Henderson         break;
452561766fe9SRichard Henderson     default:
452651b061fbSRichard Henderson         g_assert_not_reached();
452761766fe9SRichard Henderson     }
452851b061fbSRichard Henderson }
452961766fe9SRichard Henderson 
45308eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase,
45318eb806a7SRichard Henderson                               CPUState *cs, FILE *logfile)
453251b061fbSRichard Henderson {
4533c301f34eSRichard Henderson     target_ulong pc = dcbase->pc_first;
453461766fe9SRichard Henderson 
4535ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4536ba1d0b44SRichard Henderson     switch (pc) {
45377ad439dfSRichard Henderson     case 0x00:
45388eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000000:  (null)\n");
4539ba1d0b44SRichard Henderson         return;
45407ad439dfSRichard Henderson     case 0xb0:
45418eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000b0:  light-weight-syscall\n");
4542ba1d0b44SRichard Henderson         return;
45437ad439dfSRichard Henderson     case 0xe0:
45448eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000e0:  set-thread-pointer-syscall\n");
4545ba1d0b44SRichard Henderson         return;
45467ad439dfSRichard Henderson     case 0x100:
45478eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000100:  syscall\n");
4548ba1d0b44SRichard Henderson         return;
45497ad439dfSRichard Henderson     }
4550ba1d0b44SRichard Henderson #endif
4551ba1d0b44SRichard Henderson 
45528eb806a7SRichard Henderson     fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
45538eb806a7SRichard Henderson     target_disas(logfile, cs, pc, dcbase->tb->size);
455461766fe9SRichard Henderson }
455551b061fbSRichard Henderson 
455651b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = {
455751b061fbSRichard Henderson     .init_disas_context = hppa_tr_init_disas_context,
455851b061fbSRichard Henderson     .tb_start           = hppa_tr_tb_start,
455951b061fbSRichard Henderson     .insn_start         = hppa_tr_insn_start,
456051b061fbSRichard Henderson     .translate_insn     = hppa_tr_translate_insn,
456151b061fbSRichard Henderson     .tb_stop            = hppa_tr_tb_stop,
456251b061fbSRichard Henderson     .disas_log          = hppa_tr_disas_log,
456351b061fbSRichard Henderson };
456451b061fbSRichard Henderson 
4565597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
4566306c8721SRichard Henderson                            target_ulong pc, void *host_pc)
456751b061fbSRichard Henderson {
456851b061fbSRichard Henderson     DisasContext ctx;
4569306c8721SRichard Henderson     translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
457061766fe9SRichard Henderson }
4571