xref: /openbmc/qemu/target/hppa/translate.c (revision f9b11bc2e75de806f189f7a5d1e63ba735ef4207)
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"
2574781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h"
26dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
270843563fSRichard Henderson #include "tcg/tcg-op-gvec.h"
2861766fe9SRichard Henderson #include "exec/helper-proto.h"
2961766fe9SRichard Henderson #include "exec/helper-gen.h"
30869051eaSRichard Henderson #include "exec/translator.h"
3161766fe9SRichard Henderson #include "exec/log.h"
3261766fe9SRichard Henderson 
33d53106c9SRichard Henderson #define HELPER_H "helper.h"
34d53106c9SRichard Henderson #include "exec/helper-info.c.inc"
35d53106c9SRichard Henderson #undef  HELPER_H
36d53106c9SRichard Henderson 
37aac0f603SRichard Henderson /* Choose to use explicit sizes within this file. */
38aac0f603SRichard Henderson #undef tcg_temp_new
39d53106c9SRichard Henderson 
4061766fe9SRichard Henderson typedef struct DisasCond {
4161766fe9SRichard Henderson     TCGCond c;
426fd0c7bcSRichard Henderson     TCGv_i64 a0, a1;
4361766fe9SRichard Henderson } DisasCond;
4461766fe9SRichard Henderson 
4561766fe9SRichard Henderson typedef struct DisasContext {
46d01a3625SRichard Henderson     DisasContextBase base;
4761766fe9SRichard Henderson     CPUState *cs;
4861766fe9SRichard Henderson 
49c53e401eSRichard Henderson     uint64_t iaoq_f;
50c53e401eSRichard Henderson     uint64_t iaoq_b;
51c53e401eSRichard Henderson     uint64_t iaoq_n;
526fd0c7bcSRichard Henderson     TCGv_i64 iaoq_n_var;
5361766fe9SRichard Henderson 
5461766fe9SRichard Henderson     DisasCond null_cond;
5561766fe9SRichard Henderson     TCGLabel *null_lab;
5661766fe9SRichard Henderson 
57a4db4a78SRichard Henderson     TCGv_i64 zero;
58a4db4a78SRichard Henderson 
591a19da0dSRichard Henderson     uint32_t insn;
60494737b7SRichard Henderson     uint32_t tb_flags;
613d68ee7bSRichard Henderson     int mmu_idx;
623d68ee7bSRichard Henderson     int privilege;
6361766fe9SRichard Henderson     bool psw_n_nonzero;
64bd6243a3SRichard Henderson     bool is_pa20;
6524638bd1SRichard Henderson     bool insn_start_updated;
66217d1a5eSRichard Henderson 
67217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
68217d1a5eSRichard Henderson     MemOp unalign;
69217d1a5eSRichard Henderson #endif
7061766fe9SRichard Henderson } DisasContext;
7161766fe9SRichard Henderson 
72217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
73217d1a5eSRichard Henderson #define UNALIGN(C)       (C)->unalign
7417fe594cSRichard Henderson #define MMU_DISABLED(C)  false
75217d1a5eSRichard Henderson #else
762d4afb03SRichard Henderson #define UNALIGN(C)       MO_ALIGN
7717fe594cSRichard Henderson #define MMU_DISABLED(C)  MMU_IDX_MMU_DISABLED((C)->mmu_idx)
78217d1a5eSRichard Henderson #endif
79217d1a5eSRichard Henderson 
80e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently.  */
81451e4ffdSRichard Henderson static int expand_sm_imm(DisasContext *ctx, int val)
82e36f27efSRichard Henderson {
83881d1073SHelge Deller     /* Keep unimplemented bits disabled -- see cpu_hppa_put_psw. */
84881d1073SHelge Deller     if (ctx->is_pa20) {
85e36f27efSRichard Henderson         if (val & PSW_SM_W) {
86881d1073SHelge Deller             val |= PSW_W;
87881d1073SHelge Deller         }
88881d1073SHelge Deller         val &= ~(PSW_SM_W | PSW_SM_E | PSW_G);
89881d1073SHelge Deller     } else {
90881d1073SHelge Deller         val &= ~(PSW_SM_W | PSW_SM_E | PSW_O);
91e36f27efSRichard Henderson     }
92e36f27efSRichard Henderson     return val;
93e36f27efSRichard Henderson }
94e36f27efSRichard Henderson 
95deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base.  */
96451e4ffdSRichard Henderson static int expand_sr3x(DisasContext *ctx, int val)
97deee69a1SRichard Henderson {
98deee69a1SRichard Henderson     return ~val;
99deee69a1SRichard Henderson }
100deee69a1SRichard Henderson 
1011cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value
1021cd012a5SRichard Henderson    we use for the final M.  */
103451e4ffdSRichard Henderson static int ma_to_m(DisasContext *ctx, int val)
1041cd012a5SRichard Henderson {
1051cd012a5SRichard Henderson     return val & 2 ? (val & 1 ? -1 : 1) : 0;
1061cd012a5SRichard Henderson }
1071cd012a5SRichard Henderson 
108740038d7SRichard Henderson /* Convert the sign of the displacement to a pre or post-modify.  */
109451e4ffdSRichard Henderson static int pos_to_m(DisasContext *ctx, int val)
110740038d7SRichard Henderson {
111740038d7SRichard Henderson     return val ? 1 : -1;
112740038d7SRichard Henderson }
113740038d7SRichard Henderson 
114451e4ffdSRichard Henderson static int neg_to_m(DisasContext *ctx, int val)
115740038d7SRichard Henderson {
116740038d7SRichard Henderson     return val ? -1 : 1;
117740038d7SRichard Henderson }
118740038d7SRichard Henderson 
119740038d7SRichard Henderson /* Used for branch targets and fp memory ops.  */
120451e4ffdSRichard Henderson static int expand_shl2(DisasContext *ctx, int val)
12101afb7beSRichard Henderson {
12201afb7beSRichard Henderson     return val << 2;
12301afb7beSRichard Henderson }
12401afb7beSRichard Henderson 
1250588e061SRichard Henderson /* Used for assemble_21.  */
126451e4ffdSRichard Henderson static int expand_shl11(DisasContext *ctx, int val)
1270588e061SRichard Henderson {
1280588e061SRichard Henderson     return val << 11;
1290588e061SRichard Henderson }
1300588e061SRichard Henderson 
13172ae4f2bSRichard Henderson static int assemble_6(DisasContext *ctx, int val)
13272ae4f2bSRichard Henderson {
13372ae4f2bSRichard Henderson     /*
13472ae4f2bSRichard Henderson      * Officially, 32 * x + 32 - y.
13572ae4f2bSRichard Henderson      * Here, x is already in bit 5, and y is [4:0].
13672ae4f2bSRichard Henderson      * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1,
13772ae4f2bSRichard Henderson      * with the overflow from bit 4 summing with x.
13872ae4f2bSRichard Henderson      */
13972ae4f2bSRichard Henderson     return (val ^ 31) + 1;
14072ae4f2bSRichard Henderson }
14172ae4f2bSRichard Henderson 
1424768c28eSRichard Henderson /* Expander for assemble_16a(s,cat(im10a,0),i). */
1434768c28eSRichard Henderson static int expand_11a(DisasContext *ctx, int val)
1444768c28eSRichard Henderson {
1454768c28eSRichard Henderson     /*
1464768c28eSRichard Henderson      * @val is bit 0 and bits [4:15].
1474768c28eSRichard Henderson      * Swizzle thing around depending on PSW.W.
1484768c28eSRichard Henderson      */
1494768c28eSRichard Henderson     int im10a = extract32(val, 1, 10);
1504768c28eSRichard Henderson     int s = extract32(val, 11, 2);
1514768c28eSRichard Henderson     int i = (-(val & 1) << 13) | (im10a << 3);
1524768c28eSRichard Henderson 
1534768c28eSRichard Henderson     if (ctx->tb_flags & PSW_W) {
1544768c28eSRichard Henderson         i ^= s << 13;
1554768c28eSRichard Henderson     }
1564768c28eSRichard Henderson     return i;
1574768c28eSRichard Henderson }
1584768c28eSRichard Henderson 
15946174e14SRichard Henderson /* Expander for assemble_16a(s,im11a,i). */
16046174e14SRichard Henderson static int expand_12a(DisasContext *ctx, int val)
16146174e14SRichard Henderson {
16246174e14SRichard Henderson     /*
16346174e14SRichard Henderson      * @val is bit 0 and bits [3:15].
16446174e14SRichard Henderson      * Swizzle thing around depending on PSW.W.
16546174e14SRichard Henderson      */
16646174e14SRichard Henderson     int im11a = extract32(val, 1, 11);
16746174e14SRichard Henderson     int s = extract32(val, 12, 2);
16846174e14SRichard Henderson     int i = (-(val & 1) << 13) | (im11a << 2);
16946174e14SRichard Henderson 
17046174e14SRichard Henderson     if (ctx->tb_flags & PSW_W) {
17146174e14SRichard Henderson         i ^= s << 13;
17246174e14SRichard Henderson     }
17346174e14SRichard Henderson     return i;
17446174e14SRichard Henderson }
17546174e14SRichard Henderson 
17672bace2dSRichard Henderson /* Expander for assemble_16(s,im14). */
17772bace2dSRichard Henderson static int expand_16(DisasContext *ctx, int val)
17872bace2dSRichard Henderson {
17972bace2dSRichard Henderson     /*
18072bace2dSRichard Henderson      * @val is bits [0:15], containing both im14 and s.
18172bace2dSRichard Henderson      * Swizzle thing around depending on PSW.W.
18272bace2dSRichard Henderson      */
18372bace2dSRichard Henderson     int s = extract32(val, 14, 2);
18472bace2dSRichard Henderson     int i = (-(val & 1) << 13) | extract32(val, 1, 13);
18572bace2dSRichard Henderson 
18672bace2dSRichard Henderson     if (ctx->tb_flags & PSW_W) {
18772bace2dSRichard Henderson         i ^= s << 13;
18872bace2dSRichard Henderson     }
18972bace2dSRichard Henderson     return i;
19072bace2dSRichard Henderson }
19172bace2dSRichard Henderson 
19272bace2dSRichard Henderson /* The sp field is only present with !PSW_W. */
19372bace2dSRichard Henderson static int sp0_if_wide(DisasContext *ctx, int sp)
19472bace2dSRichard Henderson {
19572bace2dSRichard Henderson     return ctx->tb_flags & PSW_W ? 0 : sp;
19672bace2dSRichard Henderson }
19772bace2dSRichard Henderson 
198c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */
199c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val)
200c65c3ee1SRichard Henderson {
201c65c3ee1SRichard Henderson     return val ? val : 4; /* 0 == "*<<" */
202c65c3ee1SRichard Henderson }
203c65c3ee1SRichard Henderson 
20482d0c831SRichard Henderson /*
20582d0c831SRichard Henderson  * In many places pa1.x did not decode the bit that later became
20682d0c831SRichard Henderson  * the pa2.0 D bit.  Suppress D unless the cpu is pa2.0.
20782d0c831SRichard Henderson  */
20882d0c831SRichard Henderson static int pa20_d(DisasContext *ctx, int val)
20982d0c831SRichard Henderson {
21082d0c831SRichard Henderson     return ctx->is_pa20 & val;
21182d0c831SRichard Henderson }
21201afb7beSRichard Henderson 
21340f9f908SRichard Henderson /* Include the auto-generated decoder.  */
214abff1abfSPaolo Bonzini #include "decode-insns.c.inc"
21540f9f908SRichard Henderson 
21661766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated
21761766fe9SRichard Henderson    the iaq (for whatever reason), so don't do it again on exit.  */
218869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED  DISAS_TARGET_0
21961766fe9SRichard Henderson 
22061766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor
22161766fe9SRichard Henderson    updated the iaq for the next instruction to be executed.  */
222869051eaSRichard Henderson #define DISAS_IAQ_N_STALE    DISAS_TARGET_1
22361766fe9SRichard Henderson 
224e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately
225e1b5a5edSRichard Henderson    to recognize unmasked interrupts.  */
226e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT      DISAS_TARGET_2
227c5d0aec2SRichard Henderson #define DISAS_EXIT                  DISAS_TARGET_3
228e1b5a5edSRichard Henderson 
22961766fe9SRichard Henderson /* global register indexes */
2306fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32];
23133423472SRichard Henderson static TCGv_i64 cpu_sr[4];
232494737b7SRichard Henderson static TCGv_i64 cpu_srH;
2336fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f;
2346fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b;
235c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f;
236c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b;
2376fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar;
2386fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n;
2396fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v;
2406fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb;
2416fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb;
24261766fe9SRichard Henderson 
24361766fe9SRichard Henderson void hppa_translate_init(void)
24461766fe9SRichard Henderson {
24561766fe9SRichard Henderson #define DEF_VAR(V)  { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
24661766fe9SRichard Henderson 
2476fd0c7bcSRichard Henderson     typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar;
24861766fe9SRichard Henderson     static const GlobalVar vars[] = {
24935136a77SRichard Henderson         { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) },
25061766fe9SRichard Henderson         DEF_VAR(psw_n),
25161766fe9SRichard Henderson         DEF_VAR(psw_v),
25261766fe9SRichard Henderson         DEF_VAR(psw_cb),
25361766fe9SRichard Henderson         DEF_VAR(psw_cb_msb),
25461766fe9SRichard Henderson         DEF_VAR(iaoq_f),
25561766fe9SRichard Henderson         DEF_VAR(iaoq_b),
25661766fe9SRichard Henderson     };
25761766fe9SRichard Henderson 
25861766fe9SRichard Henderson #undef DEF_VAR
25961766fe9SRichard Henderson 
26061766fe9SRichard Henderson     /* Use the symbolic register names that match the disassembler.  */
26161766fe9SRichard Henderson     static const char gr_names[32][4] = {
26261766fe9SRichard Henderson         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
26361766fe9SRichard Henderson         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
26461766fe9SRichard Henderson         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
26561766fe9SRichard Henderson         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
26661766fe9SRichard Henderson     };
26733423472SRichard Henderson     /* SR[4-7] are not global registers so that we can index them.  */
268494737b7SRichard Henderson     static const char sr_names[5][4] = {
269494737b7SRichard Henderson         "sr0", "sr1", "sr2", "sr3", "srH"
27033423472SRichard Henderson     };
27161766fe9SRichard Henderson 
27261766fe9SRichard Henderson     int i;
27361766fe9SRichard Henderson 
274f764718dSRichard Henderson     cpu_gr[0] = NULL;
27561766fe9SRichard Henderson     for (i = 1; i < 32; i++) {
276ad75a51eSRichard Henderson         cpu_gr[i] = tcg_global_mem_new(tcg_env,
27761766fe9SRichard Henderson                                        offsetof(CPUHPPAState, gr[i]),
27861766fe9SRichard Henderson                                        gr_names[i]);
27961766fe9SRichard Henderson     }
28033423472SRichard Henderson     for (i = 0; i < 4; i++) {
281ad75a51eSRichard Henderson         cpu_sr[i] = tcg_global_mem_new_i64(tcg_env,
28233423472SRichard Henderson                                            offsetof(CPUHPPAState, sr[i]),
28333423472SRichard Henderson                                            sr_names[i]);
28433423472SRichard Henderson     }
285ad75a51eSRichard Henderson     cpu_srH = tcg_global_mem_new_i64(tcg_env,
286494737b7SRichard Henderson                                      offsetof(CPUHPPAState, sr[4]),
287494737b7SRichard Henderson                                      sr_names[4]);
28861766fe9SRichard Henderson 
28961766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(vars); ++i) {
29061766fe9SRichard Henderson         const GlobalVar *v = &vars[i];
291ad75a51eSRichard Henderson         *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name);
29261766fe9SRichard Henderson     }
293c301f34eSRichard Henderson 
294ad75a51eSRichard Henderson     cpu_iasq_f = tcg_global_mem_new_i64(tcg_env,
295c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_f),
296c301f34eSRichard Henderson                                         "iasq_f");
297ad75a51eSRichard Henderson     cpu_iasq_b = tcg_global_mem_new_i64(tcg_env,
298c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_b),
299c301f34eSRichard Henderson                                         "iasq_b");
30061766fe9SRichard Henderson }
30161766fe9SRichard Henderson 
302f5b5c857SRichard Henderson static void set_insn_breg(DisasContext *ctx, int breg)
303f5b5c857SRichard Henderson {
30424638bd1SRichard Henderson     assert(!ctx->insn_start_updated);
30524638bd1SRichard Henderson     ctx->insn_start_updated = true;
30624638bd1SRichard Henderson     tcg_set_insn_start_param(ctx->base.insn_start, 2, breg);
307f5b5c857SRichard Henderson }
308f5b5c857SRichard Henderson 
309129e9cc3SRichard Henderson static DisasCond cond_make_f(void)
310129e9cc3SRichard Henderson {
311f764718dSRichard Henderson     return (DisasCond){
312f764718dSRichard Henderson         .c = TCG_COND_NEVER,
313f764718dSRichard Henderson         .a0 = NULL,
314f764718dSRichard Henderson         .a1 = NULL,
315f764718dSRichard Henderson     };
316129e9cc3SRichard Henderson }
317129e9cc3SRichard Henderson 
318df0232feSRichard Henderson static DisasCond cond_make_t(void)
319df0232feSRichard Henderson {
320df0232feSRichard Henderson     return (DisasCond){
321df0232feSRichard Henderson         .c = TCG_COND_ALWAYS,
322df0232feSRichard Henderson         .a0 = NULL,
323df0232feSRichard Henderson         .a1 = NULL,
324df0232feSRichard Henderson     };
325df0232feSRichard Henderson }
326df0232feSRichard Henderson 
327129e9cc3SRichard Henderson static DisasCond cond_make_n(void)
328129e9cc3SRichard Henderson {
329f764718dSRichard Henderson     return (DisasCond){
330f764718dSRichard Henderson         .c = TCG_COND_NE,
331f764718dSRichard Henderson         .a0 = cpu_psw_n,
3326fd0c7bcSRichard Henderson         .a1 = tcg_constant_i64(0)
333f764718dSRichard Henderson     };
334129e9cc3SRichard Henderson }
335129e9cc3SRichard Henderson 
3366fd0c7bcSRichard Henderson static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
337b47a4a02SSven Schnelle {
338b47a4a02SSven Schnelle     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
3394fe9533aSRichard Henderson     return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 };
3404fe9533aSRichard Henderson }
3414fe9533aSRichard Henderson 
3426fd0c7bcSRichard Henderson static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0)
3434fe9533aSRichard Henderson {
3446fd0c7bcSRichard Henderson     return cond_make_tmp(c, a0, tcg_constant_i64(0));
345b47a4a02SSven Schnelle }
346b47a4a02SSven Schnelle 
3476fd0c7bcSRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0)
348129e9cc3SRichard Henderson {
349aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3506fd0c7bcSRichard Henderson     tcg_gen_mov_i64(tmp, a0);
351b47a4a02SSven Schnelle     return cond_make_0_tmp(c, tmp);
352129e9cc3SRichard Henderson }
353129e9cc3SRichard Henderson 
3546fd0c7bcSRichard Henderson static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
355129e9cc3SRichard Henderson {
356aac0f603SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
357aac0f603SRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
358129e9cc3SRichard Henderson 
3596fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t0, a0);
3606fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t1, a1);
3614fe9533aSRichard Henderson     return cond_make_tmp(c, t0, t1);
362129e9cc3SRichard Henderson }
363129e9cc3SRichard Henderson 
364129e9cc3SRichard Henderson static void cond_free(DisasCond *cond)
365129e9cc3SRichard Henderson {
366129e9cc3SRichard Henderson     switch (cond->c) {
367129e9cc3SRichard Henderson     default:
368f764718dSRichard Henderson         cond->a0 = NULL;
369f764718dSRichard Henderson         cond->a1 = NULL;
370129e9cc3SRichard Henderson         /* fallthru */
371129e9cc3SRichard Henderson     case TCG_COND_ALWAYS:
372129e9cc3SRichard Henderson         cond->c = TCG_COND_NEVER;
373129e9cc3SRichard Henderson         break;
374129e9cc3SRichard Henderson     case TCG_COND_NEVER:
375129e9cc3SRichard Henderson         break;
376129e9cc3SRichard Henderson     }
377129e9cc3SRichard Henderson }
378129e9cc3SRichard Henderson 
3796fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg)
38061766fe9SRichard Henderson {
38161766fe9SRichard Henderson     if (reg == 0) {
382bc3da3cfSRichard Henderson         return ctx->zero;
38361766fe9SRichard Henderson     } else {
38461766fe9SRichard Henderson         return cpu_gr[reg];
38561766fe9SRichard Henderson     }
38661766fe9SRichard Henderson }
38761766fe9SRichard Henderson 
3886fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg)
38961766fe9SRichard Henderson {
390129e9cc3SRichard Henderson     if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
391aac0f603SRichard Henderson         return tcg_temp_new_i64();
39261766fe9SRichard Henderson     } else {
39361766fe9SRichard Henderson         return cpu_gr[reg];
39461766fe9SRichard Henderson     }
39561766fe9SRichard Henderson }
39661766fe9SRichard Henderson 
3976fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t)
398129e9cc3SRichard Henderson {
399129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
4006fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0,
401129e9cc3SRichard Henderson                             ctx->null_cond.a1, dest, t);
402129e9cc3SRichard Henderson     } else {
4036fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, t);
404129e9cc3SRichard Henderson     }
405129e9cc3SRichard Henderson }
406129e9cc3SRichard Henderson 
4076fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t)
408129e9cc3SRichard Henderson {
409129e9cc3SRichard Henderson     if (reg != 0) {
410129e9cc3SRichard Henderson         save_or_nullify(ctx, cpu_gr[reg], t);
411129e9cc3SRichard Henderson     }
412129e9cc3SRichard Henderson }
413129e9cc3SRichard Henderson 
414e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
41596d6407fSRichard Henderson # define HI_OFS  0
41696d6407fSRichard Henderson # define LO_OFS  4
41796d6407fSRichard Henderson #else
41896d6407fSRichard Henderson # define HI_OFS  4
41996d6407fSRichard Henderson # define LO_OFS  0
42096d6407fSRichard Henderson #endif
42196d6407fSRichard Henderson 
42296d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt)
42396d6407fSRichard Henderson {
42496d6407fSRichard Henderson     TCGv_i32 ret = tcg_temp_new_i32();
425ad75a51eSRichard Henderson     tcg_gen_ld_i32(ret, tcg_env,
42696d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
42796d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
42896d6407fSRichard Henderson     return ret;
42996d6407fSRichard Henderson }
43096d6407fSRichard Henderson 
431ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt)
432ebe9383cSRichard Henderson {
433ebe9383cSRichard Henderson     if (rt == 0) {
4340992a930SRichard Henderson         TCGv_i32 ret = tcg_temp_new_i32();
4350992a930SRichard Henderson         tcg_gen_movi_i32(ret, 0);
4360992a930SRichard Henderson         return ret;
437ebe9383cSRichard Henderson     } else {
438ebe9383cSRichard Henderson         return load_frw_i32(rt);
439ebe9383cSRichard Henderson     }
440ebe9383cSRichard Henderson }
441ebe9383cSRichard Henderson 
442ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt)
443ebe9383cSRichard Henderson {
444ebe9383cSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
4450992a930SRichard Henderson     if (rt == 0) {
4460992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
4470992a930SRichard Henderson     } else {
448ad75a51eSRichard Henderson         tcg_gen_ld32u_i64(ret, tcg_env,
449ebe9383cSRichard Henderson                           offsetof(CPUHPPAState, fr[rt & 31])
450ebe9383cSRichard Henderson                           + (rt & 32 ? LO_OFS : HI_OFS));
451ebe9383cSRichard Henderson     }
4520992a930SRichard Henderson     return ret;
453ebe9383cSRichard Henderson }
454ebe9383cSRichard Henderson 
45596d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val)
45696d6407fSRichard Henderson {
457ad75a51eSRichard Henderson     tcg_gen_st_i32(val, tcg_env,
45896d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
45996d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
46096d6407fSRichard Henderson }
46196d6407fSRichard Henderson 
46296d6407fSRichard Henderson #undef HI_OFS
46396d6407fSRichard Henderson #undef LO_OFS
46496d6407fSRichard Henderson 
46596d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt)
46696d6407fSRichard Henderson {
46796d6407fSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
468ad75a51eSRichard Henderson     tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt]));
46996d6407fSRichard Henderson     return ret;
47096d6407fSRichard Henderson }
47196d6407fSRichard Henderson 
472ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt)
473ebe9383cSRichard Henderson {
474ebe9383cSRichard Henderson     if (rt == 0) {
4750992a930SRichard Henderson         TCGv_i64 ret = tcg_temp_new_i64();
4760992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
4770992a930SRichard Henderson         return ret;
478ebe9383cSRichard Henderson     } else {
479ebe9383cSRichard Henderson         return load_frd(rt);
480ebe9383cSRichard Henderson     }
481ebe9383cSRichard Henderson }
482ebe9383cSRichard Henderson 
48396d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val)
48496d6407fSRichard Henderson {
485ad75a51eSRichard Henderson     tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt]));
48696d6407fSRichard Henderson }
48796d6407fSRichard Henderson 
48833423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg)
48933423472SRichard Henderson {
49033423472SRichard Henderson #ifdef CONFIG_USER_ONLY
49133423472SRichard Henderson     tcg_gen_movi_i64(dest, 0);
49233423472SRichard Henderson #else
49333423472SRichard Henderson     if (reg < 4) {
49433423472SRichard Henderson         tcg_gen_mov_i64(dest, cpu_sr[reg]);
495494737b7SRichard Henderson     } else if (ctx->tb_flags & TB_FLAG_SR_SAME) {
496494737b7SRichard Henderson         tcg_gen_mov_i64(dest, cpu_srH);
49733423472SRichard Henderson     } else {
498ad75a51eSRichard Henderson         tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg]));
49933423472SRichard Henderson     }
50033423472SRichard Henderson #endif
50133423472SRichard Henderson }
50233423472SRichard Henderson 
503129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified.
504129e9cc3SRichard Henderson    Use this when the insn is too complex for a conditional move.  */
505129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx)
506129e9cc3SRichard Henderson {
507129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
508129e9cc3SRichard Henderson         /* The always condition should have been handled in the main loop.  */
509129e9cc3SRichard Henderson         assert(ctx->null_cond.c != TCG_COND_ALWAYS);
510129e9cc3SRichard Henderson 
511129e9cc3SRichard Henderson         ctx->null_lab = gen_new_label();
512129e9cc3SRichard Henderson 
513129e9cc3SRichard Henderson         /* If we're using PSW[N], copy it to a temp because... */
5146e94937aSRichard Henderson         if (ctx->null_cond.a0 == cpu_psw_n) {
515aac0f603SRichard Henderson             ctx->null_cond.a0 = tcg_temp_new_i64();
5166fd0c7bcSRichard Henderson             tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n);
517129e9cc3SRichard Henderson         }
518129e9cc3SRichard Henderson         /* ... we clear it before branching over the implementation,
519129e9cc3SRichard Henderson            so that (1) it's clear after nullifying this insn and
520129e9cc3SRichard Henderson            (2) if this insn nullifies the next, PSW[N] is valid.  */
521129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
522129e9cc3SRichard Henderson             ctx->psw_n_nonzero = false;
5236fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
524129e9cc3SRichard Henderson         }
525129e9cc3SRichard Henderson 
5266fd0c7bcSRichard Henderson         tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0,
527129e9cc3SRichard Henderson                            ctx->null_cond.a1, ctx->null_lab);
528129e9cc3SRichard Henderson         cond_free(&ctx->null_cond);
529129e9cc3SRichard Henderson     }
530129e9cc3SRichard Henderson }
531129e9cc3SRichard Henderson 
532129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N].  */
533129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx)
534129e9cc3SRichard Henderson {
535129e9cc3SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
536129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
5376fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
538129e9cc3SRichard Henderson         }
539129e9cc3SRichard Henderson         return;
540129e9cc3SRichard Henderson     }
5416e94937aSRichard Henderson     if (ctx->null_cond.a0 != cpu_psw_n) {
5426fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n,
543129e9cc3SRichard Henderson                             ctx->null_cond.a0, ctx->null_cond.a1);
544129e9cc3SRichard Henderson         ctx->psw_n_nonzero = true;
545129e9cc3SRichard Henderson     }
546129e9cc3SRichard Henderson     cond_free(&ctx->null_cond);
547129e9cc3SRichard Henderson }
548129e9cc3SRichard Henderson 
549129e9cc3SRichard Henderson /* Set a PSW[N] to X.  The intention is that this is used immediately
550129e9cc3SRichard Henderson    before a goto_tb/exit_tb, so that there is no fallthru path to other
551129e9cc3SRichard Henderson    code within the TB.  Therefore we do not update psw_n_nonzero.  */
552129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x)
553129e9cc3SRichard Henderson {
554129e9cc3SRichard Henderson     if (ctx->psw_n_nonzero || x) {
5556fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, x);
556129e9cc3SRichard Henderson     }
557129e9cc3SRichard Henderson }
558129e9cc3SRichard Henderson 
559129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified.
56040f9f908SRichard Henderson    This is the pair to nullify_over.  Always returns true so that
56140f9f908SRichard Henderson    it may be tail-called from a translate function.  */
56231234768SRichard Henderson static bool nullify_end(DisasContext *ctx)
563129e9cc3SRichard Henderson {
564129e9cc3SRichard Henderson     TCGLabel *null_lab = ctx->null_lab;
56531234768SRichard Henderson     DisasJumpType status = ctx->base.is_jmp;
566129e9cc3SRichard Henderson 
567f49b3537SRichard Henderson     /* For NEXT, NORETURN, STALE, we can easily continue (or exit).
568f49b3537SRichard Henderson        For UPDATED, we cannot update on the nullified path.  */
569f49b3537SRichard Henderson     assert(status != DISAS_IAQ_N_UPDATED);
570f49b3537SRichard Henderson 
571129e9cc3SRichard Henderson     if (likely(null_lab == NULL)) {
572129e9cc3SRichard Henderson         /* The current insn wasn't conditional or handled the condition
573129e9cc3SRichard Henderson            applied to it without a branch, so the (new) setting of
574129e9cc3SRichard Henderson            NULL_COND can be applied directly to the next insn.  */
57531234768SRichard Henderson         return true;
576129e9cc3SRichard Henderson     }
577129e9cc3SRichard Henderson     ctx->null_lab = NULL;
578129e9cc3SRichard Henderson 
579129e9cc3SRichard Henderson     if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
580129e9cc3SRichard Henderson         /* The next instruction will be unconditional,
581129e9cc3SRichard Henderson            and NULL_COND already reflects that.  */
582129e9cc3SRichard Henderson         gen_set_label(null_lab);
583129e9cc3SRichard Henderson     } else {
584129e9cc3SRichard Henderson         /* The insn that we just executed is itself nullifying the next
585129e9cc3SRichard Henderson            instruction.  Store the condition in the PSW[N] global.
586129e9cc3SRichard Henderson            We asserted PSW[N] = 0 in nullify_over, so that after the
587129e9cc3SRichard Henderson            label we have the proper value in place.  */
588129e9cc3SRichard Henderson         nullify_save(ctx);
589129e9cc3SRichard Henderson         gen_set_label(null_lab);
590129e9cc3SRichard Henderson         ctx->null_cond = cond_make_n();
591129e9cc3SRichard Henderson     }
592869051eaSRichard Henderson     if (status == DISAS_NORETURN) {
59331234768SRichard Henderson         ctx->base.is_jmp = DISAS_NEXT;
594129e9cc3SRichard Henderson     }
59531234768SRichard Henderson     return true;
596129e9cc3SRichard Henderson }
597129e9cc3SRichard Henderson 
5986fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest,
5996fd0c7bcSRichard Henderson                             uint64_t ival, TCGv_i64 vval)
60061766fe9SRichard Henderson {
6017d50b696SSven Schnelle     uint64_t mask = gva_offset_mask(ctx->tb_flags);
602f13bf343SRichard Henderson 
603f13bf343SRichard Henderson     if (ival != -1) {
6046fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, ival & mask);
605f13bf343SRichard Henderson         return;
606f13bf343SRichard Henderson     }
607f13bf343SRichard Henderson     tcg_debug_assert(vval != NULL);
608f13bf343SRichard Henderson 
609f13bf343SRichard Henderson     /*
610f13bf343SRichard Henderson      * We know that the IAOQ is already properly masked.
611f13bf343SRichard Henderson      * This optimization is primarily for "iaoq_f = iaoq_b".
612f13bf343SRichard Henderson      */
613f13bf343SRichard Henderson     if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) {
6146fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, vval);
61561766fe9SRichard Henderson     } else {
6166fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, vval, mask);
61761766fe9SRichard Henderson     }
61861766fe9SRichard Henderson }
61961766fe9SRichard Henderson 
620c53e401eSRichard Henderson static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp)
62161766fe9SRichard Henderson {
62261766fe9SRichard Henderson     return ctx->iaoq_f + disp + 8;
62361766fe9SRichard Henderson }
62461766fe9SRichard Henderson 
62561766fe9SRichard Henderson static void gen_excp_1(int exception)
62661766fe9SRichard Henderson {
627ad75a51eSRichard Henderson     gen_helper_excp(tcg_env, tcg_constant_i32(exception));
62861766fe9SRichard Henderson }
62961766fe9SRichard Henderson 
63031234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception)
63161766fe9SRichard Henderson {
632741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
633741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
634129e9cc3SRichard Henderson     nullify_save(ctx);
63561766fe9SRichard Henderson     gen_excp_1(exception);
63631234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
63761766fe9SRichard Henderson }
63861766fe9SRichard Henderson 
63931234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc)
6401a19da0dSRichard Henderson {
64131234768SRichard Henderson     nullify_over(ctx);
6426fd0c7bcSRichard Henderson     tcg_gen_st_i64(tcg_constant_i64(ctx->insn),
643ad75a51eSRichard Henderson                    tcg_env, offsetof(CPUHPPAState, cr[CR_IIR]));
64431234768SRichard Henderson     gen_excp(ctx, exc);
64531234768SRichard Henderson     return nullify_end(ctx);
6461a19da0dSRichard Henderson }
6471a19da0dSRichard Henderson 
64831234768SRichard Henderson static bool gen_illegal(DisasContext *ctx)
64961766fe9SRichard Henderson {
65031234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_ILL);
65161766fe9SRichard Henderson }
65261766fe9SRichard Henderson 
65340f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY
65440f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
65540f9f908SRichard Henderson     return gen_excp_iir(ctx, EXCP)
65640f9f908SRichard Henderson #else
657e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
658e1b5a5edSRichard Henderson     do {                                     \
659e1b5a5edSRichard Henderson         if (ctx->privilege != 0) {           \
66031234768SRichard Henderson             return gen_excp_iir(ctx, EXCP);  \
661e1b5a5edSRichard Henderson         }                                    \
662e1b5a5edSRichard Henderson     } while (0)
66340f9f908SRichard Henderson #endif
664e1b5a5edSRichard Henderson 
6654e31e68bSRichard Henderson static bool use_goto_tb(DisasContext *ctx, uint64_t bofs, uint64_t nofs)
66661766fe9SRichard Henderson {
6674e31e68bSRichard Henderson     return (bofs != -1 && nofs != -1 &&
6684e31e68bSRichard Henderson             translator_use_goto_tb(&ctx->base, bofs));
66961766fe9SRichard Henderson }
67061766fe9SRichard Henderson 
671129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page,
672129e9cc3SRichard Henderson    and we're not attempting to set a breakpoint on it, then we can
673129e9cc3SRichard Henderson    totally skip the nullified insn.  This avoids creating and
674129e9cc3SRichard Henderson    executing a TB that merely branches to the next TB.  */
675129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx)
676129e9cc3SRichard Henderson {
677*f9b11bc2SRichard Henderson     return (!(tb_cflags(ctx->base.tb) & CF_BP_PAGE)
678*f9b11bc2SRichard Henderson             && ctx->iaoq_b != -1
679*f9b11bc2SRichard Henderson             && is_same_page(&ctx->base, ctx->iaoq_b));
680129e9cc3SRichard Henderson }
681129e9cc3SRichard Henderson 
68261766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which,
6834e31e68bSRichard Henderson                         uint64_t b, uint64_t n)
68461766fe9SRichard Henderson {
6854e31e68bSRichard Henderson     if (use_goto_tb(ctx, b, n)) {
68661766fe9SRichard Henderson         tcg_gen_goto_tb(which);
6874e31e68bSRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, b, NULL);
6884e31e68bSRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, n, NULL);
68907ea28b4SRichard Henderson         tcg_gen_exit_tb(ctx->base.tb, which);
69061766fe9SRichard Henderson     } else {
6914e31e68bSRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, b, cpu_iaoq_b);
6924e31e68bSRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, n, ctx->iaoq_n_var);
6937f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
69461766fe9SRichard Henderson     }
69561766fe9SRichard Henderson }
69661766fe9SRichard Henderson 
697b47a4a02SSven Schnelle static bool cond_need_sv(int c)
698b47a4a02SSven Schnelle {
699b47a4a02SSven Schnelle     return c == 2 || c == 3 || c == 6;
700b47a4a02SSven Schnelle }
701b47a4a02SSven Schnelle 
702b47a4a02SSven Schnelle static bool cond_need_cb(int c)
703b47a4a02SSven Schnelle {
704b47a4a02SSven Schnelle     return c == 4 || c == 5;
705b47a4a02SSven Schnelle }
706b47a4a02SSven Schnelle 
707b47a4a02SSven Schnelle /*
708b47a4a02SSven Schnelle  * Compute conditional for arithmetic.  See Page 5-3, Table 5-1, of
709b47a4a02SSven Schnelle  * the Parisc 1.1 Architecture Reference Manual for details.
710b47a4a02SSven Schnelle  */
711b2167459SRichard Henderson 
712a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d,
713fe2d066aSRichard Henderson                          TCGv_i64 res, TCGv_i64 uv, TCGv_i64 sv)
714b2167459SRichard Henderson {
715b2167459SRichard Henderson     DisasCond cond;
7166fd0c7bcSRichard Henderson     TCGv_i64 tmp;
717b2167459SRichard Henderson 
718b2167459SRichard Henderson     switch (cf >> 1) {
719b47a4a02SSven Schnelle     case 0: /* Never / TR    (0 / 1) */
720b2167459SRichard Henderson         cond = cond_make_f();
721b2167459SRichard Henderson         break;
722b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
72382d0c831SRichard Henderson         if (!d) {
724aac0f603SRichard Henderson             tmp = tcg_temp_new_i64();
7256fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
726a751eb31SRichard Henderson             res = tmp;
727a751eb31SRichard Henderson         }
728b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, res);
729b2167459SRichard Henderson         break;
730b47a4a02SSven Schnelle     case 2: /* < / >=        (N ^ V / !(N ^ V) */
731aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
7326fd0c7bcSRichard Henderson         tcg_gen_xor_i64(tmp, res, sv);
73382d0c831SRichard Henderson         if (!d) {
7346fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, tmp);
735a751eb31SRichard Henderson         }
736b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_LT, tmp);
737b2167459SRichard Henderson         break;
738b47a4a02SSven Schnelle     case 3: /* <= / >        (N ^ V) | Z / !((N ^ V) | Z) */
739b47a4a02SSven Schnelle         /*
740b47a4a02SSven Schnelle          * Simplify:
741b47a4a02SSven Schnelle          *   (N ^ V) | Z
742b47a4a02SSven Schnelle          *   ((res < 0) ^ (sv < 0)) | !res
743b47a4a02SSven Schnelle          *   ((res ^ sv) < 0) | !res
744b47a4a02SSven Schnelle          *   (~(res ^ sv) >= 0) | !res
745b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31) | !res
746b47a4a02SSven Schnelle          *   !(~(res ^ sv) >> 31 & res)
747b47a4a02SSven Schnelle          */
748aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
7496fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(tmp, res, sv);
75082d0c831SRichard Henderson         if (!d) {
7516fd0c7bcSRichard Henderson             tcg_gen_sextract_i64(tmp, tmp, 31, 1);
7526fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
7536fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
754a751eb31SRichard Henderson         } else {
7556fd0c7bcSRichard Henderson             tcg_gen_sari_i64(tmp, tmp, 63);
7566fd0c7bcSRichard Henderson             tcg_gen_and_i64(tmp, tmp, res);
757a751eb31SRichard Henderson         }
758b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
759b2167459SRichard Henderson         break;
760fe2d066aSRichard Henderson     case 4: /* NUV / UV      (!UV / UV) */
761fe2d066aSRichard Henderson         cond = cond_make_0(TCG_COND_EQ, uv);
762b2167459SRichard Henderson         break;
763fe2d066aSRichard Henderson     case 5: /* ZNV / VNZ     (!UV | Z / UV & !Z) */
764aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
765fe2d066aSRichard Henderson         tcg_gen_movcond_i64(TCG_COND_EQ, tmp, uv, ctx->zero, ctx->zero, res);
76682d0c831SRichard Henderson         if (!d) {
7676fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, tmp);
768a751eb31SRichard Henderson         }
769b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
770b2167459SRichard Henderson         break;
771b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
77282d0c831SRichard Henderson         if (!d) {
773aac0f603SRichard Henderson             tmp = tcg_temp_new_i64();
7746fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, sv);
775a751eb31SRichard Henderson             sv = tmp;
776a751eb31SRichard Henderson         }
777b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, sv);
778b2167459SRichard Henderson         break;
779b2167459SRichard Henderson     case 7: /* OD / EV */
780aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
7816fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, res, 1);
782b47a4a02SSven Schnelle         cond = cond_make_0_tmp(TCG_COND_NE, tmp);
783b2167459SRichard Henderson         break;
784b2167459SRichard Henderson     default:
785b2167459SRichard Henderson         g_assert_not_reached();
786b2167459SRichard Henderson     }
787b2167459SRichard Henderson     if (cf & 1) {
788b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
789b2167459SRichard Henderson     }
790b2167459SRichard Henderson 
791b2167459SRichard Henderson     return cond;
792b2167459SRichard Henderson }
793b2167459SRichard Henderson 
794b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
795b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
796b2167459SRichard Henderson    deleted as unused.  */
797b2167459SRichard Henderson 
7984fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d,
7996fd0c7bcSRichard Henderson                              TCGv_i64 res, TCGv_i64 in1,
8006fd0c7bcSRichard Henderson                              TCGv_i64 in2, TCGv_i64 sv)
801b2167459SRichard Henderson {
8024fe9533aSRichard Henderson     TCGCond tc;
8034fe9533aSRichard Henderson     bool ext_uns;
804b2167459SRichard Henderson 
805b2167459SRichard Henderson     switch (cf >> 1) {
806b2167459SRichard Henderson     case 1: /* = / <> */
8074fe9533aSRichard Henderson         tc = TCG_COND_EQ;
8084fe9533aSRichard Henderson         ext_uns = true;
809b2167459SRichard Henderson         break;
810b2167459SRichard Henderson     case 2: /* < / >= */
8114fe9533aSRichard Henderson         tc = TCG_COND_LT;
8124fe9533aSRichard Henderson         ext_uns = false;
813b2167459SRichard Henderson         break;
814b2167459SRichard Henderson     case 3: /* <= / > */
8154fe9533aSRichard Henderson         tc = TCG_COND_LE;
8164fe9533aSRichard Henderson         ext_uns = false;
817b2167459SRichard Henderson         break;
818b2167459SRichard Henderson     case 4: /* << / >>= */
8194fe9533aSRichard Henderson         tc = TCG_COND_LTU;
8204fe9533aSRichard Henderson         ext_uns = true;
821b2167459SRichard Henderson         break;
822b2167459SRichard Henderson     case 5: /* <<= / >> */
8234fe9533aSRichard Henderson         tc = TCG_COND_LEU;
8244fe9533aSRichard Henderson         ext_uns = true;
825b2167459SRichard Henderson         break;
826b2167459SRichard Henderson     default:
827a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, sv);
828b2167459SRichard Henderson     }
829b2167459SRichard Henderson 
8304fe9533aSRichard Henderson     if (cf & 1) {
8314fe9533aSRichard Henderson         tc = tcg_invert_cond(tc);
8324fe9533aSRichard Henderson     }
83382d0c831SRichard Henderson     if (!d) {
834aac0f603SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
835aac0f603SRichard Henderson         TCGv_i64 t2 = tcg_temp_new_i64();
8364fe9533aSRichard Henderson 
8374fe9533aSRichard Henderson         if (ext_uns) {
8386fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t1, in1);
8396fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t2, in2);
8404fe9533aSRichard Henderson         } else {
8416fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t1, in1);
8426fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t2, in2);
8434fe9533aSRichard Henderson         }
8444fe9533aSRichard Henderson         return cond_make_tmp(tc, t1, t2);
8454fe9533aSRichard Henderson     }
8464fe9533aSRichard Henderson     return cond_make(tc, in1, in2);
847b2167459SRichard Henderson }
848b2167459SRichard Henderson 
849df0232feSRichard Henderson /*
850df0232feSRichard Henderson  * Similar, but for logicals, where the carry and overflow bits are not
851df0232feSRichard Henderson  * computed, and use of them is undefined.
852df0232feSRichard Henderson  *
853df0232feSRichard Henderson  * Undefined or not, hardware does not trap.  It seems reasonable to
854df0232feSRichard Henderson  * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's
855df0232feSRichard Henderson  * how cases c={2,3} are treated.
856df0232feSRichard Henderson  */
857b2167459SRichard Henderson 
858b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d,
8596fd0c7bcSRichard Henderson                              TCGv_i64 res)
860b2167459SRichard Henderson {
861b5af8423SRichard Henderson     TCGCond tc;
862b5af8423SRichard Henderson     bool ext_uns;
863a751eb31SRichard Henderson 
864df0232feSRichard Henderson     switch (cf) {
865df0232feSRichard Henderson     case 0:  /* never */
866df0232feSRichard Henderson     case 9:  /* undef, C */
867df0232feSRichard Henderson     case 11: /* undef, C & !Z */
868df0232feSRichard Henderson     case 12: /* undef, V */
869df0232feSRichard Henderson         return cond_make_f();
870df0232feSRichard Henderson 
871df0232feSRichard Henderson     case 1:  /* true */
872df0232feSRichard Henderson     case 8:  /* undef, !C */
873df0232feSRichard Henderson     case 10: /* undef, !C | Z */
874df0232feSRichard Henderson     case 13: /* undef, !V */
875df0232feSRichard Henderson         return cond_make_t();
876df0232feSRichard Henderson 
877df0232feSRichard Henderson     case 2:  /* == */
878b5af8423SRichard Henderson         tc = TCG_COND_EQ;
879b5af8423SRichard Henderson         ext_uns = true;
880b5af8423SRichard Henderson         break;
881df0232feSRichard Henderson     case 3:  /* <> */
882b5af8423SRichard Henderson         tc = TCG_COND_NE;
883b5af8423SRichard Henderson         ext_uns = true;
884b5af8423SRichard Henderson         break;
885df0232feSRichard Henderson     case 4:  /* < */
886b5af8423SRichard Henderson         tc = TCG_COND_LT;
887b5af8423SRichard Henderson         ext_uns = false;
888b5af8423SRichard Henderson         break;
889df0232feSRichard Henderson     case 5:  /* >= */
890b5af8423SRichard Henderson         tc = TCG_COND_GE;
891b5af8423SRichard Henderson         ext_uns = false;
892b5af8423SRichard Henderson         break;
893df0232feSRichard Henderson     case 6:  /* <= */
894b5af8423SRichard Henderson         tc = TCG_COND_LE;
895b5af8423SRichard Henderson         ext_uns = false;
896b5af8423SRichard Henderson         break;
897df0232feSRichard Henderson     case 7:  /* > */
898b5af8423SRichard Henderson         tc = TCG_COND_GT;
899b5af8423SRichard Henderson         ext_uns = false;
900b5af8423SRichard Henderson         break;
901df0232feSRichard Henderson 
902df0232feSRichard Henderson     case 14: /* OD */
903df0232feSRichard Henderson     case 15: /* EV */
904a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, NULL);
905df0232feSRichard Henderson 
906df0232feSRichard Henderson     default:
907df0232feSRichard Henderson         g_assert_not_reached();
908b2167459SRichard Henderson     }
909b5af8423SRichard Henderson 
91082d0c831SRichard Henderson     if (!d) {
911aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
912b5af8423SRichard Henderson 
913b5af8423SRichard Henderson         if (ext_uns) {
9146fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(tmp, res);
915b5af8423SRichard Henderson         } else {
9166fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, res);
917b5af8423SRichard Henderson         }
918b5af8423SRichard Henderson         return cond_make_0_tmp(tc, tmp);
919b5af8423SRichard Henderson     }
920b5af8423SRichard Henderson     return cond_make_0(tc, res);
921b2167459SRichard Henderson }
922b2167459SRichard Henderson 
92398cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
92498cd9ca7SRichard Henderson 
9254fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d,
9266fd0c7bcSRichard Henderson                              TCGv_i64 res)
92798cd9ca7SRichard Henderson {
92898cd9ca7SRichard Henderson     unsigned c, f;
92998cd9ca7SRichard Henderson 
93098cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
93198cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
93298cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
93398cd9ca7SRichard Henderson     c = orig & 3;
93498cd9ca7SRichard Henderson     if (c == 3) {
93598cd9ca7SRichard Henderson         c = 7;
93698cd9ca7SRichard Henderson     }
93798cd9ca7SRichard Henderson     f = (orig & 4) / 4;
93898cd9ca7SRichard Henderson 
939b5af8423SRichard Henderson     return do_log_cond(ctx, c * 2 + f, d, res);
94098cd9ca7SRichard Henderson }
94198cd9ca7SRichard Henderson 
94246bb3d46SRichard Henderson /* Similar, but for unit zero conditions.  */
94346bb3d46SRichard Henderson static DisasCond do_unit_zero_cond(unsigned cf, bool d, TCGv_i64 res)
944b2167459SRichard Henderson {
94546bb3d46SRichard Henderson     TCGv_i64 tmp;
946c53e401eSRichard Henderson     uint64_t d_repl = d ? 0x0000000100000001ull : 1;
94746bb3d46SRichard Henderson     uint64_t ones = 0, sgns = 0;
948b2167459SRichard Henderson 
949b2167459SRichard Henderson     switch (cf >> 1) {
950578b8132SSven Schnelle     case 1: /* SBW / NBW */
951578b8132SSven Schnelle         if (d) {
95246bb3d46SRichard Henderson             ones = d_repl;
95346bb3d46SRichard Henderson             sgns = d_repl << 31;
954578b8132SSven Schnelle         }
955578b8132SSven Schnelle         break;
956b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
95746bb3d46SRichard Henderson         ones = d_repl * 0x01010101u;
95846bb3d46SRichard Henderson         sgns = ones << 7;
95946bb3d46SRichard Henderson         break;
96046bb3d46SRichard Henderson     case 3: /* SHZ / NHZ */
96146bb3d46SRichard Henderson         ones = d_repl * 0x00010001u;
96246bb3d46SRichard Henderson         sgns = ones << 15;
96346bb3d46SRichard Henderson         break;
96446bb3d46SRichard Henderson     }
96546bb3d46SRichard Henderson     if (ones == 0) {
96646bb3d46SRichard Henderson         /* Undefined, or 0/1 (never/always). */
96746bb3d46SRichard Henderson         return cf & 1 ? cond_make_t() : cond_make_f();
96846bb3d46SRichard Henderson     }
96946bb3d46SRichard Henderson 
97046bb3d46SRichard Henderson     /*
97146bb3d46SRichard Henderson      * See hasless(v,1) from
972b2167459SRichard Henderson      * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
973b2167459SRichard Henderson      */
974aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
97546bb3d46SRichard Henderson     tcg_gen_subi_i64(tmp, res, ones);
9766fd0c7bcSRichard Henderson     tcg_gen_andc_i64(tmp, tmp, res);
97746bb3d46SRichard Henderson     tcg_gen_andi_i64(tmp, tmp, sgns);
978b2167459SRichard Henderson 
97946bb3d46SRichard Henderson     return cond_make_0_tmp(cf & 1 ? TCG_COND_EQ : TCG_COND_NE, tmp);
980b2167459SRichard Henderson }
981b2167459SRichard Henderson 
9826fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d,
9836fd0c7bcSRichard Henderson                           TCGv_i64 cb, TCGv_i64 cb_msb)
98472ca8753SRichard Henderson {
98582d0c831SRichard Henderson     if (!d) {
986aac0f603SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
9876fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, cb, 32, 1);
98872ca8753SRichard Henderson         return t;
98972ca8753SRichard Henderson     }
99072ca8753SRichard Henderson     return cb_msb;
99172ca8753SRichard Henderson }
99272ca8753SRichard Henderson 
9936fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d)
99472ca8753SRichard Henderson {
99572ca8753SRichard Henderson     return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb);
99672ca8753SRichard Henderson }
99772ca8753SRichard Henderson 
998b2167459SRichard Henderson /* Compute signed overflow for addition.  */
9996fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res,
1000f8f5986eSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2,
1001f8f5986eSRichard Henderson                           TCGv_i64 orig_in1, int shift, bool d)
1002b2167459SRichard Henderson {
1003aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
1004aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
1005b2167459SRichard Henderson 
10066fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
10076fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
10086fd0c7bcSRichard Henderson     tcg_gen_andc_i64(sv, sv, tmp);
1009b2167459SRichard Henderson 
1010f8f5986eSRichard Henderson     switch (shift) {
1011f8f5986eSRichard Henderson     case 0:
1012f8f5986eSRichard Henderson         break;
1013f8f5986eSRichard Henderson     case 1:
1014f8f5986eSRichard Henderson         /* Shift left by one and compare the sign. */
1015f8f5986eSRichard Henderson         tcg_gen_add_i64(tmp, orig_in1, orig_in1);
1016f8f5986eSRichard Henderson         tcg_gen_xor_i64(tmp, tmp, orig_in1);
1017f8f5986eSRichard Henderson         /* Incorporate into the overflow. */
1018f8f5986eSRichard Henderson         tcg_gen_or_i64(sv, sv, tmp);
1019f8f5986eSRichard Henderson         break;
1020f8f5986eSRichard Henderson     default:
1021f8f5986eSRichard Henderson         {
1022f8f5986eSRichard Henderson             int sign_bit = d ? 63 : 31;
1023f8f5986eSRichard Henderson 
1024f8f5986eSRichard Henderson             /* Compare the sign against all lower bits. */
1025f8f5986eSRichard Henderson             tcg_gen_sextract_i64(tmp, orig_in1, sign_bit, 1);
1026f8f5986eSRichard Henderson             tcg_gen_xor_i64(tmp, tmp, orig_in1);
1027f8f5986eSRichard Henderson             /*
1028f8f5986eSRichard Henderson              * If one of the bits shifting into or through the sign
1029f8f5986eSRichard Henderson              * differs, then we have overflow.
1030f8f5986eSRichard Henderson              */
1031f8f5986eSRichard Henderson             tcg_gen_extract_i64(tmp, tmp, sign_bit - shift, shift);
1032f8f5986eSRichard Henderson             tcg_gen_movcond_i64(TCG_COND_NE, sv, tmp, ctx->zero,
1033f8f5986eSRichard Henderson                                 tcg_constant_i64(-1), sv);
1034f8f5986eSRichard Henderson         }
1035f8f5986eSRichard Henderson     }
1036b2167459SRichard Henderson     return sv;
1037b2167459SRichard Henderson }
1038b2167459SRichard Henderson 
1039f8f5986eSRichard Henderson /* Compute unsigned overflow for addition.  */
1040f8f5986eSRichard Henderson static TCGv_i64 do_add_uv(DisasContext *ctx, TCGv_i64 cb, TCGv_i64 cb_msb,
1041f8f5986eSRichard Henderson                           TCGv_i64 in1, int shift, bool d)
1042f8f5986eSRichard Henderson {
1043f8f5986eSRichard Henderson     if (shift == 0) {
1044f8f5986eSRichard Henderson         return get_carry(ctx, d, cb, cb_msb);
1045f8f5986eSRichard Henderson     } else {
1046f8f5986eSRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
1047f8f5986eSRichard Henderson         tcg_gen_extract_i64(tmp, in1, (d ? 63 : 31) - shift, shift);
1048f8f5986eSRichard Henderson         tcg_gen_or_i64(tmp, tmp, get_carry(ctx, d, cb, cb_msb));
1049f8f5986eSRichard Henderson         return tmp;
1050f8f5986eSRichard Henderson     }
1051f8f5986eSRichard Henderson }
1052f8f5986eSRichard Henderson 
1053b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
10546fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res,
10556fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
1056b2167459SRichard Henderson {
1057aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
1058aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
1059b2167459SRichard Henderson 
10606fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
10616fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
10626fd0c7bcSRichard Henderson     tcg_gen_and_i64(sv, sv, tmp);
1063b2167459SRichard Henderson 
1064b2167459SRichard Henderson     return sv;
1065b2167459SRichard Henderson }
1066b2167459SRichard Henderson 
1067f8f5986eSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 orig_in1,
10686fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned shift, bool is_l,
1069faf97ba1SRichard Henderson                    bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d)
1070b2167459SRichard Henderson {
1071f8f5986eSRichard Henderson     TCGv_i64 dest, cb, cb_msb, in1, uv, sv, tmp;
1072b2167459SRichard Henderson     unsigned c = cf >> 1;
1073b2167459SRichard Henderson     DisasCond cond;
1074b2167459SRichard Henderson 
1075aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1076f764718dSRichard Henderson     cb = NULL;
1077f764718dSRichard Henderson     cb_msb = NULL;
1078b2167459SRichard Henderson 
1079f8f5986eSRichard Henderson     in1 = orig_in1;
1080b2167459SRichard Henderson     if (shift) {
1081aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
10826fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, in1, shift);
1083b2167459SRichard Henderson         in1 = tmp;
1084b2167459SRichard Henderson     }
1085b2167459SRichard Henderson 
1086b47a4a02SSven Schnelle     if (!is_l || cond_need_cb(c)) {
1087aac0f603SRichard Henderson         cb_msb = tcg_temp_new_i64();
1088aac0f603SRichard Henderson         cb = tcg_temp_new_i64();
1089bdcccc17SRichard Henderson 
1090a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero);
1091b2167459SRichard Henderson         if (is_c) {
10926fd0c7bcSRichard Henderson             tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb,
1093a4db4a78SRichard Henderson                              get_psw_carry(ctx, d), ctx->zero);
1094b2167459SRichard Henderson         }
10956fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
10966fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1097b2167459SRichard Henderson     } else {
10986fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
1099b2167459SRichard Henderson         if (is_c) {
11006fd0c7bcSRichard Henderson             tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d));
1101b2167459SRichard Henderson         }
1102b2167459SRichard Henderson     }
1103b2167459SRichard Henderson 
1104b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1105f764718dSRichard Henderson     sv = NULL;
1106b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1107f8f5986eSRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2, orig_in1, shift, d);
1108b2167459SRichard Henderson         if (is_tsv) {
1109bd1ad92cSSven Schnelle             if (!d) {
1110bd1ad92cSSven Schnelle                 tcg_gen_ext32s_i64(sv, sv);
1111bd1ad92cSSven Schnelle             }
1112ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1113b2167459SRichard Henderson         }
1114b2167459SRichard Henderson     }
1115b2167459SRichard Henderson 
1116f8f5986eSRichard Henderson     /* Compute unsigned overflow if required.  */
1117f8f5986eSRichard Henderson     uv = NULL;
1118f8f5986eSRichard Henderson     if (cond_need_cb(c)) {
1119f8f5986eSRichard Henderson         uv = do_add_uv(ctx, cb, cb_msb, orig_in1, shift, d);
1120f8f5986eSRichard Henderson     }
1121f8f5986eSRichard Henderson 
1122b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1123f8f5986eSRichard Henderson     cond = do_cond(ctx, cf, d, dest, uv, sv);
1124b2167459SRichard Henderson     if (is_tc) {
1125aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
11266fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1127ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1128b2167459SRichard Henderson     }
1129b2167459SRichard Henderson 
1130b2167459SRichard Henderson     /* Write back the result.  */
1131b2167459SRichard Henderson     if (!is_l) {
1132b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
1133b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1134b2167459SRichard Henderson     }
1135b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1136b2167459SRichard Henderson 
1137b2167459SRichard Henderson     /* Install the new nullification.  */
1138b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1139b2167459SRichard Henderson     ctx->null_cond = cond;
1140b2167459SRichard Henderson }
1141b2167459SRichard Henderson 
1142faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a,
11430c982a28SRichard Henderson                        bool is_l, bool is_tsv, bool is_tc, bool is_c)
11440c982a28SRichard Henderson {
11456fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
11460c982a28SRichard Henderson 
11470c982a28SRichard Henderson     if (a->cf) {
11480c982a28SRichard Henderson         nullify_over(ctx);
11490c982a28SRichard Henderson     }
11500c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
11510c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1152faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l,
1153faf97ba1SRichard Henderson            is_tsv, is_tc, is_c, a->cf, a->d);
11540c982a28SRichard Henderson     return nullify_end(ctx);
11550c982a28SRichard Henderson }
11560c982a28SRichard Henderson 
11570588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a,
11580588e061SRichard Henderson                        bool is_tsv, bool is_tc)
11590588e061SRichard Henderson {
11606fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
11610588e061SRichard Henderson 
11620588e061SRichard Henderson     if (a->cf) {
11630588e061SRichard Henderson         nullify_over(ctx);
11640588e061SRichard Henderson     }
11656fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
11660588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
1167faf97ba1SRichard Henderson     /* All ADDI conditions are 32-bit. */
1168faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false);
11690588e061SRichard Henderson     return nullify_end(ctx);
11700588e061SRichard Henderson }
11710588e061SRichard Henderson 
11726fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
11736fd0c7bcSRichard Henderson                    TCGv_i64 in2, bool is_tsv, bool is_b,
117463c427c6SRichard Henderson                    bool is_tc, unsigned cf, bool d)
1175b2167459SRichard Henderson {
1176a4db4a78SRichard Henderson     TCGv_i64 dest, sv, cb, cb_msb, tmp;
1177b2167459SRichard Henderson     unsigned c = cf >> 1;
1178b2167459SRichard Henderson     DisasCond cond;
1179b2167459SRichard Henderson 
1180aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1181aac0f603SRichard Henderson     cb = tcg_temp_new_i64();
1182aac0f603SRichard Henderson     cb_msb = tcg_temp_new_i64();
1183b2167459SRichard Henderson 
1184b2167459SRichard Henderson     if (is_b) {
1185b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
11866fd0c7bcSRichard Henderson         tcg_gen_not_i64(cb, in2);
1187a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero,
1188a4db4a78SRichard Henderson                          get_psw_carry(ctx, d), ctx->zero);
1189a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero);
11906fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, in1);
11916fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1192b2167459SRichard Henderson     } else {
1193bdcccc17SRichard Henderson         /*
1194bdcccc17SRichard Henderson          * DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
1195bdcccc17SRichard Henderson          * operations by seeding the high word with 1 and subtracting.
1196bdcccc17SRichard Henderson          */
11976fd0c7bcSRichard Henderson         TCGv_i64 one = tcg_constant_i64(1);
1198a4db4a78SRichard Henderson         tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero);
11996fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(cb, in1, in2);
12006fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1201b2167459SRichard Henderson     }
1202b2167459SRichard Henderson 
1203b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1204f764718dSRichard Henderson     sv = NULL;
1205b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1206b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1207b2167459SRichard Henderson         if (is_tsv) {
1208bd1ad92cSSven Schnelle             if (!d) {
1209bd1ad92cSSven Schnelle                 tcg_gen_ext32s_i64(sv, sv);
1210bd1ad92cSSven Schnelle             }
1211ad75a51eSRichard Henderson             gen_helper_tsv(tcg_env, sv);
1212b2167459SRichard Henderson         }
1213b2167459SRichard Henderson     }
1214b2167459SRichard Henderson 
1215b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
1216b2167459SRichard Henderson     if (!is_b) {
12174fe9533aSRichard Henderson         cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1218b2167459SRichard Henderson     } else {
1219a751eb31SRichard Henderson         cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv);
1220b2167459SRichard Henderson     }
1221b2167459SRichard Henderson 
1222b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1223b2167459SRichard Henderson     if (is_tc) {
1224aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
12256fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1226ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1227b2167459SRichard Henderson     }
1228b2167459SRichard Henderson 
1229b2167459SRichard Henderson     /* Write back the result.  */
1230b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
1231b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1232b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1233b2167459SRichard Henderson 
1234b2167459SRichard Henderson     /* Install the new nullification.  */
1235b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1236b2167459SRichard Henderson     ctx->null_cond = cond;
1237b2167459SRichard Henderson }
1238b2167459SRichard Henderson 
123963c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a,
12400c982a28SRichard Henderson                        bool is_tsv, bool is_b, bool is_tc)
12410c982a28SRichard Henderson {
12426fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
12430c982a28SRichard Henderson 
12440c982a28SRichard Henderson     if (a->cf) {
12450c982a28SRichard Henderson         nullify_over(ctx);
12460c982a28SRichard Henderson     }
12470c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
12480c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
124963c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d);
12500c982a28SRichard Henderson     return nullify_end(ctx);
12510c982a28SRichard Henderson }
12520c982a28SRichard Henderson 
12530588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv)
12540588e061SRichard Henderson {
12556fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
12560588e061SRichard Henderson 
12570588e061SRichard Henderson     if (a->cf) {
12580588e061SRichard Henderson         nullify_over(ctx);
12590588e061SRichard Henderson     }
12606fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
12610588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
126263c427c6SRichard Henderson     /* All SUBI conditions are 32-bit. */
126363c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false);
12640588e061SRichard Henderson     return nullify_end(ctx);
12650588e061SRichard Henderson }
12660588e061SRichard Henderson 
12676fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12686fd0c7bcSRichard Henderson                       TCGv_i64 in2, unsigned cf, bool d)
1269b2167459SRichard Henderson {
12706fd0c7bcSRichard Henderson     TCGv_i64 dest, sv;
1271b2167459SRichard Henderson     DisasCond cond;
1272b2167459SRichard Henderson 
1273aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
12746fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
1275b2167459SRichard Henderson 
1276b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1277f764718dSRichard Henderson     sv = NULL;
1278b47a4a02SSven Schnelle     if (cond_need_sv(cf >> 1)) {
1279b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1280b2167459SRichard Henderson     }
1281b2167459SRichard Henderson 
1282b2167459SRichard Henderson     /* Form the condition for the compare.  */
12834fe9533aSRichard Henderson     cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1284b2167459SRichard Henderson 
1285b2167459SRichard Henderson     /* Clear.  */
12866fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
1287b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1288b2167459SRichard Henderson 
1289b2167459SRichard Henderson     /* Install the new nullification.  */
1290b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1291b2167459SRichard Henderson     ctx->null_cond = cond;
1292b2167459SRichard Henderson }
1293b2167459SRichard Henderson 
12946fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12956fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned cf, bool d,
12966fd0c7bcSRichard Henderson                    void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1297b2167459SRichard Henderson {
12986fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, rt);
1299b2167459SRichard Henderson 
1300b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
1301b2167459SRichard Henderson     fn(dest, in1, in2);
1302b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1303b2167459SRichard Henderson 
1304b2167459SRichard Henderson     /* Install the new nullification.  */
1305b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1306b2167459SRichard Henderson     if (cf) {
1307b5af8423SRichard Henderson         ctx->null_cond = do_log_cond(ctx, cf, d, dest);
1308b2167459SRichard Henderson     }
1309b2167459SRichard Henderson }
1310b2167459SRichard Henderson 
1311fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a,
13126fd0c7bcSRichard Henderson                        void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
13130c982a28SRichard Henderson {
13146fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
13150c982a28SRichard Henderson 
13160c982a28SRichard Henderson     if (a->cf) {
13170c982a28SRichard Henderson         nullify_over(ctx);
13180c982a28SRichard Henderson     }
13190c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
13200c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1321fa8e3bedSRichard Henderson     do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn);
13220c982a28SRichard Henderson     return nullify_end(ctx);
13230c982a28SRichard Henderson }
13240c982a28SRichard Henderson 
132546bb3d46SRichard Henderson static void do_unit_addsub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
132646bb3d46SRichard Henderson                            TCGv_i64 in2, unsigned cf, bool d,
132746bb3d46SRichard Henderson                            bool is_tc, bool is_add)
1328b2167459SRichard Henderson {
132946bb3d46SRichard Henderson     TCGv_i64 dest = tcg_temp_new_i64();
133046bb3d46SRichard Henderson     uint64_t test_cb = 0;
1331b2167459SRichard Henderson     DisasCond cond;
1332b2167459SRichard Henderson 
133346bb3d46SRichard Henderson     /* Select which carry-out bits to test. */
133446bb3d46SRichard Henderson     switch (cf >> 1) {
133546bb3d46SRichard Henderson     case 4: /* NDC / SDC -- 4-bit carries */
133646bb3d46SRichard Henderson         test_cb = dup_const(MO_8, 0x88);
133746bb3d46SRichard Henderson         break;
133846bb3d46SRichard Henderson     case 5: /* NWC / SWC -- 32-bit carries */
133946bb3d46SRichard Henderson         if (d) {
134046bb3d46SRichard Henderson             test_cb = dup_const(MO_32, INT32_MIN);
1341b2167459SRichard Henderson         } else {
134246bb3d46SRichard Henderson             cf &= 1; /* undefined -- map to never/always */
134346bb3d46SRichard Henderson         }
134446bb3d46SRichard Henderson         break;
134546bb3d46SRichard Henderson     case 6: /* NBC / SBC -- 8-bit carries */
134646bb3d46SRichard Henderson         test_cb = dup_const(MO_8, INT8_MIN);
134746bb3d46SRichard Henderson         break;
134846bb3d46SRichard Henderson     case 7: /* NHC / SHC -- 16-bit carries */
134946bb3d46SRichard Henderson         test_cb = dup_const(MO_16, INT16_MIN);
135046bb3d46SRichard Henderson         break;
135146bb3d46SRichard Henderson     }
135246bb3d46SRichard Henderson     if (!d) {
135346bb3d46SRichard Henderson         test_cb = (uint32_t)test_cb;
135446bb3d46SRichard Henderson     }
1355b2167459SRichard Henderson 
135646bb3d46SRichard Henderson     if (!test_cb) {
135746bb3d46SRichard Henderson         /* No need to compute carries if we don't need to test them. */
135846bb3d46SRichard Henderson         if (is_add) {
135946bb3d46SRichard Henderson             tcg_gen_add_i64(dest, in1, in2);
136046bb3d46SRichard Henderson         } else {
136146bb3d46SRichard Henderson             tcg_gen_sub_i64(dest, in1, in2);
136246bb3d46SRichard Henderson         }
136346bb3d46SRichard Henderson         cond = do_unit_zero_cond(cf, d, dest);
136446bb3d46SRichard Henderson     } else {
136546bb3d46SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
136646bb3d46SRichard Henderson 
136746bb3d46SRichard Henderson         if (d) {
136846bb3d46SRichard Henderson             TCGv_i64 cb_msb = tcg_temp_new_i64();
136946bb3d46SRichard Henderson             if (is_add) {
137046bb3d46SRichard Henderson                 tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero);
137146bb3d46SRichard Henderson                 tcg_gen_xor_i64(cb, in1, in2);
137246bb3d46SRichard Henderson             } else {
137346bb3d46SRichard Henderson                 /* See do_sub, !is_b. */
137446bb3d46SRichard Henderson                 TCGv_i64 one = tcg_constant_i64(1);
137546bb3d46SRichard Henderson                 tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero);
137646bb3d46SRichard Henderson                 tcg_gen_eqv_i64(cb, in1, in2);
137746bb3d46SRichard Henderson             }
137846bb3d46SRichard Henderson             tcg_gen_xor_i64(cb, cb, dest);
137946bb3d46SRichard Henderson             tcg_gen_extract2_i64(cb, cb, cb_msb, 1);
138046bb3d46SRichard Henderson         } else {
138146bb3d46SRichard Henderson             if (is_add) {
138246bb3d46SRichard Henderson                 tcg_gen_add_i64(dest, in1, in2);
138346bb3d46SRichard Henderson                 tcg_gen_xor_i64(cb, in1, in2);
138446bb3d46SRichard Henderson             } else {
138546bb3d46SRichard Henderson                 tcg_gen_sub_i64(dest, in1, in2);
138646bb3d46SRichard Henderson                 tcg_gen_eqv_i64(cb, in1, in2);
138746bb3d46SRichard Henderson             }
138846bb3d46SRichard Henderson             tcg_gen_xor_i64(cb, cb, dest);
138946bb3d46SRichard Henderson             tcg_gen_shri_i64(cb, cb, 1);
139046bb3d46SRichard Henderson         }
139146bb3d46SRichard Henderson 
139246bb3d46SRichard Henderson         tcg_gen_andi_i64(cb, cb, test_cb);
139346bb3d46SRichard Henderson         cond = cond_make_0_tmp(cf & 1 ? TCG_COND_EQ : TCG_COND_NE, cb);
139446bb3d46SRichard Henderson     }
1395b2167459SRichard Henderson 
1396b2167459SRichard Henderson     if (is_tc) {
1397aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
13986fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
1399ad75a51eSRichard Henderson         gen_helper_tcond(tcg_env, tmp);
1400b2167459SRichard Henderson     }
1401b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1402b2167459SRichard Henderson 
1403b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1404b2167459SRichard Henderson     ctx->null_cond = cond;
1405b2167459SRichard Henderson }
1406b2167459SRichard Henderson 
140786f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY
14088d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space
14098d6ae7fbSRichard Henderson    from the top 2 bits of the base register.  There are a few system
14108d6ae7fbSRichard Henderson    instructions that have a 3-bit space specifier, for which SR0 is
14118d6ae7fbSRichard Henderson    not special.  To handle this, pass ~SP.  */
14126fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base)
141386f8d05fSRichard Henderson {
141486f8d05fSRichard Henderson     TCGv_ptr ptr;
14156fd0c7bcSRichard Henderson     TCGv_i64 tmp;
141686f8d05fSRichard Henderson     TCGv_i64 spc;
141786f8d05fSRichard Henderson 
141886f8d05fSRichard Henderson     if (sp != 0) {
14198d6ae7fbSRichard Henderson         if (sp < 0) {
14208d6ae7fbSRichard Henderson             sp = ~sp;
14218d6ae7fbSRichard Henderson         }
14226fd0c7bcSRichard Henderson         spc = tcg_temp_new_i64();
14238d6ae7fbSRichard Henderson         load_spr(ctx, spc, sp);
14248d6ae7fbSRichard Henderson         return spc;
142586f8d05fSRichard Henderson     }
1426494737b7SRichard Henderson     if (ctx->tb_flags & TB_FLAG_SR_SAME) {
1427494737b7SRichard Henderson         return cpu_srH;
1428494737b7SRichard Henderson     }
142986f8d05fSRichard Henderson 
143086f8d05fSRichard Henderson     ptr = tcg_temp_new_ptr();
1431aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
14326fd0c7bcSRichard Henderson     spc = tcg_temp_new_i64();
143386f8d05fSRichard Henderson 
1434698240d1SRichard Henderson     /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */
14356fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5);
14366fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, 030);
14376fd0c7bcSRichard Henderson     tcg_gen_trunc_i64_ptr(ptr, tmp);
143886f8d05fSRichard Henderson 
1439ad75a51eSRichard Henderson     tcg_gen_add_ptr(ptr, ptr, tcg_env);
144086f8d05fSRichard Henderson     tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4]));
144186f8d05fSRichard Henderson 
144286f8d05fSRichard Henderson     return spc;
144386f8d05fSRichard Henderson }
144486f8d05fSRichard Henderson #endif
144586f8d05fSRichard Henderson 
14466fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
1447c53e401eSRichard Henderson                      unsigned rb, unsigned rx, int scale, int64_t disp,
144886f8d05fSRichard Henderson                      unsigned sp, int modify, bool is_phys)
144986f8d05fSRichard Henderson {
14506fd0c7bcSRichard Henderson     TCGv_i64 base = load_gpr(ctx, rb);
14516fd0c7bcSRichard Henderson     TCGv_i64 ofs;
14526fd0c7bcSRichard Henderson     TCGv_i64 addr;
145386f8d05fSRichard Henderson 
1454f5b5c857SRichard Henderson     set_insn_breg(ctx, rb);
1455f5b5c857SRichard Henderson 
145686f8d05fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
145786f8d05fSRichard Henderson     if (rx) {
1458aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
14596fd0c7bcSRichard Henderson         tcg_gen_shli_i64(ofs, cpu_gr[rx], scale);
14606fd0c7bcSRichard Henderson         tcg_gen_add_i64(ofs, ofs, base);
146186f8d05fSRichard Henderson     } else if (disp || modify) {
1462aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
14636fd0c7bcSRichard Henderson         tcg_gen_addi_i64(ofs, base, disp);
146486f8d05fSRichard Henderson     } else {
146586f8d05fSRichard Henderson         ofs = base;
146686f8d05fSRichard Henderson     }
146786f8d05fSRichard Henderson 
146886f8d05fSRichard Henderson     *pofs = ofs;
14696fd0c7bcSRichard Henderson     *pgva = addr = tcg_temp_new_i64();
14707d50b696SSven Schnelle     tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base,
14717d50b696SSven Schnelle                      gva_offset_mask(ctx->tb_flags));
1472698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY
147386f8d05fSRichard Henderson     if (!is_phys) {
1474d265360fSRichard Henderson         tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base));
147586f8d05fSRichard Henderson     }
147686f8d05fSRichard Henderson #endif
147786f8d05fSRichard Henderson }
147886f8d05fSRichard Henderson 
147996d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
148096d6407fSRichard Henderson  * < 0 for pre-modify,
148196d6407fSRichard Henderson  * > 0 for post-modify,
148296d6407fSRichard Henderson  * = 0 for no base register update.
148396d6407fSRichard Henderson  */
148496d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1485c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
148614776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
148796d6407fSRichard Henderson {
14886fd0c7bcSRichard Henderson     TCGv_i64 ofs;
14896fd0c7bcSRichard Henderson     TCGv_i64 addr;
149096d6407fSRichard Henderson 
149196d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
149296d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
149396d6407fSRichard Henderson 
149486f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
149517fe594cSRichard Henderson              MMU_DISABLED(ctx));
1496c1f55d97SRichard Henderson     tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
149786f8d05fSRichard Henderson     if (modify) {
149886f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
149996d6407fSRichard Henderson     }
150096d6407fSRichard Henderson }
150196d6407fSRichard Henderson 
150296d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1503c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
150414776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
150596d6407fSRichard Henderson {
15066fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15076fd0c7bcSRichard Henderson     TCGv_i64 addr;
150896d6407fSRichard Henderson 
150996d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
151096d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
151196d6407fSRichard Henderson 
151286f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
151317fe594cSRichard Henderson              MMU_DISABLED(ctx));
1514217d1a5eSRichard Henderson     tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
151586f8d05fSRichard Henderson     if (modify) {
151686f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
151796d6407fSRichard Henderson     }
151896d6407fSRichard Henderson }
151996d6407fSRichard Henderson 
152096d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1521c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
152214776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
152396d6407fSRichard Henderson {
15246fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15256fd0c7bcSRichard Henderson     TCGv_i64 addr;
152696d6407fSRichard Henderson 
152796d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
152896d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
152996d6407fSRichard Henderson 
153086f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
153117fe594cSRichard Henderson              MMU_DISABLED(ctx));
1532217d1a5eSRichard Henderson     tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
153386f8d05fSRichard Henderson     if (modify) {
153486f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
153596d6407fSRichard Henderson     }
153696d6407fSRichard Henderson }
153796d6407fSRichard Henderson 
153896d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1539c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
154014776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
154196d6407fSRichard Henderson {
15426fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15436fd0c7bcSRichard Henderson     TCGv_i64 addr;
154496d6407fSRichard Henderson 
154596d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
154696d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
154796d6407fSRichard Henderson 
154886f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
154917fe594cSRichard Henderson              MMU_DISABLED(ctx));
1550217d1a5eSRichard Henderson     tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
155186f8d05fSRichard Henderson     if (modify) {
155286f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
155396d6407fSRichard Henderson     }
155496d6407fSRichard Henderson }
155596d6407fSRichard Henderson 
15561cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1557c53e401eSRichard Henderson                     unsigned rx, int scale, int64_t disp,
155814776ab5STony Nguyen                     unsigned sp, int modify, MemOp mop)
155996d6407fSRichard Henderson {
15606fd0c7bcSRichard Henderson     TCGv_i64 dest;
156196d6407fSRichard Henderson 
156296d6407fSRichard Henderson     nullify_over(ctx);
156396d6407fSRichard Henderson 
156496d6407fSRichard Henderson     if (modify == 0) {
156596d6407fSRichard Henderson         /* No base register update.  */
156696d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
156796d6407fSRichard Henderson     } else {
156896d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
1569aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
157096d6407fSRichard Henderson     }
15716fd0c7bcSRichard Henderson     do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
157296d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
157396d6407fSRichard Henderson 
15741cd012a5SRichard Henderson     return nullify_end(ctx);
157596d6407fSRichard Henderson }
157696d6407fSRichard Henderson 
1577740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
1578c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
157986f8d05fSRichard Henderson                       unsigned sp, int modify)
158096d6407fSRichard Henderson {
158196d6407fSRichard Henderson     TCGv_i32 tmp;
158296d6407fSRichard Henderson 
158396d6407fSRichard Henderson     nullify_over(ctx);
158496d6407fSRichard Henderson 
158596d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
158686f8d05fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
158796d6407fSRichard Henderson     save_frw_i32(rt, tmp);
158896d6407fSRichard Henderson 
158996d6407fSRichard Henderson     if (rt == 0) {
1590ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
159196d6407fSRichard Henderson     }
159296d6407fSRichard Henderson 
1593740038d7SRichard Henderson     return nullify_end(ctx);
159496d6407fSRichard Henderson }
159596d6407fSRichard Henderson 
1596740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a)
1597740038d7SRichard Henderson {
1598740038d7SRichard Henderson     return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1599740038d7SRichard Henderson                      a->disp, a->sp, a->m);
1600740038d7SRichard Henderson }
1601740038d7SRichard Henderson 
1602740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1603c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
160486f8d05fSRichard Henderson                       unsigned sp, int modify)
160596d6407fSRichard Henderson {
160696d6407fSRichard Henderson     TCGv_i64 tmp;
160796d6407fSRichard Henderson 
160896d6407fSRichard Henderson     nullify_over(ctx);
160996d6407fSRichard Henderson 
161096d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
1611fc313c64SFrédéric Pétrot     do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
161296d6407fSRichard Henderson     save_frd(rt, tmp);
161396d6407fSRichard Henderson 
161496d6407fSRichard Henderson     if (rt == 0) {
1615ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
161696d6407fSRichard Henderson     }
161796d6407fSRichard Henderson 
1618740038d7SRichard Henderson     return nullify_end(ctx);
1619740038d7SRichard Henderson }
1620740038d7SRichard Henderson 
1621740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a)
1622740038d7SRichard Henderson {
1623740038d7SRichard Henderson     return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1624740038d7SRichard Henderson                      a->disp, a->sp, a->m);
162596d6407fSRichard Henderson }
162696d6407fSRichard Henderson 
16271cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb,
1628c53e401eSRichard Henderson                      int64_t disp, unsigned sp,
162914776ab5STony Nguyen                      int modify, MemOp mop)
163096d6407fSRichard Henderson {
163196d6407fSRichard Henderson     nullify_over(ctx);
16326fd0c7bcSRichard Henderson     do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
16331cd012a5SRichard Henderson     return nullify_end(ctx);
163496d6407fSRichard Henderson }
163596d6407fSRichard Henderson 
1636740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1637c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
163886f8d05fSRichard Henderson                        unsigned sp, int modify)
163996d6407fSRichard Henderson {
164096d6407fSRichard Henderson     TCGv_i32 tmp;
164196d6407fSRichard Henderson 
164296d6407fSRichard Henderson     nullify_over(ctx);
164396d6407fSRichard Henderson 
164496d6407fSRichard Henderson     tmp = load_frw_i32(rt);
164586f8d05fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
164696d6407fSRichard Henderson 
1647740038d7SRichard Henderson     return nullify_end(ctx);
164896d6407fSRichard Henderson }
164996d6407fSRichard Henderson 
1650740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a)
1651740038d7SRichard Henderson {
1652740038d7SRichard Henderson     return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1653740038d7SRichard Henderson                       a->disp, a->sp, a->m);
1654740038d7SRichard Henderson }
1655740038d7SRichard Henderson 
1656740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1657c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
165886f8d05fSRichard Henderson                        unsigned sp, int modify)
165996d6407fSRichard Henderson {
166096d6407fSRichard Henderson     TCGv_i64 tmp;
166196d6407fSRichard Henderson 
166296d6407fSRichard Henderson     nullify_over(ctx);
166396d6407fSRichard Henderson 
166496d6407fSRichard Henderson     tmp = load_frd(rt);
1665fc313c64SFrédéric Pétrot     do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
166696d6407fSRichard Henderson 
1667740038d7SRichard Henderson     return nullify_end(ctx);
1668740038d7SRichard Henderson }
1669740038d7SRichard Henderson 
1670740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a)
1671740038d7SRichard Henderson {
1672740038d7SRichard Henderson     return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1673740038d7SRichard Henderson                       a->disp, a->sp, a->m);
167496d6407fSRichard Henderson }
167596d6407fSRichard Henderson 
16761ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1677ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1678ebe9383cSRichard Henderson {
1679ebe9383cSRichard Henderson     TCGv_i32 tmp;
1680ebe9383cSRichard Henderson 
1681ebe9383cSRichard Henderson     nullify_over(ctx);
1682ebe9383cSRichard Henderson     tmp = load_frw0_i32(ra);
1683ebe9383cSRichard Henderson 
1684ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1685ebe9383cSRichard Henderson 
1686ebe9383cSRichard Henderson     save_frw_i32(rt, tmp);
16871ca74648SRichard Henderson     return nullify_end(ctx);
1688ebe9383cSRichard Henderson }
1689ebe9383cSRichard Henderson 
16901ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1691ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1692ebe9383cSRichard Henderson {
1693ebe9383cSRichard Henderson     TCGv_i32 dst;
1694ebe9383cSRichard Henderson     TCGv_i64 src;
1695ebe9383cSRichard Henderson 
1696ebe9383cSRichard Henderson     nullify_over(ctx);
1697ebe9383cSRichard Henderson     src = load_frd(ra);
1698ebe9383cSRichard Henderson     dst = tcg_temp_new_i32();
1699ebe9383cSRichard Henderson 
1700ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1701ebe9383cSRichard Henderson 
1702ebe9383cSRichard Henderson     save_frw_i32(rt, dst);
17031ca74648SRichard Henderson     return nullify_end(ctx);
1704ebe9383cSRichard Henderson }
1705ebe9383cSRichard Henderson 
17061ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1707ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1708ebe9383cSRichard Henderson {
1709ebe9383cSRichard Henderson     TCGv_i64 tmp;
1710ebe9383cSRichard Henderson 
1711ebe9383cSRichard Henderson     nullify_over(ctx);
1712ebe9383cSRichard Henderson     tmp = load_frd0(ra);
1713ebe9383cSRichard Henderson 
1714ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1715ebe9383cSRichard Henderson 
1716ebe9383cSRichard Henderson     save_frd(rt, tmp);
17171ca74648SRichard Henderson     return nullify_end(ctx);
1718ebe9383cSRichard Henderson }
1719ebe9383cSRichard Henderson 
17201ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1721ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1722ebe9383cSRichard Henderson {
1723ebe9383cSRichard Henderson     TCGv_i32 src;
1724ebe9383cSRichard Henderson     TCGv_i64 dst;
1725ebe9383cSRichard Henderson 
1726ebe9383cSRichard Henderson     nullify_over(ctx);
1727ebe9383cSRichard Henderson     src = load_frw0_i32(ra);
1728ebe9383cSRichard Henderson     dst = tcg_temp_new_i64();
1729ebe9383cSRichard Henderson 
1730ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1731ebe9383cSRichard Henderson 
1732ebe9383cSRichard Henderson     save_frd(rt, dst);
17331ca74648SRichard Henderson     return nullify_end(ctx);
1734ebe9383cSRichard Henderson }
1735ebe9383cSRichard Henderson 
17361ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt,
1737ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
173831234768SRichard Henderson                         void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
1739ebe9383cSRichard Henderson {
1740ebe9383cSRichard Henderson     TCGv_i32 a, b;
1741ebe9383cSRichard Henderson 
1742ebe9383cSRichard Henderson     nullify_over(ctx);
1743ebe9383cSRichard Henderson     a = load_frw0_i32(ra);
1744ebe9383cSRichard Henderson     b = load_frw0_i32(rb);
1745ebe9383cSRichard Henderson 
1746ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1747ebe9383cSRichard Henderson 
1748ebe9383cSRichard Henderson     save_frw_i32(rt, a);
17491ca74648SRichard Henderson     return nullify_end(ctx);
1750ebe9383cSRichard Henderson }
1751ebe9383cSRichard Henderson 
17521ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt,
1753ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
175431234768SRichard Henderson                         void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
1755ebe9383cSRichard Henderson {
1756ebe9383cSRichard Henderson     TCGv_i64 a, b;
1757ebe9383cSRichard Henderson 
1758ebe9383cSRichard Henderson     nullify_over(ctx);
1759ebe9383cSRichard Henderson     a = load_frd0(ra);
1760ebe9383cSRichard Henderson     b = load_frd0(rb);
1761ebe9383cSRichard Henderson 
1762ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1763ebe9383cSRichard Henderson 
1764ebe9383cSRichard Henderson     save_frd(rt, a);
17651ca74648SRichard Henderson     return nullify_end(ctx);
1766ebe9383cSRichard Henderson }
1767ebe9383cSRichard Henderson 
176898cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
176998cd9ca7SRichard Henderson    have already had nullification handled.  */
17702644f80bSRichard Henderson static bool do_dbranch(DisasContext *ctx, int64_t disp,
177198cd9ca7SRichard Henderson                        unsigned link, bool is_n)
177298cd9ca7SRichard Henderson {
17732644f80bSRichard Henderson     uint64_t dest = iaoq_dest(ctx, disp);
17742644f80bSRichard Henderson 
177598cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
177698cd9ca7SRichard Henderson         if (link != 0) {
1777741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
177898cd9ca7SRichard Henderson         }
177998cd9ca7SRichard Henderson         ctx->iaoq_n = dest;
178098cd9ca7SRichard Henderson         if (is_n) {
178198cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
178298cd9ca7SRichard Henderson         }
178398cd9ca7SRichard Henderson     } else {
178498cd9ca7SRichard Henderson         nullify_over(ctx);
178598cd9ca7SRichard Henderson 
178698cd9ca7SRichard Henderson         if (link != 0) {
1787741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
178898cd9ca7SRichard Henderson         }
178998cd9ca7SRichard Henderson 
179098cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
179198cd9ca7SRichard Henderson             nullify_set(ctx, 0);
179298cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, dest, dest + 4);
179398cd9ca7SRichard Henderson         } else {
179498cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
179598cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
179698cd9ca7SRichard Henderson         }
179798cd9ca7SRichard Henderson 
179831234768SRichard Henderson         nullify_end(ctx);
179998cd9ca7SRichard Henderson 
180098cd9ca7SRichard Henderson         nullify_set(ctx, 0);
180198cd9ca7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
180231234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
180398cd9ca7SRichard Henderson     }
180401afb7beSRichard Henderson     return true;
180598cd9ca7SRichard Henderson }
180698cd9ca7SRichard Henderson 
180798cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
180898cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
1809c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n,
181098cd9ca7SRichard Henderson                        DisasCond *cond)
181198cd9ca7SRichard Henderson {
1812c53e401eSRichard Henderson     uint64_t dest = iaoq_dest(ctx, disp);
181398cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
181498cd9ca7SRichard Henderson     TCGCond c = cond->c;
181598cd9ca7SRichard Henderson     bool n;
181698cd9ca7SRichard Henderson 
181798cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
181898cd9ca7SRichard Henderson 
181998cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
182098cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
18212644f80bSRichard Henderson         return do_dbranch(ctx, disp, 0, is_n && disp >= 0);
182298cd9ca7SRichard Henderson     }
182398cd9ca7SRichard Henderson 
182498cd9ca7SRichard Henderson     taken = gen_new_label();
18256fd0c7bcSRichard Henderson     tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken);
182698cd9ca7SRichard Henderson     cond_free(cond);
182798cd9ca7SRichard Henderson 
182898cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
182998cd9ca7SRichard Henderson     n = is_n && disp < 0;
183098cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
183198cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1832a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
183398cd9ca7SRichard Henderson     } else {
183498cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
183598cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
183698cd9ca7SRichard Henderson             ctx->null_lab = NULL;
183798cd9ca7SRichard Henderson         }
183898cd9ca7SRichard Henderson         nullify_set(ctx, n);
1839c301f34eSRichard Henderson         if (ctx->iaoq_n == -1) {
1840c301f34eSRichard Henderson             /* The temporary iaoq_n_var died at the branch above.
1841c301f34eSRichard Henderson                Regenerate it here instead of saving it.  */
18426fd0c7bcSRichard Henderson             tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
1843c301f34eSRichard Henderson         }
1844a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
184598cd9ca7SRichard Henderson     }
184698cd9ca7SRichard Henderson 
184798cd9ca7SRichard Henderson     gen_set_label(taken);
184898cd9ca7SRichard Henderson 
184998cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
185098cd9ca7SRichard Henderson     n = is_n && disp >= 0;
185198cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
185298cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1853a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, dest, dest + 4);
185498cd9ca7SRichard Henderson     } else {
185598cd9ca7SRichard Henderson         nullify_set(ctx, n);
1856a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
185798cd9ca7SRichard Henderson     }
185898cd9ca7SRichard Henderson 
185998cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
186098cd9ca7SRichard Henderson     if (ctx->null_lab) {
186198cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
186298cd9ca7SRichard Henderson         ctx->null_lab = NULL;
186331234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
186498cd9ca7SRichard Henderson     } else {
186531234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
186698cd9ca7SRichard Henderson     }
186701afb7beSRichard Henderson     return true;
186898cd9ca7SRichard Henderson }
186998cd9ca7SRichard Henderson 
187098cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target.  This handles
187198cd9ca7SRichard Henderson    nullification of the branch itself.  */
18726fd0c7bcSRichard Henderson static bool do_ibranch(DisasContext *ctx, TCGv_i64 dest,
187398cd9ca7SRichard Henderson                        unsigned link, bool is_n)
187498cd9ca7SRichard Henderson {
1875d582c1faSRichard Henderson     TCGv_i64 next;
187698cd9ca7SRichard Henderson 
1877d582c1faSRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
1878d582c1faSRichard Henderson         next = tcg_temp_new_i64();
1879d582c1faSRichard Henderson         tcg_gen_mov_i64(next, dest);
188098cd9ca7SRichard Henderson 
188198cd9ca7SRichard Henderson         if (link != 0) {
1882741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
188398cd9ca7SRichard Henderson         }
188498cd9ca7SRichard Henderson         if (is_n) {
1885c301f34eSRichard Henderson             if (use_nullify_skip(ctx)) {
1886a0180973SRichard Henderson                 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, next);
18876fd0c7bcSRichard Henderson                 tcg_gen_addi_i64(next, next, 4);
1888a0180973SRichard Henderson                 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
1889c301f34eSRichard Henderson                 nullify_set(ctx, 0);
189031234768SRichard Henderson                 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
189101afb7beSRichard Henderson                 return true;
1892c301f34eSRichard Henderson             }
189398cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
189498cd9ca7SRichard Henderson         }
1895c301f34eSRichard Henderson         ctx->iaoq_n = -1;
1896c301f34eSRichard Henderson         ctx->iaoq_n_var = next;
1897d582c1faSRichard Henderson         return true;
1898d582c1faSRichard Henderson     }
189998cd9ca7SRichard Henderson 
1900d582c1faSRichard Henderson     nullify_over(ctx);
1901d582c1faSRichard Henderson 
1902d582c1faSRichard Henderson     if (is_n && use_nullify_skip(ctx)) {
1903a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, dest);
1904aac0f603SRichard Henderson         next = tcg_temp_new_i64();
19056fd0c7bcSRichard Henderson         tcg_gen_addi_i64(next, dest, 4);
1906a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
1907d582c1faSRichard Henderson         nullify_set(ctx, 0);
1908d582c1faSRichard Henderson     } else {
1909d582c1faSRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
1910d582c1faSRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest);
1911d582c1faSRichard Henderson         nullify_set(ctx, is_n);
1912d582c1faSRichard Henderson     }
191398cd9ca7SRichard Henderson     if (link != 0) {
19149a91dd84SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
191598cd9ca7SRichard Henderson     }
1916d582c1faSRichard Henderson 
19177f11636dSEmilio G. Cota     tcg_gen_lookup_and_goto_ptr();
1918d582c1faSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
191901afb7beSRichard Henderson     return nullify_end(ctx);
192098cd9ca7SRichard Henderson }
192198cd9ca7SRichard Henderson 
1922660eefe1SRichard Henderson /* Implement
1923660eefe1SRichard Henderson  *    if (IAOQ_Front{30..31} < GR[b]{30..31})
1924660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← GR[b]{30..31};
1925660eefe1SRichard Henderson  *    else
1926660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← IAOQ_Front{30..31};
1927660eefe1SRichard Henderson  * which keeps the privilege level from being increased.
1928660eefe1SRichard Henderson  */
19296fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset)
1930660eefe1SRichard Henderson {
19316fd0c7bcSRichard Henderson     TCGv_i64 dest;
1932660eefe1SRichard Henderson     switch (ctx->privilege) {
1933660eefe1SRichard Henderson     case 0:
1934660eefe1SRichard Henderson         /* Privilege 0 is maximum and is allowed to decrease.  */
1935660eefe1SRichard Henderson         return offset;
1936660eefe1SRichard Henderson     case 3:
1937993119feSRichard Henderson         /* Privilege 3 is minimum and is never allowed to increase.  */
1938aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
19396fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, offset, 3);
1940660eefe1SRichard Henderson         break;
1941660eefe1SRichard Henderson     default:
1942aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
19436fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, offset, -4);
19446fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, ctx->privilege);
19456fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(TCG_COND_GTU, dest, dest, offset, dest, offset);
1946660eefe1SRichard Henderson         break;
1947660eefe1SRichard Henderson     }
1948660eefe1SRichard Henderson     return dest;
1949660eefe1SRichard Henderson }
1950660eefe1SRichard Henderson 
1951ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
19527ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
19537ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
19547ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
19557ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
19567ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
19577ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
19587ad439dfSRichard Henderson    aforementioned BE.  */
195931234768SRichard Henderson static void do_page_zero(DisasContext *ctx)
19607ad439dfSRichard Henderson {
19616fd0c7bcSRichard Henderson     TCGv_i64 tmp;
1962a0180973SRichard Henderson 
19637ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
19647ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
19658b81968cSMichael Tokarev        next insn within the privileged page.  */
19667ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
19677ad439dfSRichard Henderson     case TCG_COND_NEVER:
19687ad439dfSRichard Henderson         break;
19697ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
19706fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, 0);
19717ad439dfSRichard Henderson         goto do_sigill;
19727ad439dfSRichard Henderson     default:
19737ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
19747ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
19757ad439dfSRichard Henderson         g_assert_not_reached();
19767ad439dfSRichard Henderson     }
19777ad439dfSRichard Henderson 
19787ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
19797ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
19807ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
19817ad439dfSRichard Henderson        under such conditions.  */
19827ad439dfSRichard Henderson     if (ctx->iaoq_b != ctx->iaoq_f + 4) {
19837ad439dfSRichard Henderson         goto do_sigill;
19847ad439dfSRichard Henderson     }
19857ad439dfSRichard Henderson 
1986ebd0e151SRichard Henderson     switch (ctx->iaoq_f & -4) {
19877ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
19882986721dSRichard Henderson         gen_excp_1(EXCP_IMP);
198931234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
199031234768SRichard Henderson         break;
19917ad439dfSRichard Henderson 
19927ad439dfSRichard Henderson     case 0xb0: /* LWS */
19937ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
199431234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
199531234768SRichard Henderson         break;
19967ad439dfSRichard Henderson 
19977ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
19986fd0c7bcSRichard Henderson         tcg_gen_st_i64(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27]));
1999aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
20006fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_gr[31], 3);
2001a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
20026fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, 4);
2003a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
200431234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
200531234768SRichard Henderson         break;
20067ad439dfSRichard Henderson 
20077ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
20087ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
200931234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
201031234768SRichard Henderson         break;
20117ad439dfSRichard Henderson 
20127ad439dfSRichard Henderson     default:
20137ad439dfSRichard Henderson     do_sigill:
20142986721dSRichard Henderson         gen_excp_1(EXCP_ILL);
201531234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
201631234768SRichard Henderson         break;
20177ad439dfSRichard Henderson     }
20187ad439dfSRichard Henderson }
2019ba1d0b44SRichard Henderson #endif
20207ad439dfSRichard Henderson 
2021deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a)
2022b2167459SRichard Henderson {
2023b2167459SRichard Henderson     cond_free(&ctx->null_cond);
202431234768SRichard Henderson     return true;
2025b2167459SRichard Henderson }
2026b2167459SRichard Henderson 
202740f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a)
202898a9cb79SRichard Henderson {
202931234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_BREAK);
203098a9cb79SRichard Henderson }
203198a9cb79SRichard Henderson 
2032e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a)
203398a9cb79SRichard Henderson {
203498a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
203598a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
203698a9cb79SRichard Henderson 
203798a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
203831234768SRichard Henderson     return true;
203998a9cb79SRichard Henderson }
204098a9cb79SRichard Henderson 
2041c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a)
204298a9cb79SRichard Henderson {
2043c603e14aSRichard Henderson     unsigned rt = a->t;
20446fd0c7bcSRichard Henderson     TCGv_i64 tmp = dest_gpr(ctx, rt);
2045b5e0b3a5SSven Schnelle     tcg_gen_movi_i64(tmp, ctx->iaoq_f & ~3ULL);
204698a9cb79SRichard Henderson     save_gpr(ctx, rt, tmp);
204798a9cb79SRichard Henderson 
204898a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
204931234768SRichard Henderson     return true;
205098a9cb79SRichard Henderson }
205198a9cb79SRichard Henderson 
2052c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a)
205398a9cb79SRichard Henderson {
2054c603e14aSRichard Henderson     unsigned rt = a->t;
2055c603e14aSRichard Henderson     unsigned rs = a->sp;
205633423472SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
205798a9cb79SRichard Henderson 
205833423472SRichard Henderson     load_spr(ctx, t0, rs);
205933423472SRichard Henderson     tcg_gen_shri_i64(t0, t0, 32);
206033423472SRichard Henderson 
2061967662cdSRichard Henderson     save_gpr(ctx, rt, t0);
206298a9cb79SRichard Henderson 
206398a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
206431234768SRichard Henderson     return true;
206598a9cb79SRichard Henderson }
206698a9cb79SRichard Henderson 
2067c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a)
206898a9cb79SRichard Henderson {
2069c603e14aSRichard Henderson     unsigned rt = a->t;
2070c603e14aSRichard Henderson     unsigned ctl = a->r;
20716fd0c7bcSRichard Henderson     TCGv_i64 tmp;
207298a9cb79SRichard Henderson 
207398a9cb79SRichard Henderson     switch (ctl) {
207435136a77SRichard Henderson     case CR_SAR:
2075c603e14aSRichard Henderson         if (a->e == 0) {
207698a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
207798a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
20786fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
207998a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
208035136a77SRichard Henderson             goto done;
208198a9cb79SRichard Henderson         }
208298a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
208335136a77SRichard Henderson         goto done;
208435136a77SRichard Henderson     case CR_IT: /* Interval Timer */
208535136a77SRichard Henderson         /* FIXME: Respect PSW_S bit.  */
208635136a77SRichard Henderson         nullify_over(ctx);
208798a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
2088dfd1b812SRichard Henderson         if (translator_io_start(&ctx->base)) {
208931234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
209049c29d6cSRichard Henderson         }
20910c58c1bcSRichard Henderson         gen_helper_read_interval_timer(tmp);
209298a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
209331234768SRichard Henderson         return nullify_end(ctx);
209498a9cb79SRichard Henderson     case 26:
209598a9cb79SRichard Henderson     case 27:
209698a9cb79SRichard Henderson         break;
209798a9cb79SRichard Henderson     default:
209898a9cb79SRichard Henderson         /* All other control registers are privileged.  */
209935136a77SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
210035136a77SRichard Henderson         break;
210198a9cb79SRichard Henderson     }
210298a9cb79SRichard Henderson 
2103aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
21046fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
210535136a77SRichard Henderson     save_gpr(ctx, rt, tmp);
210635136a77SRichard Henderson 
210735136a77SRichard Henderson  done:
210898a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
210931234768SRichard Henderson     return true;
211098a9cb79SRichard Henderson }
211198a9cb79SRichard Henderson 
2112c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
211333423472SRichard Henderson {
2114c603e14aSRichard Henderson     unsigned rr = a->r;
2115c603e14aSRichard Henderson     unsigned rs = a->sp;
2116967662cdSRichard Henderson     TCGv_i64 tmp;
211733423472SRichard Henderson 
211833423472SRichard Henderson     if (rs >= 5) {
211933423472SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
212033423472SRichard Henderson     }
212133423472SRichard Henderson     nullify_over(ctx);
212233423472SRichard Henderson 
2123967662cdSRichard Henderson     tmp = tcg_temp_new_i64();
2124967662cdSRichard Henderson     tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32);
212533423472SRichard Henderson 
212633423472SRichard Henderson     if (rs >= 4) {
2127967662cdSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs]));
2128494737b7SRichard Henderson         ctx->tb_flags &= ~TB_FLAG_SR_SAME;
212933423472SRichard Henderson     } else {
2130967662cdSRichard Henderson         tcg_gen_mov_i64(cpu_sr[rs], tmp);
213133423472SRichard Henderson     }
213233423472SRichard Henderson 
213331234768SRichard Henderson     return nullify_end(ctx);
213433423472SRichard Henderson }
213533423472SRichard Henderson 
2136c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
213798a9cb79SRichard Henderson {
2138c603e14aSRichard Henderson     unsigned ctl = a->t;
21396fd0c7bcSRichard Henderson     TCGv_i64 reg;
21406fd0c7bcSRichard Henderson     TCGv_i64 tmp;
214198a9cb79SRichard Henderson 
214235136a77SRichard Henderson     if (ctl == CR_SAR) {
21434845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
2144aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
21456fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31);
214698a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
214798a9cb79SRichard Henderson 
214898a9cb79SRichard Henderson         cond_free(&ctx->null_cond);
214931234768SRichard Henderson         return true;
215098a9cb79SRichard Henderson     }
215198a9cb79SRichard Henderson 
215235136a77SRichard Henderson     /* All other control registers are privileged or read-only.  */
215335136a77SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
215435136a77SRichard Henderson 
2155c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
215635136a77SRichard Henderson     nullify_over(ctx);
21574c34bab0SHelge Deller 
21584c34bab0SHelge Deller     if (ctx->is_pa20) {
21594845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
21604c34bab0SHelge Deller     } else {
21614c34bab0SHelge Deller         reg = tcg_temp_new_i64();
21624c34bab0SHelge Deller         tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r));
21634c34bab0SHelge Deller     }
21644845f015SSven Schnelle 
216535136a77SRichard Henderson     switch (ctl) {
216635136a77SRichard Henderson     case CR_IT:
2167104281c1SRichard Henderson         if (translator_io_start(&ctx->base)) {
2168104281c1SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2169104281c1SRichard Henderson         }
2170ad75a51eSRichard Henderson         gen_helper_write_interval_timer(tcg_env, reg);
217135136a77SRichard Henderson         break;
21724f5f2548SRichard Henderson     case CR_EIRR:
21736ebebea7SRichard Henderson         /* Helper modifies interrupt lines and is therefore IO. */
21746ebebea7SRichard Henderson         translator_io_start(&ctx->base);
2175ad75a51eSRichard Henderson         gen_helper_write_eirr(tcg_env, reg);
21766ebebea7SRichard Henderson         /* Exit to re-evaluate interrupts in the main loop. */
217731234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
21784f5f2548SRichard Henderson         break;
21794f5f2548SRichard Henderson 
218035136a77SRichard Henderson     case CR_IIASQ:
218135136a77SRichard Henderson     case CR_IIAOQ:
218235136a77SRichard Henderson         /* FIXME: Respect PSW_Q bit */
218335136a77SRichard Henderson         /* The write advances the queue and stores to the back element.  */
2184aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
21856fd0c7bcSRichard Henderson         tcg_gen_ld_i64(tmp, tcg_env,
218635136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
21876fd0c7bcSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
21886fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env,
218935136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
219035136a77SRichard Henderson         break;
219135136a77SRichard Henderson 
2192d5de20bdSSven Schnelle     case CR_PID1:
2193d5de20bdSSven Schnelle     case CR_PID2:
2194d5de20bdSSven Schnelle     case CR_PID3:
2195d5de20bdSSven Schnelle     case CR_PID4:
21966fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
2197d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY
2198ad75a51eSRichard Henderson         gen_helper_change_prot_id(tcg_env);
2199d5de20bdSSven Schnelle #endif
2200d5de20bdSSven Schnelle         break;
2201d5de20bdSSven Schnelle 
22026ebebea7SRichard Henderson     case CR_EIEM:
22036ebebea7SRichard Henderson         /* Exit to re-evaluate interrupts in the main loop. */
22046ebebea7SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
22056ebebea7SRichard Henderson         /* FALLTHRU */
220635136a77SRichard Henderson     default:
22076fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
220835136a77SRichard Henderson         break;
220935136a77SRichard Henderson     }
221031234768SRichard Henderson     return nullify_end(ctx);
22114f5f2548SRichard Henderson #endif
221235136a77SRichard Henderson }
221335136a77SRichard Henderson 
2214c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
221598a9cb79SRichard Henderson {
2216aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
221798a9cb79SRichard Henderson 
22186fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, load_gpr(ctx, a->r));
22196fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31);
222098a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
222198a9cb79SRichard Henderson 
222298a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
222331234768SRichard Henderson     return true;
222498a9cb79SRichard Henderson }
222598a9cb79SRichard Henderson 
2226e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a)
222798a9cb79SRichard Henderson {
22286fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
222998a9cb79SRichard Henderson 
22302330504cSHelge Deller #ifdef CONFIG_USER_ONLY
22312330504cSHelge Deller     /* We don't implement space registers in user mode. */
22326fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
22332330504cSHelge Deller #else
2234967662cdSRichard Henderson     tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
2235967662cdSRichard Henderson     tcg_gen_shri_i64(dest, dest, 32);
22362330504cSHelge Deller #endif
2237e36f27efSRichard Henderson     save_gpr(ctx, a->t, dest);
223898a9cb79SRichard Henderson 
223998a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
224031234768SRichard Henderson     return true;
224198a9cb79SRichard Henderson }
224298a9cb79SRichard Henderson 
2243e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a)
2244e36f27efSRichard Henderson {
22457b2d70a1SHelge Deller #ifdef CONFIG_USER_ONLY
2246e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
22477b2d70a1SHelge Deller #else
22486fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2249e1b5a5edSRichard Henderson 
22507b2d70a1SHelge Deller     /* HP-UX 11i and HP ODE use rsm for read-access to PSW */
22517b2d70a1SHelge Deller     if (a->i) {
22527b2d70a1SHelge Deller         CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
22537b2d70a1SHelge Deller     }
22547b2d70a1SHelge Deller 
2255e1b5a5edSRichard Henderson     nullify_over(ctx);
2256e1b5a5edSRichard Henderson 
2257aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
22586fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
22596fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ~a->i);
2260ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2261e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2262e1b5a5edSRichard Henderson 
2263e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_M.  */
226431234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
226531234768SRichard Henderson     return nullify_end(ctx);
2266e36f27efSRichard Henderson #endif
2267e1b5a5edSRichard Henderson }
2268e1b5a5edSRichard Henderson 
2269e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
2270e1b5a5edSRichard Henderson {
2271e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2272e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
22736fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2274e1b5a5edSRichard Henderson 
2275e1b5a5edSRichard Henderson     nullify_over(ctx);
2276e1b5a5edSRichard Henderson 
2277aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
22786fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
22796fd0c7bcSRichard Henderson     tcg_gen_ori_i64(tmp, tmp, a->i);
2280ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2281e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2282e1b5a5edSRichard Henderson 
2283e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_I.  */
228431234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
228531234768SRichard Henderson     return nullify_end(ctx);
2286e36f27efSRichard Henderson #endif
2287e1b5a5edSRichard Henderson }
2288e1b5a5edSRichard Henderson 
2289c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
2290e1b5a5edSRichard Henderson {
2291e1b5a5edSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2292c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
22936fd0c7bcSRichard Henderson     TCGv_i64 tmp, reg;
2294e1b5a5edSRichard Henderson     nullify_over(ctx);
2295e1b5a5edSRichard Henderson 
2296c603e14aSRichard Henderson     reg = load_gpr(ctx, a->r);
2297aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2298ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, reg);
2299e1b5a5edSRichard Henderson 
2300e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts.  */
230131234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
230231234768SRichard Henderson     return nullify_end(ctx);
2303c603e14aSRichard Henderson #endif
2304e1b5a5edSRichard Henderson }
2305f49b3537SRichard Henderson 
2306e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r)
2307f49b3537SRichard Henderson {
2308f49b3537SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2309e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
2310f49b3537SRichard Henderson     nullify_over(ctx);
2311f49b3537SRichard Henderson 
2312e36f27efSRichard Henderson     if (rfi_r) {
2313ad75a51eSRichard Henderson         gen_helper_rfi_r(tcg_env);
2314f49b3537SRichard Henderson     } else {
2315ad75a51eSRichard Henderson         gen_helper_rfi(tcg_env);
2316f49b3537SRichard Henderson     }
231731234768SRichard Henderson     /* Exit the TB to recognize new interrupts.  */
231807ea28b4SRichard Henderson     tcg_gen_exit_tb(NULL, 0);
231931234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
2320f49b3537SRichard Henderson 
232131234768SRichard Henderson     return nullify_end(ctx);
2322e36f27efSRichard Henderson #endif
2323f49b3537SRichard Henderson }
23246210db05SHelge Deller 
2325e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a)
2326e36f27efSRichard Henderson {
2327e36f27efSRichard Henderson     return do_rfi(ctx, false);
2328e36f27efSRichard Henderson }
2329e36f27efSRichard Henderson 
2330e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a)
2331e36f27efSRichard Henderson {
2332e36f27efSRichard Henderson     return do_rfi(ctx, true);
2333e36f27efSRichard Henderson }
2334e36f27efSRichard Henderson 
233596927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a)
23366210db05SHelge Deller {
23376210db05SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
233896927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
23396210db05SHelge Deller     nullify_over(ctx);
2340ad75a51eSRichard Henderson     gen_helper_halt(tcg_env);
234131234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
234231234768SRichard Henderson     return nullify_end(ctx);
234396927adbSRichard Henderson #endif
23446210db05SHelge Deller }
234596927adbSRichard Henderson 
234696927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a)
234796927adbSRichard Henderson {
234896927adbSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
234996927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
235096927adbSRichard Henderson     nullify_over(ctx);
2351ad75a51eSRichard Henderson     gen_helper_reset(tcg_env);
235296927adbSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
235396927adbSRichard Henderson     return nullify_end(ctx);
235496927adbSRichard Henderson #endif
235596927adbSRichard Henderson }
2356e1b5a5edSRichard Henderson 
2357558c09beSRichard Henderson static bool do_getshadowregs(DisasContext *ctx)
23584a4554c6SHelge Deller {
23594a4554c6SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
23604a4554c6SHelge Deller     nullify_over(ctx);
2361558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0]));
2362558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1]));
2363558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2]));
2364558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3]));
2365558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4]));
2366558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5]));
2367558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6]));
23684a4554c6SHelge Deller     return nullify_end(ctx);
2369558c09beSRichard Henderson }
2370558c09beSRichard Henderson 
23713bdf2081SHelge Deller static bool do_putshadowregs(DisasContext *ctx)
23723bdf2081SHelge Deller {
23733bdf2081SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
23743bdf2081SHelge Deller     nullify_over(ctx);
23753bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0]));
23763bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1]));
23773bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2]));
23783bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3]));
23793bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4]));
23803bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5]));
23813bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6]));
23823bdf2081SHelge Deller     return nullify_end(ctx);
23833bdf2081SHelge Deller }
23843bdf2081SHelge Deller 
2385558c09beSRichard Henderson static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
2386558c09beSRichard Henderson {
2387558c09beSRichard Henderson     return do_getshadowregs(ctx);
23884a4554c6SHelge Deller }
23894a4554c6SHelge Deller 
2390deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
239198a9cb79SRichard Henderson {
2392deee69a1SRichard Henderson     if (a->m) {
23936fd0c7bcSRichard Henderson         TCGv_i64 dest = dest_gpr(ctx, a->b);
23946fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->b);
23956fd0c7bcSRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->x);
239698a9cb79SRichard Henderson 
239798a9cb79SRichard Henderson         /* The only thing we need to do is the base register modification.  */
23986fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, src1, src2);
2399deee69a1SRichard Henderson         save_gpr(ctx, a->b, dest);
2400deee69a1SRichard Henderson     }
240198a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
240231234768SRichard Henderson     return true;
240398a9cb79SRichard Henderson }
240498a9cb79SRichard Henderson 
2405ad1fdacdSSven Schnelle static bool trans_fic(DisasContext *ctx, arg_ldst *a)
2406ad1fdacdSSven Schnelle {
2407ad1fdacdSSven Schnelle     /* End TB for flush instruction cache, so we pick up new insns. */
2408ad1fdacdSSven Schnelle     ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2409ad1fdacdSSven Schnelle     return trans_nop_addrx(ctx, a);
2410ad1fdacdSSven Schnelle }
2411ad1fdacdSSven Schnelle 
2412deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a)
241398a9cb79SRichard Henderson {
24146fd0c7bcSRichard Henderson     TCGv_i64 dest, ofs;
2415eed14219SRichard Henderson     TCGv_i32 level, want;
24166fd0c7bcSRichard Henderson     TCGv_i64 addr;
241798a9cb79SRichard Henderson 
241898a9cb79SRichard Henderson     nullify_over(ctx);
241998a9cb79SRichard Henderson 
2420deee69a1SRichard Henderson     dest = dest_gpr(ctx, a->t);
2421deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2422eed14219SRichard Henderson 
2423deee69a1SRichard Henderson     if (a->imm) {
2424e5d487c9SRichard Henderson         level = tcg_constant_i32(a->ri & 3);
242598a9cb79SRichard Henderson     } else {
2426eed14219SRichard Henderson         level = tcg_temp_new_i32();
24276fd0c7bcSRichard Henderson         tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri));
2428eed14219SRichard Henderson         tcg_gen_andi_i32(level, level, 3);
242998a9cb79SRichard Henderson     }
243029dd6f64SRichard Henderson     want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ);
2431eed14219SRichard Henderson 
2432ad75a51eSRichard Henderson     gen_helper_probe(dest, tcg_env, addr, level, want);
2433eed14219SRichard Henderson 
2434deee69a1SRichard Henderson     save_gpr(ctx, a->t, dest);
243531234768SRichard Henderson     return nullify_end(ctx);
243698a9cb79SRichard Henderson }
243798a9cb79SRichard Henderson 
2438deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
24398d6ae7fbSRichard Henderson {
24408577f354SRichard Henderson     if (ctx->is_pa20) {
24418577f354SRichard Henderson         return false;
24428577f354SRichard Henderson     }
2443deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2444deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
24456fd0c7bcSRichard Henderson     TCGv_i64 addr;
24466fd0c7bcSRichard Henderson     TCGv_i64 ofs, reg;
24478d6ae7fbSRichard Henderson 
24488d6ae7fbSRichard Henderson     nullify_over(ctx);
24498d6ae7fbSRichard Henderson 
2450deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2451deee69a1SRichard Henderson     reg = load_gpr(ctx, a->r);
2452deee69a1SRichard Henderson     if (a->addr) {
24538577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
24548d6ae7fbSRichard Henderson     } else {
24558577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
24568d6ae7fbSRichard Henderson     }
24578d6ae7fbSRichard Henderson 
245832dc7569SSven Schnelle     /* Exit TB for TLB change if mmu is enabled.  */
245932dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
246031234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
246131234768SRichard Henderson     }
246231234768SRichard Henderson     return nullify_end(ctx);
2463deee69a1SRichard Henderson #endif
24648d6ae7fbSRichard Henderson }
246563300a00SRichard Henderson 
2466eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local)
246763300a00SRichard Henderson {
2468deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2469deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
24706fd0c7bcSRichard Henderson     TCGv_i64 addr;
24716fd0c7bcSRichard Henderson     TCGv_i64 ofs;
247263300a00SRichard Henderson 
247363300a00SRichard Henderson     nullify_over(ctx);
247463300a00SRichard Henderson 
2475deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2476eb25d10fSHelge Deller 
2477eb25d10fSHelge Deller     /*
2478eb25d10fSHelge Deller      * Page align now, rather than later, so that we can add in the
2479eb25d10fSHelge Deller      * page_size field from pa2.0 from the low 4 bits of GR[b].
2480eb25d10fSHelge Deller      */
2481eb25d10fSHelge Deller     tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK);
2482eb25d10fSHelge Deller     if (ctx->is_pa20) {
2483eb25d10fSHelge Deller         tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4);
248463300a00SRichard Henderson     }
2485eb25d10fSHelge Deller 
2486eb25d10fSHelge Deller     if (local) {
2487eb25d10fSHelge Deller         gen_helper_ptlb_l(tcg_env, addr);
248863300a00SRichard Henderson     } else {
2489ad75a51eSRichard Henderson         gen_helper_ptlb(tcg_env, addr);
249063300a00SRichard Henderson     }
249163300a00SRichard Henderson 
2492eb25d10fSHelge Deller     if (a->m) {
2493eb25d10fSHelge Deller         save_gpr(ctx, a->b, ofs);
2494eb25d10fSHelge Deller     }
2495eb25d10fSHelge Deller 
2496eb25d10fSHelge Deller     /* Exit TB for TLB change if mmu is enabled.  */
2497eb25d10fSHelge Deller     if (ctx->tb_flags & PSW_C) {
2498eb25d10fSHelge Deller         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2499eb25d10fSHelge Deller     }
2500eb25d10fSHelge Deller     return nullify_end(ctx);
2501eb25d10fSHelge Deller #endif
2502eb25d10fSHelge Deller }
2503eb25d10fSHelge Deller 
2504eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a)
2505eb25d10fSHelge Deller {
2506eb25d10fSHelge Deller     return do_pxtlb(ctx, a, false);
2507eb25d10fSHelge Deller }
2508eb25d10fSHelge Deller 
2509eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a)
2510eb25d10fSHelge Deller {
2511eb25d10fSHelge Deller     return ctx->is_pa20 && do_pxtlb(ctx, a, true);
2512eb25d10fSHelge Deller }
2513eb25d10fSHelge Deller 
2514eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a)
2515eb25d10fSHelge Deller {
2516eb25d10fSHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2517eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY
2518eb25d10fSHelge Deller     nullify_over(ctx);
2519eb25d10fSHelge Deller 
2520eb25d10fSHelge Deller     trans_nop_addrx(ctx, a);
2521eb25d10fSHelge Deller     gen_helper_ptlbe(tcg_env);
2522eb25d10fSHelge Deller 
252363300a00SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
252432dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
252531234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
252631234768SRichard Henderson     }
252731234768SRichard Henderson     return nullify_end(ctx);
2528deee69a1SRichard Henderson #endif
252963300a00SRichard Henderson }
25302dfcca9fSRichard Henderson 
25316797c315SNick Hudson /*
25326797c315SNick Hudson  * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
25336797c315SNick Hudson  * See
25346797c315SNick Hudson  *     https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
25356797c315SNick Hudson  *     page 13-9 (195/206)
25366797c315SNick Hudson  */
25376797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
25386797c315SNick Hudson {
25398577f354SRichard Henderson     if (ctx->is_pa20) {
25408577f354SRichard Henderson         return false;
25418577f354SRichard Henderson     }
25426797c315SNick Hudson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
25436797c315SNick Hudson #ifndef CONFIG_USER_ONLY
25446fd0c7bcSRichard Henderson     TCGv_i64 addr, atl, stl;
25456fd0c7bcSRichard Henderson     TCGv_i64 reg;
25466797c315SNick Hudson 
25476797c315SNick Hudson     nullify_over(ctx);
25486797c315SNick Hudson 
25496797c315SNick Hudson     /*
25506797c315SNick Hudson      * FIXME:
25516797c315SNick Hudson      *  if (not (pcxl or pcxl2))
25526797c315SNick Hudson      *    return gen_illegal(ctx);
25536797c315SNick Hudson      */
25546797c315SNick Hudson 
25556fd0c7bcSRichard Henderson     atl = tcg_temp_new_i64();
25566fd0c7bcSRichard Henderson     stl = tcg_temp_new_i64();
25576fd0c7bcSRichard Henderson     addr = tcg_temp_new_i64();
25586797c315SNick Hudson 
2559ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(stl, tcg_env,
25606797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
25616797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIASQ]));
2562ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(atl, tcg_env,
25636797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
25646797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIAOQ]));
25656797c315SNick Hudson     tcg_gen_shli_i64(stl, stl, 32);
2566d265360fSRichard Henderson     tcg_gen_or_i64(addr, atl, stl);
25676797c315SNick Hudson 
25686797c315SNick Hudson     reg = load_gpr(ctx, a->r);
25696797c315SNick Hudson     if (a->addr) {
25708577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
25716797c315SNick Hudson     } else {
25728577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
25736797c315SNick Hudson     }
25746797c315SNick Hudson 
25756797c315SNick Hudson     /* Exit TB for TLB change if mmu is enabled.  */
25766797c315SNick Hudson     if (ctx->tb_flags & PSW_C) {
25776797c315SNick Hudson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
25786797c315SNick Hudson     }
25796797c315SNick Hudson     return nullify_end(ctx);
25806797c315SNick Hudson #endif
25816797c315SNick Hudson }
25826797c315SNick Hudson 
25838577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
25848577f354SRichard Henderson {
25858577f354SRichard Henderson     if (!ctx->is_pa20) {
25868577f354SRichard Henderson         return false;
25878577f354SRichard Henderson     }
25888577f354SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
25898577f354SRichard Henderson #ifndef CONFIG_USER_ONLY
25908577f354SRichard Henderson     nullify_over(ctx);
25918577f354SRichard Henderson     {
25928577f354SRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
25938577f354SRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->r2);
25948577f354SRichard Henderson 
25958577f354SRichard Henderson         if (a->data) {
25968577f354SRichard Henderson             gen_helper_idtlbt_pa20(tcg_env, src1, src2);
25978577f354SRichard Henderson         } else {
25988577f354SRichard Henderson             gen_helper_iitlbt_pa20(tcg_env, src1, src2);
25998577f354SRichard Henderson         }
26008577f354SRichard Henderson     }
26018577f354SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
26028577f354SRichard Henderson     if (ctx->tb_flags & PSW_C) {
26038577f354SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
26048577f354SRichard Henderson     }
26058577f354SRichard Henderson     return nullify_end(ctx);
26068577f354SRichard Henderson #endif
26078577f354SRichard Henderson }
26088577f354SRichard Henderson 
2609deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
26102dfcca9fSRichard Henderson {
2611deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2612deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
26136fd0c7bcSRichard Henderson     TCGv_i64 vaddr;
26146fd0c7bcSRichard Henderson     TCGv_i64 ofs, paddr;
26152dfcca9fSRichard Henderson 
26162dfcca9fSRichard Henderson     nullify_over(ctx);
26172dfcca9fSRichard Henderson 
2618deee69a1SRichard Henderson     form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
26192dfcca9fSRichard Henderson 
2620aac0f603SRichard Henderson     paddr = tcg_temp_new_i64();
2621ad75a51eSRichard Henderson     gen_helper_lpa(paddr, tcg_env, vaddr);
26222dfcca9fSRichard Henderson 
26232dfcca9fSRichard Henderson     /* Note that physical address result overrides base modification.  */
2624deee69a1SRichard Henderson     if (a->m) {
2625deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
26262dfcca9fSRichard Henderson     }
2627deee69a1SRichard Henderson     save_gpr(ctx, a->t, paddr);
26282dfcca9fSRichard Henderson 
262931234768SRichard Henderson     return nullify_end(ctx);
2630deee69a1SRichard Henderson #endif
26312dfcca9fSRichard Henderson }
263243a97b81SRichard Henderson 
2633deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a)
263443a97b81SRichard Henderson {
263543a97b81SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
263643a97b81SRichard Henderson 
263743a97b81SRichard Henderson     /* The Coherence Index is an implementation-defined function of the
263843a97b81SRichard Henderson        physical address.  Two addresses with the same CI have a coherent
263943a97b81SRichard Henderson        view of the cache.  Our implementation is to return 0 for all,
264043a97b81SRichard Henderson        since the entire address space is coherent.  */
2641a4db4a78SRichard Henderson     save_gpr(ctx, a->t, ctx->zero);
264243a97b81SRichard Henderson 
264331234768SRichard Henderson     cond_free(&ctx->null_cond);
264431234768SRichard Henderson     return true;
264543a97b81SRichard Henderson }
264698a9cb79SRichard Henderson 
2647faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2648b2167459SRichard Henderson {
26490c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, false);
2650b2167459SRichard Henderson }
2651b2167459SRichard Henderson 
2652faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2653b2167459SRichard Henderson {
26540c982a28SRichard Henderson     return do_add_reg(ctx, a, true, false, false, false);
2655b2167459SRichard Henderson }
2656b2167459SRichard Henderson 
2657faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2658b2167459SRichard Henderson {
26590c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, false);
2660b2167459SRichard Henderson }
2661b2167459SRichard Henderson 
2662faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2663b2167459SRichard Henderson {
26640c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, true);
26650c982a28SRichard Henderson }
2666b2167459SRichard Henderson 
2667faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
26680c982a28SRichard Henderson {
26690c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, true);
26700c982a28SRichard Henderson }
26710c982a28SRichard Henderson 
267263c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
26730c982a28SRichard Henderson {
26740c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, false);
26750c982a28SRichard Henderson }
26760c982a28SRichard Henderson 
267763c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
26780c982a28SRichard Henderson {
26790c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, false);
26800c982a28SRichard Henderson }
26810c982a28SRichard Henderson 
268263c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
26830c982a28SRichard Henderson {
26840c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, true);
26850c982a28SRichard Henderson }
26860c982a28SRichard Henderson 
268763c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
26880c982a28SRichard Henderson {
26890c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, true);
26900c982a28SRichard Henderson }
26910c982a28SRichard Henderson 
269263c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
26930c982a28SRichard Henderson {
26940c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, true, false);
26950c982a28SRichard Henderson }
26960c982a28SRichard Henderson 
269763c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
26980c982a28SRichard Henderson {
26990c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, true, false);
27000c982a28SRichard Henderson }
27010c982a28SRichard Henderson 
2702fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
27030c982a28SRichard Henderson {
27046fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_andc_i64);
27050c982a28SRichard Henderson }
27060c982a28SRichard Henderson 
2707fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
27080c982a28SRichard Henderson {
27096fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_and_i64);
27100c982a28SRichard Henderson }
27110c982a28SRichard Henderson 
2712fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
27130c982a28SRichard Henderson {
27140c982a28SRichard Henderson     if (a->cf == 0) {
27150c982a28SRichard Henderson         unsigned r2 = a->r2;
27160c982a28SRichard Henderson         unsigned r1 = a->r1;
27170c982a28SRichard Henderson         unsigned rt = a->t;
27180c982a28SRichard Henderson 
27197aee8189SRichard Henderson         if (rt == 0) { /* NOP */
27207aee8189SRichard Henderson             cond_free(&ctx->null_cond);
27217aee8189SRichard Henderson             return true;
27227aee8189SRichard Henderson         }
27237aee8189SRichard Henderson         if (r2 == 0) { /* COPY */
2724b2167459SRichard Henderson             if (r1 == 0) {
27256fd0c7bcSRichard Henderson                 TCGv_i64 dest = dest_gpr(ctx, rt);
27266fd0c7bcSRichard Henderson                 tcg_gen_movi_i64(dest, 0);
2727b2167459SRichard Henderson                 save_gpr(ctx, rt, dest);
2728b2167459SRichard Henderson             } else {
2729b2167459SRichard Henderson                 save_gpr(ctx, rt, cpu_gr[r1]);
2730b2167459SRichard Henderson             }
2731b2167459SRichard Henderson             cond_free(&ctx->null_cond);
273231234768SRichard Henderson             return true;
2733b2167459SRichard Henderson         }
27347aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY
27357aee8189SRichard Henderson         /* These are QEMU extensions and are nops in the real architecture:
27367aee8189SRichard Henderson          *
27377aee8189SRichard Henderson          * or %r10,%r10,%r10 -- idle loop; wait for interrupt
27387aee8189SRichard Henderson          * or %r31,%r31,%r31 -- death loop; offline cpu
27397aee8189SRichard Henderson          *                      currently implemented as idle.
27407aee8189SRichard Henderson          */
27417aee8189SRichard Henderson         if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
27427aee8189SRichard Henderson             /* No need to check for supervisor, as userland can only pause
27437aee8189SRichard Henderson                until the next timer interrupt.  */
27447aee8189SRichard Henderson             nullify_over(ctx);
27457aee8189SRichard Henderson 
27467aee8189SRichard Henderson             /* Advance the instruction queue.  */
2747741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
2748741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
27497aee8189SRichard Henderson             nullify_set(ctx, 0);
27507aee8189SRichard Henderson 
27517aee8189SRichard Henderson             /* Tell the qemu main loop to halt until this cpu has work.  */
2752ad75a51eSRichard Henderson             tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
275329dd6f64SRichard Henderson                            offsetof(CPUState, halted) - offsetof(HPPACPU, env));
27547aee8189SRichard Henderson             gen_excp_1(EXCP_HALTED);
27557aee8189SRichard Henderson             ctx->base.is_jmp = DISAS_NORETURN;
27567aee8189SRichard Henderson 
27577aee8189SRichard Henderson             return nullify_end(ctx);
27587aee8189SRichard Henderson         }
27597aee8189SRichard Henderson #endif
27607aee8189SRichard Henderson     }
27616fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_or_i64);
27627aee8189SRichard Henderson }
2763b2167459SRichard Henderson 
2764fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
2765b2167459SRichard Henderson {
27666fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_xor_i64);
27670c982a28SRichard Henderson }
27680c982a28SRichard Henderson 
2769345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
27700c982a28SRichard Henderson {
27716fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2772b2167459SRichard Henderson 
27730c982a28SRichard Henderson     if (a->cf) {
2774b2167459SRichard Henderson         nullify_over(ctx);
2775b2167459SRichard Henderson     }
27760c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
27770c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2778345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
277931234768SRichard Henderson     return nullify_end(ctx);
2780b2167459SRichard Henderson }
2781b2167459SRichard Henderson 
2782af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
2783b2167459SRichard Henderson {
278446bb3d46SRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, dest;
2785b2167459SRichard Henderson 
27860c982a28SRichard Henderson     if (a->cf) {
2787b2167459SRichard Henderson         nullify_over(ctx);
2788b2167459SRichard Henderson     }
278946bb3d46SRichard Henderson 
27900c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
27910c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
279246bb3d46SRichard Henderson     dest = dest_gpr(ctx, a->t);
279346bb3d46SRichard Henderson 
279446bb3d46SRichard Henderson     tcg_gen_xor_i64(dest, tcg_r1, tcg_r2);
279546bb3d46SRichard Henderson     save_gpr(ctx, a->t, dest);
279646bb3d46SRichard Henderson 
279746bb3d46SRichard Henderson     cond_free(&ctx->null_cond);
279846bb3d46SRichard Henderson     if (a->cf) {
279946bb3d46SRichard Henderson         ctx->null_cond = do_unit_zero_cond(a->cf, a->d, dest);
280046bb3d46SRichard Henderson     }
280146bb3d46SRichard Henderson 
280231234768SRichard Henderson     return nullify_end(ctx);
2803b2167459SRichard Henderson }
2804b2167459SRichard Henderson 
2805af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
2806b2167459SRichard Henderson {
28076fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, tmp;
2808b2167459SRichard Henderson 
2809ababac16SRichard Henderson     if (a->cf == 0) {
2810ababac16SRichard Henderson         tcg_r2 = load_gpr(ctx, a->r2);
2811ababac16SRichard Henderson         tmp = dest_gpr(ctx, a->t);
2812ababac16SRichard Henderson 
2813ababac16SRichard Henderson         if (a->r1 == 0) {
2814ababac16SRichard Henderson             /* UADDCM r0,src,dst is the common idiom for dst = ~src. */
2815ababac16SRichard Henderson             tcg_gen_not_i64(tmp, tcg_r2);
2816ababac16SRichard Henderson         } else {
2817ababac16SRichard Henderson             /*
2818ababac16SRichard Henderson              * Recall that r1 - r2 == r1 + ~r2 + 1.
2819ababac16SRichard Henderson              * Thus r1 + ~r2 == r1 - r2 - 1,
2820ababac16SRichard Henderson              * which does not require an extra temporary.
2821ababac16SRichard Henderson              */
2822ababac16SRichard Henderson             tcg_r1 = load_gpr(ctx, a->r1);
2823ababac16SRichard Henderson             tcg_gen_sub_i64(tmp, tcg_r1, tcg_r2);
2824ababac16SRichard Henderson             tcg_gen_subi_i64(tmp, tmp, 1);
2825b2167459SRichard Henderson         }
2826ababac16SRichard Henderson         save_gpr(ctx, a->t, tmp);
2827ababac16SRichard Henderson         cond_free(&ctx->null_cond);
2828ababac16SRichard Henderson         return true;
2829ababac16SRichard Henderson     }
2830ababac16SRichard Henderson 
2831ababac16SRichard Henderson     nullify_over(ctx);
28320c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
28330c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2834aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
28356fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, tcg_r2);
283646bb3d46SRichard Henderson     do_unit_addsub(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, true);
283731234768SRichard Henderson     return nullify_end(ctx);
2838b2167459SRichard Henderson }
2839b2167459SRichard Henderson 
2840af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
2841b2167459SRichard Henderson {
28420c982a28SRichard Henderson     return do_uaddcm(ctx, a, false);
28430c982a28SRichard Henderson }
28440c982a28SRichard Henderson 
2845af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
28460c982a28SRichard Henderson {
28470c982a28SRichard Henderson     return do_uaddcm(ctx, a, true);
28480c982a28SRichard Henderson }
28490c982a28SRichard Henderson 
2850af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
28510c982a28SRichard Henderson {
28526fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2853b2167459SRichard Henderson 
2854b2167459SRichard Henderson     nullify_over(ctx);
2855b2167459SRichard Henderson 
2856aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2857d0ae87a2SRichard Henderson     tcg_gen_extract2_i64(tmp, cpu_psw_cb, cpu_psw_cb_msb, 4);
2858b2167459SRichard Henderson     if (!is_i) {
28596fd0c7bcSRichard Henderson         tcg_gen_not_i64(tmp, tmp);
2860b2167459SRichard Henderson     }
28616fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
28626fd0c7bcSRichard Henderson     tcg_gen_muli_i64(tmp, tmp, 6);
286346bb3d46SRichard Henderson     do_unit_addsub(ctx, a->t, load_gpr(ctx, a->r), tmp,
286446bb3d46SRichard Henderson                    a->cf, a->d, false, is_i);
286531234768SRichard Henderson     return nullify_end(ctx);
2866b2167459SRichard Henderson }
2867b2167459SRichard Henderson 
2868af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
2869b2167459SRichard Henderson {
28700c982a28SRichard Henderson     return do_dcor(ctx, a, false);
28710c982a28SRichard Henderson }
28720c982a28SRichard Henderson 
2873af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
28740c982a28SRichard Henderson {
28750c982a28SRichard Henderson     return do_dcor(ctx, a, true);
28760c982a28SRichard Henderson }
28770c982a28SRichard Henderson 
28780c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
28790c982a28SRichard Henderson {
2880a4db4a78SRichard Henderson     TCGv_i64 dest, add1, add2, addc, in1, in2;
2881b2167459SRichard Henderson 
2882b2167459SRichard Henderson     nullify_over(ctx);
2883b2167459SRichard Henderson 
28840c982a28SRichard Henderson     in1 = load_gpr(ctx, a->r1);
28850c982a28SRichard Henderson     in2 = load_gpr(ctx, a->r2);
2886b2167459SRichard Henderson 
2887aac0f603SRichard Henderson     add1 = tcg_temp_new_i64();
2888aac0f603SRichard Henderson     add2 = tcg_temp_new_i64();
2889aac0f603SRichard Henderson     addc = tcg_temp_new_i64();
2890aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
2891b2167459SRichard Henderson 
2892b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
28936fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, in1, in1);
28946fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
2895b2167459SRichard Henderson 
289672ca8753SRichard Henderson     /*
289772ca8753SRichard Henderson      * Add or subtract R2, depending on PSW[V].  Proper computation of
289872ca8753SRichard Henderson      * carry requires that we subtract via + ~R2 + 1, as described in
289972ca8753SRichard Henderson      * the manual.  By extracting and masking V, we can produce the
290072ca8753SRichard Henderson      * proper inputs to the addition without movcond.
290172ca8753SRichard Henderson      */
29026fd0c7bcSRichard Henderson     tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
29036fd0c7bcSRichard Henderson     tcg_gen_xor_i64(add2, in2, addc);
29046fd0c7bcSRichard Henderson     tcg_gen_andi_i64(addc, addc, 1);
290572ca8753SRichard Henderson 
2906a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero);
2907a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb,
2908a4db4a78SRichard Henderson                      addc, ctx->zero);
2909b2167459SRichard Henderson 
2910b2167459SRichard Henderson     /* Write back the result register.  */
29110c982a28SRichard Henderson     save_gpr(ctx, a->t, dest);
2912b2167459SRichard Henderson 
2913b2167459SRichard Henderson     /* Write back PSW[CB].  */
29146fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
29156fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
2916b2167459SRichard Henderson 
2917f8f5986eSRichard Henderson     /*
2918f8f5986eSRichard Henderson      * Write back PSW[V] for the division step.
2919f8f5986eSRichard Henderson      * Shift cb{8} from where it lives in bit 32 to bit 31,
2920f8f5986eSRichard Henderson      * so that it overlaps r2{32} in bit 31.
2921f8f5986eSRichard Henderson      */
2922f8f5986eSRichard Henderson     tcg_gen_shri_i64(cpu_psw_v, cpu_psw_cb, 1);
29236fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
2924b2167459SRichard Henderson 
2925b2167459SRichard Henderson     /* Install the new nullification.  */
29260c982a28SRichard Henderson     if (a->cf) {
2927f8f5986eSRichard Henderson         TCGv_i64 sv = NULL, uv = NULL;
2928b47a4a02SSven Schnelle         if (cond_need_sv(a->cf >> 1)) {
2929f8f5986eSRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2, in1, 1, false);
2930f8f5986eSRichard Henderson         } else if (cond_need_cb(a->cf >> 1)) {
2931f8f5986eSRichard Henderson             uv = do_add_uv(ctx, cpu_psw_cb, NULL, in1, 1, false);
2932b2167459SRichard Henderson         }
2933f8f5986eSRichard Henderson         ctx->null_cond = do_cond(ctx, a->cf, false, dest, uv, sv);
2934b2167459SRichard Henderson     }
2935b2167459SRichard Henderson 
293631234768SRichard Henderson     return nullify_end(ctx);
2937b2167459SRichard Henderson }
2938b2167459SRichard Henderson 
29390588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a)
2940b2167459SRichard Henderson {
29410588e061SRichard Henderson     return do_add_imm(ctx, a, false, false);
29420588e061SRichard Henderson }
29430588e061SRichard Henderson 
29440588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a)
29450588e061SRichard Henderson {
29460588e061SRichard Henderson     return do_add_imm(ctx, a, true, false);
29470588e061SRichard Henderson }
29480588e061SRichard Henderson 
29490588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a)
29500588e061SRichard Henderson {
29510588e061SRichard Henderson     return do_add_imm(ctx, a, false, true);
29520588e061SRichard Henderson }
29530588e061SRichard Henderson 
29540588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a)
29550588e061SRichard Henderson {
29560588e061SRichard Henderson     return do_add_imm(ctx, a, true, true);
29570588e061SRichard Henderson }
29580588e061SRichard Henderson 
29590588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a)
29600588e061SRichard Henderson {
29610588e061SRichard Henderson     return do_sub_imm(ctx, a, false);
29620588e061SRichard Henderson }
29630588e061SRichard Henderson 
29640588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
29650588e061SRichard Henderson {
29660588e061SRichard Henderson     return do_sub_imm(ctx, a, true);
29670588e061SRichard Henderson }
29680588e061SRichard Henderson 
2969345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
29700588e061SRichard Henderson {
29716fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
2972b2167459SRichard Henderson 
29730588e061SRichard Henderson     if (a->cf) {
2974b2167459SRichard Henderson         nullify_over(ctx);
2975b2167459SRichard Henderson     }
2976b2167459SRichard Henderson 
29776fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
29780588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
2979345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
2980b2167459SRichard Henderson 
298131234768SRichard Henderson     return nullify_end(ctx);
2982b2167459SRichard Henderson }
2983b2167459SRichard Henderson 
29840843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a,
29850843563fSRichard Henderson                           void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
29860843563fSRichard Henderson {
29870843563fSRichard Henderson     TCGv_i64 r1, r2, dest;
29880843563fSRichard Henderson 
29890843563fSRichard Henderson     if (!ctx->is_pa20) {
29900843563fSRichard Henderson         return false;
29910843563fSRichard Henderson     }
29920843563fSRichard Henderson 
29930843563fSRichard Henderson     nullify_over(ctx);
29940843563fSRichard Henderson 
29950843563fSRichard Henderson     r1 = load_gpr(ctx, a->r1);
29960843563fSRichard Henderson     r2 = load_gpr(ctx, a->r2);
29970843563fSRichard Henderson     dest = dest_gpr(ctx, a->t);
29980843563fSRichard Henderson 
29990843563fSRichard Henderson     fn(dest, r1, r2);
30000843563fSRichard Henderson     save_gpr(ctx, a->t, dest);
30010843563fSRichard Henderson 
30020843563fSRichard Henderson     return nullify_end(ctx);
30030843563fSRichard Henderson }
30040843563fSRichard Henderson 
3005151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a,
3006151f309bSRichard Henderson                              void (*fn)(TCGv_i64, TCGv_i64, int64_t))
3007151f309bSRichard Henderson {
3008151f309bSRichard Henderson     TCGv_i64 r, dest;
3009151f309bSRichard Henderson 
3010151f309bSRichard Henderson     if (!ctx->is_pa20) {
3011151f309bSRichard Henderson         return false;
3012151f309bSRichard Henderson     }
3013151f309bSRichard Henderson 
3014151f309bSRichard Henderson     nullify_over(ctx);
3015151f309bSRichard Henderson 
3016151f309bSRichard Henderson     r = load_gpr(ctx, a->r);
3017151f309bSRichard Henderson     dest = dest_gpr(ctx, a->t);
3018151f309bSRichard Henderson 
3019151f309bSRichard Henderson     fn(dest, r, a->i);
3020151f309bSRichard Henderson     save_gpr(ctx, a->t, dest);
3021151f309bSRichard Henderson 
3022151f309bSRichard Henderson     return nullify_end(ctx);
3023151f309bSRichard Henderson }
3024151f309bSRichard Henderson 
30253bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a,
30263bbb8e48SRichard Henderson                                 void (*fn)(TCGv_i64, TCGv_i64,
30273bbb8e48SRichard Henderson                                            TCGv_i64, TCGv_i32))
30283bbb8e48SRichard Henderson {
30293bbb8e48SRichard Henderson     TCGv_i64 r1, r2, dest;
30303bbb8e48SRichard Henderson 
30313bbb8e48SRichard Henderson     if (!ctx->is_pa20) {
30323bbb8e48SRichard Henderson         return false;
30333bbb8e48SRichard Henderson     }
30343bbb8e48SRichard Henderson 
30353bbb8e48SRichard Henderson     nullify_over(ctx);
30363bbb8e48SRichard Henderson 
30373bbb8e48SRichard Henderson     r1 = load_gpr(ctx, a->r1);
30383bbb8e48SRichard Henderson     r2 = load_gpr(ctx, a->r2);
30393bbb8e48SRichard Henderson     dest = dest_gpr(ctx, a->t);
30403bbb8e48SRichard Henderson 
30413bbb8e48SRichard Henderson     fn(dest, r1, r2, tcg_constant_i32(a->sh));
30423bbb8e48SRichard Henderson     save_gpr(ctx, a->t, dest);
30433bbb8e48SRichard Henderson 
30443bbb8e48SRichard Henderson     return nullify_end(ctx);
30453bbb8e48SRichard Henderson }
30463bbb8e48SRichard Henderson 
30470843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a)
30480843563fSRichard Henderson {
30490843563fSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_add16_i64);
30500843563fSRichard Henderson }
30510843563fSRichard Henderson 
30520843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a)
30530843563fSRichard Henderson {
30540843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_ss);
30550843563fSRichard Henderson }
30560843563fSRichard Henderson 
30570843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a)
30580843563fSRichard Henderson {
30590843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_us);
30600843563fSRichard Henderson }
30610843563fSRichard Henderson 
30621b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a)
30631b3cb7c8SRichard Henderson {
30641b3cb7c8SRichard Henderson     return do_multimedia(ctx, a, gen_helper_havg);
30651b3cb7c8SRichard Henderson }
30661b3cb7c8SRichard Henderson 
3067151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a)
3068151f309bSRichard Henderson {
3069151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64);
3070151f309bSRichard Henderson }
3071151f309bSRichard Henderson 
3072151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a)
3073151f309bSRichard Henderson {
3074151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64);
3075151f309bSRichard Henderson }
3076151f309bSRichard Henderson 
3077151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a)
3078151f309bSRichard Henderson {
3079151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64);
3080151f309bSRichard Henderson }
3081151f309bSRichard Henderson 
30823bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a)
30833bbb8e48SRichard Henderson {
30843bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshladd);
30853bbb8e48SRichard Henderson }
30863bbb8e48SRichard Henderson 
30873bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a)
30883bbb8e48SRichard Henderson {
30893bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshradd);
30903bbb8e48SRichard Henderson }
30913bbb8e48SRichard Henderson 
309210c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a)
309310c9e58dSRichard Henderson {
309410c9e58dSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64);
309510c9e58dSRichard Henderson }
309610c9e58dSRichard Henderson 
309710c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a)
309810c9e58dSRichard Henderson {
309910c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_ss);
310010c9e58dSRichard Henderson }
310110c9e58dSRichard Henderson 
310210c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a)
310310c9e58dSRichard Henderson {
310410c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_us);
310510c9e58dSRichard Henderson }
310610c9e58dSRichard Henderson 
3107c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3108c2a7ee3fSRichard Henderson {
3109c2a7ee3fSRichard Henderson     uint64_t mask = 0xffff0000ffff0000ull;
3110c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3111c2a7ee3fSRichard Henderson 
3112c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r2, mask);
3113c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r1, mask);
3114c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, tmp, 16);
3115c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
3116c2a7ee3fSRichard Henderson }
3117c2a7ee3fSRichard Henderson 
3118c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a)
3119c2a7ee3fSRichard Henderson {
3120c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_l);
3121c2a7ee3fSRichard Henderson }
3122c2a7ee3fSRichard Henderson 
3123c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3124c2a7ee3fSRichard Henderson {
3125c2a7ee3fSRichard Henderson     uint64_t mask = 0x0000ffff0000ffffull;
3126c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3127c2a7ee3fSRichard Henderson 
3128c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r1, mask);
3129c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r2, mask);
3130c2a7ee3fSRichard Henderson     tcg_gen_shli_i64(tmp, tmp, 16);
3131c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
3132c2a7ee3fSRichard Henderson }
3133c2a7ee3fSRichard Henderson 
3134c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a)
3135c2a7ee3fSRichard Henderson {
3136c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_r);
3137c2a7ee3fSRichard Henderson }
3138c2a7ee3fSRichard Henderson 
3139c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3140c2a7ee3fSRichard Henderson {
3141c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3142c2a7ee3fSRichard Henderson 
3143c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, r2, 32);
3144c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r1, tmp, 0, 32);
3145c2a7ee3fSRichard Henderson }
3146c2a7ee3fSRichard Henderson 
3147c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a)
3148c2a7ee3fSRichard Henderson {
3149c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_l);
3150c2a7ee3fSRichard Henderson }
3151c2a7ee3fSRichard Henderson 
3152c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3153c2a7ee3fSRichard Henderson {
3154c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r2, r1, 32, 32);
3155c2a7ee3fSRichard Henderson }
3156c2a7ee3fSRichard Henderson 
3157c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a)
3158c2a7ee3fSRichard Henderson {
3159c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_r);
3160c2a7ee3fSRichard Henderson }
3161c2a7ee3fSRichard Henderson 
31624e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a)
31634e7abdb1SRichard Henderson {
31644e7abdb1SRichard Henderson     TCGv_i64 r, t0, t1, t2, t3;
31654e7abdb1SRichard Henderson 
31664e7abdb1SRichard Henderson     if (!ctx->is_pa20) {
31674e7abdb1SRichard Henderson         return false;
31684e7abdb1SRichard Henderson     }
31694e7abdb1SRichard Henderson 
31704e7abdb1SRichard Henderson     nullify_over(ctx);
31714e7abdb1SRichard Henderson 
31724e7abdb1SRichard Henderson     r = load_gpr(ctx, a->r1);
31734e7abdb1SRichard Henderson     t0 = tcg_temp_new_i64();
31744e7abdb1SRichard Henderson     t1 = tcg_temp_new_i64();
31754e7abdb1SRichard Henderson     t2 = tcg_temp_new_i64();
31764e7abdb1SRichard Henderson     t3 = tcg_temp_new_i64();
31774e7abdb1SRichard Henderson 
31784e7abdb1SRichard Henderson     tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16);
31794e7abdb1SRichard Henderson     tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16);
31804e7abdb1SRichard Henderson     tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16);
31814e7abdb1SRichard Henderson     tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16);
31824e7abdb1SRichard Henderson 
31834e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t1, t0, 16, 48);
31844e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t2, t3, t2, 16, 48);
31854e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t2, t0, 32, 32);
31864e7abdb1SRichard Henderson 
31874e7abdb1SRichard Henderson     save_gpr(ctx, a->t, t0);
31884e7abdb1SRichard Henderson     return nullify_end(ctx);
31894e7abdb1SRichard Henderson }
31904e7abdb1SRichard Henderson 
31911cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a)
319296d6407fSRichard Henderson {
3193b5caa17cSRichard Henderson     if (ctx->is_pa20) {
3194b5caa17cSRichard Henderson        /*
3195b5caa17cSRichard Henderson         * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches.
3196b5caa17cSRichard Henderson         * Any base modification still occurs.
3197b5caa17cSRichard Henderson         */
3198b5caa17cSRichard Henderson         if (a->t == 0) {
3199b5caa17cSRichard Henderson             return trans_nop_addrx(ctx, a);
3200b5caa17cSRichard Henderson         }
3201b5caa17cSRichard Henderson     } else if (a->size > MO_32) {
32020786a3b6SHelge Deller         return gen_illegal(ctx);
3203c53e401eSRichard Henderson     }
32041cd012a5SRichard Henderson     return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
32051cd012a5SRichard Henderson                    a->disp, a->sp, a->m, a->size | MO_TE);
320696d6407fSRichard Henderson }
320796d6407fSRichard Henderson 
32081cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a)
320996d6407fSRichard Henderson {
32101cd012a5SRichard Henderson     assert(a->x == 0 && a->scale == 0);
3211c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
32120786a3b6SHelge Deller         return gen_illegal(ctx);
321396d6407fSRichard Henderson     }
3214c53e401eSRichard Henderson     return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
32150786a3b6SHelge Deller }
321696d6407fSRichard Henderson 
32171cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
321896d6407fSRichard Henderson {
3219b1af755cSRichard Henderson     MemOp mop = MO_TE | MO_ALIGN | a->size;
3220a4db4a78SRichard Henderson     TCGv_i64 dest, ofs;
32216fd0c7bcSRichard Henderson     TCGv_i64 addr;
322296d6407fSRichard Henderson 
3223c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
322451416c4eSRichard Henderson         return gen_illegal(ctx);
322551416c4eSRichard Henderson     }
322651416c4eSRichard Henderson 
322796d6407fSRichard Henderson     nullify_over(ctx);
322896d6407fSRichard Henderson 
32291cd012a5SRichard Henderson     if (a->m) {
323086f8d05fSRichard Henderson         /* Base register modification.  Make sure if RT == RB,
323186f8d05fSRichard Henderson            we see the result of the load.  */
3232aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
323396d6407fSRichard Henderson     } else {
32341cd012a5SRichard Henderson         dest = dest_gpr(ctx, a->t);
323596d6407fSRichard Henderson     }
323696d6407fSRichard Henderson 
3237c3ea1996SSven Schnelle     form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? 3 : 0,
323817fe594cSRichard Henderson              a->disp, a->sp, a->m, MMU_DISABLED(ctx));
3239b1af755cSRichard Henderson 
3240b1af755cSRichard Henderson     /*
3241b1af755cSRichard Henderson      * For hppa1.1, LDCW is undefined unless aligned mod 16.
3242b1af755cSRichard Henderson      * However actual hardware succeeds with aligned mod 4.
3243b1af755cSRichard Henderson      * Detect this case and log a GUEST_ERROR.
3244b1af755cSRichard Henderson      *
3245b1af755cSRichard Henderson      * TODO: HPPA64 relaxes the over-alignment requirement
3246b1af755cSRichard Henderson      * with the ,co completer.
3247b1af755cSRichard Henderson      */
3248b1af755cSRichard Henderson     gen_helper_ldc_check(addr);
3249b1af755cSRichard Henderson 
3250a4db4a78SRichard Henderson     tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop);
3251b1af755cSRichard Henderson 
32521cd012a5SRichard Henderson     if (a->m) {
32531cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
325496d6407fSRichard Henderson     }
32551cd012a5SRichard Henderson     save_gpr(ctx, a->t, dest);
325696d6407fSRichard Henderson 
325731234768SRichard Henderson     return nullify_end(ctx);
325896d6407fSRichard Henderson }
325996d6407fSRichard Henderson 
32601cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a)
326196d6407fSRichard Henderson {
32626fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
32636fd0c7bcSRichard Henderson     TCGv_i64 addr;
326496d6407fSRichard Henderson 
326596d6407fSRichard Henderson     nullify_over(ctx);
326696d6407fSRichard Henderson 
32671cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
326817fe594cSRichard Henderson              MMU_DISABLED(ctx));
32691cd012a5SRichard Henderson     val = load_gpr(ctx, a->r);
32701cd012a5SRichard Henderson     if (a->a) {
3271f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3272ad75a51eSRichard Henderson             gen_helper_stby_e_parallel(tcg_env, addr, val);
3273f9f46db4SEmilio G. Cota         } else {
3274ad75a51eSRichard Henderson             gen_helper_stby_e(tcg_env, addr, val);
3275f9f46db4SEmilio G. Cota         }
3276f9f46db4SEmilio G. Cota     } else {
3277f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3278ad75a51eSRichard Henderson             gen_helper_stby_b_parallel(tcg_env, addr, val);
327996d6407fSRichard Henderson         } else {
3280ad75a51eSRichard Henderson             gen_helper_stby_b(tcg_env, addr, val);
328196d6407fSRichard Henderson         }
3282f9f46db4SEmilio G. Cota     }
32831cd012a5SRichard Henderson     if (a->m) {
32846fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~3);
32851cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
328696d6407fSRichard Henderson     }
328796d6407fSRichard Henderson 
328831234768SRichard Henderson     return nullify_end(ctx);
328996d6407fSRichard Henderson }
329096d6407fSRichard Henderson 
329125460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a)
329225460fc5SRichard Henderson {
32936fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
32946fd0c7bcSRichard Henderson     TCGv_i64 addr;
329525460fc5SRichard Henderson 
329625460fc5SRichard Henderson     if (!ctx->is_pa20) {
329725460fc5SRichard Henderson         return false;
329825460fc5SRichard Henderson     }
329925460fc5SRichard Henderson     nullify_over(ctx);
330025460fc5SRichard Henderson 
330125460fc5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
330217fe594cSRichard Henderson              MMU_DISABLED(ctx));
330325460fc5SRichard Henderson     val = load_gpr(ctx, a->r);
330425460fc5SRichard Henderson     if (a->a) {
330525460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
330625460fc5SRichard Henderson             gen_helper_stdby_e_parallel(tcg_env, addr, val);
330725460fc5SRichard Henderson         } else {
330825460fc5SRichard Henderson             gen_helper_stdby_e(tcg_env, addr, val);
330925460fc5SRichard Henderson         }
331025460fc5SRichard Henderson     } else {
331125460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
331225460fc5SRichard Henderson             gen_helper_stdby_b_parallel(tcg_env, addr, val);
331325460fc5SRichard Henderson         } else {
331425460fc5SRichard Henderson             gen_helper_stdby_b(tcg_env, addr, val);
331525460fc5SRichard Henderson         }
331625460fc5SRichard Henderson     }
331725460fc5SRichard Henderson     if (a->m) {
33186fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~7);
331925460fc5SRichard Henderson         save_gpr(ctx, a->b, ofs);
332025460fc5SRichard Henderson     }
332125460fc5SRichard Henderson 
332225460fc5SRichard Henderson     return nullify_end(ctx);
332325460fc5SRichard Henderson }
332425460fc5SRichard Henderson 
33251cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a)
3326d0a851ccSRichard Henderson {
3327d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3328d0a851ccSRichard Henderson 
3329d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3330451d993dSRichard Henderson     ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX;
33311cd012a5SRichard Henderson     trans_ld(ctx, a);
3332d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
333331234768SRichard Henderson     return true;
3334d0a851ccSRichard Henderson }
3335d0a851ccSRichard Henderson 
33361cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a)
3337d0a851ccSRichard Henderson {
3338d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3339d0a851ccSRichard Henderson 
3340d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3341451d993dSRichard Henderson     ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX;
33421cd012a5SRichard Henderson     trans_st(ctx, a);
3343d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
334431234768SRichard Henderson     return true;
3345d0a851ccSRichard Henderson }
334695412a61SRichard Henderson 
33470588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
3348b2167459SRichard Henderson {
33496fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3350b2167459SRichard Henderson 
33516fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tcg_rt, a->i);
33520588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3353b2167459SRichard Henderson     cond_free(&ctx->null_cond);
335431234768SRichard Henderson     return true;
3355b2167459SRichard Henderson }
3356b2167459SRichard Henderson 
33570588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a)
3358b2167459SRichard Henderson {
33596fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
33606fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
3361b2167459SRichard Henderson 
33626fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
3363b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
3364b2167459SRichard Henderson     cond_free(&ctx->null_cond);
336531234768SRichard Henderson     return true;
3366b2167459SRichard Henderson }
3367b2167459SRichard Henderson 
33680588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
3369b2167459SRichard Henderson {
33706fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3371b2167459SRichard Henderson 
3372b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
3373d265360fSRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_i64.  */
33740588e061SRichard Henderson     if (a->b == 0) {
33756fd0c7bcSRichard Henderson         tcg_gen_movi_i64(tcg_rt, a->i);
3376b2167459SRichard Henderson     } else {
33776fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
3378b2167459SRichard Henderson     }
33790588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3380b2167459SRichard Henderson     cond_free(&ctx->null_cond);
338131234768SRichard Henderson     return true;
3382b2167459SRichard Henderson }
3383b2167459SRichard Henderson 
33846fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
3385e9efd4bcSRichard Henderson                     unsigned c, unsigned f, bool d, unsigned n, int disp)
338698cd9ca7SRichard Henderson {
33876fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv;
338898cd9ca7SRichard Henderson     DisasCond cond;
338998cd9ca7SRichard Henderson 
339098cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3391aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
339298cd9ca7SRichard Henderson 
33936fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
339498cd9ca7SRichard Henderson 
3395f764718dSRichard Henderson     sv = NULL;
3396b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
339798cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
339898cd9ca7SRichard Henderson     }
339998cd9ca7SRichard Henderson 
34004fe9533aSRichard Henderson     cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
340101afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
340298cd9ca7SRichard Henderson }
340398cd9ca7SRichard Henderson 
340401afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
340598cd9ca7SRichard Henderson {
3406e9efd4bcSRichard Henderson     if (!ctx->is_pa20 && a->d) {
3407e9efd4bcSRichard Henderson         return false;
3408e9efd4bcSRichard Henderson     }
340901afb7beSRichard Henderson     nullify_over(ctx);
3410e9efd4bcSRichard Henderson     return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
3411e9efd4bcSRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
341201afb7beSRichard Henderson }
341301afb7beSRichard Henderson 
341401afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
341501afb7beSRichard Henderson {
3416c65c3ee1SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3417c65c3ee1SRichard Henderson         return false;
3418c65c3ee1SRichard Henderson     }
341901afb7beSRichard Henderson     nullify_over(ctx);
34206fd0c7bcSRichard Henderson     return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
3421c65c3ee1SRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
342201afb7beSRichard Henderson }
342301afb7beSRichard Henderson 
34246fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
342501afb7beSRichard Henderson                     unsigned c, unsigned f, unsigned n, int disp)
342601afb7beSRichard Henderson {
34276fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv, cb_cond;
342898cd9ca7SRichard Henderson     DisasCond cond;
3429bdcccc17SRichard Henderson     bool d = false;
343098cd9ca7SRichard Henderson 
3431f25d3160SRichard Henderson     /*
3432f25d3160SRichard Henderson      * For hppa64, the ADDB conditions change with PSW.W,
3433f25d3160SRichard Henderson      * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3434f25d3160SRichard Henderson      */
3435f25d3160SRichard Henderson     if (ctx->tb_flags & PSW_W) {
3436f25d3160SRichard Henderson         d = c >= 5;
3437f25d3160SRichard Henderson         if (d) {
3438f25d3160SRichard Henderson             c &= 3;
3439f25d3160SRichard Henderson         }
3440f25d3160SRichard Henderson     }
3441f25d3160SRichard Henderson 
344298cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3443aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
3444f764718dSRichard Henderson     sv = NULL;
3445bdcccc17SRichard Henderson     cb_cond = NULL;
344698cd9ca7SRichard Henderson 
3447b47a4a02SSven Schnelle     if (cond_need_cb(c)) {
3448aac0f603SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
3449aac0f603SRichard Henderson         TCGv_i64 cb_msb = tcg_temp_new_i64();
3450bdcccc17SRichard Henderson 
34516fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cb_msb, 0);
34526fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
34536fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
34546fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
3455bdcccc17SRichard Henderson         cb_cond = get_carry(ctx, d, cb, cb_msb);
3456b47a4a02SSven Schnelle     } else {
34576fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
3458b47a4a02SSven Schnelle     }
3459b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
3460f8f5986eSRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2, in1, 0, d);
346198cd9ca7SRichard Henderson     }
346298cd9ca7SRichard Henderson 
3463a751eb31SRichard Henderson     cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
346443675d20SSven Schnelle     save_gpr(ctx, r, dest);
346501afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
346698cd9ca7SRichard Henderson }
346798cd9ca7SRichard Henderson 
346801afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a)
346998cd9ca7SRichard Henderson {
347001afb7beSRichard Henderson     nullify_over(ctx);
347101afb7beSRichard Henderson     return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
347201afb7beSRichard Henderson }
347301afb7beSRichard Henderson 
347401afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
347501afb7beSRichard Henderson {
347601afb7beSRichard Henderson     nullify_over(ctx);
34776fd0c7bcSRichard Henderson     return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
347801afb7beSRichard Henderson }
347901afb7beSRichard Henderson 
348001afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
348101afb7beSRichard Henderson {
34826fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
348398cd9ca7SRichard Henderson     DisasCond cond;
348498cd9ca7SRichard Henderson 
348598cd9ca7SRichard Henderson     nullify_over(ctx);
348698cd9ca7SRichard Henderson 
3487aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
348801afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
348982d0c831SRichard Henderson     if (a->d) {
349082d0c831SRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
349182d0c831SRichard Henderson     } else {
34921e9ab9fbSRichard Henderson         /* Force shift into [32,63] */
34936fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_sar, 32);
34946fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, tmp);
34951e9ab9fbSRichard Henderson     }
349698cd9ca7SRichard Henderson 
34971e9ab9fbSRichard Henderson     cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
349801afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
349998cd9ca7SRichard Henderson }
350098cd9ca7SRichard Henderson 
350101afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
350298cd9ca7SRichard Henderson {
35036fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
350401afb7beSRichard Henderson     DisasCond cond;
35051e9ab9fbSRichard Henderson     int p;
350601afb7beSRichard Henderson 
350701afb7beSRichard Henderson     nullify_over(ctx);
350801afb7beSRichard Henderson 
3509aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
351001afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
351182d0c831SRichard Henderson     p = a->p | (a->d ? 0 : 32);
35126fd0c7bcSRichard Henderson     tcg_gen_shli_i64(tmp, tcg_r, p);
351301afb7beSRichard Henderson 
351401afb7beSRichard Henderson     cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
351501afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
351601afb7beSRichard Henderson }
351701afb7beSRichard Henderson 
351801afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a)
351901afb7beSRichard Henderson {
35206fd0c7bcSRichard Henderson     TCGv_i64 dest;
352198cd9ca7SRichard Henderson     DisasCond cond;
352298cd9ca7SRichard Henderson 
352398cd9ca7SRichard Henderson     nullify_over(ctx);
352498cd9ca7SRichard Henderson 
352501afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r2);
352601afb7beSRichard Henderson     if (a->r1 == 0) {
35276fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, 0);
352898cd9ca7SRichard Henderson     } else {
35296fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
353098cd9ca7SRichard Henderson     }
353198cd9ca7SRichard Henderson 
35324fa52edfSRichard Henderson     /* All MOVB conditions are 32-bit. */
35334fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
353401afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
353501afb7beSRichard Henderson }
353601afb7beSRichard Henderson 
353701afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
353801afb7beSRichard Henderson {
35396fd0c7bcSRichard Henderson     TCGv_i64 dest;
354001afb7beSRichard Henderson     DisasCond cond;
354101afb7beSRichard Henderson 
354201afb7beSRichard Henderson     nullify_over(ctx);
354301afb7beSRichard Henderson 
354401afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r);
35456fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, a->i);
354601afb7beSRichard Henderson 
35474fa52edfSRichard Henderson     /* All MOVBI conditions are 32-bit. */
35484fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
354901afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
355098cd9ca7SRichard Henderson }
355198cd9ca7SRichard Henderson 
3552f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
35530b1347d2SRichard Henderson {
35546fd0c7bcSRichard Henderson     TCGv_i64 dest, src2;
35550b1347d2SRichard Henderson 
3556f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3557f7b775a9SRichard Henderson         return false;
3558f7b775a9SRichard Henderson     }
355930878590SRichard Henderson     if (a->c) {
35600b1347d2SRichard Henderson         nullify_over(ctx);
35610b1347d2SRichard Henderson     }
35620b1347d2SRichard Henderson 
356330878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
3564f7b775a9SRichard Henderson     src2 = load_gpr(ctx, a->r2);
356530878590SRichard Henderson     if (a->r1 == 0) {
3566f7b775a9SRichard Henderson         if (a->d) {
35676fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src2, cpu_sar);
3568f7b775a9SRichard Henderson         } else {
3569aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
3570f7b775a9SRichard Henderson 
35716fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src2);
35726fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
35736fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, dest, tmp);
3574f7b775a9SRichard Henderson         }
357530878590SRichard Henderson     } else if (a->r1 == a->r2) {
3576f7b775a9SRichard Henderson         if (a->d) {
35776fd0c7bcSRichard Henderson             tcg_gen_rotr_i64(dest, src2, cpu_sar);
3578f7b775a9SRichard Henderson         } else {
35790b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
3580e1d635e8SRichard Henderson             TCGv_i32 s32 = tcg_temp_new_i32();
3581e1d635e8SRichard Henderson 
35826fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, src2);
35836fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(s32, cpu_sar);
3584f7b775a9SRichard Henderson             tcg_gen_andi_i32(s32, s32, 31);
3585e1d635e8SRichard Henderson             tcg_gen_rotr_i32(t32, t32, s32);
35866fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
3587f7b775a9SRichard Henderson         }
3588f7b775a9SRichard Henderson     } else {
35896fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
3590f7b775a9SRichard Henderson 
3591f7b775a9SRichard Henderson         if (a->d) {
3592aac0f603SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
3593aac0f603SRichard Henderson             TCGv_i64 n = tcg_temp_new_i64();
3594f7b775a9SRichard Henderson 
35956fd0c7bcSRichard Henderson             tcg_gen_xori_i64(n, cpu_sar, 63);
3596a01491a2SHelge Deller             tcg_gen_shl_i64(t, src1, n);
35976fd0c7bcSRichard Henderson             tcg_gen_shli_i64(t, t, 1);
3598a01491a2SHelge Deller             tcg_gen_shr_i64(dest, src2, cpu_sar);
35996fd0c7bcSRichard Henderson             tcg_gen_or_i64(dest, dest, t);
36000b1347d2SRichard Henderson         } else {
36010b1347d2SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
36020b1347d2SRichard Henderson             TCGv_i64 s = tcg_temp_new_i64();
36030b1347d2SRichard Henderson 
36046fd0c7bcSRichard Henderson             tcg_gen_concat32_i64(t, src2, src1);
3605967662cdSRichard Henderson             tcg_gen_andi_i64(s, cpu_sar, 31);
3606967662cdSRichard Henderson             tcg_gen_shr_i64(dest, t, s);
36070b1347d2SRichard Henderson         }
3608f7b775a9SRichard Henderson     }
360930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36100b1347d2SRichard Henderson 
36110b1347d2SRichard Henderson     /* Install the new nullification.  */
36120b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
361330878590SRichard Henderson     if (a->c) {
3614d37fad0aSSven Schnelle         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
36150b1347d2SRichard Henderson     }
361631234768SRichard Henderson     return nullify_end(ctx);
36170b1347d2SRichard Henderson }
36180b1347d2SRichard Henderson 
3619f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
36200b1347d2SRichard Henderson {
3621f7b775a9SRichard Henderson     unsigned width, sa;
36226fd0c7bcSRichard Henderson     TCGv_i64 dest, t2;
36230b1347d2SRichard Henderson 
3624f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3625f7b775a9SRichard Henderson         return false;
3626f7b775a9SRichard Henderson     }
362730878590SRichard Henderson     if (a->c) {
36280b1347d2SRichard Henderson         nullify_over(ctx);
36290b1347d2SRichard Henderson     }
36300b1347d2SRichard Henderson 
3631f7b775a9SRichard Henderson     width = a->d ? 64 : 32;
3632f7b775a9SRichard Henderson     sa = width - 1 - a->cpos;
3633f7b775a9SRichard Henderson 
363430878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
363530878590SRichard Henderson     t2 = load_gpr(ctx, a->r2);
363605bfd4dbSRichard Henderson     if (a->r1 == 0) {
36376fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, t2, sa, width - sa);
3638c53e401eSRichard Henderson     } else if (width == TARGET_LONG_BITS) {
36396fd0c7bcSRichard Henderson         tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
3640f7b775a9SRichard Henderson     } else {
3641f7b775a9SRichard Henderson         assert(!a->d);
3642f7b775a9SRichard Henderson         if (a->r1 == a->r2) {
36430b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
36446fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, t2);
36450b1347d2SRichard Henderson             tcg_gen_rotri_i32(t32, t32, sa);
36466fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
36470b1347d2SRichard Henderson         } else {
3648967662cdSRichard Henderson             tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]);
3649967662cdSRichard Henderson             tcg_gen_extract_i64(dest, dest, sa, 32);
36500b1347d2SRichard Henderson         }
3651f7b775a9SRichard Henderson     }
365230878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36530b1347d2SRichard Henderson 
36540b1347d2SRichard Henderson     /* Install the new nullification.  */
36550b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
365630878590SRichard Henderson     if (a->c) {
3657d37fad0aSSven Schnelle         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
36580b1347d2SRichard Henderson     }
365931234768SRichard Henderson     return nullify_end(ctx);
36600b1347d2SRichard Henderson }
36610b1347d2SRichard Henderson 
3662bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
36630b1347d2SRichard Henderson {
3664bd792da3SRichard Henderson     unsigned widthm1 = a->d ? 63 : 31;
36656fd0c7bcSRichard Henderson     TCGv_i64 dest, src, tmp;
36660b1347d2SRichard Henderson 
3667bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3668bd792da3SRichard Henderson         return false;
3669bd792da3SRichard Henderson     }
367030878590SRichard Henderson     if (a->c) {
36710b1347d2SRichard Henderson         nullify_over(ctx);
36720b1347d2SRichard Henderson     }
36730b1347d2SRichard Henderson 
367430878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
367530878590SRichard Henderson     src = load_gpr(ctx, a->r);
3676aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
36770b1347d2SRichard Henderson 
36780b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
36796fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
36806fd0c7bcSRichard Henderson     tcg_gen_xori_i64(tmp, tmp, widthm1);
3681d781cb77SRichard Henderson 
368230878590SRichard Henderson     if (a->se) {
3683bd792da3SRichard Henderson         if (!a->d) {
36846fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(dest, src);
3685bd792da3SRichard Henderson             src = dest;
3686bd792da3SRichard Henderson         }
36876fd0c7bcSRichard Henderson         tcg_gen_sar_i64(dest, src, tmp);
36886fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, dest, 0, a->len);
36890b1347d2SRichard Henderson     } else {
3690bd792da3SRichard Henderson         if (!a->d) {
36916fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src);
3692bd792da3SRichard Henderson             src = dest;
3693bd792da3SRichard Henderson         }
36946fd0c7bcSRichard Henderson         tcg_gen_shr_i64(dest, src, tmp);
36956fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, dest, 0, a->len);
36960b1347d2SRichard Henderson     }
369730878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36980b1347d2SRichard Henderson 
36990b1347d2SRichard Henderson     /* Install the new nullification.  */
37000b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
370130878590SRichard Henderson     if (a->c) {
3702bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
37030b1347d2SRichard Henderson     }
370431234768SRichard Henderson     return nullify_end(ctx);
37050b1347d2SRichard Henderson }
37060b1347d2SRichard Henderson 
3707bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
37080b1347d2SRichard Henderson {
3709bd792da3SRichard Henderson     unsigned len, cpos, width;
37106fd0c7bcSRichard Henderson     TCGv_i64 dest, src;
37110b1347d2SRichard Henderson 
3712bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3713bd792da3SRichard Henderson         return false;
3714bd792da3SRichard Henderson     }
371530878590SRichard Henderson     if (a->c) {
37160b1347d2SRichard Henderson         nullify_over(ctx);
37170b1347d2SRichard Henderson     }
37180b1347d2SRichard Henderson 
3719bd792da3SRichard Henderson     len = a->len;
3720bd792da3SRichard Henderson     width = a->d ? 64 : 32;
3721bd792da3SRichard Henderson     cpos = width - 1 - a->pos;
3722bd792da3SRichard Henderson     if (cpos + len > width) {
3723bd792da3SRichard Henderson         len = width - cpos;
3724bd792da3SRichard Henderson     }
3725bd792da3SRichard Henderson 
372630878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
372730878590SRichard Henderson     src = load_gpr(ctx, a->r);
372830878590SRichard Henderson     if (a->se) {
37296fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, src, cpos, len);
37300b1347d2SRichard Henderson     } else {
37316fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, src, cpos, len);
37320b1347d2SRichard Henderson     }
373330878590SRichard Henderson     save_gpr(ctx, a->t, dest);
37340b1347d2SRichard Henderson 
37350b1347d2SRichard Henderson     /* Install the new nullification.  */
37360b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
373730878590SRichard Henderson     if (a->c) {
3738bd792da3SRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
37390b1347d2SRichard Henderson     }
374031234768SRichard Henderson     return nullify_end(ctx);
37410b1347d2SRichard Henderson }
37420b1347d2SRichard Henderson 
374372ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
37440b1347d2SRichard Henderson {
374572ae4f2bSRichard Henderson     unsigned len, width;
3746c53e401eSRichard Henderson     uint64_t mask0, mask1;
37476fd0c7bcSRichard Henderson     TCGv_i64 dest;
37480b1347d2SRichard Henderson 
374972ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
375072ae4f2bSRichard Henderson         return false;
375172ae4f2bSRichard Henderson     }
375230878590SRichard Henderson     if (a->c) {
37530b1347d2SRichard Henderson         nullify_over(ctx);
37540b1347d2SRichard Henderson     }
375572ae4f2bSRichard Henderson 
375672ae4f2bSRichard Henderson     len = a->len;
375772ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
375872ae4f2bSRichard Henderson     if (a->cpos + len > width) {
375972ae4f2bSRichard Henderson         len = width - a->cpos;
37600b1347d2SRichard Henderson     }
37610b1347d2SRichard Henderson 
376230878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
376330878590SRichard Henderson     mask0 = deposit64(0, a->cpos, len, a->i);
376430878590SRichard Henderson     mask1 = deposit64(-1, a->cpos, len, a->i);
37650b1347d2SRichard Henderson 
376630878590SRichard Henderson     if (a->nz) {
37676fd0c7bcSRichard Henderson         TCGv_i64 src = load_gpr(ctx, a->t);
37686fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, src, mask1);
37696fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, mask0);
37700b1347d2SRichard Henderson     } else {
37716fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, mask0);
37720b1347d2SRichard Henderson     }
377330878590SRichard Henderson     save_gpr(ctx, a->t, dest);
37740b1347d2SRichard Henderson 
37750b1347d2SRichard Henderson     /* Install the new nullification.  */
37760b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
377730878590SRichard Henderson     if (a->c) {
377872ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
37790b1347d2SRichard Henderson     }
378031234768SRichard Henderson     return nullify_end(ctx);
37810b1347d2SRichard Henderson }
37820b1347d2SRichard Henderson 
378372ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
37840b1347d2SRichard Henderson {
378530878590SRichard Henderson     unsigned rs = a->nz ? a->t : 0;
378672ae4f2bSRichard Henderson     unsigned len, width;
37876fd0c7bcSRichard Henderson     TCGv_i64 dest, val;
37880b1347d2SRichard Henderson 
378972ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
379072ae4f2bSRichard Henderson         return false;
379172ae4f2bSRichard Henderson     }
379230878590SRichard Henderson     if (a->c) {
37930b1347d2SRichard Henderson         nullify_over(ctx);
37940b1347d2SRichard Henderson     }
379572ae4f2bSRichard Henderson 
379672ae4f2bSRichard Henderson     len = a->len;
379772ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
379872ae4f2bSRichard Henderson     if (a->cpos + len > width) {
379972ae4f2bSRichard Henderson         len = width - a->cpos;
38000b1347d2SRichard Henderson     }
38010b1347d2SRichard Henderson 
380230878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
380330878590SRichard Henderson     val = load_gpr(ctx, a->r);
38040b1347d2SRichard Henderson     if (rs == 0) {
38056fd0c7bcSRichard Henderson         tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
38060b1347d2SRichard Henderson     } else {
38076fd0c7bcSRichard Henderson         tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
38080b1347d2SRichard Henderson     }
380930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
38100b1347d2SRichard Henderson 
38110b1347d2SRichard Henderson     /* Install the new nullification.  */
38120b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
381330878590SRichard Henderson     if (a->c) {
381472ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
38150b1347d2SRichard Henderson     }
381631234768SRichard Henderson     return nullify_end(ctx);
38170b1347d2SRichard Henderson }
38180b1347d2SRichard Henderson 
381972ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
38206fd0c7bcSRichard Henderson                        bool d, bool nz, unsigned len, TCGv_i64 val)
38210b1347d2SRichard Henderson {
38220b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
382372ae4f2bSRichard Henderson     unsigned widthm1 = d ? 63 : 31;
38246fd0c7bcSRichard Henderson     TCGv_i64 mask, tmp, shift, dest;
3825c53e401eSRichard Henderson     uint64_t msb = 1ULL << (len - 1);
38260b1347d2SRichard Henderson 
38270b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
3828aac0f603SRichard Henderson     shift = tcg_temp_new_i64();
3829aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
38300b1347d2SRichard Henderson 
38310b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
38326fd0c7bcSRichard Henderson     tcg_gen_andi_i64(shift, cpu_sar, widthm1);
38336fd0c7bcSRichard Henderson     tcg_gen_xori_i64(shift, shift, widthm1);
38340b1347d2SRichard Henderson 
3835aac0f603SRichard Henderson     mask = tcg_temp_new_i64();
38366fd0c7bcSRichard Henderson     tcg_gen_movi_i64(mask, msb + (msb - 1));
38376fd0c7bcSRichard Henderson     tcg_gen_and_i64(tmp, val, mask);
38380b1347d2SRichard Henderson     if (rs) {
38396fd0c7bcSRichard Henderson         tcg_gen_shl_i64(mask, mask, shift);
38406fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tmp, shift);
38416fd0c7bcSRichard Henderson         tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
38426fd0c7bcSRichard Henderson         tcg_gen_or_i64(dest, dest, tmp);
38430b1347d2SRichard Henderson     } else {
38446fd0c7bcSRichard Henderson         tcg_gen_shl_i64(dest, tmp, shift);
38450b1347d2SRichard Henderson     }
38460b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
38470b1347d2SRichard Henderson 
38480b1347d2SRichard Henderson     /* Install the new nullification.  */
38490b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
38500b1347d2SRichard Henderson     if (c) {
385172ae4f2bSRichard Henderson         ctx->null_cond = do_sed_cond(ctx, c, d, dest);
38520b1347d2SRichard Henderson     }
385331234768SRichard Henderson     return nullify_end(ctx);
38540b1347d2SRichard Henderson }
38550b1347d2SRichard Henderson 
385672ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
385730878590SRichard Henderson {
385872ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
385972ae4f2bSRichard Henderson         return false;
386072ae4f2bSRichard Henderson     }
3861a6deecceSSven Schnelle     if (a->c) {
3862a6deecceSSven Schnelle         nullify_over(ctx);
3863a6deecceSSven Schnelle     }
386472ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
386572ae4f2bSRichard Henderson                       load_gpr(ctx, a->r));
386630878590SRichard Henderson }
386730878590SRichard Henderson 
386872ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
386930878590SRichard Henderson {
387072ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
387172ae4f2bSRichard Henderson         return false;
387272ae4f2bSRichard Henderson     }
3873a6deecceSSven Schnelle     if (a->c) {
3874a6deecceSSven Schnelle         nullify_over(ctx);
3875a6deecceSSven Schnelle     }
387672ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
38776fd0c7bcSRichard Henderson                       tcg_constant_i64(a->i));
387830878590SRichard Henderson }
38790b1347d2SRichard Henderson 
38808340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a)
388198cd9ca7SRichard Henderson {
38826fd0c7bcSRichard Henderson     TCGv_i64 tmp;
388398cd9ca7SRichard Henderson 
3884aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
38856fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp);
3886660eefe1SRichard Henderson     tmp = do_ibranch_priv(ctx, tmp);
3887c301f34eSRichard Henderson 
3888c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
38898340f534SRichard Henderson     return do_ibranch(ctx, tmp, a->l, a->n);
3890c301f34eSRichard Henderson #else
3891c301f34eSRichard Henderson     TCGv_i64 new_spc = tcg_temp_new_i64();
3892c301f34eSRichard Henderson 
38932644f80bSRichard Henderson     nullify_over(ctx);
38942644f80bSRichard Henderson 
38958340f534SRichard Henderson     load_spr(ctx, new_spc, a->sp);
38968340f534SRichard Henderson     if (a->l) {
3897741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
38987fb7c9daSRichard Henderson         tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_b);
3899c301f34eSRichard Henderson     }
39008340f534SRichard Henderson     if (a->n && use_nullify_skip(ctx)) {
3901a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
39026fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, 4);
3903a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3904c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, new_spc);
3905c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f);
39064a3aa11eSRichard Henderson         nullify_set(ctx, 0);
3907c301f34eSRichard Henderson     } else {
3908741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3909c301f34eSRichard Henderson         if (ctx->iaoq_b == -1) {
3910c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3911c301f34eSRichard Henderson         }
3912a0180973SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
3913c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, new_spc);
39148340f534SRichard Henderson         nullify_set(ctx, a->n);
3915c301f34eSRichard Henderson     }
3916c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
391731234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
391831234768SRichard Henderson     return nullify_end(ctx);
3919c301f34eSRichard Henderson #endif
392098cd9ca7SRichard Henderson }
392198cd9ca7SRichard Henderson 
39228340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a)
392398cd9ca7SRichard Henderson {
39242644f80bSRichard Henderson     return do_dbranch(ctx, a->disp, a->l, a->n);
392598cd9ca7SRichard Henderson }
392698cd9ca7SRichard Henderson 
39278340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
392843e05652SRichard Henderson {
3929c53e401eSRichard Henderson     uint64_t dest = iaoq_dest(ctx, a->disp);
393043e05652SRichard Henderson 
39316e5f5300SSven Schnelle     nullify_over(ctx);
39326e5f5300SSven Schnelle 
393343e05652SRichard Henderson     /* Make sure the caller hasn't done something weird with the queue.
393443e05652SRichard Henderson      * ??? This is not quite the same as the PSW[B] bit, which would be
393543e05652SRichard Henderson      * expensive to track.  Real hardware will trap for
393643e05652SRichard Henderson      *    b  gateway
393743e05652SRichard Henderson      *    b  gateway+4  (in delay slot of first branch)
393843e05652SRichard Henderson      * However, checking for a non-sequential instruction queue *will*
393943e05652SRichard Henderson      * diagnose the security hole
394043e05652SRichard Henderson      *    b  gateway
394143e05652SRichard Henderson      *    b  evil
394243e05652SRichard Henderson      * in which instructions at evil would run with increased privs.
394343e05652SRichard Henderson      */
394443e05652SRichard Henderson     if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) {
394543e05652SRichard Henderson         return gen_illegal(ctx);
394643e05652SRichard Henderson     }
394743e05652SRichard Henderson 
394843e05652SRichard Henderson #ifndef CONFIG_USER_ONLY
394943e05652SRichard Henderson     if (ctx->tb_flags & PSW_C) {
395094956d7bSPhilippe Mathieu-Daudé         int type = hppa_artype_for_page(cpu_env(ctx->cs), ctx->base.pc_next);
395143e05652SRichard Henderson         /* If we could not find a TLB entry, then we need to generate an
395243e05652SRichard Henderson            ITLB miss exception so the kernel will provide it.
395343e05652SRichard Henderson            The resulting TLB fill operation will invalidate this TB and
395443e05652SRichard Henderson            we will re-translate, at which point we *will* be able to find
395543e05652SRichard Henderson            the TLB entry and determine if this is in fact a gateway page.  */
395643e05652SRichard Henderson         if (type < 0) {
395731234768SRichard Henderson             gen_excp(ctx, EXCP_ITLB_MISS);
395831234768SRichard Henderson             return true;
395943e05652SRichard Henderson         }
396043e05652SRichard Henderson         /* No change for non-gateway pages or for priv decrease.  */
396143e05652SRichard Henderson         if (type >= 4 && type - 4 < ctx->privilege) {
39622f48ba7bSRichard Henderson             dest = deposit64(dest, 0, 2, type - 4);
396343e05652SRichard Henderson         }
396443e05652SRichard Henderson     } else {
396543e05652SRichard Henderson         dest &= -4;  /* priv = 0 */
396643e05652SRichard Henderson     }
396743e05652SRichard Henderson #endif
396843e05652SRichard Henderson 
39696e5f5300SSven Schnelle     if (a->l) {
39706fd0c7bcSRichard Henderson         TCGv_i64 tmp = dest_gpr(ctx, a->l);
39716e5f5300SSven Schnelle         if (ctx->privilege < 3) {
39726fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, tmp, -4);
39736e5f5300SSven Schnelle         }
39746fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
39756e5f5300SSven Schnelle         save_gpr(ctx, a->l, tmp);
39766e5f5300SSven Schnelle     }
39776e5f5300SSven Schnelle 
39782644f80bSRichard Henderson     return do_dbranch(ctx, dest - iaoq_dest(ctx, 0), 0, a->n);
397943e05652SRichard Henderson }
398043e05652SRichard Henderson 
39818340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a)
398298cd9ca7SRichard Henderson {
3983b35aec85SRichard Henderson     if (a->x) {
3984aac0f603SRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
39856fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3);
39866fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8);
3987660eefe1SRichard Henderson         /* The computation here never changes privilege level.  */
39888340f534SRichard Henderson         return do_ibranch(ctx, tmp, a->l, a->n);
3989b35aec85SRichard Henderson     } else {
3990b35aec85SRichard Henderson         /* BLR R0,RX is a good way to load PC+8 into RX.  */
39912644f80bSRichard Henderson         return do_dbranch(ctx, 0, a->l, a->n);
3992b35aec85SRichard Henderson     }
399398cd9ca7SRichard Henderson }
399498cd9ca7SRichard Henderson 
39958340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a)
399698cd9ca7SRichard Henderson {
39976fd0c7bcSRichard Henderson     TCGv_i64 dest;
399898cd9ca7SRichard Henderson 
39998340f534SRichard Henderson     if (a->x == 0) {
40008340f534SRichard Henderson         dest = load_gpr(ctx, a->b);
400198cd9ca7SRichard Henderson     } else {
4002aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
40036fd0c7bcSRichard Henderson         tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
40046fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
400598cd9ca7SRichard Henderson     }
4006660eefe1SRichard Henderson     dest = do_ibranch_priv(ctx, dest);
40078340f534SRichard Henderson     return do_ibranch(ctx, dest, 0, a->n);
400898cd9ca7SRichard Henderson }
400998cd9ca7SRichard Henderson 
40108340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a)
401198cd9ca7SRichard Henderson {
40126fd0c7bcSRichard Henderson     TCGv_i64 dest;
401398cd9ca7SRichard Henderson 
4014c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
40158340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
40168340f534SRichard Henderson     return do_ibranch(ctx, dest, a->l, a->n);
4017c301f34eSRichard Henderson #else
4018c301f34eSRichard Henderson     nullify_over(ctx);
40198340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
4020c301f34eSRichard Henderson 
4021741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
4022c301f34eSRichard Henderson     if (ctx->iaoq_b == -1) {
4023c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
4024c301f34eSRichard Henderson     }
4025741322f4SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest);
4026c301f34eSRichard Henderson     tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
40278340f534SRichard Henderson     if (a->l) {
4028741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var);
4029c301f34eSRichard Henderson     }
40308340f534SRichard Henderson     nullify_set(ctx, a->n);
4031c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
403231234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
403331234768SRichard Henderson     return nullify_end(ctx);
4034c301f34eSRichard Henderson #endif
403598cd9ca7SRichard Henderson }
403698cd9ca7SRichard Henderson 
4037a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
4038a8966ba7SRichard Henderson {
4039a8966ba7SRichard Henderson     /* All branch target stack instructions implement as nop. */
4040a8966ba7SRichard Henderson     return ctx->is_pa20;
4041a8966ba7SRichard Henderson }
4042a8966ba7SRichard Henderson 
40431ca74648SRichard Henderson /*
40441ca74648SRichard Henderson  * Float class 0
40451ca74648SRichard Henderson  */
4046ebe9383cSRichard Henderson 
40471ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4048ebe9383cSRichard Henderson {
4049ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
4050ebe9383cSRichard Henderson }
4051ebe9383cSRichard Henderson 
405259f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
405359f8c04bSHelge Deller {
4054a300dad3SRichard Henderson     uint64_t ret;
4055a300dad3SRichard Henderson 
4056c53e401eSRichard Henderson     if (ctx->is_pa20) {
4057a300dad3SRichard Henderson         ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
4058a300dad3SRichard Henderson     } else {
4059a300dad3SRichard Henderson         ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
4060a300dad3SRichard Henderson     }
4061a300dad3SRichard Henderson 
406259f8c04bSHelge Deller     nullify_over(ctx);
4063a300dad3SRichard Henderson     save_frd(0, tcg_constant_i64(ret));
406459f8c04bSHelge Deller     return nullify_end(ctx);
406559f8c04bSHelge Deller }
406659f8c04bSHelge Deller 
40671ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a)
40681ca74648SRichard Henderson {
40691ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f);
40701ca74648SRichard Henderson }
40711ca74648SRichard Henderson 
4072ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4073ebe9383cSRichard Henderson {
4074ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
4075ebe9383cSRichard Henderson }
4076ebe9383cSRichard Henderson 
40771ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a)
40781ca74648SRichard Henderson {
40791ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d);
40801ca74648SRichard Henderson }
40811ca74648SRichard Henderson 
40821ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4083ebe9383cSRichard Henderson {
4084ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
4085ebe9383cSRichard Henderson }
4086ebe9383cSRichard Henderson 
40871ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a)
40881ca74648SRichard Henderson {
40891ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fabs_f);
40901ca74648SRichard Henderson }
40911ca74648SRichard Henderson 
4092ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4093ebe9383cSRichard Henderson {
4094ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
4095ebe9383cSRichard Henderson }
4096ebe9383cSRichard Henderson 
40971ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a)
40981ca74648SRichard Henderson {
40991ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fabs_d);
41001ca74648SRichard Henderson }
41011ca74648SRichard Henderson 
41021ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a)
41031ca74648SRichard Henderson {
41041ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s);
41051ca74648SRichard Henderson }
41061ca74648SRichard Henderson 
41071ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a)
41081ca74648SRichard Henderson {
41091ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d);
41101ca74648SRichard Henderson }
41111ca74648SRichard Henderson 
41121ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a)
41131ca74648SRichard Henderson {
41141ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s);
41151ca74648SRichard Henderson }
41161ca74648SRichard Henderson 
41171ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a)
41181ca74648SRichard Henderson {
41191ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d);
41201ca74648SRichard Henderson }
41211ca74648SRichard Henderson 
41221ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4123ebe9383cSRichard Henderson {
4124ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
4125ebe9383cSRichard Henderson }
4126ebe9383cSRichard Henderson 
41271ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a)
41281ca74648SRichard Henderson {
41291ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fneg_f);
41301ca74648SRichard Henderson }
41311ca74648SRichard Henderson 
4132ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4133ebe9383cSRichard Henderson {
4134ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
4135ebe9383cSRichard Henderson }
4136ebe9383cSRichard Henderson 
41371ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a)
41381ca74648SRichard Henderson {
41391ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fneg_d);
41401ca74648SRichard Henderson }
41411ca74648SRichard Henderson 
41421ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4143ebe9383cSRichard Henderson {
4144ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
4145ebe9383cSRichard Henderson }
4146ebe9383cSRichard Henderson 
41471ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a)
41481ca74648SRichard Henderson {
41491ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f);
41501ca74648SRichard Henderson }
41511ca74648SRichard Henderson 
4152ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4153ebe9383cSRichard Henderson {
4154ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
4155ebe9383cSRichard Henderson }
4156ebe9383cSRichard Henderson 
41571ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a)
41581ca74648SRichard Henderson {
41591ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d);
41601ca74648SRichard Henderson }
41611ca74648SRichard Henderson 
41621ca74648SRichard Henderson /*
41631ca74648SRichard Henderson  * Float class 1
41641ca74648SRichard Henderson  */
41651ca74648SRichard Henderson 
41661ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a)
41671ca74648SRichard Henderson {
41681ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s);
41691ca74648SRichard Henderson }
41701ca74648SRichard Henderson 
41711ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a)
41721ca74648SRichard Henderson {
41731ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d);
41741ca74648SRichard Henderson }
41751ca74648SRichard Henderson 
41761ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a)
41771ca74648SRichard Henderson {
41781ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s);
41791ca74648SRichard Henderson }
41801ca74648SRichard Henderson 
41811ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a)
41821ca74648SRichard Henderson {
41831ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s);
41841ca74648SRichard Henderson }
41851ca74648SRichard Henderson 
41861ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a)
41871ca74648SRichard Henderson {
41881ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d);
41891ca74648SRichard Henderson }
41901ca74648SRichard Henderson 
41911ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a)
41921ca74648SRichard Henderson {
41931ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d);
41941ca74648SRichard Henderson }
41951ca74648SRichard Henderson 
41961ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a)
41971ca74648SRichard Henderson {
41981ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w);
41991ca74648SRichard Henderson }
42001ca74648SRichard Henderson 
42011ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a)
42021ca74648SRichard Henderson {
42031ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w);
42041ca74648SRichard Henderson }
42051ca74648SRichard Henderson 
42061ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a)
42071ca74648SRichard Henderson {
42081ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw);
42091ca74648SRichard Henderson }
42101ca74648SRichard Henderson 
42111ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a)
42121ca74648SRichard Henderson {
42131ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw);
42141ca74648SRichard Henderson }
42151ca74648SRichard Henderson 
42161ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a)
42171ca74648SRichard Henderson {
42181ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w);
42191ca74648SRichard Henderson }
42201ca74648SRichard Henderson 
42211ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a)
42221ca74648SRichard Henderson {
42231ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w);
42241ca74648SRichard Henderson }
42251ca74648SRichard Henderson 
42261ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a)
42271ca74648SRichard Henderson {
42281ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw);
42291ca74648SRichard Henderson }
42301ca74648SRichard Henderson 
42311ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a)
42321ca74648SRichard Henderson {
42331ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw);
42341ca74648SRichard Henderson }
42351ca74648SRichard Henderson 
42361ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a)
42371ca74648SRichard Henderson {
42381ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s);
42391ca74648SRichard Henderson }
42401ca74648SRichard Henderson 
42411ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a)
42421ca74648SRichard Henderson {
42431ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s);
42441ca74648SRichard Henderson }
42451ca74648SRichard Henderson 
42461ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a)
42471ca74648SRichard Henderson {
42481ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d);
42491ca74648SRichard Henderson }
42501ca74648SRichard Henderson 
42511ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a)
42521ca74648SRichard Henderson {
42531ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d);
42541ca74648SRichard Henderson }
42551ca74648SRichard Henderson 
42561ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a)
42571ca74648SRichard Henderson {
42581ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw);
42591ca74648SRichard Henderson }
42601ca74648SRichard Henderson 
42611ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a)
42621ca74648SRichard Henderson {
42631ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw);
42641ca74648SRichard Henderson }
42651ca74648SRichard Henderson 
42661ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a)
42671ca74648SRichard Henderson {
42681ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw);
42691ca74648SRichard Henderson }
42701ca74648SRichard Henderson 
42711ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a)
42721ca74648SRichard Henderson {
42731ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw);
42741ca74648SRichard Henderson }
42751ca74648SRichard Henderson 
42761ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a)
42771ca74648SRichard Henderson {
42781ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw);
42791ca74648SRichard Henderson }
42801ca74648SRichard Henderson 
42811ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a)
42821ca74648SRichard Henderson {
42831ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw);
42841ca74648SRichard Henderson }
42851ca74648SRichard Henderson 
42861ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a)
42871ca74648SRichard Henderson {
42881ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw);
42891ca74648SRichard Henderson }
42901ca74648SRichard Henderson 
42911ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a)
42921ca74648SRichard Henderson {
42931ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw);
42941ca74648SRichard Henderson }
42951ca74648SRichard Henderson 
42961ca74648SRichard Henderson /*
42971ca74648SRichard Henderson  * Float class 2
42981ca74648SRichard Henderson  */
42991ca74648SRichard Henderson 
43001ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a)
4301ebe9383cSRichard Henderson {
4302ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
4303ebe9383cSRichard Henderson 
4304ebe9383cSRichard Henderson     nullify_over(ctx);
4305ebe9383cSRichard Henderson 
43061ca74648SRichard Henderson     ta = load_frw0_i32(a->r1);
43071ca74648SRichard Henderson     tb = load_frw0_i32(a->r2);
430829dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
430929dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4310ebe9383cSRichard Henderson 
4311ad75a51eSRichard Henderson     gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc);
4312ebe9383cSRichard Henderson 
43131ca74648SRichard Henderson     return nullify_end(ctx);
4314ebe9383cSRichard Henderson }
4315ebe9383cSRichard Henderson 
43161ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
4317ebe9383cSRichard Henderson {
4318ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
4319ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
4320ebe9383cSRichard Henderson 
4321ebe9383cSRichard Henderson     nullify_over(ctx);
4322ebe9383cSRichard Henderson 
43231ca74648SRichard Henderson     ta = load_frd0(a->r1);
43241ca74648SRichard Henderson     tb = load_frd0(a->r2);
432529dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
432629dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4327ebe9383cSRichard Henderson 
4328ad75a51eSRichard Henderson     gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc);
4329ebe9383cSRichard Henderson 
433031234768SRichard Henderson     return nullify_end(ctx);
4331ebe9383cSRichard Henderson }
4332ebe9383cSRichard Henderson 
43331ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
4334ebe9383cSRichard Henderson {
43356fd0c7bcSRichard Henderson     TCGv_i64 t;
4336ebe9383cSRichard Henderson 
4337ebe9383cSRichard Henderson     nullify_over(ctx);
4338ebe9383cSRichard Henderson 
4339aac0f603SRichard Henderson     t = tcg_temp_new_i64();
43406fd0c7bcSRichard Henderson     tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
4341ebe9383cSRichard Henderson 
43421ca74648SRichard Henderson     if (a->y == 1) {
4343ebe9383cSRichard Henderson         int mask;
4344ebe9383cSRichard Henderson         bool inv = false;
4345ebe9383cSRichard Henderson 
43461ca74648SRichard Henderson         switch (a->c) {
4347ebe9383cSRichard Henderson         case 0: /* simple */
43486fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, 0x4000000);
4349ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_NE, t);
4350ebe9383cSRichard Henderson             goto done;
4351ebe9383cSRichard Henderson         case 2: /* rej */
4352ebe9383cSRichard Henderson             inv = true;
4353ebe9383cSRichard Henderson             /* fallthru */
4354ebe9383cSRichard Henderson         case 1: /* acc */
4355ebe9383cSRichard Henderson             mask = 0x43ff800;
4356ebe9383cSRichard Henderson             break;
4357ebe9383cSRichard Henderson         case 6: /* rej8 */
4358ebe9383cSRichard Henderson             inv = true;
4359ebe9383cSRichard Henderson             /* fallthru */
4360ebe9383cSRichard Henderson         case 5: /* acc8 */
4361ebe9383cSRichard Henderson             mask = 0x43f8000;
4362ebe9383cSRichard Henderson             break;
4363ebe9383cSRichard Henderson         case 9: /* acc6 */
4364ebe9383cSRichard Henderson             mask = 0x43e0000;
4365ebe9383cSRichard Henderson             break;
4366ebe9383cSRichard Henderson         case 13: /* acc4 */
4367ebe9383cSRichard Henderson             mask = 0x4380000;
4368ebe9383cSRichard Henderson             break;
4369ebe9383cSRichard Henderson         case 17: /* acc2 */
4370ebe9383cSRichard Henderson             mask = 0x4200000;
4371ebe9383cSRichard Henderson             break;
4372ebe9383cSRichard Henderson         default:
43731ca74648SRichard Henderson             gen_illegal(ctx);
43741ca74648SRichard Henderson             return true;
4375ebe9383cSRichard Henderson         }
4376ebe9383cSRichard Henderson         if (inv) {
43776fd0c7bcSRichard Henderson             TCGv_i64 c = tcg_constant_i64(mask);
43786fd0c7bcSRichard Henderson             tcg_gen_or_i64(t, t, c);
4379ebe9383cSRichard Henderson             ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
4380ebe9383cSRichard Henderson         } else {
43816fd0c7bcSRichard Henderson             tcg_gen_andi_i64(t, t, mask);
4382ebe9383cSRichard Henderson             ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
4383ebe9383cSRichard Henderson         }
43841ca74648SRichard Henderson     } else {
43851ca74648SRichard Henderson         unsigned cbit = (a->y ^ 1) - 1;
43861ca74648SRichard Henderson 
43876fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, t, 21 - cbit, 1);
43881ca74648SRichard Henderson         ctx->null_cond = cond_make_0(TCG_COND_NE, t);
43891ca74648SRichard Henderson     }
43901ca74648SRichard Henderson 
4391ebe9383cSRichard Henderson  done:
439231234768SRichard Henderson     return nullify_end(ctx);
4393ebe9383cSRichard Henderson }
4394ebe9383cSRichard Henderson 
43951ca74648SRichard Henderson /*
43961ca74648SRichard Henderson  * Float class 2
43971ca74648SRichard Henderson  */
43981ca74648SRichard Henderson 
43991ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a)
4400ebe9383cSRichard Henderson {
44011ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s);
44021ca74648SRichard Henderson }
44031ca74648SRichard Henderson 
44041ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a)
44051ca74648SRichard Henderson {
44061ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d);
44071ca74648SRichard Henderson }
44081ca74648SRichard Henderson 
44091ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a)
44101ca74648SRichard Henderson {
44111ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s);
44121ca74648SRichard Henderson }
44131ca74648SRichard Henderson 
44141ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a)
44151ca74648SRichard Henderson {
44161ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d);
44171ca74648SRichard Henderson }
44181ca74648SRichard Henderson 
44191ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a)
44201ca74648SRichard Henderson {
44211ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s);
44221ca74648SRichard Henderson }
44231ca74648SRichard Henderson 
44241ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a)
44251ca74648SRichard Henderson {
44261ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d);
44271ca74648SRichard Henderson }
44281ca74648SRichard Henderson 
44291ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a)
44301ca74648SRichard Henderson {
44311ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s);
44321ca74648SRichard Henderson }
44331ca74648SRichard Henderson 
44341ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a)
44351ca74648SRichard Henderson {
44361ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d);
44371ca74648SRichard Henderson }
44381ca74648SRichard Henderson 
44391ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a)
44401ca74648SRichard Henderson {
44411ca74648SRichard Henderson     TCGv_i64 x, y;
4442ebe9383cSRichard Henderson 
4443ebe9383cSRichard Henderson     nullify_over(ctx);
4444ebe9383cSRichard Henderson 
44451ca74648SRichard Henderson     x = load_frw0_i64(a->r1);
44461ca74648SRichard Henderson     y = load_frw0_i64(a->r2);
44471ca74648SRichard Henderson     tcg_gen_mul_i64(x, x, y);
44481ca74648SRichard Henderson     save_frd(a->t, x);
4449ebe9383cSRichard Henderson 
445031234768SRichard Henderson     return nullify_end(ctx);
4451ebe9383cSRichard Henderson }
4452ebe9383cSRichard Henderson 
4453ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
4454ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
4455ebe9383cSRichard Henderson {
4456ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
4457ebe9383cSRichard Henderson }
4458ebe9383cSRichard Henderson 
4459b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4460ebe9383cSRichard Henderson {
4461b1e2af57SRichard Henderson     int tm = fmpyadd_s_reg(a->tm);
4462b1e2af57SRichard Henderson     int ra = fmpyadd_s_reg(a->ra);
4463b1e2af57SRichard Henderson     int ta = fmpyadd_s_reg(a->ta);
4464b1e2af57SRichard Henderson     int rm2 = fmpyadd_s_reg(a->rm2);
4465b1e2af57SRichard Henderson     int rm1 = fmpyadd_s_reg(a->rm1);
4466ebe9383cSRichard Henderson 
4467ebe9383cSRichard Henderson     nullify_over(ctx);
4468ebe9383cSRichard Henderson 
4469ebe9383cSRichard Henderson     do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4470ebe9383cSRichard Henderson     do_fop_weww(ctx, ta, ta, ra,
4471ebe9383cSRichard Henderson                 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
4472ebe9383cSRichard Henderson 
447331234768SRichard Henderson     return nullify_end(ctx);
4474ebe9383cSRichard Henderson }
4475ebe9383cSRichard Henderson 
4476b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4477b1e2af57SRichard Henderson {
4478b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, false);
4479b1e2af57SRichard Henderson }
4480b1e2af57SRichard Henderson 
4481b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4482b1e2af57SRichard Henderson {
4483b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, true);
4484b1e2af57SRichard Henderson }
4485b1e2af57SRichard Henderson 
4486b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4487b1e2af57SRichard Henderson {
4488b1e2af57SRichard Henderson     nullify_over(ctx);
4489b1e2af57SRichard Henderson 
4490b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4491b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4492b1e2af57SRichard Henderson                 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4493b1e2af57SRichard Henderson 
4494b1e2af57SRichard Henderson     return nullify_end(ctx);
4495b1e2af57SRichard Henderson }
4496b1e2af57SRichard Henderson 
4497b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4498b1e2af57SRichard Henderson {
4499b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, false);
4500b1e2af57SRichard Henderson }
4501b1e2af57SRichard Henderson 
4502b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4503b1e2af57SRichard Henderson {
4504b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, true);
4505b1e2af57SRichard Henderson }
4506b1e2af57SRichard Henderson 
4507c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a)
4508ebe9383cSRichard Henderson {
4509c3bad4f8SRichard Henderson     TCGv_i32 x, y, z;
4510ebe9383cSRichard Henderson 
4511ebe9383cSRichard Henderson     nullify_over(ctx);
4512c3bad4f8SRichard Henderson     x = load_frw0_i32(a->rm1);
4513c3bad4f8SRichard Henderson     y = load_frw0_i32(a->rm2);
4514c3bad4f8SRichard Henderson     z = load_frw0_i32(a->ra3);
4515ebe9383cSRichard Henderson 
4516c3bad4f8SRichard Henderson     if (a->neg) {
4517ad75a51eSRichard Henderson         gen_helper_fmpynfadd_s(x, tcg_env, x, y, z);
4518ebe9383cSRichard Henderson     } else {
4519ad75a51eSRichard Henderson         gen_helper_fmpyfadd_s(x, tcg_env, x, y, z);
4520ebe9383cSRichard Henderson     }
4521ebe9383cSRichard Henderson 
4522c3bad4f8SRichard Henderson     save_frw_i32(a->t, x);
452331234768SRichard Henderson     return nullify_end(ctx);
4524ebe9383cSRichard Henderson }
4525ebe9383cSRichard Henderson 
4526c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
4527ebe9383cSRichard Henderson {
4528c3bad4f8SRichard Henderson     TCGv_i64 x, y, z;
4529ebe9383cSRichard Henderson 
4530ebe9383cSRichard Henderson     nullify_over(ctx);
4531c3bad4f8SRichard Henderson     x = load_frd0(a->rm1);
4532c3bad4f8SRichard Henderson     y = load_frd0(a->rm2);
4533c3bad4f8SRichard Henderson     z = load_frd0(a->ra3);
4534ebe9383cSRichard Henderson 
4535c3bad4f8SRichard Henderson     if (a->neg) {
4536ad75a51eSRichard Henderson         gen_helper_fmpynfadd_d(x, tcg_env, x, y, z);
4537ebe9383cSRichard Henderson     } else {
4538ad75a51eSRichard Henderson         gen_helper_fmpyfadd_d(x, tcg_env, x, y, z);
4539ebe9383cSRichard Henderson     }
4540ebe9383cSRichard Henderson 
4541c3bad4f8SRichard Henderson     save_frd(a->t, x);
454231234768SRichard Henderson     return nullify_end(ctx);
4543ebe9383cSRichard Henderson }
4544ebe9383cSRichard Henderson 
454538193127SRichard Henderson /* Emulate PDC BTLB, called by SeaBIOS-hppa */
454638193127SRichard Henderson static bool trans_diag_btlb(DisasContext *ctx, arg_diag_btlb *a)
454715da177bSSven Schnelle {
4548cf6b28d4SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4549cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY
4550ad75a51eSRichard Henderson     nullify_over(ctx);
4551ad75a51eSRichard Henderson     gen_helper_diag_btlb(tcg_env);
4552cf6b28d4SHelge Deller     return nullify_end(ctx);
455338193127SRichard Henderson #endif
455415da177bSSven Schnelle }
455538193127SRichard Henderson 
455638193127SRichard Henderson /* Print char in %r26 to first serial console, used by SeaBIOS-hppa */
455738193127SRichard Henderson static bool trans_diag_cout(DisasContext *ctx, arg_diag_cout *a)
455838193127SRichard Henderson {
455938193127SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
456038193127SRichard Henderson #ifndef CONFIG_USER_ONLY
4561dbca0835SHelge Deller     nullify_over(ctx);
4562dbca0835SHelge Deller     gen_helper_diag_console_output(tcg_env);
4563dbca0835SHelge Deller     return nullify_end(ctx);
4564ad75a51eSRichard Henderson #endif
456538193127SRichard Henderson }
456638193127SRichard Henderson 
45673bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa1(DisasContext *ctx, arg_empty *a)
45683bdf2081SHelge Deller {
45693bdf2081SHelge Deller     return !ctx->is_pa20 && do_getshadowregs(ctx);
45703bdf2081SHelge Deller }
45713bdf2081SHelge Deller 
45723bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa2(DisasContext *ctx, arg_empty *a)
45733bdf2081SHelge Deller {
45743bdf2081SHelge Deller     return ctx->is_pa20 && do_getshadowregs(ctx);
45753bdf2081SHelge Deller }
45763bdf2081SHelge Deller 
45773bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa1(DisasContext *ctx, arg_empty *a)
45783bdf2081SHelge Deller {
45793bdf2081SHelge Deller     return !ctx->is_pa20 && do_putshadowregs(ctx);
45803bdf2081SHelge Deller }
45813bdf2081SHelge Deller 
45823bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa2(DisasContext *ctx, arg_empty *a)
45833bdf2081SHelge Deller {
45843bdf2081SHelge Deller     return ctx->is_pa20 && do_putshadowregs(ctx);
45853bdf2081SHelge Deller }
45863bdf2081SHelge Deller 
458738193127SRichard Henderson static bool trans_diag_unimp(DisasContext *ctx, arg_diag_unimp *a)
458838193127SRichard Henderson {
458938193127SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4590ad75a51eSRichard Henderson     qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i);
4591ad75a51eSRichard Henderson     return true;
4592ad75a51eSRichard Henderson }
459315da177bSSven Schnelle 
4594b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
459561766fe9SRichard Henderson {
459651b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4597f764718dSRichard Henderson     int bound;
459861766fe9SRichard Henderson 
459951b061fbSRichard Henderson     ctx->cs = cs;
4600494737b7SRichard Henderson     ctx->tb_flags = ctx->base.tb->flags;
4601bd6243a3SRichard Henderson     ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
46023d68ee7bSRichard Henderson 
46033d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY
4604c01e5dfbSHelge Deller     ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX);
46053d68ee7bSRichard Henderson     ctx->mmu_idx = MMU_USER_IDX;
4606c01e5dfbSHelge Deller     ctx->iaoq_f = ctx->base.pc_first | ctx->privilege;
4607c01e5dfbSHelge Deller     ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege;
4608217d1a5eSRichard Henderson     ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
4609c301f34eSRichard Henderson #else
4610494737b7SRichard Henderson     ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
4611bb67ec32SRichard Henderson     ctx->mmu_idx = (ctx->tb_flags & PSW_D
4612bb67ec32SRichard Henderson                     ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
4613451d993dSRichard Henderson                     : ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX);
46143d68ee7bSRichard Henderson 
4615c301f34eSRichard Henderson     /* Recover the IAOQ values from the GVA + PRIV.  */
4616c301f34eSRichard Henderson     uint64_t cs_base = ctx->base.tb->cs_base;
4617c301f34eSRichard Henderson     uint64_t iasq_f = cs_base & ~0xffffffffull;
4618c301f34eSRichard Henderson     int32_t diff = cs_base;
4619c301f34eSRichard Henderson 
4620c301f34eSRichard Henderson     ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
4621c301f34eSRichard Henderson     ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1);
4622c301f34eSRichard Henderson #endif
462351b061fbSRichard Henderson     ctx->iaoq_n = -1;
4624f764718dSRichard Henderson     ctx->iaoq_n_var = NULL;
462561766fe9SRichard Henderson 
4626a4db4a78SRichard Henderson     ctx->zero = tcg_constant_i64(0);
4627a4db4a78SRichard Henderson 
46283d68ee7bSRichard Henderson     /* Bound the number of instructions by those left on the page.  */
46293d68ee7bSRichard Henderson     bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
4630b542683dSEmilio G. Cota     ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
463161766fe9SRichard Henderson }
463261766fe9SRichard Henderson 
463351b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
463451b061fbSRichard Henderson {
463551b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
463661766fe9SRichard Henderson 
46373d68ee7bSRichard Henderson     /* Seed the nullification status from PSW[N], as saved in TB->FLAGS.  */
463851b061fbSRichard Henderson     ctx->null_cond = cond_make_f();
463951b061fbSRichard Henderson     ctx->psw_n_nonzero = false;
4640494737b7SRichard Henderson     if (ctx->tb_flags & PSW_N) {
464151b061fbSRichard Henderson         ctx->null_cond.c = TCG_COND_ALWAYS;
464251b061fbSRichard Henderson         ctx->psw_n_nonzero = true;
4643129e9cc3SRichard Henderson     }
464451b061fbSRichard Henderson     ctx->null_lab = NULL;
464561766fe9SRichard Henderson }
464661766fe9SRichard Henderson 
464751b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
464851b061fbSRichard Henderson {
464951b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
465051b061fbSRichard Henderson 
4651f5b5c857SRichard Henderson     tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b, 0);
465224638bd1SRichard Henderson     ctx->insn_start_updated = false;
465351b061fbSRichard Henderson }
465451b061fbSRichard Henderson 
465551b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
465651b061fbSRichard Henderson {
465751b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4658b77af26eSRichard Henderson     CPUHPPAState *env = cpu_env(cs);
465951b061fbSRichard Henderson     DisasJumpType ret;
466051b061fbSRichard Henderson 
466151b061fbSRichard Henderson     /* Execute one insn.  */
4662ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4663c301f34eSRichard Henderson     if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
466431234768SRichard Henderson         do_page_zero(ctx);
466531234768SRichard Henderson         ret = ctx->base.is_jmp;
4666869051eaSRichard Henderson         assert(ret != DISAS_NEXT);
4667ba1d0b44SRichard Henderson     } else
4668ba1d0b44SRichard Henderson #endif
4669ba1d0b44SRichard Henderson     {
467061766fe9SRichard Henderson         /* Always fetch the insn, even if nullified, so that we check
467161766fe9SRichard Henderson            the page permissions for execute.  */
46724e116893SIlya Leoshkevich         uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next);
467361766fe9SRichard Henderson 
467461766fe9SRichard Henderson         /* Set up the IA queue for the next insn.
467561766fe9SRichard Henderson            This will be overwritten by a branch.  */
467651b061fbSRichard Henderson         if (ctx->iaoq_b == -1) {
467751b061fbSRichard Henderson             ctx->iaoq_n = -1;
4678aac0f603SRichard Henderson             ctx->iaoq_n_var = tcg_temp_new_i64();
46796fd0c7bcSRichard Henderson             tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
468061766fe9SRichard Henderson         } else {
468151b061fbSRichard Henderson             ctx->iaoq_n = ctx->iaoq_b + 4;
4682f764718dSRichard Henderson             ctx->iaoq_n_var = NULL;
468361766fe9SRichard Henderson         }
468461766fe9SRichard Henderson 
468551b061fbSRichard Henderson         if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
468651b061fbSRichard Henderson             ctx->null_cond.c = TCG_COND_NEVER;
4687869051eaSRichard Henderson             ret = DISAS_NEXT;
4688129e9cc3SRichard Henderson         } else {
46891a19da0dSRichard Henderson             ctx->insn = insn;
469031274b46SRichard Henderson             if (!decode(ctx, insn)) {
469131274b46SRichard Henderson                 gen_illegal(ctx);
469231274b46SRichard Henderson             }
469331234768SRichard Henderson             ret = ctx->base.is_jmp;
469451b061fbSRichard Henderson             assert(ctx->null_lab == NULL);
4695129e9cc3SRichard Henderson         }
469661766fe9SRichard Henderson     }
469761766fe9SRichard Henderson 
46983d68ee7bSRichard Henderson     /* Advance the insn queue.  Note that this check also detects
46993d68ee7bSRichard Henderson        a priority change within the instruction queue.  */
470051b061fbSRichard Henderson     if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
47014e31e68bSRichard Henderson         if (use_goto_tb(ctx, ctx->iaoq_b, ctx->iaoq_n)
4702c301f34eSRichard Henderson             && (ctx->null_cond.c == TCG_COND_NEVER
4703c301f34eSRichard Henderson                 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
470451b061fbSRichard Henderson             nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
470551b061fbSRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
470631234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_NORETURN;
4707129e9cc3SRichard Henderson         } else {
470831234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE;
470961766fe9SRichard Henderson         }
4710129e9cc3SRichard Henderson     }
471151b061fbSRichard Henderson     ctx->iaoq_f = ctx->iaoq_b;
471251b061fbSRichard Henderson     ctx->iaoq_b = ctx->iaoq_n;
4713c301f34eSRichard Henderson     ctx->base.pc_next += 4;
471461766fe9SRichard Henderson 
4715c5d0aec2SRichard Henderson     switch (ret) {
4716c5d0aec2SRichard Henderson     case DISAS_NORETURN:
4717c5d0aec2SRichard Henderson     case DISAS_IAQ_N_UPDATED:
4718c5d0aec2SRichard Henderson         break;
4719c5d0aec2SRichard Henderson 
4720c5d0aec2SRichard Henderson     case DISAS_NEXT:
4721c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE:
4722c5d0aec2SRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
472351b061fbSRichard Henderson         if (ctx->iaoq_f == -1) {
4724a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b);
4725741322f4SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
4726c301f34eSRichard Henderson #ifndef CONFIG_USER_ONLY
4727c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
4728c301f34eSRichard Henderson #endif
472951b061fbSRichard Henderson             nullify_save(ctx);
4730c5d0aec2SRichard Henderson             ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT
4731c5d0aec2SRichard Henderson                                 ? DISAS_EXIT
4732c5d0aec2SRichard Henderson                                 : DISAS_IAQ_N_UPDATED);
473351b061fbSRichard Henderson         } else if (ctx->iaoq_b == -1) {
4734a0180973SRichard Henderson             copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var);
473561766fe9SRichard Henderson         }
4736c5d0aec2SRichard Henderson         break;
4737c5d0aec2SRichard Henderson 
4738c5d0aec2SRichard Henderson     default:
4739c5d0aec2SRichard Henderson         g_assert_not_reached();
4740c5d0aec2SRichard Henderson     }
474161766fe9SRichard Henderson }
474261766fe9SRichard Henderson 
474351b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
474451b061fbSRichard Henderson {
474551b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4746e1b5a5edSRichard Henderson     DisasJumpType is_jmp = ctx->base.is_jmp;
474751b061fbSRichard Henderson 
4748e1b5a5edSRichard Henderson     switch (is_jmp) {
4749869051eaSRichard Henderson     case DISAS_NORETURN:
475061766fe9SRichard Henderson         break;
475151b061fbSRichard Henderson     case DISAS_TOO_MANY:
4752869051eaSRichard Henderson     case DISAS_IAQ_N_STALE:
4753e1b5a5edSRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
4754741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
4755741322f4SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
475651b061fbSRichard Henderson         nullify_save(ctx);
475761766fe9SRichard Henderson         /* FALLTHRU */
4758869051eaSRichard Henderson     case DISAS_IAQ_N_UPDATED:
47598532a14eSRichard Henderson         if (is_jmp != DISAS_IAQ_N_STALE_EXIT) {
47607f11636dSEmilio G. Cota             tcg_gen_lookup_and_goto_ptr();
47618532a14eSRichard Henderson             break;
476261766fe9SRichard Henderson         }
4763c5d0aec2SRichard Henderson         /* FALLTHRU */
4764c5d0aec2SRichard Henderson     case DISAS_EXIT:
4765c5d0aec2SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
476661766fe9SRichard Henderson         break;
476761766fe9SRichard Henderson     default:
476851b061fbSRichard Henderson         g_assert_not_reached();
476961766fe9SRichard Henderson     }
477051b061fbSRichard Henderson }
477161766fe9SRichard Henderson 
47728eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase,
47738eb806a7SRichard Henderson                               CPUState *cs, FILE *logfile)
477451b061fbSRichard Henderson {
4775c301f34eSRichard Henderson     target_ulong pc = dcbase->pc_first;
477661766fe9SRichard Henderson 
4777ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4778ba1d0b44SRichard Henderson     switch (pc) {
47797ad439dfSRichard Henderson     case 0x00:
47808eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000000:  (null)\n");
4781ba1d0b44SRichard Henderson         return;
47827ad439dfSRichard Henderson     case 0xb0:
47838eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000b0:  light-weight-syscall\n");
4784ba1d0b44SRichard Henderson         return;
47857ad439dfSRichard Henderson     case 0xe0:
47868eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000e0:  set-thread-pointer-syscall\n");
4787ba1d0b44SRichard Henderson         return;
47887ad439dfSRichard Henderson     case 0x100:
47898eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000100:  syscall\n");
4790ba1d0b44SRichard Henderson         return;
47917ad439dfSRichard Henderson     }
4792ba1d0b44SRichard Henderson #endif
4793ba1d0b44SRichard Henderson 
47948eb806a7SRichard Henderson     fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
47958eb806a7SRichard Henderson     target_disas(logfile, cs, pc, dcbase->tb->size);
479661766fe9SRichard Henderson }
479751b061fbSRichard Henderson 
479851b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = {
479951b061fbSRichard Henderson     .init_disas_context = hppa_tr_init_disas_context,
480051b061fbSRichard Henderson     .tb_start           = hppa_tr_tb_start,
480151b061fbSRichard Henderson     .insn_start         = hppa_tr_insn_start,
480251b061fbSRichard Henderson     .translate_insn     = hppa_tr_translate_insn,
480351b061fbSRichard Henderson     .tb_stop            = hppa_tr_tb_stop,
480451b061fbSRichard Henderson     .disas_log          = hppa_tr_disas_log,
480551b061fbSRichard Henderson };
480651b061fbSRichard Henderson 
4807597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
480832f0c394SAnton Johansson                            vaddr pc, void *host_pc)
480951b061fbSRichard Henderson {
481051b061fbSRichard Henderson     DisasContext ctx;
4811306c8721SRichard Henderson     translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
481261766fe9SRichard Henderson }
4813